def check_add_overflow(a, b): ## integer overflow detection for addition. overflow = ast_and(ast_gt(b, ast(0)), ast_gt(a, ast_minus(ast(INT_MAX), b))) underflow = ast_and(ast_lt(b, ast(0)), ast_lt(a, ast_minus(ast(INT_MIN), b))) return z3expr(ast_or(overflow, underflow))
def __cmp__(self, o): res = self.__v.__cmp__(o) if concolic_bool(ast_lt(self.__ast, ast(o)), res < 0): return -1 if concolic_bool(ast_gt(self.__ast, ast(o)), res > 0): return 1 return 0
def concolic_bool(sym, v): ## Python claims that 'bool' is not an acceptable base type, ## so it seems difficult to subclass bool. Luckily, bool has ## only two possible values, so whenever we get a concolic ## bool, add its value to the constraint. add_pc(ast_eq(sym, ast(v))) return v
def symbolic_bool(sym): pid = os.fork() ## even we limit the number of processes running simultaneously, ## we still need to fork one process which stays in blocked state ## until the semaphore is active... so, memory usage is a shitty issue. if pid: # parent solver.add(z3expr(ast_eq(sym, ast(True)))) r = True log("assume (%s)" % str(sym)) else: # child sem.acquire() solver.add(z3expr(ast_eq(sym, ast(False)))) r = False log("assume ¬(%s)" % str(sym)) if solver.check() != sat: log("unreachable") sys.exit(0) return r
def check_multiply_overflow(a, b): ## integer overflow detection for multiplication. overflow = ast_gt(a, ast_div(ast(INT_MAX), b)) underflow = ast_lt(a, ast_div(ast(INT_MIN), b)) special1 = ast_and(ast_eq(a, ast(-1)), ast_eq(b, ast(INT_MIN))) special2 = ast_and(ast_eq(b, ast(-1)), ast_eq(a, ast(INT_MIN))) return z3expr(ast_and(overflow, underflow, special1, special2))
def _wrapper(*args): arg_names = inspect.getargspec(self.func).args num_expected = len(arg_names) if num_expected != len(args): msg = "{}() takes exactly {} arguments ({} given)" raise TypeError(msg.format(self.func.__name__, num_expected, len(args))) specs = {name: arg_spec(a, name) for a, name in zip(args, arg_names)} if not self.return_ast: return kernel(self.func, specs, env=self.env) return ast(self.func, specs, env=self.env)
def generate_ast(raw_ast): iterator = iter(raw_ast) # find parent map c = "" while c != "parent_map": c = next(iterator) # skip parent map num_edges = int(next(iterator)) for i in range(0, num_edges): next(iterator) next(iterator) return ast(iterator)
def __rand__(self, o): res = value(o) & self.__v return concolic_int(ast_bwand(ast(o), self.__ast), res)
def __rmod__(self, o): if _check_divided_by_zero: check_divided_by_zero(self.__ast) res = value(o) % self.__v return concolic_int(ast_mod(ast(o), self.__ast), res)
def __and__(self, o): res = self.__v & value(o) return concolic_int(ast_bwand(self.__ast, ast(o)), res)
def __eq__(self, o): if not isinstance(o, int): return False res = (self.__v == value(o)) return concolic_bool(ast_eq(self.__ast, ast(o)), res)
def __le__(self, o): res = self.__v <= o return concolic_bool(ast_not(ast_gt(self.__ast, ast(o))), res)
def __rlshift__(self, o): res = value(o) << self.__v return concolic_int(ast_lshift(ast(o), self.__ast), res)
def __rrshift__(self, o): res = value(o) >> self.__v return concolic_int(ast_rshift(ast(o), self.__ast), res)
def __rsub__(self, o): if _check_overflow: check_minus_overflow(ast(o), self.__ast) res = value(o) - self.__v return concolic_int(ast_minus(ast(o), self.__ast), res)
def check_divided_by_zero(d): return z3expr(ast_eq(d, ast(0)))
def __radd__(self, o): if _check_overflow: check_add_overflow(ast(o), self.__ast) res = value(o) + self.__v return concolic_int(ast_plus(ast(o), self.__ast), res)
def __sub__(self, o): if _check_overflow: check_minus_overflow(self.__ast, ast(o)) res = self.__v - value(o) return concolic_int(ast_minus(self.__ast, ast(o)), res)
def __add__(self, o): if _check_overflow: check_add_overflow(self.__ast, ast(o)) res = self.__v + value(o) return concolic_int(ast_plus(self.__ast, ast(o)), res)
def __ge__(self, o): res = self.__v >= o return concolic_bool(ast_not(ast_lt(self.__ast, ast(o))), res)
def __gt__(self, o): res = self.__v > o return concolic_bool(ast_gt(self.__ast, ast(o)), res)
def __or__(self, o): res = self.__v | value(o) return concolic_int(ast_bwor(self.__ast, ast(o)), res)
def show_expanded(tree, expand_macros, **kw): expanded_tree = expand_macros(tree) new_tree = q(wrap_simple(log, u(unparse_ast(expanded_tree)), ast(expanded_tree))) return new_tree
def __ror__(self, o): res = value(o) | self.__v return concolic_int(ast_bwor(ast(o), self.__ast), res)
""" Exec Command Pre-processing =========================== This module defines the :func:`transform_source` and :func:`transform_ast` functions, which take pre-processes code from :class:`msg.Exec` instances before `exec`-ing. Source Transformations (:func:`transform_source`) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ These are transforms that act on the string source of the command, and return the modified source. These are generally hack-ish, so if you're adding a transform, try to do it with an ast transform. ast (Abstract Syntax Tree) Transformations (:func:`transform_ast`) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ These are transforms that act on the ast, and return the modified ast: * :func:`displayhook_last` -- if the last node in an in-order traversal of the ast is an `Expr`(ession node), add a call to :func:`__displayhook__`. * :class:`DisplayhookAll` -- a subclass of :class:`ast.NodeTransformer` that adds the displayhook to all :class:`ast.Expr` nodes. * :class:`AssignhookAll` -- a subclass of :class:`ast.NodeTransformer` that prints out assignment statements. """ import ast import astpp
def __rshift__(self, o): res = self.__v >> value(o) return concolic_int(ast_rshift(self.__ast, ast(o)), res)
def __rfloordiv__(self, o): if _check_divided_by_zero: check_divided_by_zero(self.__ast) res = value(o) // self.__v return concolic_int(ast_div(ast(o), self.__ast), res)
def flip_pc(pc): assert isinstance(pc, ast_eq) return ast_eq(pc.a, ast(not pc.b.b))
def __mod__(self, o): if _check_divided_by_zero: check_divided_by_zero(ast(o)) res = self.__v % value(o) return concolic_int(ast_mod(self.__ast, ast(o)), res)
def __mul__(self, o): if _check_overflow: check_multiply_overflow(self.__ast, ast(o)) res = self.__v * value(o) return concolic_int(ast_mul(self.__ast, ast(o)), res)
def __lt__(self, o): res = self.__v < o return concolic_bool(ast_lt(self.__ast, ast(o)), res)
def log(tree, exact_src, **kw): new_tree = q(wrap(log, u(exact_src(tree)), ast(tree))) return new_tree
def __rmul__(self, o): if _check_overflow: check_multiply_overflow(ast(o), self.__ast) res = value(o) * self.__v return concolic_int(ast_mul(ast(o), self.__ast), res)
def _require_transform(tree, exact_src): ret = trace_walk.recurse(copy.deepcopy(tree), exact_src) trace_walk.recurse(copy.deepcopy(tree), exact_src) new = q(ast(tree) or handle(lambda log: ast(ret))) return new
def __floordiv__(self, o): if _check_divided_by_zero: check_divided_by_zero(ast(o)) res = self.__v // value(o) return concolic_int(ast_div(self.__ast, ast(o)), res)