Skip to content

Commit 40d12b6

Browse files
authored
Merge pull request #7380 from remi-delmas-3000/contracts-fix-havoc-codegen
CONTRACTS: Fix conditional havoc code
2 parents 742f4ce + 6b2a4ee commit 40d12b6

File tree

6 files changed

+75
-3
lines changed

6 files changed

+75
-3
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#include <stdlib.h>
2+
3+
void foo(int *out)
4+
// clang-format off
5+
__CPROVER_requires(out ==> __CPROVER_is_fresh(out, sizeof(*out)))
6+
__CPROVER_assigns(out: *out)
7+
__CPROVER_ensures(out ==> *out == 1)
8+
// clang-format on
9+
{
10+
if(out)
11+
*out = 1;
12+
}
13+
14+
int nondet_int();
15+
16+
void main()
17+
{
18+
int *out;
19+
foo(out);
20+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
CORE
2+
check-foo.c
3+
--dfcc main --enforce-contract foo _ --pointer-check
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
--
9+
This test checks conditional havocs are behaving as expected.
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#include <stdlib.h>
2+
3+
void foo(int *out)
4+
// clang-format off
5+
__CPROVER_requires(out ==> __CPROVER_is_fresh(out, sizeof(*out)))
6+
__CPROVER_assigns(out: *out)
7+
__CPROVER_ensures(out ==> *out == 1)
8+
// clang-format on
9+
{
10+
if(out)
11+
*out = 1;
12+
}
13+
14+
int nondet_int();
15+
16+
void bar()
17+
{
18+
int i = 0;
19+
int *out = nondet_int() ? &i : NULL;
20+
foo(out);
21+
// clang-format off
22+
__CPROVER_assert(!out ==> (i == 0), "out not null implies initial value");
23+
__CPROVER_assert(out ==> (i == 1), "out null implies updated value");
24+
// clang-format on
25+
}
26+
27+
int main(void)
28+
{
29+
bar();
30+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
CORE
2+
replace-foo.c
3+
--dfcc main --enforce-contract bar --replace-call-with-contract foo _ --pointer-check
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
--
9+
This test checks conditional havocs are behaving as expected.

src/ansi-c/library/cprover_contracts.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1290,6 +1290,10 @@ void *__CPROVER_contracts_write_set_havoc_get_assignable_target(
12901290
__CPROVER_size_t idx)
12911291
{
12921292
__CPROVER_HIDE:;
1293+
#ifdef DFCC_DEBUG
1294+
__CPROVER_assert(write_set != 0, "write_set not NULL");
1295+
#endif
1296+
12931297
__CPROVER_contracts_car_t car = set->contract_assigns.elems[idx];
12941298
if(car.is_writable)
12951299
return car.lb;

src/goto-instrument/contracts/dynamic-frames/dfcc_spec_functions.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -200,10 +200,9 @@ void dfcc_spec_functionst::generate_havoc_function(
200200
// Use same source location as original call
201201
source_locationt location(ins_it->source_location());
202202
auto hook = hook_opt.value();
203-
auto write_set_var = write_set_symbol.symbol_expr();
204203
code_function_callt call(
205204
library.dfcc_fun_symbol.at(hook).symbol_expr(),
206-
{write_set_var, from_integer(next_idx, size_type())});
205+
{write_set_symbol.symbol_expr(), from_integer(next_idx, size_type())});
207206

208207
if(hook == dfcc_funt::WRITE_SET_HAVOC_GET_ASSIGNABLE_TARGET)
209208
{
@@ -233,7 +232,8 @@ void dfcc_spec_functionst::generate_havoc_function(
233232
body.add(goto_programt::make_function_call(call, location));
234233

235234
auto goto_instruction = body.add(goto_programt::make_incomplete_goto(
236-
utils.make_null_check_expr(write_set_var)));
235+
utils.make_null_check_expr(target_expr), location));
236+
237237
// create nondet assignment to the target
238238
side_effect_expr_nondett nondet(target_type, location);
239239
body.add(goto_programt::make_assignment(

0 commit comments

Comments
 (0)