-
Notifications
You must be signed in to change notification settings - Fork 274
Symex: propagate assumptions and conditions #4386
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
Merged
smowton
merged 5 commits into
diffblue:develop
from
smowton:smowton/feature/symex-condition-driving
Mar 19, 2019
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
929c21d
Move goto_symex_is_constantt into its own file
smowton 6441467
Move increase_generation onto goto_statet
smowton 7d2b070
Split l2_thread_write_encoding apart from write_is_shared
smowton c5d7bae
Symex: propagate constants implied by assumptions and conditions
smowton e0d4d78
Add tests for symex condition propagation
smowton File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Binary file not shown.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
public class Test { | ||
|
||
public static void main(int unknown) { | ||
|
||
try { | ||
mayThrow(unknown % 7 == 5); | ||
} | ||
catch(Exception e) { | ||
} | ||
|
||
// This test checks that symex can tell there is no exception in flight | ||
// (i.e. @inflight_exception is null) at this point, requiring it to | ||
// converge the `if @inflight_exception == null` test on mayThrow's return | ||
// with the explicit `@inflight_exception = null;` assignment that concludes | ||
// the catch block. | ||
|
||
// If it knows that, it will also know the following catch block is | ||
// unreachable; if not it will pursue both paths. | ||
try { | ||
mayThrow(false); | ||
} | ||
catch(Exception e) { | ||
unreachable(); | ||
} | ||
|
||
// Try it once more, to check we also know after an unreachable catch that | ||
// there is still no inflight exception | ||
try { | ||
mayThrow(false); | ||
} | ||
catch(Exception e) { | ||
unreachable(); | ||
} | ||
|
||
} | ||
|
||
public static void mayThrow(boolean shouldThrow) throws Exception { | ||
if(shouldThrow) | ||
throw new Exception(); | ||
} | ||
|
||
public static void unreachable() { assert false; } | ||
|
||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
CORE | ||
Test.class | ||
--function Test.main | ||
^EXIT=0$ | ||
^SIGNAL=0$ | ||
^VERIFICATION SUCCESSFUL$ | ||
1 remaining after simplification$ | ||
-- | ||
^warning: ignoring | ||
-- | ||
The function "unreachable" should be successfully noted as unreachable by symex, | ||
but the final uncaught-exception test in __CPROVER__start is not yet decidable | ||
in symex, as it requires symex to note that within a catch block | ||
@inflight_exception is definitely *not* null, which it can't just yet. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
CORE | ||
Test.class | ||
--function Test.main --show-vcc | ||
^EXIT=0$ | ||
^SIGNAL=0$ | ||
file Test\.java line 6 function java::Test.main:\(I\)V | ||
no uncaught exception | ||
-- | ||
file Test\.java line 42 function java::Test\.unreachable:\(\)V bytecode-index 5 | ||
assertion at file Test\.java line 42 function java::Test\.unreachable:\(\)V bytecode-index 5 | ||
java::Test\.unreachable:\(\)V | ||
^warning: ignoring | ||
-- | ||
Supplemental to test.desc, check that the right condition remains to be tested by the solver, | ||
and the unreachable function indeed does not occur in the VCCs. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
int main(int argc, char **argv) | ||
{ | ||
if(argc == 1) | ||
assert(argc == 1); | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
CORE | ||
test.c | ||
|
||
^EXIT=0$ | ||
^SIGNAL=0$ | ||
^VERIFICATION SUCCESSFUL$ | ||
0 remaining after simplification$ | ||
-- | ||
^warning: ignoring | ||
-- | ||
Assumption and GOTO condition propagation means this test should be | ||
entirely decided by symex. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
int main(int argc, char **argv) | ||
{ | ||
__CPROVER_assume(argc == 1); | ||
assert(argc == 1); | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
CORE | ||
test.c | ||
|
||
^EXIT=0$ | ||
^SIGNAL=0$ | ||
^VERIFICATION SUCCESSFUL$ | ||
0 remaining after simplification$ | ||
-- | ||
^warning: ignoring | ||
-- | ||
Assumption and GOTO condition propagation means this test should be | ||
entirely decided by symex. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
int main(int argc, char **argv) | ||
{ | ||
if(argc != 1) | ||
{ | ||
} | ||
else | ||
{ | ||
assert(argc == 1); | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
CORE | ||
test.c | ||
|
||
^EXIT=0$ | ||
^SIGNAL=0$ | ||
^VERIFICATION SUCCESSFUL$ | ||
0 remaining after simplification$ | ||
-- | ||
^warning: ignoring | ||
-- | ||
Assumption and GOTO condition propagation means this test should be | ||
entirely decided by symex. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
int main(int argc, char **argv) | ||
{ | ||
int unknown; | ||
|
||
if(argc != 1) | ||
{ | ||
} | ||
else | ||
{ | ||
if(unknown == argc) | ||
{ | ||
assert(unknown == 1); | ||
} | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
CORE | ||
test.c | ||
|
||
^EXIT=0$ | ||
^SIGNAL=0$ | ||
^VERIFICATION SUCCESSFUL$ | ||
0 remaining after simplification$ | ||
-- | ||
^warning: ignoring | ||
-- | ||
Assumption and GOTO condition propagation means this test should be | ||
entirely decided by symex. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,6 +7,8 @@ Author: Romain Brenguier, [email protected] | |
\*******************************************************************/ | ||
|
||
#include "goto_state.h" | ||
#include "goto_symex_is_constant.h" | ||
#include "goto_symex_state.h" | ||
|
||
#include <util/format_expr.h> | ||
|
||
|
@@ -20,3 +22,74 @@ void goto_statet::output_propagation_map(std::ostream &out) | |
out << name_value.first << " <- " << format(name_value.second) << "\n"; | ||
} | ||
} | ||
|
||
std::size_t goto_statet::increase_generation( | ||
const irep_idt l1_identifier, | ||
const ssa_exprt &lhs, | ||
std::function<std::size_t(const irep_idt &)> fresh_l2_name_provider) | ||
{ | ||
auto current_emplace_res = | ||
level2.current_names.emplace(l1_identifier, std::make_pair(lhs, 0)); | ||
|
||
current_emplace_res.first->second.second = | ||
fresh_l2_name_provider(l1_identifier); | ||
|
||
return current_emplace_res.first->second.second; | ||
} | ||
|
||
/// Given a condition that must hold on this path, propagate as much knowledge | ||
/// as possible. For example, if the condition is (x == 5), whether that's an | ||
/// assumption or a GOTO condition that we just passed through, we can propagate | ||
/// the constant '5' for future 'x' references. If the condition is (y == &o1) | ||
/// then we can use that to populate the value set. | ||
/// \param condition: condition that must hold on this path. Expected to already | ||
/// be L2-renamed. | ||
/// \param previous_state: currently active state, not necessarily the same as | ||
/// *this. For a GOTO instruction this is the state immediately preceding the | ||
/// branch while *this is the state that will be used on the taken- or | ||
/// not-taken path. For an ASSUME instruction \p previous_state and *this are | ||
/// equal. | ||
/// \param ns: global namespace | ||
void goto_statet::apply_condition( | ||
const exprt &condition, | ||
const goto_symex_statet &previous_state, | ||
const namespacet &ns) | ||
{ | ||
if(condition.id() == ID_and) | ||
{ | ||
for(const auto &op : condition.operands()) | ||
apply_condition(op, previous_state, ns); | ||
} | ||
else if(condition.id() == ID_equal) | ||
{ | ||
exprt lhs = condition.op0(); | ||
exprt rhs = condition.op1(); | ||
if(is_ssa_expr(rhs)) | ||
std::swap(lhs, rhs); | ||
|
||
if(is_ssa_expr(lhs) && goto_symex_is_constantt()(rhs)) | ||
{ | ||
const ssa_exprt &ssa_lhs = to_ssa_expr(lhs); | ||
INVARIANT( | ||
!ssa_lhs.get_level_2().empty(), | ||
"apply_condition operand should be L2 renamed"); | ||
|
||
if( | ||
previous_state.threads.size() == 1 || | ||
previous_state.write_is_shared(ssa_lhs, ns) != | ||
goto_symex_statet::write_is_shared_resultt::SHARED) | ||
{ | ||
ssa_exprt l1_lhs = ssa_lhs; | ||
l1_lhs.remove_level_2(); | ||
const irep_idt &l1_identifier = l1_lhs.get_identifier(); | ||
|
||
increase_generation( | ||
l1_identifier, l1_lhs, previous_state.get_l2_name_provider()); | ||
|
||
propagation[l1_identifier] = rhs; | ||
|
||
value_set.assign(l1_lhs, rhs, ns, true, false); | ||
} | ||
} | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -74,6 +74,16 @@ class goto_statet | |
: guard(true_exprt(), guard_manager) | ||
{ | ||
} | ||
|
||
void apply_condition( | ||
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. Please briefly document this function 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. Documented at definition site |
||
const exprt &condition, // L2 | ||
const goto_symex_statet &previous_state, | ||
const namespacet &ns); | ||
|
||
std::size_t increase_generation( | ||
const irep_idt l1_identifier, | ||
const ssa_exprt &lhs, | ||
std::function<std::size_t(const irep_idt &)> fresh_l2_name_provider); | ||
}; | ||
|
||
#endif // CPROVER_GOTO_SYMEX_GOTO_STATE_H |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
/*******************************************************************\ | ||
|
||
Module: Symbolic Execution Constant Propagation | ||
|
||
Author: Michael Tautschig, [email protected] | ||
|
||
\*******************************************************************/ | ||
|
||
/// \file | ||
/// GOTO Symex constant propagation | ||
|
||
#ifndef CPROVER_GOTO_SYMEX_GOTO_SYMEX_IS_CONSTANT_H | ||
#define CPROVER_GOTO_SYMEX_GOTO_SYMEX_IS_CONSTANT_H | ||
|
||
#include <util/expr.h> | ||
#include <util/expr_util.h> | ||
|
||
class goto_symex_is_constantt : public is_constantt | ||
{ | ||
protected: | ||
bool is_constant(const exprt &expr) const override | ||
{ | ||
if(expr.id() == ID_mult) | ||
{ | ||
// propagate stuff with sizeof in it | ||
forall_operands(it, expr) | ||
{ | ||
if(it->find(ID_C_c_sizeof_type).is_not_nil()) | ||
return true; | ||
else if(!is_constant(*it)) | ||
return false; | ||
} | ||
|
||
return true; | ||
} | ||
else if(expr.id() == ID_with) | ||
{ | ||
// this is bad | ||
/* | ||
forall_operands(it, expr) | ||
if(!is_constant(expr.op0())) | ||
return false; | ||
|
||
return true; | ||
*/ | ||
return false; | ||
} | ||
|
||
return is_constantt::is_constant(expr); | ||
} | ||
}; | ||
|
||
#endif // CPROVER_GOTO_SYMEX_GOTO_SYMEX_IS_CONSTANT_H |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
💡 A test with nested try-catch would be useful to prove that point.
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.
Such a case actually does not work yet, because symex can't tell that all exceptions were caught (i.e. the catch dispatch table is exhaustive). The reason is it isn't yet smart enough to notice that upon entering the catch block the incoming pointer cannot be null, and therefore e instanceof Exception certainly succeeds (null instanceof A returns false for any A).
Fixing that is my next task!
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.
You could add a KNOWNBUG test for it now and turn it on as part of your next task.