-
Notifications
You must be signed in to change notification settings - Fork 42
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
SV-COMP: unreach-call
failure in reducercommutativity/max.i
#844
Comments
A little experimentation leads me to believe that the counterexample chosen is usually (always?) the largest power of 2 which is below the chosen iteration bound, so it does seem related. |
The iteration bound and the choice of the length of the array is a red herring. Fixing the value of I think the actual issue here is the reads from the uninitialized array |
Oh wow, you're exactly right. Here is an even smaller program which exhibits the same issue when compiled with #include <stdlib.h>
int main() {
int x;
if (x && !x) {
abort();
}
return 0;
} Logically, one would expect that How should we fix this? I suppose one option is to check for variables that are declared without being initialized during translation, and if |
I think we have two options.
|
For (1), would we fall back to the degenerate (wrong-ish) behavior if the size was symbolic? I know that a symbolic size is probably going to be bad in general anyway |
I don't think a symbolic size is a problem, as long as we're careful. We should be able to use an uninterpreted SMT array to write enough fresh bytes in that case (or, in every case?) |
Indeed, I'm wondering if we shouldn't just use |
I don't think it's relevant to the behavior of |
A very good point. I should be more precise and avoid saying "logically" but rather "what SV-COMP expects to happen". As far as I can tell, SV-COMP expects something like (1) in #844 (comment), although I can't find any official documentation stating as such. Oh well. |
…loads-and-stores Previously, `lax-loads-and-stores` would make it so that all reads from uninitialized memory would return a new, fresh value. This isn't quite what we want, however, as this implies that consecutive reads from the same, uninititalized variable would return different results. Instead, we now write a fresh value of the right shape (using `freshConstant`/`doArrayStore`) whenever allocating something (with `alloca`, `malloc`, or otherwise) when `lax-loads-and-stores` is enabled. Fixes #844.
I whipped up an implementation of (1) from #844 (comment) at #906. It makes the test case from #844 (comment) pass, and it makes |
Thanks for those links Langston. That lead me to the following: I've only skimmed it so far, but it seems like an excellent analysis of this question from the C standardization angle. EDIT: and it touches on the bitfield questions we have been grappling with recently as well. |
Previously, `laxLoadsAndStores` would make it so that all reads from uninitialized memory would return a new, fresh value. This isn't always what you want, however, as this implies that consecutive reads from the same, uninititalized variable would return different results. This patch adds another knob in the form of the `indeterminateLoadBehavior` field of `MemOptions`, which has two settings: * `unstable-symbolic`: The previous behavior, in which each read from uninitialized memory will return a fresh symbolic value each time. * `stable-symbolic` (now the default): After memory is allocated (be it through `alloca`, `malloc`, `calloc`, etc.), it is written with a fresh symbolic value. This makes it so that reading from the same section of uninitialized memory multiple times will always return the same symbolic value. Note that `indeterminateLoadBehavior` only takes effect when `laxLoadsAndStores` is enabled. Fixes #844.
Previously, `laxLoadsAndStores` would make it so that all reads from uninitialized memory would return a new, fresh value. This isn't always what you want, however, as this implies that consecutive reads from the same, uninititalized variable would return different results. This patch adds another knob in the form of the `indeterminateLoadBehavior` field of `MemOptions`, which has two settings: * `unstable-symbolic`: The previous behavior, in which each read from uninitialized memory will return a fresh symbolic value each time. * `stable-symbolic` (now the default): After memory is allocated (be it through `alloca`, `malloc`, `calloc`, etc.), it is written with a fresh symbolic value. This makes it so that reading from the same section of uninitialized memory multiple times will always return the same symbolic value. Note that `indeterminateLoadBehavior` only takes effect when `laxLoadsAndStores` is enabled. Fixes #844.
…906) * Revert "Use readUnwrittenMemory in readMem'" This reverts commit 819adc8. * crucible-llvm: Control granularity of reading uninitialized memory Previously, `laxLoadsAndStores` would make it so that all reads from uninitialized memory would return a new, fresh value. This isn't always what you want, however, as this implies that consecutive reads from the same, uninititalized variable would return different results. This patch adds another knob in the form of the `indeterminateLoadBehavior` field of `MemOptions`, which has two settings: * `unstable-symbolic`: The previous behavior, in which each read from uninitialized memory will return a fresh symbolic value each time. * `stable-symbolic` (now the default): After memory is allocated (be it through `alloca`, `malloc`, `calloc`, etc.), it is written with a fresh symbolic value. This makes it so that reading from the same section of uninitialized memory multiple times will always return the same symbolic value. Note that `indeterminateLoadBehavior` only takes effect when `laxLoadsAndStores` is enabled. Fixes #844. * Only apply the `stable-symbolic` semantics for heap allocations in `doMalloc`. This avoids a bug that was causing global variables to be incorrectly initialized. The ultimate source of that bug still needs to be fixed, but this avoids the bug for now, and is also the right thing to do. * Remove a fall through case in `writeMemWithAllocationCheck` that was sometimes causing memory writes to be silently discarded. In particular, writing an `LLVMZero` value into an SMT array backed location would have no effect. Unhandled cases in this code will now panic instead of silently giving incorrect answers. * Fix a bug in global initialization that could incorrectly "undo" some global variable setup if there is a chain of global variables that refer to others via constant expressions. * Update crucible-llvm test suite * Include globals in T844 test cases * Handle "extern" global variables in the lax-loads/stable-symbolic case. This involves making a special case so that external globals recive an initializing write with fresh sybmolic values at global population time. * Add some notes about deferencing pointers with lax-loads-and-stores Co-authored-by: Rob Dockins <[email protected]>
crux-llvm-svcomp
incorrectly concludes thatreach_error
is reachable in thereducercommutativity/max.i
SV-COMP benchmark program:There are several other programs of a similar caliber that also give the same error, but
max.i
is probably the most self-contained example. Crux claims thatN = 0x20
is a counterexample, which is untrue. I think the use ofiteration-bound: 50
inunreach-call.config
might be partially responsible for this, but I'm not sure.The text was updated successfully, but these errors were encountered: