-
Notifications
You must be signed in to change notification settings - Fork 63
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
Symbolic execution fails for infinite sequences in some circumstances #1703
Comments
If we change
the proof passes as well. So this looks like something going wrong with, as you say, infinite sequences. The palindrome thing is very strange. |
It appears that using What4 is important to triggering this bug. If I change from a What4-based Z3 to an SBV-based one: - weird_ov = llvm_verify(mod, "weird", Contract_weird(), script=ProofScript([UseProver(Z3([]))]))
+ weird_ov = llvm_verify(mod, "weird", Contract_weird(), script=ProofScript([UseProver(Z3_SBV([]))])) Then the proof succeeds. |
The handling of infinite sequences is one of the few places where the code paths for the SAW symbolic simulators differ between What4 and SBV, so that's probably where to start looking. |
SAWCore assumes the invariant that when indexing into an infinite stream using a symbolic index, the mux tree constructed over the index will test each bit in big-endian order. This is the responsibility of the `selectV` function found in `saw-core`, `saw-core-sbv`, and `saw-core-what4`. All of these functions save for `saw-core-what4`'s `selectV` were upholding this invariant, as `saw-core-what4`'s was testing each bit in little-endian order, resulting in the oddities observed in #1703. This corrects the mistake in `saw-core-what4'`s implementation, fixing #1703. It also leaves some more documentation to make the fact that each `selectV` should be proceeding in big-endian order more apparent.
I happened to figure out what is going on here while investigating #1768. When indexing into an infinite SAWCore bitvector using a symbolic index, SAW will create a giant mux of all possible bits. The topmost saw-script/saw-core/src/Verifier/SAW/Simulator/Prims.hs Lines 487 to 498 in 200d0e5
In saw-script/saw-core-sbv/src/Verifier/SAW/Simulator/SBV.hs Lines 317 to 329 in a31e031
And in saw-script/saw-core-what4/src/Verifier/SAW/Simulator/What4.hs Lines 583 to 599 in a31e031
While comparing these functions, I realized that This is the opposite order of the other two I believe this also explains why your example happened to work when the index is a palindrome, as those are precisely the conditions under which MSB-first order would be equivalent to LSB-first order. A change that fixes the issue is therefore: diff --git a/saw-core-what4/src/Verifier/SAW/Simulator/What4.hs b/saw-core-what4/src/Verifier/SAW/Simulator/What4.hs
index e5789d85..b4de3b96 100644
--- a/saw-core-what4/src/Verifier/SAW/Simulator/What4.hs
+++ b/saw-core-what4/src/Verifier/SAW/Simulator/What4.hs
@@ -595,7 +595,7 @@ selectV sym merger maxValue valueFn vx =
impl _ x | x > maxValue || x < 0 = valueFn maxValue
impl 0 y = valueFn y
impl i y = do
- p <- SW.bvAtBE sym vx (toInteger j)
+ p <- SW.bvAtLE sym vx (toInteger j)
merger p (impl j (y `setBit` j)) (impl j y) where j = i - 1
instance Show (SArray sym) where I've included this in #1773, along with some documentation on the |
SAWCore assumes the invariant that when indexing into an infinite stream using a symbolic index, the mux tree constructed over the index will test each bit in big-endian order. This is the responsibility of the `selectV` function found in `saw-core`, `saw-core-sbv`, and `saw-core-what4`. All of these functions save for `saw-core-what4`'s `selectV` were upholding this invariant, as `saw-core-what4`'s was testing each bit in little-endian order, resulting in the oddities observed in #1703. This corrects the mistake in `saw-core-what4'`s implementation, fixing #1703. It also leaves some more documentation to make the fact that each `selectV` should be proceeding in big-endian order more apparent.
Fixed in #1773. |
For reference, the below uses Cryptol 2.13.0.99 and SAW 0.9.0.99. Using the SAW Python Module, I was attempting to prove equivalence between a C function and a Cryptol one:
The idea is that I can simulate
cvs
infinitely repeatingcv
in the Cryptol implementation by taking the modulus of the index in the C implementation, since C does not support infinite sequences.I used the following Python script to do so:
However, this contract failed to verify:
So, I put that input through C and Cryptol:
The counterexample, erm, does not seem to be a counterexample. After some playing around, I discovered a few interesting things. First, if I hard-code a value for i, the proof succeeds:
I'm not really an expert on symbolic execution or formal verification, but this seems to suggest that something is amiss with the symbolic execution.
Further, if
i
is a palindrome, the proof also succeeds:I'm not sure what to make of this one, but it was interesting, so I felt like I should include it.
The text was updated successfully, but these errors were encountered: