-
Notifications
You must be signed in to change notification settings - Fork 273
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
Control dependency computation fix #1858
Conversation
Can you explain in more detail what you are doing here? What bug are you fixing here? Also, this seems to be a fairly significant change in the code - is this also a significant change in behavior, or did you combine your bug fix with a refactoring? |
The PR does three things: (1) It fixes a bug in the control dependency computation. Previously in We use the following definition of control dependencies: A node N is control dependent on a node M iff N postdominates one but not all of M's CFG successors. Consider the following example:
Lines 6 and 8 do not have a control dependency on line 3, line 10 does have a control dependency on line 3. However, the previous implementation missed the latter dependency. The reason is that when computing the control dependencies at a node (e.g., line 10), only the control dependencies at the CFG predecessors (in this case lines 6 and 8) were considered candidates for the control dependencies. This PR introduces a new set (2) It fixes an issue where This PR introduces a flag (3) It simplifies the merging of the abstract states. |
It would be helpful to have these as separate commits (or even PRs) to make it easier to review. For 3), does this PR help to address that/make it worse: #1843 In any case, could you have use |
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 don't fully understand the definition of the control dependency so going to pause reviewing. How come in your example line 6 doesn't have control dependency on line 3? My reading of your definition led me to,
3 -> 5 -> 6 -> 10 (postdominates one)
3 -> 5 -> 7 -> 8 -> 10 (doesn't postdominate them all)
@@ -0,0 +1,9 @@ | |||
CORE | |||
main.c | |||
--show --dependence-graph --text - |
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's with the dash at the 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.
--text
takes an argument which is the file to print to, -
means print to stdout
.
activate-multi-line-match | ||
EXIT=0 | ||
SIGNAL=0 | ||
Control dependencies: .\n\s*\n.*\n\s*g_out = 1; |
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've not looked a the output of --dependence-graph
, but what does the presence of this line signify? Should you be checking t=1
is not present?
Consider converting this to a unit test so you can be more precise.
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.
It checks that there is a control dependency (the previous version wrongly reported no control dependency). It does however not check that the control dependency is to the correct instruction. This seems not to be possible easily in regression tests as control dependencies are reported as location numbers which are not stable across different systems.
I'll add a unit test for this.
src/analyses/dependence_graph.cpp
Outdated
|
||
depst::iterator it=control_deps.begin(); | ||
for(const auto &c_dep : src.control_deps) | ||
if((has_values.is_false() || has_changed) && |
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.
has_changed already includes the case that has_values.is_false()
? I this is just has_changed && data_deps.empty()
src/analyses/dependence_graph.cpp
Outdated
} | ||
} | ||
|
||
bool dep_graph_domaint::merge_control_dependencies( | ||
const depst &other_control_deps, |
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.
To reduce the cognitive load, it would be great if all deps
could be renamed to dependencies
src/analyses/dependence_graph.cpp
Outdated
|
||
// Merge control dependencies | ||
|
||
size_t n=control_deps.size(); |
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.
Perhaps n
could be original_control_deps_size
src/analyses/dependence_graph.cpp
Outdated
|
||
// Merge control dependency candidates | ||
|
||
n=control_dep_candidates.size(); |
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.
And this n
could be original_control_dep_candidate_size
src/analyses/dependence_graph.cpp
Outdated
@@ -189,37 +214,42 @@ void dep_graph_domaint::transform( | |||
ai_baset &ai, | |||
const namespacet &ns) | |||
{ | |||
INVARIANT(!has_values.is_false(), |
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.
PRECONDITION
probably makes more sense here
src/analyses/dependence_graph.cpp
Outdated
|
||
// propagate control dependencies across function calls | ||
if(from->is_function_call()) | ||
{ | ||
if(from->function == to->function) | ||
goto_programt::const_targett next=from; |
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.
const goto_programt::const_targett next=std::next(from);
src/analyses/dependence_graph.cpp
Outdated
dep_graph_domaint *s= | ||
dynamic_cast<dep_graph_domaint*>(&(dep_graph->get_state(next))); | ||
assert(s!=nullptr); |
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.
Why is this assert no longer required?
src/analyses/dependence_graph.cpp
Outdated
pd.cfg.entry_map.find(*it); | ||
|
||
assert(e!=pd.cfg.entry_map.end()); | ||
pd.cfg.entry_map.find(cd); |
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.
Is this assertion no longer true?
|
||
return l->function; | ||
} | ||
|
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.
Didn't we just remove this 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.
Indeed 5df3fca removes this method. It seems that since by f443b18 cbmc does not do partial inlining anymore, the function field of an instruction is now guaranteed to contain the id of the function it is in. I'll remove the method again.
(In goto-instrument there are still a few cases where the function field is not adjusted when the inliner is called explicitely, but we can fix this in the future.)
I'm tempted to be lazy and say +1 "what @thk123" said. Separate commits would be great. The brilliant explanations here : #1858 (comment) as commit messages would be even better. |
@thk123 Line 6 does not have a control dependency on line 3 as it does not postdominate a CFG successor of line 3 (i.e., |
I'll split the PR up into several commits. |
df7fccb
to
4ea0d7a
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.
Main problem here: this absolutely cries out for a reasonably-thorough batch of test cases, since this is the 3rd slicer correctness fix to be PR'd in the last 6 months.
src/analyses/dependence_graph.cpp
Outdated
} | ||
else if(it!=data_deps.end()) | ||
++it; | ||
data_deps = src.data_deps; |
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.
Explain why when our own data deps are non-empty, we don't use src's data deps at 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.
We wouldn't actually need a fixpoint computation for the data dependency analysis as it merely uses the result of the prior reaching definitions analysis to compute the data dependencies at each location. For this we need to inspect each location only once. Thus if the set data_deps
is non-empty it means we have handled that location already.
That's one reason why it may be good to split up the data dependency and control dependency analysis (see issue #1859), and then implement the data dependency analysis without ait
by simply iterating over all instructions.
src/analyses/dependence_graph.cpp
Outdated
// The "successor" above refers to an immediate successor of M. | ||
|
||
// Candidates for M for "to" are "from" and all existing control | ||
// dependencies on nodes. "from" is added if it is a goto or assume |
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.
"all existing control dependencies on nodes" is less clear than the original phrasing I think. How about "all nodes X such that N is control-dependent on X"
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 just realized that this comment is not accurate anymore in the fixed version. Now we consider all control statements in the current function from which there is a path to the current statement (i.e., to
) as potential sources of control dependency edges. I'll add a comment to explain this.
src/analyses/dependence_graph.cpp
Outdated
|
||
// check all CFG successors | ||
for(const auto &cd : control_dep_candidates) |
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 bit is just cleanup for clarity and not a substantial change? If so, if not already, move it into a different commit than the substantial change.
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 set control_dep_candidates
was introduced in the fix so this is new code.
src/analyses/dependence_graph.cpp
Outdated
|
||
size_t n = control_deps.size(); | ||
|
||
control_deps.insert(other_control_deps.begin(), other_control_deps.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.
It seems a shame to degrade the previous more-efficient algorithm that makes a single walk over the target set into this one that makes |other_control_deps| searches from the root. If it bothers you that the old algorithm is less clear, how about factoring it into a util called union_ordered_range
or something?
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.
Indeed. I assumed that it would implement the same algorithm if both ranges are sorted but it's not the case. I'll add a union_ordered_range
utility function.
@smowton I'll add some more dependence graph tests. |
34df547
to
ceb9cdb
Compare
ceb9cdb
to
e243267
Compare
e243267
to
7e0dbf1
Compare
@smowton, @thk123, @martin-cs: CI is passing and I've addressed all the comments. I think this is now ready to be merged. |
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.
Changes and commits look good.
Some requests for docs
I am not familiar enough with this to work out if the tests are correct - though it would be easier to check them if there was a comment at the bottom of the desc
decoding the regex to see what is expected
src/util/container_utils.h
Outdated
#define CPROVER_UTIL_CONTAINER_UTILS_H | ||
|
||
template <class C> | ||
bool union_ordered_range(C &target, const C &source) |
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.
Document please
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.
In particular any requirements on what C can be (e.g. iterable, ordered?)
src/analyses/dependence_graph.h
Outdated
@@ -162,7 +162,9 @@ class dep_graph_domaint:public ai_domain_baset | |||
node_indext node_id; | |||
|
|||
typedef std::set<goto_programt::const_targett> depst; | |||
depst control_deps, data_deps; | |||
depst control_deps; | |||
depst control_dep_candidates; |
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.
It would be good to document here what the difference between a control dependency and a control dependency candidate is
src/analyses/dependence_graph.cpp
Outdated
|
||
// check all CFG successors | ||
for(const auto &cd : control_dep_candidates) |
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.
Expand cd
(and possibly call it control_dep_candidate
since it is a candidate not a control dependency(?? - I don't really know the difference)
src/analyses/dependence_graph.cpp
Outdated
|
||
assert(e!=pd.cfg.entry_map.end()); | ||
INVARIANT( | ||
e != pd.cfg.entry_map.end(), "cfg has an entry for every 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.
The wording for this invariant is a little confusing - do you mean cfg should have an entry for every location?
@@ -27,19 +27,20 @@ bool dep_graph_domaint::merge( | |||
goto_programt::const_targett from, |
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.
Nit: this commit message (Fix issue where merge() did not return true in the dependence graph w) isn't rendering correctly so I suggest the title is too long. Suggest making the short text:
Make dependency graph merge() return true when abstract state changes
I think that is short enough
src/analyses/dependence_graph.cpp
Outdated
{ | ||
has_values = tvt::unknown(); | ||
data_deps = src.data_deps; |
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.
Suggest something like the above comment goes into the code as this is entirely non-obvious!
It also might be clear to do:
if(changed)
{
// ...
// comment explaining why not if data_deps in non-empty
if(!data_deps.empty())
{
data_deps = src.data_deps;
}
}
@thk123 By adding a comment to the desc file which decodes the regex, do you mean adding an example (possibly with some placeholders for e.g. location numbers) for the portion of the output that the regex is designed to match? |
Comments can be added after two sets of
Assuming of course I've decoded your regex to approx right thing |
7e0dbf1
to
ad36d5a
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.
Someone with a good understanding of control dependencies should check the tests!
src/analyses/dependence_graph.cpp
Outdated
|
||
assert(e!=pd.cfg.entry_map.end()); | ||
INVARIANT( | ||
e != pd.cfg.entry_map.end(), "cfg has an entry for every 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.
The wording here looks the same, I suggest "cfg must have an entry for every 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.
Ah yes. I thought I'd change it once #2142 is resolved, but I'll rephrase it now with must.
// First assignment has a control dependency on the if | ||
\/\/ ([0-9]+).*\n.*IF.*i < 10.*THEN(.*\n)*Control dependencies: \1\n(.*\n){2,3}.*a = 1 | ||
// Second assignment has a control dependency on the if | ||
\/\/ ([0-9]+).*\n.*IF.*i < 10.*THEN(.*\n)*Control dependencies: \1\n(.*\n){2,3}.*a = 2 |
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's only one IF i < 10
how come it appears here twice with both dependencies?
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.
That's because a = 1
and a = 2
appear in the then and else branches of this if. So the statements in both branches have a control dependency on the goto that decides which branch to take.
-- | ||
^warning: ignoring | ||
-- | ||
The two regexes above match output portions like shown below (with <N> being a |
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 explanation is great, though I was hoping to have both lines laid about explicitly
EXIT=0 | ||
SIGNAL=0 | ||
// Assignment has a control dependency on the if | ||
\/\/ ([0-9]+).*\n.*IF.*a < 10.*THEN(.*\n)*Control dependencies: .*\1.*\n(.*\n){2,3}.*a = 2 |
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.
Why don't we care what has a dependency on a < 7
?
ad36d5a
to
79e6377
Compare
Ok, I've had a chat with @marek-trtik who worked on the slicer recently. He's up for double checking the control dependency regression tests. |
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.
Half done, finish on Tuesday ...
\/\/ ([0-9]+).*\n.*IF.*a < 7.*THEN(.*\n)*Control dependencies: (([0-9]+,\1)|(\1,[0-9]+))\n(.*\n){2,3}.*a = 2 | ||
// Assignment has a control dependency on the second if | ||
\/\/ ([0-9]+).*\n.*IF.*a < 10.*THEN(.*\n)*Control dependencies: (([0-9]+,\1)|(\1,[0-9]+))\n(.*\n){2,3}.*a = 2 | ||
-- |
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.
why checking only for a=2
and not also for a=1
?
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, I can add a check for a = 1
too.
location number). The intention is to check whether the assignment has a control | ||
dependency on the goto statement. | ||
|
||
// <N> file main.c line 7 function main |
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.
line 11
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 test regexes above actually ignore the line numbers and the comments currently just give examples of the kind of output that they would match. But I can change the line numbers in the output examples to match the tests.
**** 3 file main.c line 9 function main | ||
Control dependencies: <N> | ||
|
||
// 3 file main.c line 9 function main |
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.
line 13
**** 3 file main.c line 9 function main | ||
Control dependencies: <N> | ||
|
||
// 3 file main.c line 9 function main |
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.
line 14
EXIT=0 | ||
SIGNAL=0 | ||
\/\/ ([0-9]+) file.*\n.*IF.*g_in1.*THEN GOTO(.*\n)*Control dependencies: \1\n\n.*\n.*g_out = 1 | ||
-- |
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.
Would it be possible to check that neither 10 nor 12 have CD on 7?
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, I'll add a check for that too.
@@ -0,0 +1,16 @@ | |||
int g_in1, g_in2; | |||
int g_out; |
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.
Why global vars and not automatic?
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 no reason for this. The variables do not matter for control dependencies.
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 regression tests look good to me.
**** 4 file main.c line 6 function main | ||
Control dependencies: <N> | ||
|
||
// 4 file main.c line 6 function main |
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 not be here rather line 8 or 9?
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.
It seems that the source location assigned to the back edge of a loop is the source location of the loop head.
location number). The intention is to check whether the assignment has a control | ||
dependency on the if. | ||
|
||
// <N> file main.c line 6 function main |
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.
line 8
**** 3 file main.c line 8 function main | ||
Control dependencies: <N> | ||
|
||
// 3 file main.c line 8 function main |
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.
line 10
dependency on itself. | ||
|
||
Control dependencies: <N> | ||
Data dependencies: 1 |
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.
We focus only on CD. So, this info seams to be redundant/misleading? Remove? 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 dependency graph outputs both the control dependencies and the data dependencies. The regex above ignores the data dependencies actually. But the example here shows the typical output that the dependency graph produces and which would be matched by the above regex.
1f80dfc
to
a811cb3
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.
One nitpick, otherwise lgtm.
src/util/container_utils.h
Outdated
/// \param source second input set | ||
/// \return true iff `target` was changed | ||
template <class T, class Compare, class Alloc> | ||
bool util_set_union( |
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.
Suggest _union_inplace
, since set_union
would usually be a binary op that returns a new set.
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'd suggest
inplace_set_union
as that would be in keeping with the STL'sinplace_merge
. - Any ideas of how much faster this implementation is over:
std::size_t before = target.size();
decltype(target) tmp;
tmp.swap(target);
std::set_union(tmp.begin(), tmp.end(), source.begin(), source.end(), target.end());
return target.size() != before;
? Just curious.
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 just tried this, with std::set<std::size_t>
's, both sets being of equal size, and the sets containing random values. The runtimes (in microseconds) for the unions are as follows (union1 is the version in the PR). The leftmost column gives the sizes of the two sets being merged.
union1 union2
100 39 75
1K 368 698
10K 3,358 6,704
100K 54,455 104,597
1M 592,993 1,208,903
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.
Thank you!! I suppose that memory allocation is the dominating factor, which of course has to be done from scratch when using std::set_union
. So I'd still suggest to rename the function to some variation involving "inplace", and then this PR should just be merged?!
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 am confused by the comment "With this scheme however one misses control dependencies when there are nested if statements." -- are you now computing the transitive closure?
src/util/container_utils.h
Outdated
/// \param source second input set | ||
/// \return true iff `target` was changed | ||
template <class T, class Compare, class Alloc> | ||
bool util_set_union( |
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'd suggest
inplace_set_union
as that would be in keeping with the STL'sinplace_merge
. - Any ideas of how much faster this implementation is over:
std::size_t before = target.size();
decltype(target) tmp;
tmp.swap(target);
std::set_union(tmp.begin(), tmp.end(), source.begin(), source.end(), target.end());
return target.size() != before;
? Just curious.
We're not computing transitive dependencies. It's just that the bug that this PR fixes appeared when there was an if statement (with both an if and an else branch) within another if statement. Then for the code that follows the inner if statement (and is contained within the outer if statement), we would not report a control dependency on the outer if condition (as shown in the example above). |
It's not clear to me whether that should be reported? The control dependency on the outer if is a transitive one, and would be found by looking at the control dependency of the inner if. But maybe I'm misunderstanding. |
In the example above, for line 10 currently no control dependency is reported (neither on line 3 nor on line 5). It's correct that it does not have a control dependency on line 5, but we need to report a control dependency on line 3. As no control dependency is currently reported for line 10, there's no dependency chain that we could follow to know that it depends on line 3. |
Thanks a lot for the clarification! |
Previously in transform() only the control dependencies in the set control_deps (plus gotos and assumes at the from location) were considered candidates for the control dependencies at the to location. With this scheme however one misses control dependencies when there are nested if statements. We introduce a new set control_dep_candidates in addition to control_deps, which contains all control statements encountered so far.
The dependency graph has special handling for function entry edges (in transform()) where it merges the current state into the state of the return location before entering the function. This may change the abstract state at the return location. When later the function exit edge is handled, the merge() into the return location may not change the state, thus merge() may not return true, and thus the return location may not be inserted into the worklist of the fixpoint computation when it should. We introduce a flag has_changed that records whether the abstract state has changed on the handling of the function entry edge. On the function return edge later, merge() checks the flag to know whether it needs to return true.
a811cb3
to
7002909
Compare
31ef182 Merge pull request diffblue#2208 from diffblue/cleanout-goto-programs 0e84d3e Merge pull request diffblue#2195 from smowton/smowton/feature/smarter-reachability-slicer c801126 Merge pull request diffblue#2209 from diffblue/travis-no-osx-g++ 3487bf7 Reachability slicer: mark reachable code more precisely 85e8451 Merge pull request diffblue#2066 from tautschnig/bv-endianness 5e5eafb Merge pull request diffblue#2191 from smowton/smowton/feature/java-fatal-assertions 8a68ab8 remove g++ build on OS X; this is identical to the clang++ build 48e5b25 Amend faulty long-string test 3f718ba Java: make null-pointer and similar checks fatal 821eb1d remove basic_blocks and goto_program_irep d87c2db Merge pull request diffblue#2203 from diffblue/typed-lookup d77dea3 strongly type the lookup() methods in namespacet 2382f27 Merge pull request diffblue#2193 from martin-cs/feature/correct-instruction-documentation c314272 Merge pull request diffblue#2181 from diffblue/format-expr-constants 514a0a5 Merge pull request diffblue#2167 from diffblue/parse_unwindset_options 0102452 move escape(s) to string_utils f1b6174 use unwindsett in goto-instrument dcc907a introduce unwindsett for unwinding limits 10aeae8 format_expr now does index, c_bool constants, string constants 92b92d6 Correct the documentation of ASSERT : it does not alter control flow. a11add8 Expand the documentation of the goto-program instructions. a06503b Merge pull request diffblue#2197 from tautschnig/fix-help 05e4bc3 Remove stray whitespace previously demanded by clang-format 3261f4d Fix help output of --generate-function-body-options 7c67b23 Merge pull request diffblue#2110 from tautschnig/type-mismatch-exception 18fb262 Merge pull request diffblue#2025 from tautschnig/stack-depth-fix 9191b6a Merge pull request diffblue#2199 from tautschnig/simplifier-typing f99e631 Merge pull request diffblue#2198 from tautschnig/fix-test-desc 1a79a11 stack depth instrumentation: __CPROVER_initialize may be empty a7690ba Merge pull request diffblue#2185 from smowton/smowton/fix/tolerate-ts18661-types fc02e8f Restore returns before writing the simplified binary 49333eb Make restore_returns handle simplified programs 46f7987 Fix perl regular expressioons in regression test descriptions 9fe432b Merge pull request diffblue#1899 from danpoe/sharing-map-catch-unit-tests 9cc6aae Merge pull request diffblue#2081 from hannes-steffenhagen-diffblue/floating_point_simplificiation da19abe Tolerate TS 18661 (_Float32 et al) types a055454 Try all rounding modes when domain is unknown 5f7bc15 Add float support to constant propagator domain 3dc2244 Move adjust_float_expressions to goto-programs 06d8bea Merge pull request diffblue#2187 from diffblue/move-convert-nondet 6d8c3fa Merge pull request diffblue#2189 from thk123/bugfix/json-parser-restart 2ad157f Merge pull request diffblue#2186 from smowton/smowton/fix/call-graph-uninit-field cd54ad7 Corrected state persistence in the json parser 4447be0 Fix uninitialised collect_callsites field in call_grapht ead0aa3 Merge pull request diffblue#2188 from smowton/smowton/fix/init-string-types-without-refine-strings 57988fc Fix String type initialisation when --refine-strings is not active 6a76aff Move convert_nondet to java_bytecode ac6eb21 Merge pull request diffblue#1858 from danpoe/dependence-graph-fix 10b8b09 Merge pull request diffblue#2011 from thomasspriggs/final_classes a154593 Merge pull request diffblue#2087 from danpoe/feature/small-map 7002909 More dependence graph tests 66263ea Make dependence graph merge() return true when abstract state changes 3aa6dca Control dependency computation fix a408423 Simplified state merging in the dependence graph 0315816 Merge pull request diffblue#2180 from thomasspriggs/json_id2string 8941567 Merge pull request diffblue#2124 from smowton/smowton/feature/fallback-function-provider cd04e70 JBMC: use simple method stubbing pass a6b2cda Add Java simple method stubbing pass ec1127c Lazy goto model: hook for driver program to replace or stub functions b6a4382 Remove `id2string` from inside calls to the `json_stringt` constructor. b673ebb Add storage of final modifier status of java classes in `java_class_typet`. a2ad909 Small map 808dade Provide suitable diagnostics for equality-without-matching-types 89cf6fe Throw appropriate exceptions when converting constraints 2ae66c2 Produce a proper error message when catching a std::runtime_error at top level e7b3ade Workaround for Visual Studio loss of CV qualifier bug 1f661f5 Move sharing map and sharing node unit tests to util 47463a3 Use std::size_t instead of unsigned in the sharing map 3e22217 Sharing map documentation e54f740 Fix sharing map compiler warnings bcc489c Move sharing map unit tests to catch 34114b8 Use a specialised endianness map for flattening git-subtree-dir: cbmc git-subtree-split: 31ef182
Fixes a bug in the control dependency computation of the dependency graph (see regression test goto-instrument/dependence-graph4)