Skip to content

Commit 691e9fb

Browse files
author
Daniel Kroening
authored
Merge pull request #1449 from diffblue/havoc_object
added __CPROVER_havoc(...)
2 parents 1614c2c + beac327 commit 691e9fb

File tree

7 files changed

+138
-0
lines changed

7 files changed

+138
-0
lines changed

regression/cbmc/havoc_object1/main.c

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
int main()
2+
{
3+
int i=0;
4+
__CPROVER_havoc_object(&i);
5+
__CPROVER_assert(i==0, "i==0"); // should fail
6+
7+
int array[10];
8+
for(i=0; i<10; i++) array[i]=i;
9+
10+
__CPROVER_havoc_object(array);
11+
__CPROVER_assert(array[3]==3, "array[3]"); // should fail
12+
13+
struct { int i, j; } some_struct = { 1, 2 };
14+
__CPROVER_havoc_object(&some_struct.j);
15+
__CPROVER_assert(some_struct.i==1, "struct i"); // should fail
16+
__CPROVER_assert(some_struct.j==2, "struct j"); // should fail
17+
18+
// now conditional
19+
_Bool c;
20+
int *p=c?&i:&some_struct.i;
21+
i=20;
22+
some_struct.i=30;
23+
__CPROVER_havoc_object(p);
24+
if(c)
25+
{
26+
__CPROVER_assert(i==20, "i==20 (A)"); // should fail
27+
__CPROVER_assert(some_struct.i==30, "some_struct.i==30 (A)"); // should pass
28+
}
29+
else
30+
{
31+
__CPROVER_assert(i==20, "i==20 (B)"); // should pass
32+
__CPROVER_assert(some_struct.i==30, "some_struct.i==30 (B)"); // should fail
33+
}
34+
}
+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
main.c
3+
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
^VERIFICATION FAILED$
7+
^\*\* 6 of 8 failed.*$
8+
--

src/ansi-c/ansi_c_internal_additions.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ void ansi_c_internal_additions(std::string &code)
114114
"void __CPROVER_assert(__CPROVER_bool assertion, const char *description);\n"
115115
// NOLINTNEXTLINE(whitespace/line_length)
116116
"void __CPROVER_precondition(__CPROVER_bool precondition, const char *description);\n"
117+
"void __CPROVER_havoc_object(void *);\n"
117118
"__CPROVER_bool __CPROVER_equal();\n"
118119
"__CPROVER_bool __CPROVER_same_object(const void *, const void *);\n"
119120
"__CPROVER_bool __CPROVER_invalid_pointer(const void *);\n"

src/goto-programs/builtin_functions.cpp

