Example #1
0
def to_smt_expr_under_op (expr, env, solv):
	if expr.kind == 'Op':
		vals = [to_smt_expr (v, env, solv) for v in expr.vals]
		return syntax.Expr ('Op', expr.typ, name = expr.name,
			vals = vals)
	else:
		return to_smt_expr (expr, env, solv)
Example #2
0
	def get_var (k):
		head = rep.p.loop_id (i)
		if i != head:
			k += 1
		restrs2 = restrs + ((head, vc_num (k)), )
		(pc, env) = rep.get_node_pc_env ((i, restrs2))
		return (to_smt_expr (pc, env, rep.solv),
			to_smt_expr (v_i, env, rep.solv))
Example #3
0
def trace_mem(rep,
              tag,
              m,
              verbose=False,
              simplify=True,
              symbs=True,
              resolve_addrs=False):
    p = rep.p
    ns = walk_model(rep, tag, m)
    trace = []
    for (n, vc) in ns:
        if (n, vc) not in rep.arc_pc_envs:
            # this n_vc has a pre-state, but has not been emitted.
            # no point trying to evaluate its expressions, the
            # solve won't have seen them yet.
            continue
        n_nm = rep.node_count_name((n, vc))
        node = p.nodes[n]
        if node.kind == 'Call':
            exprs = list(node.args)
        elif node.kind == 'Basic':
            exprs = [expr for (_, expr) in node.upds]
        elif node.kind == 'Cond':
            exprs = [node.cond]
        env = rep.node_pc_envs[(tag, n, vc)][1]
        accs = list(
            set([acc for expr in exprs for acc in expr.get_mem_accesses()]))
        for (kind, addr, v, mem) in accs:
            addr_s = solver.smt_expr(addr, env, rep.solv)
            v_s = solver.smt_expr(v, env, rep.solv)
            addr = eval_str(addr, env, rep.solv, m)
            v = eval_str(v, env, rep.solv, m)
            m_nm = m_var_name(mem)
            print '%s: %s @ <%s>   -- %s -- %s' % (kind, m_nm, addr, v, n_nm)
            if simplify:
                addr_s = simplify_sexp(addr_s, rep, m)
                v_s = simplify_sexp(v_s, rep, m)
            if verbose:
                print '\t %s -- %s' % (addr_s, v_s)
            if symbs:
                addr_n = str_to_num(addr)
                (hit_symbs, secs) = find_symbol(addr_n, output=False)
                ss = hit_symbs + secs
                if ss:
                    print '\t [%s]' % ', '.join(ss)
        if resolve_addrs:
            accs = [(kind, solver.to_smt_expr(addr, env, rep.solv),
                     solver.to_smt_expr(v, env, rep.solv), mem)
                    for (kind, addr, v, mem) in accs]
        trace.extend([(kind, addr, v, mem, n, vc)
                      for (kind, addr, v, mem) in accs])
        if node.kind == 'Call':
            msg = '<function call to %s at %s>' % (node.fname, n_nm)
            print msg
            trace.append(msg)
    return trace
Example #4
0
def trace_mem(rep, tag, m, verbose=False, simplify=True, symbs=True, resolve_addrs=False):
    p = rep.p
    ns = walk_model(rep, tag, m)
    trace = []
    for (n, vc) in ns:
        if (n, vc) not in rep.arc_pc_envs:
            # this n_vc has a pre-state, but has not been emitted.
            # no point trying to evaluate its expressions, the
            # solve won't have seen them yet.
            continue
        n_nm = rep.node_count_name((n, vc))
        node = p.nodes[n]
        if node.kind == "Call":
            msg = "<function call to %s at %s>" % (node.fname, n_nm)
            print msg
            trace.append(msg)
        if node.kind == "Basic":
            exprs = [expr for (_, expr) in node.upds]
        elif node.kind == "Cond":
            exprs = [node.cond]
        else:
            continue
        env = rep.node_pc_envs[(tag, n, vc)][1]
        accs = list(set([acc for expr in exprs for acc in expr.get_mem_accesses()]))
        for (kind, addr, v, mem) in accs:
            addr_s = solver.smt_expr(addr, env, rep.solv)
            v_s = solver.smt_expr(v, env, rep.solv)
            addr = eval_str(addr, env, rep.solv, m)
            v = eval_str(v, env, rep.solv, m)
            m_nm = m_var_name(mem)
            print "%s: %s @ <%s>   -- %s -- %s" % (kind, m_nm, addr, v, n_nm)
            if simplify:
                addr_s = simplify_sexp(addr_s, rep, m)
                v_s = simplify_sexp(v_s, rep, m)
            if verbose:
                print "\t %s -- %s" % (addr_s, v_s)
            if symbs:
                (hit_symbs, secs) = find_symbol(addr, output=False)
                ss = hit_symbs + secs
                if ss:
                    print "\t [%s]" % ", ".join(ss)
        if resolve_addrs:
            accs = [
                (kind, solver.to_smt_expr(addr, env, rep.solv), solver.to_smt_expr(v, env, rep.solv), mem)
                for (kind, addr, v, mem) in accs
            ]
        trace.extend([(kind, addr, v, mem, n, vc) for (kind, addr, v, mem) in accs])
    return trace
Example #5
0
def eval_str(expr, env, solv, m):
    expr = solver.to_smt_expr(expr, env, solv)
    v = search.eval_model_expr(m, solv, expr)
    if v.typ == syntax.boolT:
        assert v in [syntax.true_term, syntax.false_term]
        return v.name
    elif v.typ.kind == "Word":
        return solver.smt_num(v.val, v.typ.num)
    else:
        assert not "type printable", v
Example #6
0
def eval_str(expr, env, solv, m):
    expr = solver.to_smt_expr(expr, env, solv)
    v = search.eval_model_expr(m, solv, expr)
    if v.typ == syntax.boolT:
        assert v in [syntax.true_term, syntax.false_term]
        return v.name
    elif v.typ.kind == 'Word':
        return solver.smt_num_t(v.val, v.typ)
    else:
        assert not 'type printable', v
Example #7
0
def find_case_split (p, head, restrs, hyps, tags = None):
	# are there multiple paths to the loop head 'head' and can we
	# restrict to one of them?
	preds = set ()
	frontier = list (set ([n2 for n in p.loop_body (head)
		for n2 in p.preds[n] if p.loop_id (n2) != head]))
	while frontier:
		n2 = frontier.pop ()
		if n2 in preds:
			continue
		preds.add (n2)
		frontier.extend (p.preds[n2])
	divs = [n2 for n2 in preds if len (set ([n3
		for n3 in p.nodes[n2].get_conts ()
			if n3 in preds or n3 == head])) > 1
		if n2 not in p.loop_data]

	trace ('find_case_split: possible divs %s.' % divs)

	rep = mk_graph_slice (p)
	err_restrs = restr_others (p, restrs, 2)
	if tags:
		l_tag, r_tag = tags
	else:
		l_tag, r_tag = p.pairing.tags
	hvis_restrs = tuple ([(head, rep_graph.vc_num (0))]) + restrs
	
	lhyps = hyps + [rep_graph.pc_false_hyp ((('Err', err_restrs), r_tag)),
		rep_graph.pc_true_hyp (((head, hvis_restrs),
			p.node_tags[head][0]))]

	# for this to be a usable case split, both paths must be possible
	for div in divs:
		dhyps = lhyps + [rep_graph.pc_true_hyp (((div, restrs),
			p.node_tags[div][0]))]
		assert p.nodes[div].kind == 'Cond'
		(_, env) = rep.get_node_pc_env ((div, restrs))
		c = to_smt_expr (p.nodes[div].cond, env, rep.solv)
		if (rep.test_hyp_whyps (c, dhyps)
				or rep.test_hyp_whyps (mk_not (c), dhyps)):
			continue
		trace ("attempting case split at %d" % div)
		sides = [n for n in p.nodes[div].get_conts ()
			if n not in p.loop_data
			if p.preds[n] == [div]]
		if not sides:
			trace ("skipping case split, no notable succ")
		n = sides[0]
		return ('CaseSplit', (n, p.node_tags[n][0]))
	trace ('find_case_split: no case splits possible')
	return (None, ())
Example #8
0
def ident_callables (fname, callees, idents):
	from solver import to_smt_expr, smt_expr
	from syntax import mk_not, mk_and, true_term

	auto_callables = dict ([((ident, f, true_term), True)
		for ident in idents.get (fname, [true_term])
		for f in callees if f not in idents])

	if not [f for f in callees if f in idents]:
		return auto_callables

	fun = functions[fname]
	p = fun.as_problem (problem.Problem, name = 'Target')
	check_ns = [(n, ident, cond) for n in p.nodes
		if p.nodes[n].kind == 'Call'
		if p.nodes[n].fname in idents
		for (ident, cond) in ident_conds (p.nodes[n].fname, idents)]

	p.do_analysis ()
	assert check_ns

	rep = rep_graph.mk_graph_slice (p, fast = True)
	err_hyp = rep_graph.pc_false_hyp ((default_n_vc (p, 'Err'), 'Target'))

	callables = auto_callables
	nhyps = mk_not_callable_hyps (p)

	for (ident, cond) in ident_conds (fname, idents):
		renames = p.entry_exit_renames (tags = ['Target'])
		cond = syntax.rename_expr (cond, renames['Target_IN'])
		entry = p.get_entry ('Target')
		e_vis = ((entry, ()), 'Target')
		hyps = [err_hyp, rep_graph.eq_hyp ((cond, e_vis),
				(true_term, e_vis))]

		for (n, ident2, cond2) in check_ns:
			k = (ident, p.nodes[n].fname, ident2)
			(inp_env, _, _) = rep.get_func (default_n_vc (p, n))
			pc = rep.get_pc (default_n_vc (p, n))
			cond2 = to_smt_expr (cond2, inp_env, rep.solv)
			if rep.test_hyp_whyps (mk_not (mk_and (pc, cond2)),
					hyps + nhyps):
				callables[k] = False
			else:
				callables[k] = True
	return callables
Example #9
0
def ident_callables(fname, callees, idents):
    from solver import to_smt_expr, smt_expr
    from syntax import mk_not, mk_and, true_term

    auto_callables = dict([((ident, f, true_term), True)
                           for ident in idents.get(fname, [true_term])
                           for f in callees if f not in idents])

    if not [f for f in callees if f in idents]:
        return auto_callables

    fun = functions[fname]
    p = fun.as_problem(problem.Problem, name='Target')
    check_ns = [(n, ident, cond) for n in p.nodes if p.nodes[n].kind == 'Call'
                if p.nodes[n].fname in idents
                for (ident, cond) in ident_conds(p.nodes[n].fname, idents)]

    p.do_analysis()
    assert check_ns

    rep = rep_graph.mk_graph_slice(p, fast=True)
    err_hyp = rep_graph.pc_false_hyp((default_n_vc(p, 'Err'), 'Target'))

    callables = auto_callables
    nhyps = mk_not_callable_hyps(p)

    for (ident, cond) in ident_conds(fname, idents):
        renames = p.entry_exit_renames(tags=['Target'])
        cond = syntax.rename_expr(cond, renames['Target_IN'])
        entry = p.get_entry('Target')
        e_vis = ((entry, ()), 'Target')
        hyps = [err_hyp, rep_graph.eq_hyp((cond, e_vis), (true_term, e_vis))]

        for (n, ident2, cond2) in check_ns:
            k = (ident, p.nodes[n].fname, ident2)
            (inp_env, _, _) = rep.get_func(default_n_vc(p, n))
            pc = rep.get_pc(default_n_vc(p, n))
            cond2 = to_smt_expr(cond2, inp_env, rep.solv)
            if rep.test_hyp_whyps(mk_not(mk_and(pc, cond2)), hyps + nhyps):
                callables[k] = False
            else:
                callables[k] = True
    return callables
