-
Notifications
You must be signed in to change notification settings - Fork 273
Soundness with __CPROVER_r_ok #8614
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
Comments
Hi, thanks for reporting the issue. From the perspective of CBMC, when symbolic execution uses The You should instead use a top level harness that allocates memory explicitly: #include <assert.h>
#include <limits.h>
#include <stdbool.h>
int sum(int s[], int size)
{
int res = 0;
int i = 0;
do {
res += s[i];
i++;
} while (i < size);
assert(false);
return res;
}
int main()
{
int size;
__CPROVER_assume(size==3);
int s[size];
int res = sum(s, size);
return 0;
} Then you get the expected results: ❯ cbmc sum.c
CBMC version 6.4.1 (cbmc-6.4.1) 64-bit x86_64 macos
Type-checking sum
Generating GOTO Program
Adding CPROVER library (x86_64)
Removal of function pointers and virtual functions
Generic Property Instrumentation
Starting Bounded Model Checking
Passing problem to propositional reduction
converting SSA
Running propositional reduction
SAT checker: instance is SATISFIABLE
Running propositional reduction
SAT checker inconsistent: instance is UNSATISFIABLE
** Results:
sum.c function sum
[sum.overflow.1] line 11 arithmetic overflow on signed + in res + s[(signed long int)i]: FAILURE
[sum.pointer_dereference.1] line 11 dereference failure: pointer NULL in s[(signed long int)i]: SUCCESS
[sum.pointer_dereference.2] line 11 dereference failure: pointer invalid in s[(signed long int)i]: SUCCESS
[sum.pointer_dereference.3] line 11 dereference failure: deallocated dynamic object in s[(signed long int)i]: SUCCESS
[sum.pointer_dereference.4] line 11 dereference failure: dead object in s[(signed long int)i]: SUCCESS
[sum.pointer_dereference.5] line 11 dereference failure: pointer outside object bounds in s[(signed long int)i]: SUCCESS
[sum.pointer_dereference.6] line 11 dereference failure: invalid integer address in s[(signed long int)i]: SUCCESS
[sum.overflow.2] line 12 arithmetic overflow on signed + in i + 1: SUCCESS
[sum.assertion.1] line 15 assertion false: FAILURE
** 2 of 9 failed (2 iterations)
VERIFICATION FAILED There is a tool in the CBMC toolkit called goto-harness that can generate such harnesses for you when the input types are simple. Also, enforcing a specific path within the control flow graph using assumptions may still result in CBMC symbolically executing some or all of the other paths in the CFG of the program, since symbolic execution engine may not be able to prune the branches ruled out by the constraints (it does not do very elaborate reasoning besides constant propagation to prune branches). If some of the constraints you're adding assign constants to some variables I'd recommend to encode them using assignments instead, to be sure Symex can propagate them and effectively prune the branches. Another way would be to insert |
Thanks for the quick reply!
Thank you, that makes sense! Hence, I will close the issue.
Thanks! We will look into it.
I have to say I did not quite get what you mean by assigning constants to some variables. I guess you are referring to #8428 where we used another approach to follow a control flow trace with assumptions. In this approach, a concrete control flow trace (with constant elements) is assigned once to an array variable at the beginning of the execution and then we use assumptions like you described to prune branches. I don't see how to turn these assumptions into assignments but if you have any intuition, I am quite open for suggestions! With our new approach (https://github.com/yosephinestwn/cbmc), we do not use assumptions to prune branches at all. Instead, we modified the symbolic execution engine, to be specific, we created a new method void goto_symext::symex_goto_retrace(statet &state, std::vector<int> trace) { ... } as alternative to: void goto_symext::symex_goto(statet &state) { ... } With a control-flow trace is given to cbmc via Thus the execution engine follows only the respective paths and pruning is no longer needed. This makes it much much more efficient. The downside is that the control-flow trace is based on the GOTO program, not the C source code. |
Hello, The last commit is made in retrace-execute-from-scratch branch (yosephinestwn@7931a3e), in case you want to see it. Also, thank you for the help :) |
Ok got it. So you're really controlling the symbolic execution to step through only a predefined sequence of basic blocks. |
For the following program, we get
VERIFICATION_SUCCESFUL
, although the assertion should give aFAILURE
:soundness_r_ok.c
The assertion false should be reachable with the assumptions but we get:
Expected:
Background: With assume
size==3
we check only one path of symbolic execution. My student @yosephinestwn is currently implementing an extension to CBMC, to verify just one path, we call that retracing (https://github.com/yosephinestwn/cbmc). To test the implementation, she started a version without the assumesize==3
but with the newly implemented option--retrace 110
to follow the control flow trace. This control flow trace corresponds to the branching in the GOTO program and in our case, we have just one goto instructionIF sum::1::i < sum::size THEN GOTO 1
. The--retrace 110
means the GOTO target branch is taken twice (the 11) and not taken for the third time (the 0), afterwards, assert false should give a verification failure. After trying to fix our implementation, we found out that the problem is already in the upstream CBMC with assumesize==3
.The text was updated successfully, but these errors were encountered: