Skip to content

Commit 379705f

Browse files
committed
Process array_equal the same way as array_{replace,copy}
array_equal was handled as a special snowflake in both goto-program conversion and symbolic execution. This simplifies the code and removes a sharing-unaware pass that ran over all expressions. This commit is only refactoring, no behavioural changes expected. This commit also moves a regression test from cbmc-from-CVS to the cbmc folder, and extends it to cover array_replace.
1 parent c62b957 commit 379705f

File tree

8 files changed

+126
-119
lines changed

8 files changed

+126
-119
lines changed

regression/cbmc-from-CVS/Array_operations1/main.c

-37
This file was deleted.

regression/cbmc-from-CVS/Array_operations1/test.desc

-8
This file was deleted.
+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
void test_equal()
2+
{
3+
char array1[100], array2[100];
4+
_Bool cmp;
5+
int index;
6+
7+
cmp = __CPROVER_array_equal(array1, array2);
8+
9+
__CPROVER_assume(index >= 0 && index < 100);
10+
__CPROVER_assume(cmp);
11+
12+
__CPROVER_assert(array1[index] == array2[index], "arrays are equal");
13+
}
14+
15+
void test_copy()
16+
{
17+
char array1[100], array2[100], array3[90];
18+
19+
array2[10] = 11;
20+
array3[10] = 11;
21+
array2[99] = 42;
22+
__CPROVER_array_copy(array1, array2);
23+
24+
__CPROVER_assert(array1[10] == 11, "array1[10] is OK");
25+
__CPROVER_assert(array1[99] == 42, "array1[99] is OK");
26+
27+
__CPROVER_array_copy(array1, array3);
28+
__CPROVER_assert(array1[10] == 11, "array1[10] is OK");
29+
__CPROVER_assert(array1[99] == 42, "expected to fail");
30+
}
31+
32+
void test_replace()
33+
{
34+
char array1[100], array2[90];
35+
36+
array1[99] = 42;
37+
array2[10] = 11;
38+
__CPROVER_array_replace(array1, array2);
39+
40+
__CPROVER_assert(array1[10] == 11, "array1[10] is OK");
41+
__CPROVER_assert(array1[99] == 42, "array1[99] is OK");
42+
}
43+
44+
void test_set()
45+
{
46+
char array1[100];
47+
__CPROVER_array_set(array1, 111);
48+
__CPROVER_assert(array1[44] == 111, "array1[44] is OK");
49+
}
50+
51+
int main()
52+
{
53+
test_equal();
54+
test_copy();
55+
test_replace();
56+
test_set();
57+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CORE
2+
main.c
3+
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
^\[test_copy\.assertion\.4\] expected to fail: FAILURE$
7+
^\*\* 1 of 8 failed
8+
^VERIFICATION FAILED$
9+
--
10+
^warning: ignoring

src/goto-programs/builtin_functions.cpp

+6-45
Original file line numberDiff line numberDiff line change
@@ -839,51 +839,12 @@ void goto_convertt::do_array_op(
839839
array_op_statement.operands()=arguments;
840840
array_op_statement.add_source_location()=function.source_location();
841841

842-
copy(array_op_statement, OTHER, dest);
843-
}
844-
845-
void goto_convertt::do_array_equal(
846-
const exprt &lhs,
847-
const exprt &function,
848-
const exprt::operandst &arguments,
849-
goto_programt &dest)
850-
{
851-
if(arguments.size()!=2)
852-
{
853-
error().source_location=function.find_source_location();
854-
error() << "array_equal expects two arguments" << eom;
855-
throw 0;
856-
}
857-
858-
const typet &arg0_type=ns.follow(arguments[0].type());
859-
const typet &arg1_type=ns.follow(arguments[1].type());
842+
// lhs is only used with array_equal, in all other cases it should be nil (as
843+
// they are of type void)
844+
if(id == ID_array_equal)
845+
array_op_statement.copy_to_operands(lhs);
860846

861-
if(arg0_type.id()!=ID_pointer ||
862-
arg1_type.id()!=ID_pointer)
863-
{
864-
error().source_location=function.find_source_location();
865-
error() << "array_equal expects pointer arguments" << eom;
866-
throw 0;
867-
}
868-
869-
if(lhs.is_not_nil())
870-
{
871-
code_assignt assignment;
872-
873-
// add dereferencing here
874-
dereference_exprt lhs_array, rhs_array;
875-
lhs_array.op0()=arguments[0];
876-
rhs_array.op0()=arguments[1];
877-
lhs_array.type()=arg0_type.subtype();
878-
rhs_array.type()=arg1_type.subtype();
879-
880-
assignment.lhs()=lhs;
881-
assignment.rhs()=binary_exprt(
882-
lhs_array, ID_array_equal, rhs_array, lhs.type());
883-
assignment.add_source_location()=function.source_location();
884-
885-
convert(assignment, dest);
886-
}
847+
copy(array_op_statement, OTHER, dest);
887848
}
888849

889850
bool is_lvalue(const exprt &expr)
@@ -1214,7 +1175,7 @@ void goto_convertt::do_function_call_symbol(
12141175
}
12151176
else if(identifier==CPROVER_PREFIX "array_equal")
12161177
{
1217-
do_array_equal(lhs, function, arguments, dest);
1178+
do_array_op(ID_array_equal, lhs, function, arguments, dest);
12181179
}
12191180
else if(identifier==CPROVER_PREFIX "array_set")
12201181
{

src/goto-symex/goto_symex.h

+1-2
Original file line numberDiff line numberDiff line change
@@ -245,11 +245,10 @@ class goto_symext
245245
// this does the following:
246246
// a) rename non-det choices
247247
// b) remove pointer dereferencing
248-
// c) rewrite array_equal expression into equality
248+
// c) clean up byte_extract on the lhs of an assignment
249249
void clean_expr(
250250
exprt &, statet &, bool write);
251251

252-
void replace_array_equal(exprt &);
253252
void trigger_auto_object(const exprt &, statet &);
254253
void initialize_auto_object(const exprt &, statet &);
255254
void process_array_expr(exprt &);

src/goto-symex/symex_clean_expr.cpp

-27
Original file line numberDiff line numberDiff line change
@@ -143,31 +143,6 @@ void goto_symext::process_array_expr(exprt &expr)
143143
process_array_expr(*it);
144144
}
145145

146-
void goto_symext::replace_array_equal(exprt &expr)
147-
{
148-
if(expr.id()==ID_array_equal)
149-
{
150-
assert(expr.operands().size()==2);
151-
152-
// we expect two index expressions
153-
process_array_expr(expr.op0());
154-
process_array_expr(expr.op1());
155-
156-
// type checking
157-
if(ns.follow(expr.op0().type())!=
158-
ns.follow(expr.op1().type()))
159-
expr=false_exprt();
160-
else
161-
{
162-
equal_exprt equality_expr(expr.op0(), expr.op1());
163-
expr.swap(equality_expr);
164-
}
165-
}
166-
167-
Forall_operands(it, expr)
168-
replace_array_equal(*it);
169-
}
170-
171146
/// Rewrite index/member expressions in byte_extract to offset
172147
static void adjust_byte_extract_rec(exprt &expr, const namespacet &ns)
173148
{
@@ -203,6 +178,4 @@ void goto_symext::clean_expr(
203178
// lhs
204179
if(write)
205180
adjust_byte_extract_rec(expr, ns);
206-
207-
replace_array_equal(expr);
208181
}

src/goto-symex/symex_other.cpp

+52
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ Author: Daniel Kroening, [email protected]
1414
#include <cassert>
1515

1616
#include <util/arith_tools.h>
17+
#include <util/invariant.h>
1718
#include <util/rename.h>
1819
#include <util/base_type.h>
1920
#include <util/std_expr.h>
@@ -259,6 +260,57 @@ void goto_symext::symex_other(
259260
assignment.rhs()=array_of_exprt(clean_code.op1(), array_type);
260261
symex_assign(state, assignment);
261262
}
263+
else if(statement==ID_array_equal)
264+
{
265+
DATA_INVARIANT(
266+
code.operands().size() == 3,
267+
"array_equal expected to take three arguments");
268+
269+
codet clean_code(code);
270+
271+
// we need to add dereferencing for the first two operands
272+
dereference_exprt d0, d1;
273+
d0.op0()=code.op0();
274+
d0.type()=empty_typet();
275+
d1.op0()=code.op1();
276+
d1.type()=empty_typet();
277+
278+
clean_code.op0()=d0;
279+
clean_code.op1()=d1;
280+
281+
clean_expr(clean_code.op0(), state, false);
282+
exprt op0_offset=from_integer(0, index_type());
283+
if(clean_code.op0().id()==byte_extract_id() &&
284+
clean_code.op0().type().id()==ID_empty)
285+
{
286+
op0_offset=to_byte_extract_expr(clean_code.op0()).offset();
287+
clean_code.op0()=clean_code.op0().op0();
288+
}
289+
clean_expr(clean_code.op1(), state, false);
290+
exprt op1_offset=from_integer(0, index_type());
291+
if(clean_code.op1().id()==byte_extract_id() &&
292+
clean_code.op1().type().id()==ID_empty)
293+
{
294+
op1_offset=to_byte_extract_expr(clean_code.op1()).offset();
295+
clean_code.op1()=clean_code.op1().op0();
296+
}
297+
298+
process_array_expr(clean_code.op0());
299+
clean_expr(clean_code.op0(), state, false);
300+
process_array_expr(clean_code.op1());
301+
clean_expr(clean_code.op1(), state, false);
302+
303+
if(!base_type_eq(clean_code.op0().type(),
304+
clean_code.op1().type(), ns))
305+
{
306+
clean_code.op2() = false_exprt();
307+
}
308+
309+
code_assignt assignment(
310+
clean_code.op2(),
311+
equal_exprt(clean_code.op0(), clean_code.op1()));
312+
symex_assign(state, assignment);
313+
}
262314
else if(statement==ID_user_specified_predicate ||
263315
statement==ID_user_specified_parameter_predicates ||
264316
statement==ID_user_specified_return_predicates)

0 commit comments

Comments
 (0)