Example #10
0
def find_unknown_recursion (p, group, idents, tag, assns, extra_unfolds):
	from syntax import mk_not, mk_and, foldr1
	rep = rep_graph.mk_graph_slice (p, fast = True)
	for n in p.nodes:
		if p.nodes[n].kind != 'Call':
			continue
		if p.node_tags[n][0] != tag:
			continue
		fname = p.nodes[n].fname
		if fname in extra_unfolds:
			return n
		if fname not in group:
			continue
		(inp_env, _, _) = rep.get_func (default_n_vc (p, n))
		pc = rep.get_pc (default_n_vc (p, n))
		new = foldr1 (mk_and, [pc] + [syntax.mk_not (
				solver.to_smt_expr (ident, inp_env, rep.solv))
			for ident in idents.get (fname, [])])
		if rep.test_hyp_whyps (mk_not (new), assns):
			continue
		return n
	return None
Example #11
0
def find_unknown_recursion(p, group, idents, tag, assns, extra_unfolds):
    from syntax import mk_not, mk_and, foldr1
    rep = rep_graph.mk_graph_slice(p, fast=True)
    for n in p.nodes:
        if p.nodes[n].kind != 'Call':
            continue
        if p.node_tags[n][0] != tag:
            continue
        fname = p.nodes[n].fname
        if fname in extra_unfolds:
            return n
        if fname not in group:
            continue
        (inp_env, _, _) = rep.get_func(default_n_vc(p, n))
        pc = rep.get_pc(default_n_vc(p, n))
        new = foldr1(mk_and, [pc] + [
            syntax.mk_not(solver.to_smt_expr(ident, inp_env, rep.solv))
            for ident in idents.get(fname, [])
        ])
        if rep.test_hyp_whyps(mk_not(new), assns):
            continue
        return n
    return None
Example #12
0
def add_recursion_ident(f, group, idents, extra_unfolds):
    from syntax import mk_eq, mk_implies, mk_var
    p = problem.Problem(None, name='Recursion Test')
    chain = []
    tag = 'fun0'
    p.add_entry_function(functions[f], tag)
    p.do_analysis()
    assns = []
    recursion_last_assns[0] = assns

    while True:
        res = find_unknown_recursion(p, group, idents, tag, assns,
                                     extra_unfolds)
        if res == None:
            break
        if p.nodes[res].fname not in group:
            problem.inline_at_point(p, res)
            continue
        fname = p.nodes[res].fname
        chain.append(fname)
        tag = 'fun%d' % len(chain)
        (args, _, entry) = p.add_entry_function(functions[fname], tag)
        p.do_analysis()
        assns += function_link_assns(p, res, tag)
    if chain == []:
        return None
    recursion_trace.append('  created fun chain %s' % chain)
    word_args = [(i, mk_var(s, typ)) for (i, (s, typ)) in enumerate(args)
                 if typ.kind == 'Word']
    rep = rep_graph.mk_graph_slice(p, fast=True)
    (_, env) = rep.get_node_pc_env((entry, ()))

    m = {}
    res = rep.test_hyp_whyps(syntax.false_term, assns, model=m)
    assert m

    if find_unknown_recursion(p, group, idents, tag, [], []) == None:
        idents.setdefault(fname, [])
        idents[fname].append(syntax.true_term)
        recursion_trace.append('      found final ident for %s' % fname)
        return syntax.true_term
    assert word_args
    recursion_trace.append('      scanning for ident for %s' % fname)
    for (i, arg) in word_args:
        (nm, typ) = functions[fname].inputs[i]
        arg_smt = solver.to_smt_expr(arg, env, rep.solv)
        val = search.eval_model_expr(m, rep.solv, arg_smt)
        if not rep.test_hyp_whyps(mk_eq(arg_smt, val), assns):
            recursion_trace.append('      discarded %s = 0x%x, not stable' %
                                   (nm, val.val))
            continue
        entry_vis = ((entry, ()), tag)
        ass = rep_graph.eq_hyp((arg, entry_vis), (val, entry_vis))
        res = find_unknown_recursion(p, group, idents, tag, assns + [ass], [])
        if res:
            fname2 = p.nodes[res].fname
            recursion_trace.append(
                '      discarded %s, allows recursion to %s' % (nm, fname2))
            continue
        eq = syntax.mk_eq(mk_var(nm, typ), val)
        idents.setdefault(fname, [])
        idents[fname].append(eq)
        recursion_trace.append('    found ident for %s: %s' % (fname, eq))
        return eq
    assert not "identifying assertion found"
Example #13
0
def add_recursion_ident (f, group, idents, extra_unfolds):
	from syntax import mk_eq, mk_implies, mk_var
	p = problem.Problem (None, name = 'Recursion Test')
	chain = []
	tag = 'fun0'
	p.add_entry_function (functions[f], tag)
	p.do_analysis ()
	assns = []
	recursion_last_assns[0] = assns

	while True:
		res = find_unknown_recursion (p, group, idents, tag, assns,
			extra_unfolds)
		if res == None:
			break
		if p.nodes[res].fname not in group:
			problem.inline_at_point (p, res)
			continue
		fname = p.nodes[res].fname
		chain.append (fname)
		tag = 'fun%d' % len (chain)
		(args, _, entry) = p.add_entry_function (functions[fname], tag)
		p.do_analysis ()
		assns += function_link_assns (p, res, tag)
	if chain == []:
		return None
	recursion_trace.append ('  created fun chain %s' % chain)
	word_args = [(i, mk_var (s, typ))
		for (i, (s, typ)) in enumerate (args)
		if typ.kind == 'Word']
	rep = rep_graph.mk_graph_slice (p, fast = True)
	(_, env) = rep.get_node_pc_env ((entry, ()))

	m = {}
	res = rep.test_hyp_whyps (syntax.false_term, assns, model = m)
	assert m

	if find_unknown_recursion (p, group, idents, tag, [], []) == None:
		idents.setdefault (fname, [])
		idents[fname].append (syntax.true_term)
		recursion_trace.append ('      found final ident for %s' % fname)
		return syntax.true_term
	assert word_args
	recursion_trace.append ('      scanning for ident for %s' % fname)
	for (i, arg) in word_args:
		(nm, typ) = functions[fname].inputs[i]
		arg_smt = solver.to_smt_expr (arg, env, rep.solv)
		val = search.eval_model_expr (m, rep.solv, arg_smt)
		if not rep.test_hyp_whyps (mk_eq (arg_smt, val), assns):
			recursion_trace.append ('      discarded %s = 0x%x, not stable' % (nm, val.val))
			continue
		entry_vis = ((entry, ()), tag)
		ass = rep_graph.eq_hyp ((arg, entry_vis), (val, entry_vis))
		res = find_unknown_recursion (p, group, idents, tag,
				assns + [ass], [])
		if res:
			fname2 = p.nodes[res].fname
			recursion_trace.append ('      discarded %s, allows recursion to %s' % (nm, fname2))
			continue
		eq = syntax.mk_eq (mk_var (nm, typ), val)
		idents.setdefault (fname, [])
		idents[fname].append (eq)
		recursion_trace.append ('    found ident for %s: %s' % (fname, eq))
		return eq
	assert not "identifying assertion found"
Example #14
0
				return self.get_loop_pc_env (split, vcount)

		pc_envs = [pc_env for n_prev in self.p.preds[n]
			if self.p.node_tags[n_prev][0] == tag
			for pc_env in self.get_arc_pc_envs (n_prev,
				(n, vcount))]

		pc_envs = [pc_env for pc_env in pc_envs if pc_env]
		if pc_envs == []:
			return None

		if n == 'Err':
			# we'll never care about variable values here
			# and there are sometimes a LOT of arcs to Err
			# so we save a lot of merge effort
			pc_envs = [(to_smt_expr (pc, env, self.solv), {})
				for (pc, env) in pc_envs]

		(pc, env, large) = merge_envs_pcs (pc_envs, self.solv)

		if large or len (smt_expr (pc, env, self.solv)) > 80:
			name = self.path_cond_name ((n, vcount), tag)
			name = self.solv.add_def (name, pc, env)
			pc = mk_smt_expr (name, boolT)
		
		for (nm, typ) in env:
			if len (env[(nm, typ)]) > 80:
				env[(nm, typ)] = self.contract (nm, (n, vcount),
					env[(nm, typ)], typ)

		return (pc, env)