Exemplo n.º 1
0
def get_conjuncts(qvars, conjunction):
    if conjunction.decl().kind() == z3.Z3_OP_AND:
        return [
            z3.substitute_vars(kid, *qvars) for kid in conjunction.children()
        ]
    else:
        return [z3.substitute_vars(conjunction, *qvars)]
Exemplo n.º 2
0
 def __init__(self,rule):
     """ unpacks a rule of the kind
          (I) z3.Forall(variables, head)
         or
         (II) z3.Forall(variables, z3.Implies(z3.And([tail,children]),head))
     """
     self.rule = rule        # original rule
     self.variables = None   # quantified variables
     self.predicate = None   # predicate declaration: name(pc,...)
     self.tail = None        # body predicate 
     self.children = None    # other body elements
     self.head = None        # head predicate
     # the rule is a z3 quantifier
     if z3.is_quantifier(rule):
         # quantified variables
         self.variables = list()
         for i in range(rule.num_vars()):
             sort = self.var_sort(rule,i).kind()
             if sort == z3.Z3_INT_SORT:
                 self.variables.append(z3.Int(self.var_name(rule,i)))
             elif sort == z3.Z3_BOOL_SORT:
                 self.variables.append(z3.Bool(self.var_name(rule,i)))
             else:
                 raise ValueError('unsopported sort:',sort)
         # unpacks the rule body
         head = rule.body()
         if z3.is_app_of(head,z3.Z3_OP_IMPLIES):
             # the rule is of kind (II)
             body = head.arg(0)  # z3.Implies body
             if z3.is_app_of(body,z3.Z3_OP_AND):
                 # unpacks the other body elements
                 # (assumes single uninterpreted predicate in body)
                 self.children = list()
                 for c in body.children():
                     child = z3.substitute_vars(c,*self.variables)
                     # unpacks the body predicate 
                     if z3.is_app_of(child,z3.Z3_OP_UNINTERPRETED) \
                         and self.tail is None:  
                             self.tail = child   # body predicate
                     else:
                         self.children.append(child)
             else:
                 raise ValueError('unsupported implication body:',body)
             head = head.arg(1)  # z3.Implies head
         if z3.is_app_of(head,z3.Z3_OP_UNINTERPRETED):
             # the rule is of kind (I)
             name = head.decl().name()   # predicate name
             parameters = list()         # predicate parameters
             arguments = list()          # predicate arguments
             for i in range(head.num_args()):
                 arg = head.arg(i)
                 parameters.append(arg.sort())
                 arguments.append(z3.substitute_vars(arg,*self.variables))
             parameters.append(z3.BoolSort())
             self.predicate = z3.Function(name,*parameters)
             self.head = self.predicate(*arguments)  # head predicate
         else:
             raise ValueError('unsupported rule body:',body)
Exemplo n.º 3
0
 def __init__(self, rule):
     """ unpacks a rule of the kind
          (I) z3.Forall(variables, head)
         or
         (II) z3.Forall(variables, z3.Implies(z3.And([tail,children]),head))
     """
     self.rule = rule  # original rule
     self.variables = None  # quantified variables
     self.predicate = None  # predicate declaration: name(pc,...)
     self.tail = None  # body predicate
     self.children = None  # other body elements
     self.head = None  # head predicate
     # the rule is a z3 quantifier
     if z3.is_quantifier(rule):
         # quantified variables
         self.variables = list()
         for i in range(rule.num_vars()):
             sort = self.var_sort(rule, i).kind()
             if sort == z3.Z3_INT_SORT:
                 self.variables.append(z3.Int(self.var_name(rule, i)))
             elif sort == z3.Z3_BOOL_SORT:
                 self.variables.append(z3.Bool(self.var_name(rule, i)))
             else:
                 raise ValueError("unsopported sort:", sort)
         # unpacks the rule body
         head = rule.body()
         if z3.is_app_of(head, z3.Z3_OP_IMPLIES):
             # the rule is of kind (II)
             body = head.arg(0)  # z3.Implies body
             if z3.is_app_of(body, z3.Z3_OP_AND):
                 # unpacks the other body elements
                 # (assumes single uninterpreted predicate in body)
                 self.children = list()
                 for c in body.children():
                     child = z3.substitute_vars(c, *self.variables)
                     # unpacks the body predicate
                     if z3.is_app_of(child, z3.Z3_OP_UNINTERPRETED) and self.tail is None:
                         self.tail = child  # body predicate
                     else:
                         self.children.append(child)
             else:
                 raise ValueError("unsupported implication body:", body)
             head = head.arg(1)  # z3.Implies head
         if z3.is_app_of(head, z3.Z3_OP_UNINTERPRETED):
             # the rule is of kind (I)
             name = head.decl().name()  # predicate name
             parameters = list()  # predicate parameters
             arguments = list()  # predicate arguments
             for i in range(head.num_args()):
                 arg = head.arg(i)
                 parameters.append(arg.sort())
                 arguments.append(z3.substitute_vars(arg, *self.variables))
             parameters.append(z3.BoolSort())
             self.predicate = z3.Function(name, *parameters)
             self.head = self.predicate(*arguments)  # head predicate
         else:
             raise ValueError("unsupported rule body:", body)
Exemplo n.º 4
0
def substitute_vars(t, *m):
    """Substitute the free variables in t with the expression in m."""
    # Redefining this here so that the clients of this class aren't forced to
    # import any replacement-related functions directly from z3, thus making
    # it a little easier to add other backends in the future.
    #logger.info("Will substitute into {} arguments {} of sorts {}".format(t, m, map(lambda v : v.sort(), m)))
    return z3.substitute_vars(t, *m)
Exemplo n.º 5
0
def write_clause_smt2(forall, pref, writer):
    if not (z3.is_quantifier(forall) and forall.is_forall()):
        raise Exception("Illegal clause for write_clause_smt2: {}".format(
            forall.decl()))

    writer.write("{}(forall (".format(pref))

    for idx in range(0, forall.num_vars()):
        writer.write(" ({} {})".format(forall.var_name(idx),
                                       forall.var_sort(idx).sexpr()))

    writer.write(" ) \n".format(pref))

    implication = forall.body()
    subst = list(
        reversed([
            z3.Const(forall.var_name(n), forall.var_sort(n))
            for n in range(0, forall.num_vars())
        ]))

    implication = z3.substitute_vars(implication, *subst)

    write_implication_smt2(implication, pref + '  ', None, writer)

    writer.write("\n{})".format(pref))
Exemplo n.º 6
0
def stripQuantifierBlock (expr) :
  """ strips the outermost quantifier block in a given expression and returns
  the pair (<list of consts replacing free vars>,
  <body with consts substituted for de-bruijn variables>)

  Example:

  assume expr.is_forall ()
  vars, body = strip_quantifier (expr)
  qexpr = z3.ForAll (vars, body)
  assert qexpr.eq (expr)
  """
  if not z3.is_quantifier (expr) : return ([], expr)
  global qb_counter
  z3ctx = expr.ctx
  consts = list ()
  # outside-in order of variables; z3 numbers variables inside-out but
  # substitutes outside-in
  for i in reversed (range (expr.num_vars ())) :
    #v_name = expr.var_name (i) + "!" + str(qb_counter)
    v_name = expr.var_name (i)
    qb_counter+=1
    v_sort = expr.var_sort (i)
    consts.append (z3.Const (v_name, z3_translate (v_sort, z3ctx)))
  matrix = z3.substitute_vars (expr.body (), *consts)
  return (consts, matrix)
Exemplo n.º 7
0
 def eval(self, term):
     fn = self.get_fn(term.decl().name())
     # lambdas seem to be broken at the moment
     # this is a work around
     body = fn.body()
     body = z3.substitute_vars(body, *reversed(term.children()))
     return body
Exemplo n.º 8
0
def stripQuantifierBlock (expr) :
  """ strips the outermost quantifier block in a given expression and returns
  the pair (<list of consts replacing free vars>,
  <body with consts substituted for de-bruijn variables>)

  Example:

  assume expr.is_forall ()
  vars, body = strip_quantifier (expr)
  qexpr = z3.ForAll (vars, body)
  assert qexpr.eq (expr)
  """
  if not z3.is_quantifier (expr) : return ([], expr)
  global qb_counter
  z3ctx = expr.ctx
  consts = list ()
  # outside-in order of variables; z3 numbers variables inside-out but
  # substitutes outside-in
  for i in reversed (range (expr.num_vars ())) :
    v_name = expr.var_name (i) + "!" + str(qb_counter)
    qb_counter+=1
    v_sort = expr.var_sort (i)
    consts.append (z3.Const (v_name, z3_translate (v_sort, z3ctx)))
  matrix = z3.substitute_vars (expr.body (), *consts)
  return (consts, matrix)
Exemplo n.º 9
0
Arquivo: inc.py Projeto: alx441/XSHM
def fp_get_cover_delta(fp, pred, level=-1):
    sub = []
    for i in range(0, pred.num_args()):
        sub.append(pred.arg(i))
    lemma = fp.get_cover_delta(level, pred.decl())
    if z3core.Z3_get_bool_value(fp.ctx.ctx, lemma.as_ast()) != z3.unsat:
        lemma = z3.substitute_vars(lemma, *sub)
    return lemma
Exemplo n.º 10
0
def fp_get_cover_delta (fp, pred, level=-1):
    sub = []
    for i in range (0, pred.num_args ()):
        sub.append (pred.arg (i))
    lemma = fp.get_cover_delta (level, pred.decl ())
    if z3core.Z3_get_bool_value (fp.ctx.ctx, lemma.as_ast ()) != z3.unsat:
        lemma = z3.substitute_vars (lemma, *sub)
    return lemma
Exemplo n.º 11
0
def strip_qblock(expr):
    if not z3.is_quantifier(expr): return ([], expr)
    consts = list()
    for i in reversed(range(expr.num_vars())):
        v_name = expr.var_name(i)
        v_sort = expr.var_sort(i)
        consts.append(z3.Const(v_name, v_sort))
    matrix = z3.substitute_vars(expr.body(), *consts)
    return (consts, matrix)
Exemplo n.º 12
0
def ground_quantifier(qexpr):
    body = qexpr.body()

    vars = list()
    for i in reversed(range(qexpr.num_vars())):
        vi_name = qexpr.var_name(i)
        vi_sort = qexpr.var_sort(i)
        vi = z3.Const(vi_name, vi_sort)
        vars.append(vi)

    body = z3.substitute_vars(body, *vars)
    return (body, vars)
Exemplo n.º 13
0
def extract_implies(clause):
    qvars, implies = fix_quantifier(clause)
    implies = z3.substitute_vars(implies, *list(reversed(qvars)))
    kids = implies.children()
    tail = get_conjuncts(qvars, kids[0])
    head = kids[1]

    return {
        'qvars': qvars,
        'tail': tail,
        'head': head,
    }
Exemplo n.º 14
0
def lemma_to_string(lemma, pred):
    """
    convert a lemma returned by get_cover_delta into a string that parse_smt2_string can parse
    """
    const_list = [z3.Const(pred.name()+"_"+str(j), pred.domain(j)) for j in range(pred.arity())]
    lhs = pred(*const_list)
    rhs = z3.substitute_vars(lemma, *(const_list))
    imp = z3.Implies(lhs, rhs)
    forall = z3.ForAll(list(reversed(const_list)), imp)
    lemma_str = "(assert %s)"%forall.sexpr()
    print("\toriginal lemma:", lemma)
    print("\tforall lemma:", forall.body().arg(1))
    assert lemma == forall.body().arg(1)
    return lemma_str
Exemplo n.º 15
0
def extract_implies(clause):
    clause = fix_quantifier(clause)
    qvars = [
        z3.Const(clause.var_name(n), clause.var_sort(n))
        for n in range(0, clause.num_vars())
    ]

    implies = fix_implies(clause.body())
    kids = implies.children()
    body = get_conjuncts(qvars, kids[0])
    head = z3.substitute_vars(kids[1], *qvars)

    return {
        'qvars': qvars,
        'body': body,
        'head': head,
    }
Exemplo n.º 16
0
def write_clauses_datalog(declarations, clauses, writer):
    reserved_exit_point = 'reserved_exit_point'
    writer.write('(declare-rel {} ())\n\n'.format(reserved_exit_point))

    for decl in declarations:
        symbol = quote_symbol_if_needed(decl.name())
        writer.write('(declare-rel {} ('.format(symbol))
        for n in range(0, decl.arity()):
            writer.write((" {}".format(decl.domain(n))))
        writer.write(' ))\n')

    known_vars = set([])
    implications = []
    writer.write('\n')

    for clause in clauses:
        if not (z3.is_quantifier(clause) and clause.is_forall()):
            raise Exception("Illegal clause for write_clause_smt2: {}".format(
                clause.decl()))

        for idx in range(0, clause.num_vars()):
            if (clause.var_name(idx), clause.var_sort(idx)) not in known_vars:
                known_vars.add((clause.var_name(idx), clause.var_sort(idx)))
                writer.write("(declare-var {} {})\n".format(
                    clause.var_name(idx),
                    clause.var_sort(idx).sexpr()))

        implication = clause.body()
        subst = list(
            reversed([
                z3.Const(clause.var_name(n), clause.var_sort(n))
                for n in range(0, clause.num_vars())
            ]))

        implications.append(z3.substitute_vars(implication, *subst))

    writer.write('\n')

    for implication in implications:
        writer.write('(rule\n')
        write_implication_smt2(implication, '  ', reserved_exit_point, writer)
        writer.write('\n)\n')

    writer.write('\n\n(query {})\n\n'.format(reserved_exit_point))
Exemplo n.º 17
0
def negated_body(formula):
    """Given a z3.QuantiferRef formula with z3.Int variables,
    return negation of the body.

    Returns:
        A z3.BoolRef which is the negation of the formula body.
    """
    assert z3.is_quantifier(formula), ('Formula is not a quantifier:\n',
                                       formula)
    var_names = [formula.var_name(i) for i in range(formula.num_vars())]
    vs = [z3.Int(n) for n in var_names]

    # Here simply doing z3.Not(formula.body()) doesn't work. formula.body()
    # returns an expression without any bounded variable, i.e., it refers
    # variables using indices in the order they appear instead of its names,
    # Var(0), Var(1), Var(2). Thus, we have to re-bind the variables using
    # substitute_vars. It is also necessary to reverse the list of variables.
    # See https://github.com/Z3Prover/z3/issues/402 for more details.
    return z3.Not(z3.substitute_vars(formula.body(), *reversed(vs)))
Exemplo n.º 18
0
 def termination(self,entry,header,kind,pieces,loop,exit):
     """ instruments the rules in fp with a ranking function 
         in order to extract a NON-TERMINATING execution
         such that rank is negative within the loop
     """
     def mx(rankings):
         """ builds a MAX combination of a list of ranking functions """
         if len(rankings) <= 1:
             return rankings[0]
         else:
             r = mx(rankings[1:])
             return z3.If(rankings[0] < r,r,rankings[0])
     # new z3.Fixedpoint object
     fp = z3.Fixedpoint()
     fp.set(engine='spacer')
     fp.set('xform.inline_eager', False)
     fp.set('xform.slice', False)
     fp.set('xform.inline_linear', False)
     fp.set('pdr.utvpi', False)
     # fp.set('timeout',1000)
     # variable declarations
     for x in self.variables:
         fp.declare_var(x)
     # ranking function counter
     components = len(pieces)
     R = [z3.Int('R%d' % i) for i in range(components)]
     for component in R: fp.declare_var(component)
     RR = [z3.Int('RR%d' % i) for i in range(components)]
     for component in RR: fp.declare_var(component)
     # modifying and adding rules
     for rule in self.rules:
         r = Rule(rule.rule)
         if r.is_entry(entry):
             # ranking function(s) initialization before the loop
             rank = [[z3.substitute_vars(x,*r.head_args()[1:]) 
                 for x in component] for component in pieces]
             r.add_rank(R,[mx(component) for component in rank],RR)
             fp.register_relation(r.predicate)
             # print 'ENTRY:', r
         elif r.is_loop(loop):
             # ranking function(s) strict decrease within the loop
             rank = [[z3.substitute_vars(x,*r.head_args()[1:]) 
                 for x in component] for component in pieces]
             r.add_decrease(kind,R,[mx(component) for component in rank],RR)
             # print 'LOOP:', r
             # ranking function(s) boundedness from below within the loop
             q = Rule(rule.rule)
             q.add_bound(kind,R)
             q.head_pc(-1)
             fp.rule(q.head,[q.tail] + q.children)
             # print 'EXIT:', q
             # query
             query = z3.Exists(q.variables,q.head)
         else:
             r.add_vars(R)
             # print 'NONE:', r
         # adding modified rules
         if r.tail is None:
             fp.rule(r.head)
         else:
             fp.rule(r.head,[r.tail] + r.children)
     # print '\nFP:', fp
     # querying for non-terminating execution
     result = fp.query(query)
     if result == z3.sat:
         answer = fp.get_ground_sat_answer()
         first = answer.children()[-2]
         point = [x.as_long() for x in first.children()[1:-1]]
         return list(zip(self.arguments[1:],point))
     else:
         return []
Exemplo n.º 19
0
def substitute_vars (t, *m):
  rw = SubstituteVars (*m)
  res = rw (t)
  assert res.eq (z3.substitute_vars (t, *m))
  return res
Exemplo n.º 20
0
    def termination(self, entry, header, kind, pieces, loop, exit):
        """ instruments the rules in fp with a ranking function 
            in order to extract a NON-TERMINATING execution
            such that rank is negative within the loop
        """

        def mx(rankings):
            """ builds a MAX combination of a list of ranking functions """
            if len(rankings) <= 1:
                return rankings[0]
            else:
                r = mx(rankings[1:])
                return z3.If(rankings[0] < r, r, rankings[0])

        # new z3.Fixedpoint object
        fp = z3.Fixedpoint()
        fp.set(engine="spacer")
        fp.set("xform.inline_eager", False)
        fp.set("xform.slice", False)
        fp.set("xform.inline_linear", False)
        fp.set("pdr.utvpi", False)
        # fp.set('timeout',1000)
        # variable declarations
        for x in self.variables:
            fp.declare_var(x)
        # ranking function counter
        components = len(pieces)
        R = [z3.Int("R%d" % i) for i in range(components)]
        for component in R:
            fp.declare_var(component)
        RR = [z3.Int("RR%d" % i) for i in range(components)]
        for component in RR:
            fp.declare_var(component)
        # modifying and adding rules
        for rule in self.rules:
            r = Rule(rule.rule)
            if r.is_entry(entry):
                # ranking function(s) initialization before the loop
                rank = [[z3.substitute_vars(x, *r.head_args()[1:]) for x in component] for component in pieces]
                r.add_rank(R, [mx(component) for component in rank], RR)
                fp.register_relation(r.predicate)
                # print 'ENTRY:', r
            elif r.is_loop(loop):
                # ranking function(s) strict decrease within the loop
                rank = [[z3.substitute_vars(x, *r.head_args()[1:]) for x in component] for component in pieces]
                r.add_decrease(kind, R, [mx(component) for component in rank], RR)
                # print 'LOOP:', r
                # ranking function(s) boundedness from below within the loop
                q = Rule(rule.rule)
                q.add_bound(kind, R)
                q.head_pc(-1)
                fp.rule(q.head, [q.tail] + q.children)
                # print 'EXIT:', q
                # query
                query = z3.Exists(q.variables, q.head)
            else:
                r.add_vars(R)
                # print 'NONE:', r
            # adding modified rules
            if r.tail is None:
                fp.rule(r.head)
            else:
                fp.rule(r.head, [r.tail] + r.children)
        # print '\nFP:', fp
        # querying for non-terminating execution
        result = fp.query(query)
        if result == z3.sat:
            answer = fp.get_ground_sat_answer()
            first = answer.children()[-2]
            point = [x.as_long() for x in first.children()[1:-1]]
            return zip(self.arguments[1:], point)
        else:
            return []
Exemplo n.º 21
0
def piecewise(fp):
    # program CFG
    program = Program(fp)
    parameters = program.parameters[1:]
    variables = [
        z3.Var(i, sort)
        for (i, sort) in zip(list(range(len(parameters))), parameters)
    ]
    arguments = program.arguments[1:]

    # loops identification
    loops = program.loops_identification()
    # proving termination...
    rank = dict()
    for node in loops:
        # ...for all loops involving each node
        if loops[node]:
            if debug: print('\nloop:', loops[node], '\n')
            loop = set([n for path in loops[node] for n in path])  # loop nodes
            entry = set([(n, node)
                         for n in program.prev[node] - loop])  # entry edges
            edges = set([
                n for path in loops[node] for n in zip(path[:-1], path[1:])
            ])  # loop edges
            # exit = set([(node,n)
            #     for n in program.next[node] - loop])  # exit edges
            exit = set([(i, n) for i in loop
                        for n in program.next[i] - loop])  # exit edges

            bits = list()  # (potentially) terminating bits
            pieces = [[z3.IntSort().cast(0)]]  # candidate ranking functions
            bit = program.get_bit(entry, node, 'max', pieces, edges, exit)
            while bit:
                bit[node][0][-len(pieces)] -= bit[node][-1][-len(pieces)]
                bits.append(bit[node][0][:len(bit[node][0]) - len(pieces) + 1])
                rankings = ranking(bits, variables)
                for i in range(len(bits)):
                    rankings = ranking(bits[:i + 1], variables)
                if not rankings:
                    if debug: print()
                    del bits[:-1]
                    rankings = ranking(bits, variables)
                if debug:
                    print(
                        'bit:',
                        list(
                            zip(arguments + ['-' for component in pieces],
                                bits[-1])))
                pieces[0].extend(rankings)
                if debug:
                    print('pieces:', [[
                        z3.substitute_vars(x, *arguments) for x in component
                    ] for component in pieces])
                bit = program.get_bit(entry, node, 'max', pieces, edges, exit)
            # check candidate ranking functions
            point = program.termination(entry, node, 'max', pieces, edges,
                                        exit)
            pieces = [[z3.substitute_vars(x, *arguments) for x in component]
                      for component in pieces]
            if point:
                rank[node] = (False, point)
                if debug: print('\nnon-terminating execution:', point)
                if debug: print('(partial) loop ranking functions:', pieces)
            else:
                rank[node] = (True, pieces)
                if debug: print('\nloop ranking functions:', pieces)
    if debug: print('\nranking functions:', rank)
    if all([r[0] for r in list(rank.values())]):
        stat("Result", "TRUE")
    else:
        stat("Result", "FALSE")
Exemplo n.º 22
0
    def get_bit(self, entry, header, kind, pieces, loop, exit):
        """ instruments the program rules with a ranking function
            in order to extract a TERMINATING execution
            such that rank is negative at loop exit
        """

        def mx(rankings):
            """ builds a MAX combination of a list of ranking functions """
            if len(rankings) <= 1:
                return rankings[0]
            else:
                r = mx(rankings[1:])
                return z3.If(rankings[0] < r, r, rankings[0])

        # new z3.Fixedpoint object
        fp = z3.Fixedpoint()
        fp.set(engine="spacer")
        fp.set("xform.inline_eager", False)
        fp.set("xform.slice", False)
        fp.set("xform.inline_linear", False)
        fp.set("pdr.utvpi", False)
        # fp.set('timeout',1000)
        # variable declarations
        for x in self.variables:
            fp.declare_var(x)
        # ranking function counter
        components = len(pieces)
        R = [z3.Int("R%d" % i) for i in range(components)]
        for component in R:
            fp.declare_var(component)
        RR = [z3.Int("RR%d" % i) for i in range(components)]
        for component in RR:
            fp.declare_var(component)
        # modifying and adding rules
        for rule in self.rules:
            r = Rule(rule.rule)
            if r.is_entry(entry):
                # ranking function(s) initialization before the loop
                rank = [[z3.substitute_vars(x, *r.head_args()[1:]) for x in component] for component in pieces]
                r.add_rank(R, [mx(component) for component in rank], RR)
                fp.register_relation(r.predicate)
            elif r.is_loop(loop):
                # ranking function(s) strict decrease within the loop
                rank = [[z3.substitute_vars(x, *r.head_args()[1:]) for x in component] for component in pieces]
                r.add_decrease(kind, R, [mx(component) for component in rank], RR)
            elif r.is_exit(exit):
                r.add_vars(R)
                # ranking function(s) boundedness from below after the loop
                q = Rule(rule.rule)
                q.add_bound(kind, R)
                q.head_pc(-1)
                fp.rule(q.head, [q.tail] + q.children)
                # query
                query = z3.Exists(q.variables, q.head)
            else:
                r.add_vars(R)
                # print 'NONE:', r
            # adding modified rules
            if r.tail is None:
                fp.rule(r.head)
            else:
                body = [r.tail] + r.children
                fp.rule(r.head, body)
        # querying for terminating execution with negative ranking function
        bit = dict()
        result = fp.query(query)
        if result == z3.sat:
            answer = fp.get_ground_sat_answer()
            children = answer.children()
            # print 'CHILDREN:\n', children
            bit = dict()
            for child in children:
                if child.children():  # some predicate might not have values
                    values = [x.as_long() for x in child.children()]
                    if values[0] not in bit:
                        bit[values[0]] = [values[1:]]
                    else:
                        bit[values[0]].insert(0, values[1:])
            # adding the first child to loop header to ensure progress
            # (when the source of exit edges is not the loop header)
            first = [child for child in children if child.children()][0]
            values = [x.as_long() for x in first.children()]
            if header not in bit:
                bit[header] = [values[1:]]
            else:
                bit[header].append(values[1:])
            return bit
        else:
            return bit
Exemplo n.º 23
0
def piecewise(fp):
    # program CFG
    program = Program(fp)
    parameters = program.parameters[1:]
    variables = [z3.Var(i, sort) for (i,sort)
        in zip(list(range(len(parameters))),parameters)]
    arguments = program.arguments[1:]

    # loops identification
    loops = program.loops_identification()
    # proving termination...
    rank = dict()
    for node in loops:
        # ...for all loops involving each node
        if loops[node]:
            if debug: print '\nloop:', loops[node], '\n'
            loop = set([n for path in loops[node] for n in path])   # loop nodes
            entry = set([(n,node)
                for n in program.prev[node] - loop])  # entry edges
            edges = set([n for path in loops[node]
                for n in zip(path[:-1],path[1:])])  # loop edges
            # exit = set([(node,n)
            #     for n in program.next[node] - loop])  # exit edges
            exit = set([(i,n)
                for i in loop for n in program.next[i] - loop])  # exit edges

            bits = list()   # (potentially) terminating bits
            pieces = [[z3.IntSort().cast(0)]]    # candidate ranking functions
            bit = program.get_bit(entry,node,'max',pieces,edges,exit)
            while bit:
                bit[node][0][-len(pieces)] -= bit[node][-1][-len(pieces)]
                bits.append(bit[node][0][:len(bit[node][0])-len(pieces)+1])
                rankings = ranking(bits,variables)
                for i in range(len(bits)):
                    rankings = ranking(bits[:i+1],variables)
                if not rankings:
                    if debug: print
                    del bits[:-1]
                    rankings = ranking(bits,variables)
                if debug: print 'bit:', zip(arguments + ['-'
                    for component in pieces],bits[-1])
                pieces[0].extend(rankings)
                if debug: print 'pieces:', [[z3.substitute_vars(x,*arguments)
                    for x in component] for component in pieces]
                bit = program.get_bit(entry,node,'max',pieces,edges,exit)
            # check candidate ranking functions
            point = program.termination(entry,node,'max',pieces,edges,exit)
            pieces = [[z3.substitute_vars(x,*arguments)
                for x in component] for component in pieces]
            if point:
                rank[node] = (False,point)
                if debug: print '\nnon-terminating execution:', point
                if debug: print '(partial) loop ranking functions:', pieces
            else:
                rank[node] = (True,pieces)
                if debug: print '\nloop ranking functions:', pieces
    if debug: print '\nranking functions:', rank
    if all([r[0] for r in rank.values()]):
        stat("Result", "TRUE")
    else:
        stat("Result", "FALSE")
