-
Notifications
You must be signed in to change notification settings - Fork 273
Document and refactor goto check #4611
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
Conversation
src/analyses/goto_check.cpp
Outdated
throw msg; | ||
} | ||
INVARIANT( | ||
!if_expr.cond().is_boolean(), |
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.
Should have been negated: sorry. Will be fixed.
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.
This does need cleanup as indicated in the comments, but is overall a good refactoring.
src/analyses/goto_check.cpp
Outdated
@@ -102,6 +102,8 @@ class goto_checkt | |||
/// operands (or their negations) for recursively calls) | |||
void check_rec_logical_op(const exprt &expr, guardt &guard); | |||
|
|||
void check_rec_if(const exprt &expr, guardt &guard); |
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 think this should just take an if_exprt
instead of doing the check within the method.
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.
Done.
src/analyses/goto_check.cpp
Outdated
@@ -110,6 +110,8 @@ class goto_checkt | |||
/// the) if-condition for recursively calls) | |||
void check_rec_if(const exprt &expr, guardt &guard); | |||
|
|||
void check_rec_member(const exprt &expr, guardt &guard); |
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.
Should just take a member_exprt
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.
Done.
src/analyses/goto_check.cpp
Outdated
guard.add(not_exprt(op)); | ||
else | ||
guard.add(op); | ||
guard.add(expr.id() == ID_or ? not_exprt(op) : op); |
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.
If you are touching this, I'd suggest to use boolean_negate(op)
instead of not_exprt(op)
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.
Done.
src/analyses/goto_check.cpp
Outdated
return; | ||
} | ||
check_rec_member(expr, guard); | ||
return; |
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.
This return
doesn't seem correct to me. I think you should remove it, and also remove the final forall_operands
from check_rec_member
.
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.
The return is there only to prevent the forall_operands
loop in case the check_rec_member
was existed via an explicit return
. But it seems to be only an optimisation so I did what you asked for.
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 take it back. Avoiding the recursive call on the member expression operands may be just an optimisation but one of our regression tests (Malloc23
) requires exactly 4 failing assertions. If we change this section so that the recursion is always called, this test fails.
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.
Which ... might be a bugfix? Does it generate more assertions or is it missing some?
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.
Doesn't seem so:
struct A
{
int x;
int y;
};
int main()
{
struct A *p=malloc(sizeof(int));
p->x=0; // OK
p->y=0; // out of bounds
..
Unless we skip the recursive call, we would generate a pointer check for p->ok=0
which, on it's own, would fail.
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.
But still the behaviour before and after isn't the same: previously, we only returned in some cases, now we always return early.
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.
Yes, but since I included the recursive call on sub-expressions in rec_check_member
the only thing we skip by returning early is the remaining case analyses none of which can succeed (since we know that expr.id()==ID_member
).
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.
Fair enough, I was just a bit worried that one day someone would add a case. But I suppose testing (or rather: failing tests) should catch that. So it seems fine as is.
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 thought about it a bit and tried having the check_rec_member
return a Boolean indicating if the subsequent analysis should be attempted or not: d6f7f05.
src/analyses/goto_check.cpp
Outdated
/// NaN (for floating point numbers). | ||
/// \param expr: the expression to be checked | ||
/// \param guard: the condition for the check (unmodified here) | ||
void check_rec_div(const exprt &expr, guardt &guard); |
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.
Should take a div_exprt
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.
Done.
src/analyses/goto_check.cpp
Outdated
guarded_expr = implies_exprt(guard.as_expr(), std::move(simplified_expr)); | ||
exprt guarded_expr = | ||
guard.is_true() | ||
? simplified_expr |
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.
std::move(simplified_expr)
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.
Done.
enable_assert_to_assume ? goto_programt::make_assumption( | ||
std::move(guarded_expr), source_location) | ||
: goto_programt::make_assertion( | ||
std::move(guarded_expr), source_location)); |
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.
There is another instance of this pattern (around line 1800) - just search for "ASSUME". Could you please fix this as well?
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.
Added.
it=next; | ||
it = assertions.erase(it); | ||
else | ||
++it; | ||
} |
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.
What about using std::remove_if
(until we can use erase_if
with C++20)?
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.
Unfortunately, std::remove_if
requires the iterator to be MoveAssignable
. Will have to wait for this one.
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.
Ah, ok, too bad.
91b9614
to
5289c58
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.
lgtm modulo squashing promised
src/analyses/goto_check.cpp
Outdated
/// \param source_location: the source location of the original expression | ||
/// \param src_expr: the original expression to be included in the comment | ||
/// \param guard: the condition under which the asserted expression should be | ||
/// taken into account | ||
void add_guarded_claim( |
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.
While we are here, can we rename claim
to property
since we have replaced that terminology in other places in the codebase?
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.
Done.
src/analyses/goto_check.cpp
Outdated
@@ -194,6 +199,10 @@ class goto_checkt | |||
typedef std::set<exprt> assertionst; | |||
assertionst assertions; | |||
|
|||
/// Remove all assertions containing they symbol in \p lhs as well as all |
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.
they -> the
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.
Done.
d6f7f05
to
aa16fd6
Compare
from check_rec into stand-alone function. Getting rid of the flag.
Using the checks inside to_expr methods.
into a stand-alone function.
Using invariants instead of exceptions.
into add_guarded_property.
Using invariants, to-conversion and a bit of clang-formatting.
Only clang-format, inline expr-construction, and for-each loop.
Into check_rec_div and check_rec_arithmetic_op.
Using the initializer-list constructor for sets and and standard idiom for erase_if.
instead of instructiont constructor.
to negate boolean expression and to get address_of expression.
to collect_allocations, check_rec, and check.
for the bits we touched in this PR.
d62fe0a
to
b5060ee
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.
This PR failed Diffblue compatibility checks (cbmc commit: d62fe0a).
Build URL: https://travis-ci.com/diffblue/test-gen/builds/112345526
Status will be re-evaluated on next push.
Common spurious failures include: the cbmc commit has disappeared in the mean time (e.g. in a force-push); the author is not in the list of contributors (e.g. first-time contributors); compatibility was already broken by an earlier merge.
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.
✔️
Passed Diffblue compatibility checks (cbmc commit: b5060ee).
Build URL: https://travis-ci.com/diffblue/test-gen/builds/112346598
If you go commit-by-commit it's not so horrible. There is not functional change only a bit of rewording.