Search code examples
z3z3py

Z3 Get solutions without overflow using bitVecs


I found this post that gives a way of checking for overflow in solutions when adding bitVecs z3 bitvector overflow checking from python?

However, it only works when only adding 2 bitVecs, is there any way of extending it so it works for adding an arbitrary number of bitVecs? As far as I can tell, the problem is that "z3._coerce_exprs(x, y)" in

def bvadd_no_overflow(x, y, signed=False):
    assert x.ctx_ref()==y.ctx_ref()
    a, b = z3._coerce_exprs(x, y)
    return BoolRef(Z3_mk_bvadd_no_overflow(a.ctx_ref(), a.as_ast(), 
         b.as_ast(), signed))

Only can take 2 inputs.


Solution

  • You can program this yourself, on top of the 2-place predicate z3 provides:

    from z3 import *
    
    def addition_does_not_overflow(xs, signed):
        sofar      = 0
        noOverflow = True
        for x in xs:
          noOverflow = And(noOverflow, BVAddNoOverflow(x, sofar, signed))
          sofar += x
        return noOverflow
    
    xs = [BitVec('x' + str(i), 2) for i in range(5)]
    s = Solver()
    
    s.add(addition_does_not_overflow(xs, False))
    if s.check() == sat:
        print(s.model())
    else:
        print("No solution")
    

    This prints:

    [x3 = 1, x2 = 2, x1 = 0, x4 = 0, x0 = 0]
    

    and indeed, those numbers don't overflow when added as unsigned 2-bit vectors, i.e., those that range from 0 to 3. Note that second argument of the predicate: You should pass True if you want signed-arithmetic, and False if otherwise.