-
Notifications
You must be signed in to change notification settings - Fork 283
Fix reachability slicer when used with recursive or unreachable functions #2748
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
@smowton Would you mind taking a look, and possibly check it for regressions on your end? |
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.
Does true, unknown, false really mean much here? I'd suggest using an enum (also documented) to indicate what we're doing
82f2b1e
to
de1d3de
Compare
@smowton Updated in line with the suggestions you had made yesterday - thank you! |
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, some nitpicks
{ | ||
slicer_entryt() : reaches_assertion(false), reachable_from_assertion(false) | ||
slicer_entryt() | ||
: reaches_assertion(dfs_statust::NOT_SEEN), |
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.
reaches_assertion doesn't seem like a great name anymore? Maybe just state
?
} | ||
|
||
bool reaches_assertion; | ||
/// The status of each node during backwards depth-first traversal: |
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.
How about
/// The status of each node during backwards depth-first traversal:
/// A functions starts out NOT_SEEN, is raised to BODY_SEEN if we have
/// seen a call to this function but know where it was called from (at this point
/// we mark the function and anything reachable from it), then may finally be
/// raised to BODY_AND_CALLERS_SEEN if we don't know what function
/// calls this function, and therefore mark all of its callers as well.
Oh one more thing, how convinced are you this problem is restricted to backwards operation? In forwards mode I might similarly call |
Is there a way to reduce these to well-known, standard graph problems? And then use standard algorithms for the graph problem? |
Or maybe problems on pushdown machines? |
Say use something like the bebop algorithm? |
de1d3de
to
25ea7b3
Compare
Since this is a soundness bug, which gives the user no indication that they have hit a bug, could this fix please be merged? And an issue created to investigate using the bebop algorithm, and to check that the forward reachability slicer doesn't have the same bug? (I tried to create a similar example for the forward reachability slicer and couldn't recreate it, but that doens't necessarily mean it's fixed. I don't understand what the use case is for the forward reachability slicer though so I might be missing something). |
@polgreen : I don't know this part of the code super well but am happy to approve it. However, right now we can't merge it as there are CI failures. One of them is clang-format, which can easily be fixed by someone, the other is a cmake failure which I /think/ might be transitory. |
I can take a look |
@smowton : appreciated. |
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: 25ea7b3).
Build URL: https://travis-ci.com/diffblue/test-gen/builds/87740471
CI fixed. I'm pretty sure the forwards slicer is vulnerable to the same mistake, but have also failed to come up with an example so far. It's tricky because when a function has different callers they're visited in arbitrary order. Solution-wise, thinking about it more, it would surely suffice to make sure all-callers nodes are visited before known-caller ones, since in the former case we do strictly more work. Therefore we could just maintain the working set sorted (partitioned, really) by the caller-is-known flag. Equivalently, split the visit routines into one that visits outwards (the all-callers variant) and one that visits inwards (the known-caller variant), which would look like this (and does fix the test case attached to this PR): smowton@ca85bb1 My preference order:
In any case we should surely include the forward walker -- even if we're wrong and it just happens to be (currently) impossible to break it, the new version would be more robust (if we go for options 1 or 3) and also clearer (if we go for option 2). |
Also I don't have the right to change this code anyhow -- @peterschrammel @chrisr-diffblue @kroening you're once again the relevant owners, what do you think? |
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 changes look reasonable, so I'm approving but with the caveat that I don't really know this code that well, so I'd rather someone better versed in it than myself clicks the final merge button :-)
@tautschnig any opinion on whether to go with the approach in smowton@ca85bb1 or just merge this? Effectively that approach is specialising the walk-backwards function to the |
Merged #3218 instead |
No description provided.