I think I don't understand how BitVecs work in z3. I have written the following code:
>>> import z3
>>> s = z3.Solver()
>>> a = z3.BitVec("a", 32)
>>> s.add(z3.ForAll(a, z3.Not(z3.And(a > 2147483647, a < 2147484671))))
I'd expect that this to be "unsat", because there are values inside and outside this range. But when I run s.check()
, I get:
>>> s.check()
sat
This was confusing to me, so I guessed there was overflow involved. But then I tried:
>>> b = z3.BitVec("b", 32)
>>> s = z3.Solver()
>>> s.add(b == 2147484671)
>>> s.check()
sat
>>> s.model()
[b = 2147484671]
Which confuses me a lot, because it suggests that z3 can model this number using 32 bit BitVecs. Additionally I ran:
>>> s = z3.Solver()
>>> c = z3.BitVec("c", 32)
>>> s.add(z3.And(c > 2147483647, c < 2147484671))
>>> s.check()
unsat
Which confused me even more, because it seems clearly incompatible with the second example...
The operators > and < are signed. 2147484671 is a negative number when interpreted as a 32-bit number. That's why you constraint is unsat. You can use UGT/ULT instead of >/< to ignore the sign bit.
Bottom line: bit vectors represent numbers, but you need to know what's the signedness of the operations you are using. In the Python API, all operator overloads are signed operations.