+23
Original file line numberDiff line numberDiff line change
@@ -1159,6 +1159,29 @@ void goto_convertt::do_function_call_symbol(
11591159
throw 0;
11601160
}
11611161
}
1162+
else if(identifier==CPROVER_PREFIX "havoc_object")
1163+
{
1164+
if(arguments.size()!=1)
1165+
{
1166+
error().source_location=function.find_source_location();
1167+
error() << "`" << identifier << "' expected to have one argument"
1168+
<< eom;
1169+
throw 0;
1170+
}
1171+
1172+
if(lhs.is_not_nil())
1173+
{
1174+
error().source_location=function.find_source_location();
1175+
error() << identifier << " expected not to have LHS" << eom;
1176+
throw 0;
1177+
}
1178+
1179+
goto_programt::targett t=dest.add_instruction(OTHER);
1180+
t->source_location=function.source_location();
1181+
t->code=codet(ID_havoc_object);
1182+
t->code.add_source_location()=function.source_location();
1183+
t->code.copy_to_operands(arguments[0]);
1184+
}
11621185
else if(identifier==CPROVER_PREFIX "printf")
11631186
{
11641187
do_printf(lhs, function, arguments, dest);

src/goto-symex/goto_symex.h

+3
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,9 @@ class goto_symext
262262
void symex_assign_rec(statet &state, const code_assignt &code);
263263
virtual void symex_assign(statet &state, const code_assignt &code);
264264

265+
// havocs the given object
266+
void havoc_rec(statet &, const guardt &, const exprt &);
267+
265268
typedef symex_targett::assignment_typet assignment_typet;
266269

267270
void symex_assign_rec(

src/goto-symex/symex_other.cpp

+68
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,67 @@ Author: Daniel Kroening, [email protected]
1717
#include <util/rename.h>
1818
#include <util/base_type.h>
1919
#include <util/std_expr.h>
20+
#include <util/std_code.h>
2021
#include <util/byte_operators.h>
2122

2223
#include <util/c_types.h>
2324

25+
void goto_symext::havoc_rec(
26+
statet &state,
27+
const guardt &guard,
28+
const exprt &dest)
29+
{
30+
if(dest.id()==ID_symbol)
31+
{
32+
exprt lhs;
33+
34+
if(guard.is_true())
35+
lhs=dest;
36+
else
37+
lhs=if_exprt(
38+
guard.as_expr(), dest, exprt("NULL-object", dest.type()));
39+
40+
code_assignt assignment;
41+
assignment.lhs()=lhs;
42+
assignment.rhs()=side_effect_expr_nondett(dest.type());
43+
44+
symex_assign(state, assignment);
45+
}
46+
else if(dest.id()==ID_byte_extract_little_endian ||
47+
dest.id()==ID_byte_extract_big_endian)
48+
{
49+
havoc_rec(state, guard, to_byte_extract_expr(dest).op());
50+
}
51+
else if(dest.id()==ID_if)
52+
{
53+
const if_exprt &if_expr=to_if_expr(dest);
54+
55+
guardt guard_t=state.guard;
56+
guard_t.add(if_expr.cond());
57+
havoc_rec(state, guard_t, if_expr.true_case());
58+
59+
guardt guard_f=state.guard;
60+
guard_f.add(not_exprt(if_expr.cond()));
61+
havoc_rec(state, guard_f, if_expr.false_case());
62+
}
63+
else if(dest.id()==ID_typecast)
64+
{
65+
havoc_rec(state, guard, to_typecast_expr(dest).op());
66+
}
67+
else if(dest.id()==ID_index)
68+
{
69+
havoc_rec(state, guard, to_index_expr(dest).array());
70+
}
71+
else if(dest.id()==ID_member)
72+
{
73+
havoc_rec(state, guard, to_member_expr(dest).struct_op());
74+
}
75+
else
76+
{
77+
// consider printing a warning
78+
}
79+
}
80+
2481
void goto_symext::symex_other(
2582
const goto_functionst &goto_functions,
2683
statet &state)
@@ -213,6 +270,17 @@ void goto_symext::symex_other(
213270
{
214271
target.memory_barrier(state.guard.as_expr(), state.source);
215272
}
273+
else if(statement==ID_havoc_object)
274+
{
275+
DATA_INVARIANT(code.operands().size()==1,
276+
"havoc_object must have one operand");
277+
278+
// we need to add dereferencing for the first operand
279+
exprt object=dereference_exprt(code.op0(), empty_typet());
280+
clean_expr(object, state, true);
281+
282+
havoc_rec(state, guardt(), object);
283+
}
216284
else
217285
throw "unexpected statement: "+id2string(statement);
218286
}

src/util/irep_ids.def

+1
Original file line numberDiff line numberDiff line change
@@ -830,6 +830,7 @@ IREP_ID_TWO(C_java_generic_type, #java_generic_type)
830830
IREP_ID_TWO(C_java_generics_class_type, #java_generics_class_type)
831831
IREP_ID_TWO(generic_types, #generic_types)
832832
IREP_ID_TWO(type_variables, #type_variables)
833+
IREP_ID_ONE(havoc_object)
833834

834835
#undef IREP_ID_ONE
835836
#undef IREP_ID_TWO

0 commit comments

Comments
 (0)