-
Notifications
You must be signed in to change notification settings - Fork 267
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[CONTRACTS] Check side effect of loop contracts during instrumentation #8360
[CONTRACTS] Check side effect of loop contracts during instrumentation #8360
Conversation
521d2e3
to
9e93193
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Allowing arbitrary side_effect_exprt
allows things like __CPROVER_is_fresh
and __CPROVER_r_ok
to be used in the loop invariant. Since __CPROVER_r_ok
might not work as expected in assumption contexts, and since the semantics if __CPROVER_is_fresh
is only well defined in the context of requires and ensures clauses relative to some call site, we still may want to ban them for now.
Also if when using DFCC, all functions of the model are extended with a write set parameter, and any function called in the loop invariant must be passed either a write set pointer, either NULL (in which case no checks will be done) or a valid pointer to some write set (and checks will be performed).
But we should try to actually check for side effects semantically using DFCC and an empty write set.
We already do it for preconditions and postconditions in function contracts
see here
You can declare and build the write set in PREFIX program
// PREFIX
DECL ws : write_set_t ;
DECL ws_ptr : write_set_t* ;
ASSIGN ws_ptr = &ws;
CALL write_set_create(
ws_ptr,
assigns_size = 0,
frees_size = 0,
replacement_mode = false, ... );
Then you goto-convert the invariant clause and instrument the resulting program snippet against the empty write set:
// will contain the invariant evaluation
goto_programt loop_inv_prog;
converter.goto_convert(loop_inv, loop_inv_prog, language_mode);
// fix calls to memory predicates like `__CPROVER_is_fresh`
memory_predicates.fix_calls(loop_inv_prog);
loop_inv_prog.add(goto_programt::make_end_function());
instrument.instrument_goto_program(
prog_id,
loop_inv_prog,
ws_ptr, // symbol that represents the empty loop invariant write set
function_pointer_contracts);
// turn it back into a sequence of statements
requires_program.instructions.back().turn_into_skip();
Then generate a SUFFIX program that checks that evaluating the invariant did not allocate of free any memory, release the write set :
// SUFFIX
DECL __check_no_alloc: bool;
// checks that evaluating the invariant did not use malloc or free
CALL __check_no_alloc = check_empty_alloc_dealloc(requilres_write_set);
ASSERT __check_no_alloc;
DEAD __check_no_alloc: bool;
CALL write_set_release(ws_ptr); // releases resources used by the write set.
DEAD ws_ptr;
DEAD ws;
Finally concatenate the PREFIX, invariant evaluation program and SUFFIX, and insert the into the program at the base case and step case locations.
This will ensure that the invariant expression has no side effects, and since it uses the global DFCC instrumentation system, it will also work if the side_effect_exprt
of the invariant is a call to a function that also calls other functions, etc.
regression/contracts-dfcc/loop_contracts_statement_expression/test.desc
Outdated
Show resolved
Hide resolved
Thank you @remi-delmas-3000 ! Yes, I think it is really good idea to apply the dfcc side-effect checks here. |
9e93193
to
b84880e
Compare
3c28e4a
to
3666698
Compare
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## develop #8360 +/- ##
===========================================
- Coverage 78.34% 78.25% -0.10%
===========================================
Files 1726 1726
Lines 188437 188696 +259
Branches 18244 18252 +8
===========================================
+ Hits 147638 147663 +25
- Misses 40799 41033 +234 ☔ View full report in Codecov by Sentry. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One minor optional comment about option naming.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm ok with this other than as indicated in the comment below, provided that there will be follow-up work that will make this option completely unnecessary and we instead check for which side effects we genuinely cannot tolerate.
regression/contracts-dfcc/loop_contracts_statement_expression/main.c
Outdated
Show resolved
Hide resolved
regression/contracts/loop_contracts_statement_expression/main.c
Outdated
Show resolved
Hide resolved
3666698
to
198117d
Compare
198117d
to
57511d6
Compare
57511d6
to
2d416e1
Compare
Now, CBMC check side effect of loop contracts in
goto_convertt
by rejecting allside_effect_exprt
. However, we might want to accept side-effect loop contracts and remove the side effect during instrumentation, or acceptside_effect_exprt
which is actually side-effect free (see the added regression test of this PR as an example).This PR postpone the check of side effect of loop contracts from code converting to the actual instrumentation time. It also provide a new options to disable the side-effect check.
This PR include the commit from #8359. The regression test added in this PR also test #8359 (introducing new symbols) and #8282 (containing a GOTO jump in the loop invariant).