-
Notifications
You must be signed in to change notification settings - Fork 274
Fix side-effect check on loop invariants #5942
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
#include <assert.h> | ||
#include <stdlib.h> | ||
|
||
int main() | ||
{ | ||
unsigned N, *a = malloc(sizeof(unsigned int)); | ||
|
||
*a = 0; | ||
while(*a < N) | ||
__CPROVER_loop_invariant((0 <= *a) && (*a <= N)) | ||
{ | ||
++(*a); | ||
} | ||
|
||
assert(*a == N); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
CORE | ||
main.c | ||
--enforce-all-contracts | ||
^EXIT=0$ | ||
^SIGNAL=0$ | ||
^\[main.1\] .* Check loop invariant before entry: SUCCESS$ | ||
^\[main.2\] .* Check that loop invariant is preserved: SUCCESS$ | ||
^\[main.assertion.1\] .* assertion \*a == N: SUCCESS$ | ||
^VERIFICATION SUCCESSFUL$ | ||
-- | ||
This test checks that C expressions are correctly converted to logic | ||
when enforcing loop invariant annotations. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -868,13 +868,11 @@ void goto_convertt::convert_loop_invariant( | |
if(invariant.is_nil()) | ||
return; | ||
|
||
goto_programt no_sideeffects; | ||
clean_expr(invariant, no_sideeffects, mode); | ||
|
||
INVARIANT_WITH_DIAGNOSTICS( | ||
no_sideeffects.instructions.empty(), | ||
"loop invariant is not side-effect free", | ||
code.find_source_location()); | ||
if(has_subexpr(invariant, ID_side_effect)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As I recall, this was the really contentious part last time around. This seems much less disruptive. I think throwing the exception is correct because the user can trigger this even if the tool is non-buggy. I wonder if it would be more user-friendly to check this earlier but ... I guess we need to check it here as well. I wonder if this might still be a bit too conservative but, if it works for you then fine. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thank you, yes earlier I had removed this part entirely and was doing some checking in
I completely agree with you. And it's on our roadmap to allow function calls within contracts, if those functions have an empty assigns clause (so no side effects). |
||
{ | ||
throw incorrect_goto_program_exceptiont( | ||
"Loop invariant is not side-effect free.", code.find_source_location()); | ||
} | ||
|
||
PRECONDITION(loop->is_goto()); | ||
loop->guard.add(ID_C_spec_loop_invariant).swap(invariant); | ||
|
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.
Wouldn't forward declarations do the trick?
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.
Sorry, resolved this comment by mistake without addressing it.
I
#include
d this header file for theloopt
type, which istypedef
ed as:Could I forward declare it here somehow? I wasn't sure how to.
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 believe one of
typename loopt;
orclass loopt;
might still work, and likely the compiler will telly you if it doesn't :-) Not high priority, though.