Exemplo n.º 24
0
 def get_bit(self,entry,header,kind,pieces,loop,exit):
     """ instruments the program rules with a ranking function
         in order to extract a TERMINATING execution
         such that rank is negative at loop exit
     """
     def mx(rankings):
         """ builds a MAX combination of a list of ranking functions """
         if len(rankings) <= 1:
             return rankings[0]
         else:
             r = mx(rankings[1:])
             return z3.If(rankings[0] < r,r,rankings[0])
     # new z3.Fixedpoint object
     fp = z3.Fixedpoint()
     fp.set(engine='spacer')
     fp.set('xform.inline_eager', False)
     fp.set('xform.slice', False)
     fp.set('xform.inline_linear', False)
     fp.set('pdr.utvpi', False)
     # fp.set('timeout',1000)
     # variable declarations
     for x in self.variables:
         fp.declare_var(x)
     # ranking function counter
     components = len(pieces)
     R = [z3.Int('R%d' % i) for i in range(components)]
     for component in R: fp.declare_var(component)
     RR = [z3.Int('RR%d' % i) for i in range(components)]
     for component in RR: fp.declare_var(component)
     # modifying and adding rules
     for rule in self.rules:
         r = Rule(rule.rule)
         if r.is_entry(entry):
             # ranking function(s) initialization before the loop
             rank = [[z3.substitute_vars(x,*r.head_args()[1:]) 
                 for x in component] for component in pieces]
             r.add_rank(R,[mx(component) for component in rank],RR)
             fp.register_relation(r.predicate)
         elif r.is_loop(loop):
             # ranking function(s) strict decrease within the loop
             rank = [[z3.substitute_vars(x,*r.head_args()[1:]) 
                 for x in component] for component in pieces]
             r.add_decrease(kind,R,[mx(component) for component in rank],RR)
         elif r.is_exit(exit):
             r.add_vars(R)
             # ranking function(s) boundedness from below after the loop
             q = Rule(rule.rule)
             q.add_bound(kind,R)
             q.head_pc(-1)
             fp.rule(q.head,[q.tail] + q.children)
             # query
             query = z3.Exists(q.variables,q.head)
         else:
             r.add_vars(R)
             # print 'NONE:', r
         # adding modified rules
         if r.tail is None:
             fp.rule(r.head)
         else:
             body = [r.tail] + r.children
             fp.rule(r.head,body)
     # querying for terminating execution with negative ranking function
     bit = dict()
     result = fp.query(query)
     if result == z3.sat:
         answer = fp.get_ground_sat_answer()
         children = answer.children()
         # print 'CHILDREN:\n', children
         bit = dict()
         for child in children:
             if child.children():    # some predicate might not have values
                 values = [x.as_long() for x in child.children()]
                 if values[0] not in bit:
                     bit[values[0]] = [values[1:]]
                 else:
                     bit[values[0]].insert(0,values[1:])
         # adding the first child to loop header to ensure progress 
         # (when the source of exit edges is not the loop header)
         first = [child for child in children if child.children()][0]
         values = [x.as_long() for x in first.children()]
         if header not in bit:
             bit[header] = [values[1:]]
         else:
             bit[header].append(values[1:])
         return bit
     else:
         return bit
Exemplo n.º 25
0
def substitute_vars (t, *m):
  rw = SubstituteVars (*m)
  res = rw (t)
  assert res.eq (z3.substitute_vars (t, *m))
  return res
Exemplo n.º 26
0
    def substitute(self, other, expr):
        def update_term(t, args):
            n = len(args)
            # Need to pass an AstArray type into Z3_update_term, not a python list
            args_ast_arr = (z3.Ast * n)()
            for i in range(n):
                args_ast_arr[i] = args[i].as_ast()
            return _to_expr_ref(
                z3.Z3_update_term(t.ctx_ref(), t.as_ast(), n, args_ast_arr),
                t.ctx)

        cache = z3.AstMap(ctx=expr.ctx)

        for addr, state in self._expanded_global_state.items():
            other_state = other.initial_contract_state(addr)
            cache[state.storage] = other_state.storage
            cache[state.balance] = other_state.balance
            cache[state.nonce] = other_state.nonce

        fnsubs = []
        for k, v in self._cache.items():
            if isinstance(v, mem.Memory):
                # Uses of Memory objects will produce an expression containing
                # the underlying array object (_mem). If required the index
                # (_idx) will have been substituted with the actual indexing
                # expression at that point, so we do not need to consider it
                # here.
                cache[v._mem] = getattr(other, k)()._mem
            elif z3.is_app(v) and v.num_args() > 0:
                fnsubs.append((v, getattr(other, k)()))
            else:
                cache[v] = getattr(other, k)()

        todo = [expr]
        while todo:
            n = todo[-1]
            if n in cache:
                todo.pop()
            elif z3.is_var(n):
                cache[n] = n
                todo.pop()
            elif z3.is_app(n):
                new_args = []
                for i in range(n.num_args()):
                    arg = n.arg(i)
                    if arg not in cache:
                        todo.append(arg)
                    else:
                        new_args.append(cache[arg])
                # Only actually do the substitution if all the arguments have
                # already been processed
                if len(new_args) == n.num_args():
                    todo.pop()
                    fn = n.decl()
                    for oldfn, newfn in fnsubs:
                        if z3.eq(fn, oldfn):
                            new_fn = z3.substitute_vars(newfn, *new_args)
                            break
                    else:
                        # TODO only if new_args != old_args
                        if len(new_args) != fn.arity():
                            new_fn = update_term(n, new_args)
                        else:
                            new_fn = fn(*new_args)
                    cache[n] = new_fn
            else:
                assert z3.is_quantifier(n)
                # Not currently implemented as don't use quanitifers at the
                # moment
                raise NotImplementedError()
        return cache[expr]