Skip to content

Commit

Permalink
Add SMT simplifications for bitvec subtraction (#2504)
Browse files Browse the repository at this point in the history
* Add SMT simplifications for bitvec subtraction

* Replace operator SUB by built-in '-'

* Use '==' instead of 'is' to test bitvector equality

* Lint

* Use custom exception when __bool__ fails to evaluate expression
  • Loading branch information
Boyan-MILANOV committed Nov 23, 2021
1 parent 52007a8 commit da67723
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 9 deletions.
18 changes: 13 additions & 5 deletions manticore/core/smtlib/expression.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@ class ExpressionException(SmtlibError):
pass


class ExpressionEvalError(SmtlibError):
"""Exception raised when an expression can't be concretized, typically
when calling __bool__() fails to produce a True/False boolean result
"""

pass


class XSlotted(type):
"""
Metaclass that will propagate slots on multi-inheritance classes
Expand Down Expand Up @@ -65,7 +73,7 @@ def __new__(cls, clsname, bases, attrs, abstract=False):


class Expression(object, metaclass=XSlotted, abstract=True):
""" Abstract taintable Expression. """
"""Abstract taintable Expression."""

__xslots__: Tuple[str, ...] = ("_taint",)

Expand Down Expand Up @@ -214,7 +222,7 @@ def __bool__(self):
x = simplify(self)
if isinstance(x, Constant):
return x.value
raise NotImplementedError("__bool__ for Bool")
raise ExpressionEvalError("__bool__ for Bool")


class BoolVariable(Bool):
Expand Down Expand Up @@ -259,7 +267,7 @@ def value(self):


class BoolOperation(Bool, abstract=True):
""" An operation that results in a Bool """
"""An operation that results in a Bool"""

__xslots__: Tuple[str, ...] = ("_operands",)

Expand Down Expand Up @@ -302,7 +310,7 @@ def __init__(self, *, cond: "Bool", true: "Bool", false: "Bool", **kwargs):


class BitVec(Expression, abstract=True):
""" BitVector expressions have a fixed bit size """
"""BitVector expressions have a fixed bit size"""

__xslots__: Tuple[str, ...] = ("size",)

Expand Down Expand Up @@ -564,7 +572,7 @@ def signed_value(self):


class BitVecOperation(BitVec, abstract=True):
""" An operation that results in a BitVec """
"""An operation that results in a BitVec"""

__xslots__: Tuple[str, ...] = ("_operands",)

Expand Down
19 changes: 15 additions & 4 deletions manticore/core/smtlib/visitors.py
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,7 @@ def visit_BoolAnd(self, expression, a, b):
return a

def _visit_operation(self, expression, *operands):
""" constant folding, if all operands of an expression are a Constant do the math """
"""constant folding, if all operands of an expression are a Constant do the math"""
operation = self.operations.get(type(expression), None)
if operation is not None and all(isinstance(o, Constant) for o in operands):
value = operation(*(x.value for x in operands))
Expand Down Expand Up @@ -438,7 +438,7 @@ def _changed(expression, operands):
return any(operands[i] is not expression.operands[i] for i in range(arity))

def _visit_operation(self, expression, *operands):
""" constant folding, if all operands of an expression are a Constant do the math """
"""constant folding, if all operands of an expression are a Constant do the math"""
if all(isinstance(o, Constant) for o in operands):
expression = constant_folder(expression)
if self._changed(expression, operands):
Expand Down Expand Up @@ -716,9 +716,10 @@ def visit_BitVecAdd(self, expression, *operands):
return right

def visit_BitVecSub(self, expression, *operands):
"""a - 0 ==> 0
"""a - 0 ==> a
(a + b) - b ==> a
(b + a) - b ==> a
a - a ==> 0
"""
left = operands[0]
right = operands[1]
Expand All @@ -739,6 +740,16 @@ def visit_BitVecSub(self, expression, *operands):
taint=subright.taint | right.taint,
),
)
elif isinstance(right, Constant) and right.value == 0:
return left
else:
# If equality can not be computed because of symbolic
# variables '==' will raise an exception
try:
if left == right:
return BitVecConstant(size=left.size, value=0)
except ExpressionEvalError:
pass

def visit_BitVecOr(self, expression, *operands):
"""a | 0 => a
Expand Down Expand Up @@ -1007,7 +1018,7 @@ def translate_to_smtlib(expression, **kwargs):


class Replace(Visitor):
""" Simple visitor to replaces expressions """
"""Simple visitor to replaces expressions"""

def __init__(self, bindings=None, **kwargs):
super().__init__(**kwargs)
Expand Down
7 changes: 7 additions & 0 deletions tests/other/test_smtlibv2.py
Original file line number Diff line number Diff line change
Expand Up @@ -848,6 +848,13 @@ def test_simplify_OR(self):
cs.add(simplify(Operators.OR(var, bt)) == bt)
self.assertTrue(self.solver.check(cs))

def test_simplify_SUB(self):
cs = ConstraintSet()
var = cs.new_bitvec(size=32)
cs.add(simplify(var - var) == 0)
cs.add(simplify(var - 0) == var)
self.assertTrue(self.solver.check(cs))

def testBasicReplace(self):
""" Add """
a = BitVecConstant(size=32, value=100)
Expand Down

0 comments on commit da67723

Please sign in to comment.