Exemple #1
0
def inline_reachable_unmatched(p,
                               inline_tag,
                               compare_tag,
                               force_inline=None,
                               skip_underspec=False):
    funs = [
        pair.funs[inline_tag] for n in p.nodes if p.nodes[n].kind == 'Call'
        if p.node_tags[n][0] == compare_tag
        for pair in pairings.get(p.nodes[n].fname, [])
        if inline_tag in pair.tags
    ]

    rep = mk_graph_slice(
        p, consider_inline(funs, inline_tag, force_inline, skip_underspec))
    opts = vc_double_range(3, 3)
    while True:
        try:
            heads = problem.loop_heads_including_inner(p)
            limits = [(n, opts) for n in heads]

            for n in p.nodes.keys():
                try:
                    r = rep.get_node_pc_env((n, limits))
                except rep.TooGeneral:
                    pass

            rep.get_node_pc_env(('Ret', limits), inline_tag)
            rep.get_node_pc_env(('Err', limits), inline_tag)
            break
        except rep_graph.InlineEvent:
            continue
Exemple #2
0
def check_split_induct (p, restrs, hyps, split, tags = None):
	"""perform both the induction check and a function-call based check
	on successes which can avoid some problematic inductions."""
	((l_split, (_, l_step), _), (r_split, (_, r_step), _), _, n, _) = split
	if tags == None:
		tags = p.pairing.tags

	err_hyp = check.split_r_err_pc_hyp (p, split, restrs, tags = tags)
	hyps = [err_hyp] + hyps + check.split_loop_hyps (tags, split,
		restrs, exit = False)

	rep = mk_graph_slice (p)

	if not check.check_split_induct_step_group (rep, restrs, hyps, split,
			tags = tags):
		return False

	l_succs = get_n_offset_successes (rep, l_split, l_step, restrs)
	r_succs = get_n_offset_successes (rep, r_split, r_step, restrs)

	if not l_succs:
		return True

	hyp = syntax.foldr1 (syntax.mk_and, l_succs)
	if r_succs:
		hyp = syntax.mk_implies (foldr1 (syntax.mk_and, r_succs), hyp)

	return rep.test_hyp_whyps (hyp, hyps)
Exemple #3
0
def getBinaryBoundFromC(p, c_tag, asm_split, restrs, hyps):
    c_heads = [
        h for h in search.init_loops_to_split(p, restrs)
        if p.node_tags[h][0] == c_tag
    ]
    c_bounds = [(p.loop_id(split), search_bound(p, (), hyps, split))
                for split in c_heads]
    if not [b for (n, b) in c_bounds if b]:
        trace('no C bounds found (%s).' % c_bounds)
        return None

    asm_tag = p.node_tags[asm_split][0]

    rep = rep_graph.mk_graph_slice(p)
    i_seq_opts = [(0, 1), (1, 1), (2, 1)]
    j_seq_opts = [(0, 1), (0, 2), (1, 1)]
    tags = [p.node_tags[asm_split][0], c_tag]
    try:
        split = search.find_split(rep,
                                  asm_split,
                                  restrs,
                                  hyps,
                                  i_seq_opts,
                                  j_seq_opts,
                                  5,
                                  tags=[asm_tag, c_tag])
    except solver.SolverFailure, e:
        return None
Exemple #4
0
def inline_reachable_unmatched (p, inline_tag, compare_tag,
		force_inline = None, skip_underspec = False):
	funs = [pair.funs['C']
		for n in p.nodes
		if p.nodes[n].kind == 'Call'
		if p.node_tags[n][0] == compare_tag
		for pair in pairings.get (p.nodes[n].fname, [])
		if 'C' in pair.tags]

	rep = mk_graph_slice (p,
		consider_inline_c (funs, inline_tag, force_inline,
			skip_underspec))
	opts = vc_double_range (3, 3)
	while True:
		try:
			limits = [(n, opts) for n in p.loop_heads ()]

			for n in p.nodes.keys ():
				try:
					r = rep.get_node_pc_env ((n, limits))
				except rep.TooGeneral:
					pass

			rep.get_node_pc_env (('Ret', limits), inline_tag)
			rep.get_node_pc_env (('Err', limits), inline_tag)
			break
		except rep_graph.InlineEvent:
			continue
Exemple #5
0
def search_bin_bound(p, restrs, hyps, split):
    trace('Searching for bound for 0x%x in %s.', (split, p.name))
    bound = search_bound(p, restrs, hyps, split)
    if bound:
        return bound

    # try to use a bound inferred from C
    if avoid_C_information[0]:
        # OK told not to
        return None
    if get_prior_loop_heads(p, split):
        # too difficult for now
        return None
    asm_tag = p.node_tags[split][0]
    (_, fname, _) = p.get_entry_details(asm_tag)
    funs = [
        f for pair in target_objects.pairings[fname]
        for f in pair.funs.values()
    ]
    c_tags = [
        tag for tag in p.tags()
        if p.get_entry_details(tag)[1] in funs and tag != asm_tag
    ]
    if len(c_tags) != 1:
        print 'Surprised to see multiple matching tags %s' % c_tags
        return None

    [c_tag] = c_tags

    rep = rep_graph.mk_graph_slice(p)
    if len(search.get_loop_entry_sites(rep, restrs, hyps, split)) != 1:
        # technical, but it's not going to work in this case
        return None

    return getBinaryBoundFromC(p, c_tag, split, restrs, hyps)
Exemple #6
0
def search_bound(p, restrs, hyps, split):
    last_search_bound[0] = (p, restrs, hyps, split)

    # try a naive bin search first
    # limit this to a small bound for time purposes
    #   - for larger bounds the less naive approach can be faster
    bound = findLoopBoundBS(split, p, restrs=restrs, hyps=hyps, try_seq=[0, 1, 6])
    if bound != None:
        return (bound, "NaiveBinSearch")

    l_hyps = get_linear_series_hyps(p, split, restrs, hyps)

    rep = rep_graph.mk_graph_slice(p, fast=True)

    def test(n):
        assert n > 10
        hyp = get_induct_eq_hyp(p, split, restrs, n - 2)
        visit = ((split, vc_offs(2)),) + restrs
        continue_to_split_guess = rep.get_pc((split, visit))
        return rep.test_hyp_whyps(syntax.mk_not(continue_to_split_guess), [hyp] + l_hyps + hyps)

    # findLoopBoundBS always checks to at least 16
    min_bound = 16
    max_bound = max_acceptable_bound[0]
    bound = upDownBinSearch(min_bound, max_bound, test)
    if bound != None and test(bound):
        return (bound, "InductiveBinSearch")

    # let the naive bin search go a bit further
    bound = findLoopBoundBS(split, p, restrs=restrs, hyps=hyps)
    if bound != None:
        return (bound, "NaiveBinSearch")

    return None
Exemple #7
0
def find_split_limit (p, n, restrs, hyps, kind, bound = 51, must_find = True,
		hints = [], use_rep = None):
	tag = p.node_tags[n][0]
	trace ('Finding split limit: %d (%s) %s' % (n, tag, restrs))
	trace ('  (restrs = %s)' % (restrs, ))
	trace ('  (hyps = %s)' % (hyps, ), push = 1)
	if use_rep == None:
		rep = mk_graph_slice (p, fast = True)
	else:
		rep = use_rep
	check_order = hints + [i for i in split_sample_set (bound)
		if i not in hints]
	for i in check_order:
		restrs2 = restrs + ((n, VisitCount (kind, i)), )
		pc = rep.get_pc ((n, restrs2))
		restrs3 = restr_others (p, restrs2, 2)
		epc = rep.get_pc (('Err', restrs3), tag = tag)
		hyp = mk_implies (mk_not (epc), mk_not (pc))
		if rep.test_hyp_whyps (hyp, hyps):
			trace ('split limit found: %d' % i, push = -1)
			return i

	trace ('No split limit found for %d (%s).' % (n, tag), push = -1)
	if must_find:
		assert not 'split limit found'
	return None
Exemple #8
0
def init_case_splits (p, hyps, tags = None):
	if 'init_case_splits' in p.cached_analysis:
		return p.cached_analysis['init_case_splits']
	if tags == None:
		tags = p.pairing.tags
	poss = logic.possible_graph_divs (p)
	if len (set ([p.node_tags[n][0] for n in poss])) < 2:
		return None
	rep = rep_graph.mk_graph_slice (p)
	assert all ([p.nodes[n].kind == 'Cond' for n in poss])
	pc_map = logic.dict_list ([(rep.get_pc ((c, ())), c)
		for n in poss for c in p.nodes[n].get_conts ()
		if c not in p.loop_data])
	no_loop_restrs = tuple ([(n, vc_num (0)) for n in p.loop_heads ()])
	err_pc_hyps = [rep_graph.pc_false_hyp ((('Err', no_loop_restrs), tag))
		for tag in p.pairing.tags]
	knowledge = EqSearchKnowledge (rep, hyps + err_pc_hyps, list (pc_map))
	last_knowledge[0] = knowledge
	pc_ids = knowledge.classify_vs ()
	id_n_map = logic.dict_list ([(i, n) for (pc, i) in pc_ids.iteritems ()
		for n in pc_map[pc]])
	tag_div_ns = [[[n for n in ns if p.node_tags[n][0] == t] for t in tags]
		for (i, ns) in id_n_map.iteritems ()]
	split_pairs = [(l_ns[0], r_ns[0]) for (l_ns, r_ns) in tag_div_ns
		if l_ns and r_ns]
	p.cached_analysis['init_case_splits'] = split_pairs
	return split_pairs
Exemple #9
0
def find_split_loop (p, head, restrs, hyps, unfold_limit = 9):
	assert p.loop_data[head][0] == 'Head'
	assert p.node_tags[head][0] == p.pairing.tags[0]
	
	# the idea is to loop through testable hyps, starting with ones that
	# need smaller models (the most unfolded models will time out for
	# large problems like finaliseSlot)

	rep = mk_graph_slice (p, fast = True)

	nec = get_necessary_split_opts (p, head, restrs, hyps)
	if nec and nec[0] == 'CaseSplit':
		return nec
	elif nec:
		i_j_opts = nec
	else:
		i_j_opts = default_i_j_opts (unfold_limit)

	ind_fails = []
	for (i_opts, j_opts) in i_j_opts:
		result = find_split (rep, head, restrs, hyps,
			i_opts, j_opts)
		if result[0] != None:
			return result
		ind_fails.extend (result[1])

	if ind_fails:
		trace ('Warning: inductive failures: %s' % ind_fails)
	raise NoSplit ()
Exemple #10
0
def init_loops_to_split (p, restrs):
	to_split = loops_to_split (p, restrs)

	rep = mk_graph_slice (p)
	return [n for n in to_split
		if not [n2 for n2 in to_split if n2 != n
			and rep.get_reachable (n2, n)]]
Exemple #11
0
def check_checks():
    p = problem.last_problem[0]
    rep = rep_graph.mk_graph_slice(p)
    proof = search.last_proof[0]
    checks = check.proof_checks(p, proof)
    all_hyps = set([hyp for (_, hyp, _) in checks] + [hyp for (hyps, _, _) in checks for hyp in hyps])
    results = [try_interpret_hyp(rep, hyp) for hyp in all_hyps]
    return [r[1] for r in results if r]
Exemple #12
0
def get_proof_split_limit (p, sp, restrs, hyps, kind, must_find = False):
	limit = find_split_limit (p, sp, restrs, hyps, kind,
		must_find = must_find)
	if limit == None:
		return None
	# double-check this limit with a rep constructed without the 'fast' flag
	limit = find_split_limit (p, sp, restrs, hyps, kind,
		hints = [limit, limit + 1], use_rep = mk_graph_slice (p))
	return (0, limit + 1)
Exemple #13
0
def check_checks():
    p = problem.last_problem[0]
    rep = rep_graph.mk_graph_slice(p)
    proof = search.last_proof[0]
    checks = check.proof_checks(p, proof)
    all_hyps = set([hyp for (_, hyp, _) in checks] +
                   [hyp for (hyps, _, _) in checks for hyp in hyps])
    results = [try_interpret_hyp(rep, hyp) for hyp in all_hyps]
    return [r[1] for r in results if r]
Exemple #14
0
def refute_function_arcs(call_stack, arcs, ctxt_arcs):
    last_refute_attempt[0] = (call_stack, arcs, ctxt_arcs)
    f = identify_function(call_stack, [(addr, 0) for arc in arcs for addr in arc])

    # easy function limit refutations
    if not (ctxt_within_function_limits(call_stack) and function_reachable_within_limits(f)):
        verdicts.setdefault(f, [])
        if call_stack:
            vdct = (call_stack, [], "impossible")
        else:
            min_addr = min([addr for arc in arcs for addr in arc])
            vdct = ([], [min_addr], "impossible")
        verdicts[f].append(vdct)
        new_refutes[f] = True
        print "added %s refutation %s: %s" % (f, vdct[0], vdct[1])
        return

        # ignore complex loops
    if has_complex_loop(f):
        print "has loop: %s, skipping" % f
        return

    stack = pick_stack_subset(call_stack)
    arc_extras = call_stack_parent_arc_extras(call_stack, ctxt_arcs, len(stack))

    arcs = [arc for arc in arcs if previous_verdict(stack, f, add_arc_extras(arc, arc_extras)) == None]
    if not arcs:
        return

    funs = [body_addrs[addr] for addr in stack] + [f]
    (p, hyps, addr_map, tag_pairs) = build_compound_problem(funs)
    rep = rep_graph.mk_graph_slice(p)
    call_tags = zip(tag_pairs[:-1], tag_pairs[1:])
    call_hyps = [get_call_link_hyps(p, addr_map[n], from_tp, to_tp) for (n, (from_tp, to_tp)) in zip(stack, call_tags)]

    for arc in arcs:
        arc2 = add_arc_extras(arc, arc_extras)
        if previous_verdict(stack, f, arc2) != None:
            continue
        print "fresh %s arc %s: %s" % (f, stack, arc)
        vis_pcs = [(get_pc_hyp_local(rep, addr_map[addr]), (addr, i)) for (addr, i) in arc2]
        vis_pcs = dict(vis_pcs).items()

        res = refute_minimise_vis_hyps(rep, hyps, call_hyps, vis_pcs)
        if res == None:
            verdicts.setdefault(f, [])
            verdicts[f].append((stack, list(arc2), "possible"))
            continue

        (used_call_hyps, used_vis_pcs) = res
        stack2 = stack[-len(used_call_hyps) :]
        used_vis = [(addr, i) for (_, (addr, i)) in used_vis_pcs]
        verdicts.setdefault(f, [])
        verdicts[f].append((stack2, used_vis, "impossible"))
        new_refutes[f] = True
        print "added %s refutation %s: %s" % (f, stack, used_vis)
Exemple #15
0
def get_proof_visit_restr (p, sp, restrs, hyps, kind, must_find = False):
	rep = rep_graph.mk_graph_slice (p)
	pc = rep.get_pc ((sp, restrs))
	if rep.test_hyp_whyps (pc, hyps):
		return (1, 2)
	elif rep.test_hyp_whyps (mk_not (pc), hyps):
		return (0, 1)
	else:
		assert not must_find
		return None
Exemple #16
0
def failed_test_sets (p, checks):
	failed = []
	sets = {}
	for (hyps, hyp, name) in checks:
		sets.setdefault (name, [])
		sets[name].append ((hyps, hyp))
	for name in sets:
		rep = rep_graph.mk_graph_slice (p)
		(res, _) = rep.test_hyp_imps (sets[name])
		if not res:
			failed.append (name)
	return failed
Exemple #17
0
def failed_test_sets(p, checks):
    failed = []
    sets = {}
    for (hyps, hyp, name) in checks:
        sets.setdefault(name, [])
        sets[name].append((hyps, hyp))
    for name in sets:
        rep = rep_graph.mk_graph_slice(p)
        (res, _, _) = rep.test_hyp_imps(sets[name])
        if not res:
            failed.append(name)
    return failed
Exemple #18
0
def get_ptr_offsets(p, n_ptrs, bases, hyps=[], cache=None, fail_early=False):
    """detect which ptrs are guaranteed to be at constant offsets
	from some set of basis ptrs"""
    rep = rep_graph.mk_graph_slice(p, fast=True)
    if cache == None:
        cache = {}
    last_get_ptr_offsets[0] = (p, n_ptrs, bases, hyps)

    smt_bases = []
    for (n, ptr, k) in bases:
        n_vc = default_n_vc(p, n)
        (_, env) = rep.get_node_pc_env(n_vc)
        smt = solver.smt_expr(ptr, env, rep.solv)
        smt_bases.append((smt, k))
        ptr_typ = ptr.typ

    smt_ptrs = []
    for (n, ptr) in n_ptrs:
        n_vc = default_n_vc(p, n)
        pc_env = rep.get_node_pc_env(n_vc)
        if not pc_env:
            continue
        smt = solver.smt_expr(ptr, pc_env[1], rep.solv)
        hyp = rep_graph.pc_true_hyp((n_vc, p.node_tags[n][0]))
        smt_ptrs.append(((n, ptr), smt, hyp))

    hyps = hyps + mk_not_callable_hyps(p)
    for tag in set([p.node_tags[n][0] for (n, _) in n_ptrs]):
        hyps = hyps + init_correctness_hyps(p, tag)
    tags = set([p.node_tags[n][0] for (n, ptr) in n_ptrs])
    ex_defs = {}
    for t in tags:
        ex_defs.update(get_extra_sp_defs(rep, t))

    offs = []
    for (v, ptr, hyp) in smt_ptrs:
        off = None
        for (ptr2, k) in smt_bases:
            off = offs_expr_const(ptr,
                                  ptr2,
                                  rep, [hyp] + hyps,
                                  cache=cache,
                                  extra_defs=ex_defs,
                                  typ=ptr_typ)
            if off != None:
                offs.append((v, off, k))
                break
        if off == None:
            trace('get_ptr_offs fallthrough at %d: %s' % v)
            trace(str([hyp] + hyps))
            assert not fail_early, (v, ptr)
    return offs
Exemple #19
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, ())
Exemple #20
0
def trace_split_loop_pairs_window (problem, window_size):
	(_, p, pn, restrs, hyps) = problem
	loop_head = pn.split[0][0]
	if ('v_eqs', loop_head) in p.cached_analysis:
		del p.cached_analysis[('v_eqs', loop_head)]

	rep = rep_graph.mk_graph_slice (p, fast = True)
	i_j_opts = search.mk_i_j_opts (unfold_limit = window_size)
	(i_opts, j_opts) = i_j_opts[-1]
	knowledge = search.setup_split_search (rep, loop_head, restrs, hyps,
                i_opts, j_opts, unfold_limit = window_size)

	res = search.split_search (loop_head, knowledge)
	trace = list (knowledge.live_pairs_trace)
	return (res, trace)
Exemple #21
0
def get_prior_loop_heads(p, split, use_rep=None):
    if use_rep:
        rep = use_rep
    else:
        rep = rep_graph.mk_graph_slice(p)
    prior = []
    split = p.loop_id(split)
    for h in p.loop_heads():
        s = set(prior)
        if h not in s and rep.get_reachable(h, split) and h != split:
            # need to recurse to ensure prior are in order
            prior2 = get_prior_loop_heads(p, h, use_rep=rep)
            prior.extend([h2 for h2 in prior2 if h2 not in s])
            prior.append(h)
    return prior
Exemple #22
0
def get_prior_loop_heads(p, split, use_rep=None):
    if use_rep:
        rep = use_rep
    else:
        rep = rep_graph.mk_graph_slice(p)
    prior = []
    split = p.loop_id(split)
    for h in p.loop_heads():
        s = set(prior)
        if h not in s and rep.get_reachable(h, split) and h != split:
            # need to recurse to ensure prior are in order
            prior2 = get_prior_loop_heads(p, h, use_rep=rep)
            prior.extend([h2 for h2 in prior2 if h2 not in s])
            prior.append(h)
    return prior
Exemple #23
0
def call_stack_parent_arc_extras (stack, ctxt_arcs, max_length):
	rng = range (1, len (stack))[ -3 : ]
	arc_extras = []
	for i in rng:
		prev_stack = stack[:i]
		f = body_addrs[stack[i]]
		p = functions[f].as_problem (problem.Problem)
		rep = rep_graph.mk_graph_slice (p)
		arcs = ctxt_arcs[tuple (prev_stack)]
		arcs = [a for a in arcs if all_reachable (rep, a + [stack[i]])]
		arcs = sorted ([(len (a), a) for a in arcs])
		if arcs:
			(_, arc) = arcs[-1]
			arc_extras.extend ([(addr, len (stack) - i)
				for addr in arc])
	return arc_extras 
Exemple #24
0
def find_split_loop (p, head, restrs, hyps):
	assert p.loop_data[head][0] == 'Head'
	assert p.node_tags[head][0] == p.pairing.tags[0]
	
	# the idea is to loop through testable hyps, starting with ones that
	# need smaller models (the most unfolded models will time out for
	# large problems like finaliseSlot)

	rep = mk_graph_slice (p, fast = True)
	
	i_seq_opts = [(0, 1), (1, 1), (2, 1), (3, 1)]
	j_seq_opts = [(0, 1), (0, 2), (1, 1), (1, 2), (2, 1), (2, 2), (3, 1)]
	opts_by_lim = {}
	for (start, step) in i_seq_opts:
		limit = start + (2 * step) + 1
		opts_by_lim.setdefault (limit, ([], []))
		opts_by_lim[limit][0].append ((start, step))
	for (start, step) in j_seq_opts:
		limit = start + (2 * step) + 1
		opts_by_lim.setdefault (limit, ([], []))
		opts_by_lim[limit][1].append ((start, step))

	ind_fails = []

	i_opts = []
	j_opts = []
	for unfold_limit in sorted (opts_by_lim):
		trace ('Split search at %d with unfold limit %d.' % (head,
			unfold_limit), push = 1)
		i_opts.extend (opts_by_lim[unfold_limit][0])
		j_opts.extend (opts_by_lim[unfold_limit][1])
		result = find_split (rep, head, restrs, hyps,
			i_opts, j_opts, unfold_limit)
		trace ('Split search with unfold limit %d result: %r'
			% (unfold_limit, result), push = -1)
		if result[0] != None:
			return result
		ind_fails.extend (result[1])

	result = find_case_split (p, head, restrs, hyps)
	if result[0] != None:
		return result

	trace ('All split strategies exhausted.')
	if ind_fails:
		trace ('Warning: inductive failures: %s' % ind_fails)
	raise NoSplit ()
Exemple #25
0
def proof_failed_groups(p=None, proof=None):
    if p == None:
        p = problem.last_problem[0]
    if proof == None:
        proof = search.last_proof[0]
    checks = check.proof_checks(p, proof)
    groups = check.proof_check_groups(checks)
    failed = []
    for group in groups:
        rep = rep_graph.mk_graph_slice(p)
        (res, el) = check.test_hyp_group(rep, group)
        if not res:
            failed.append(group)
            print 'Failed element: %s' % el
    failed_nms = set([s for group in failed for (_, _, s) in group])
    print 'Failed: %s' % failed_nms
    return failed
Exemple #26
0
def getBinaryBoundFromC(p, c_tag, asm_split, restrs, hyps):
    c_heads = [h for h in search.init_loops_to_split(p, restrs) if p.node_tags[h][0] == c_tag]
    c_bounds = [(p.loop_id(split), search_bound(p, (), hyps, split)) for split in c_heads]
    if not [b for (n, b) in c_bounds if b]:
        trace("no C bounds found (%s)." % c_bounds)
        return None

    asm_tag = p.node_tags[asm_split][0]

    rep = rep_graph.mk_graph_slice(p)
    i_seq_opts = [(0, 1), (1, 1), (2, 1)]
    j_seq_opts = [(0, 1), (0, 2), (1, 1)]
    tags = [p.node_tags[asm_split][0], c_tag]
    try:
        split = search.find_split(rep, asm_split, restrs, hyps, i_seq_opts, j_seq_opts, 5, tags=[asm_tag, c_tag])
    except solver.SolverFailure, e:
        return None
Exemple #27
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
Exemple #28
0
def proof_failed_groups(p=None, proof=None):
    if p == None:
        p = problem.last_problem[0]
    if proof == None:
        proof = search.last_proof[0]
    checks = check.proof_checks(p, proof)
    groups = check.proof_check_groups(checks)
    failed = []
    for group in groups:
        rep = rep_graph.mk_graph_slice(p)
        (res, el) = check.test_hyp_group(rep, group)
        if not res:
            failed.append(group)
            print "Failed element: %s" % el
    failed_nms = set([s for group in failed for (_, _, s) in group])
    print "Failed: %s" % failed_nms
    return failed
Exemple #29
0
def get_linear_series_eqs(p, split, restrs, hyps, omit_standard=False):
    k = ('linear_series_eqs', split, restrs, tuple(hyps))
    if k in p.cached_analysis:
        if omit_standard:
            standard = set(search.mk_seq_eqs(p, split, 1, with_rodata=False))
            return set(p.cached_analysis[k]) - standard
        return p.cached_analysis[k]

    cands = search.mk_seq_eqs(p, split, 1, with_rodata=False)
    cands += candidate_additional_eqs(p, split)
    (tag, _) = p.node_tags[split]

    rep = rep_graph.mk_graph_slice(p, fast=True)

    def do_checks(eqs_assume, eqs):
        checks = (check.single_loop_induct_step_checks(
            p, restrs, hyps, tag, split, 1, eqs, eqs_assume=eqs_assume) +
                  check.single_loop_induct_base_checks(p, restrs, hyps, tag,
                                                       split, 1, eqs))

        groups = check.proof_check_groups(checks)
        for group in groups:
            (res, _) = check.test_hyp_group(rep, group)
            if not res:
                return False
        return True

    eqs = []
    failed = []
    while cands:
        cand = cands.pop()
        if do_checks(eqs, [cand]):
            eqs.append(cand)
            failed.reverse()
            cands = failed + cands
            failed = []
        else:
            failed.append(cand)

    assert do_checks([], eqs)
    p.cached_analysis[k] = eqs
    if omit_standard:
        standard = set(search.mk_seq_eqs(p, split, 1, with_rodata=False))
        return set(eqs) - standard
    return eqs
Exemple #30
0
def default_searcher (p, restrs, hyps):
	# use any handy init splits
	res = init_proof_case_split (p, restrs, hyps)
	if res:
		return res

	# detect any un-split loops
	to_split_init = init_loops_to_split (p, restrs)
	rep = mk_graph_slice (p, fast = True)

	l_tag, r_tag = p.pairing.tags
	l_to_split = [n for n in to_split_init if p.node_tags[n][0] == l_tag]
	r_to_split = [n for n in to_split_init if p.node_tags[n][0] == r_tag]
	l_ep = p.get_entry (l_tag)
	r_ep = p.get_entry (r_tag)

	for r_sp in r_to_split:
		trace ('checking loop_no_match at %d' % r_sp, push = 1)
		if loop_no_match (rep, restrs, hyps, r_sp, l_tag):
			trace ('loop does not match!', push = -1)
			return ('Restr', ('Number', [r_sp]))
		trace (' .. done checking loop no match', push = -1)

	if l_to_split and not r_to_split:
		n = l_to_split[0]
		trace ('lhs loop alone, limit must be found.')
		return ('Restr', ('Number', [n]))

	if l_to_split:
		n = l_to_split[0]
		trace ('checking lhs loop_no_match at %d' % n, push = 1)
		if loop_no_match (rep, restrs, hyps, n, r_tag):
			trace ('loop does not match!', push = -1)
			return ('Restr', ('Number', [n]))
		trace (' .. done checking loop no match', push = -1)

		(kind, split) = find_split_loop (p, n, restrs, hyps)
		return (kind, split)

	if r_to_split:
		n = r_to_split[0]
		trace ('rhs loop alone, limit must be found.')
		return ('Restr', ('Number', [n]))

	return ('Leaf', None)
Exemple #31
0
def findLoopBoundBS(p_n, p, restrs=None, hyps=None, try_seq=None):
    if hyps == None:
        hyps = []
    # print 'restrs: %s' % str(restrs)
    if try_seq == None:
        # bound_try_seq = [1,2,3,4,5,10,50,130,200,260]
        # bound_try_seq = [0,1,2,3,4,5,10,50,260]
        calls = [n for n in p.loop_body(p_n) if p.nodes[n].kind == "Call"]
        if calls:
            bound_try_seq = [0, 1, 20]
        else:
            bound_try_seq = [0, 1, 20, 34]
    else:
        bound_try_seq = try_seq
    rep = mk_graph_slice(p, fast=True)
    # get the head
    # print 'Binary addr: %s' % toHexs(self.toPhyAddrs(p_loop_heads))
    loop_bound = None
    p_loop_heads = [n for n in p.loop_data if p.loop_data[n][0] == "Head"]
    print "p_loop_heads: %s" % p_loop_heads

    if restrs == None:
        others = [x for x in p_loop_heads if not x == p_n]
        # vc_options([concrete numbers], [offsets])
        restrs = tuple([(n2, rep_graph.vc_options([0], [1])) for n2 in others])

    print "getting the initial bound"
    # try:
    index = tryLoopBound(p_n, p, bound_try_seq, rep, restrs=restrs, hyps=hyps)
    if index == -1:
        return None
    print "got the initial bound %d" % bound_try_seq[index]

    # do a downward binary search to find the concrete loop bound
    if index == 0:
        loop_bound = bound_try_seq[0]
        print "bound = %d" % loop_bound
        return loop_bound
    loop_bound = downBinSearch(
        bound_try_seq[index - 1],
        bound_try_seq[index],
        lambda x: tryLoopBound(p_n, p, [x], rep, restrs=restrs, hyps=hyps, bin_return=True),
    )
    print "bound = %d" % loop_bound
    return loop_bound
Exemple #32
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
Exemple #33
0
def findLoopBoundBS(p_n, p, restrs=None, hyps=None, try_seq=None):
    if hyps == None:
        hyps = []
    #print 'restrs: %s' % str(restrs)
    if try_seq == None:
        #bound_try_seq = [1,2,3,4,5,10,50,130,200,260]
        #bound_try_seq = [0,1,2,3,4,5,10,50,260]
        calls = [n for n in p.loop_body(p_n) if p.nodes[n].kind == 'Call']
        if calls:
            bound_try_seq = [0, 1, 20]
        else:
            bound_try_seq = [0, 1, 20, 34]
    else:
        bound_try_seq = try_seq
    rep = mk_graph_slice(p, fast=True)
    #get the head
    #print 'Binary addr: %s' % toHexs(self.toPhyAddrs(p_loop_heads))
    loop_bound = None
    p_loop_heads = [n for n in p.loop_data if p.loop_data[n][0] == 'Head']
    print 'p_loop_heads: %s' % p_loop_heads

    if restrs == None:
        others = [x for x in p_loop_heads if not x == p_n]
        #vc_options([concrete numbers], [offsets])
        restrs = tuple([(n2, rep_graph.vc_options([0], [1])) for n2 in others])

    print 'getting the initial bound'
    #try:
    index = tryLoopBound(p_n, p, bound_try_seq, rep, restrs=restrs, hyps=hyps)
    if index == -1:
        return None
    print 'got the initial bound %d' % bound_try_seq[index]

    #do a downward binary search to find the concrete loop bound
    if index == 0:
        loop_bound = bound_try_seq[0]
        print 'bound = %d' % loop_bound
        return loop_bound
    loop_bound = downBinSearch(
        bound_try_seq[index - 1], bound_try_seq[index], lambda x: tryLoopBound(
            p_n, p, [x], rep, restrs=restrs, hyps=hyps, bin_return=True))
    print 'bound = %d' % loop_bound
    return loop_bound
Exemple #34
0
def get_linear_series_hyps(p, split, restrs, hyps):

    k = ("linear_series_hyps", split, restrs, tuple(hyps))
    if k in p.cached_analysis:
        return p.cached_analysis[k]

    cands = search.mk_seq_eqs(p, split, 1, with_rodata=False)
    cands += candidate_additional_eqs(p, split)
    (tag, _) = p.node_tags[split]

    rep = rep_graph.mk_graph_slice(p, fast=True)

    def do_checks(eqs_assume, eqs):
        checks = linear_eq_induct_step_checks(
            p, restrs, hyps, tag, split, eqs_assume, eqs
        ) + linear_eq_induct_base_checks(p, restrs, hyps, tag, split, eqs)

        groups = check.proof_check_groups(checks)
        for group in groups:
            (res, _) = check.test_hyp_group(rep, group)
            if not res:
                return False
        return True

    eqs = []
    failed = []
    while cands:
        cand = cands.pop()
        if do_checks(eqs, [cand]):
            eqs.append(cand)
            failed.reverse()
            cands = failed + cands
            failed = []
        else:
            failed.append(cand)

    assert do_checks([], eqs)

    hyps = [h for (h, _) in linear_eq_hyps_at_visit(tag, split, eqs, restrs, vc_offs(0))]
    p.cached_analysis[k] = hyps
    return hyps
Exemple #35
0
def check_proof (p, proof, use_rep = None):
	checks = proof_checks (p, proof)
	groups = proof_check_groups (checks)

	for group in groups:
		if use_rep == None:
			rep = rep_graph.mk_graph_slice (p)
		else:
			rep = use_rep

		(verdict, elt) = test_hyp_group (rep, group)
		if verdict:
			continue
		(hyps, hyp, name) = elt
		last_failed_check[0] = elt
		trace ('%s: proof failed!' % name)
		return False
	if save_checked_proofs[0]:
		save = save_checked_proofs[0]
		save (p, proof)
	return True
Exemple #36
0
def get_ptr_offsets (p, n_ptrs, bases, hyps = []):
	"""detect which ptrs are guaranteed to be at constant offsets
	from some set of basis ptrs"""
	rep = rep_graph.mk_graph_slice (p, fast = True)
	cache = {}
	last_get_ptr_offsets[0] = (p, n_ptrs, bases, hyps)

	smt_bases = []
	for (n, ptr, k) in bases:
		n_vc = default_n_vc (p, n)
		(_, env) = rep.get_node_pc_env (n_vc)
		smt = solver.smt_expr (ptr, env, rep.solv)
		smt_bases.append ((smt, k))

	smt_ptrs = []
	for (n, ptr) in n_ptrs:
		n_vc = default_n_vc (p, n)
		pc_env = rep.get_node_pc_env (n_vc)
		if not pc_env:
			continue
		smt = solver.smt_expr (ptr, pc_env[1], rep.solv)
		hyp = rep_graph.pc_true_hyp ((n_vc, p.node_tags[n][0]))
		smt_ptrs.append (((n, ptr), smt, hyp))

	hyps = hyps + mk_not_callable_hyps (p)
	tags = set ([p.node_tags[n][0] for (n, ptr) in n_ptrs])
	ex_defs = {}
	for t in tags:
		ex_defs.update (get_extra_sp_defs (rep, t))

	offs = []
	for (v, ptr, hyp) in smt_ptrs:
		for (ptr2, k) in smt_bases:
			off = offs_expr_const (ptr, ptr2, rep, [hyp] + hyps,
				cache = cache, extra_defs = ex_defs)
			if off != None:
				offs.append ((v, off, k))
				break
		trace ('get_ptr_offs fallthrough at %d: %s' % v)
	return offs
Exemple #37
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
Exemple #38
0
def search_bound(p, restrs, hyps, split):
    last_search_bound[0] = (p, restrs, hyps, split)

    # try a naive bin search first
    # limit this to a small bound for time purposes
    #   - for larger bounds the less naive approach can be faster
    bound = findLoopBoundBS(split,
                            p,
                            restrs=restrs,
                            hyps=hyps,
                            try_seq=[0, 1, 6])
    if bound != None:
        return (bound, 'NaiveBinSearch')

    l_hyps = get_linear_series_hyps(p, split, restrs, hyps)

    rep = rep_graph.mk_graph_slice(p, fast=True)

    def test(n):
        assert n > 10
        hyp = check.mk_loop_counter_eq_hyp(p, split, restrs, n - 2)
        visit = ((split, vc_offs(2)), ) + restrs
        continue_to_split_guess = rep.get_pc((split, visit))
        return rep.test_hyp_whyps(syntax.mk_not(continue_to_split_guess),
                                  [hyp] + l_hyps + hyps)

    # findLoopBoundBS always checks to at least 16
    min_bound = 16
    max_bound = max_acceptable_bound[0]
    bound = upDownBinSearch(min_bound, max_bound, test)
    if bound != None and test(bound):
        return (bound, 'InductiveBinSearch')

    # let the naive bin search go a bit further
    bound = findLoopBoundBS(split, p, restrs=restrs, hyps=hyps)
    if bound != None:
        return (bound, 'NaiveBinSearch')

    return None
Exemple #39
0
def check_proof(p, proof, use_rep=None):
    checks = proof_checks(p, proof)
    groups = proof_check_groups(checks)

    for group in groups:
        if use_rep == None:
            rep = rep_graph.mk_graph_slice(p)
        else:
            rep = use_rep

        detail = [0]
        (verdict, elt) = test_hyp_group(rep, group, detail)
        if verdict:
            continue
        (hyps, hyp, name) = elt
        last_failed_check[0] = elt
        trace('%s: proof failed!' % name)
        trace('  (failure kind: %r)' % detail[0])
        return False
    if save_checked_proofs[0]:
        save = save_checked_proofs[0]
        save(p, proof)
    return True
Exemple #40
0
def build_proof_rec_with_restrs (split_points, kind, searcher, p, restrs, hyps):
	sp = split_points[0]
	use_hyps = list (hyps)
	if p.node_tags[sp][0] != p.pairing.tags[1]:
		nrerr_hyp = check.non_r_err_pc_hyp (p.pairing.tags,
			restr_others (p, restrs, 2))
		use_hyps = use_hyps + [nrerr_hyp]
	limit = find_split_limit (p, sp, restrs, use_hyps, kind)
	# double-check this limit with a rep constructed without the 'fast' flag
	limit = find_split_limit (p, sp, restrs, use_hyps, kind,
		hints = [limit, limit + 1], use_rep = mk_graph_slice (p))
	if kind == 'Number':
		vc_opts = vc_upto (limit + 1)
	else:
		vc_opts = vc_offset_upto (limit + 1)
	restrs = restrs + ((sp, vc_opts), )
	if len (split_points) == 1:
		subproof = build_proof_rec (searcher, p, restrs, hyps)
	else:
		subproof = build_proof_rec_with_restrs (split_points[1:],
			kind, searcher, p, restrs, hyps)

	return ProofNode ('Restr', (sp, (kind, (0, limit + 1))), [subproof])
Exemple #41
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
Exemple #42
0
def init_proof_case_split (p, restrs, hyps):
	ps = init_case_splits (p, hyps)
	if ps == None:
		return None
	p.cached_analysis.setdefault ('finished_init_case_splits', [])
	fin = p.cached_analysis['finished_init_case_splits']
	known_s = set.union (set (restrs), set (hyps))
	for rs in fin:
		if rs <= known_s:
			return None
	rep = rep_graph.mk_graph_slice (p)
	no_loop_restrs = tuple ([(n, vc_num (0)) for n in p.loop_heads ()])
	err_pc_hyps = [rep_graph.pc_false_hyp ((('Err', no_loop_restrs), tag))
		for tag in p.pairing.tags]
	for (n1, n2) in ps:
		pc = rep.get_pc ((n1, ()))
		if rep.test_hyp_whyps (pc, hyps + err_pc_hyps):
			continue
		if rep.test_hyp_whyps (mk_not (pc), hyps + err_pc_hyps):
			continue
		case_split_tr.append ((n1, restrs, hyps))
		return ('CaseSplit', ((n1, p.node_tags[n1][0]), [n1, n2]))
	fin.append (known_s)
	return None
Exemple #43
0
last_asm_stack_depth_fun = [0]


def check_before_guess_asm_stack_depth(fun):
    from solver import smt_expr
    if not fun.entry:
        return None
    p = fun.as_problem(problem.Problem, name='Target')
    try:
        p.do_analysis()
        p.check_no_inner_loops()
        inline_no_pre_pairing(p)
    except problem.Abort, e:
        return None
    rep = rep_graph.mk_graph_slice(p, fast=True)
    try:
        rep.get_pc(default_n_vc(p, 'Ret'), 'Target')
        err_pc = rep.get_pc(default_n_vc(p, 'Err'), 'Target')
    except solver.EnvMiss, e:
        return None

    inlined_funs = set([fn for (_, _, fn) in p.inline_scripts['Target']])
    if inlined_funs:
        printout('  (stack analysis also involves %s)' %
                 ', '.join(inlined_funs))

    return p


def guess_asm_stack_depth(fun):
Exemple #44
0
    asm_tag = p.node_tags[asm_split][0]

    rep = rep_graph.mk_graph_slice(p)
    i_seq_opts = [(0, 1), (1, 1), (2, 1)]
    j_seq_opts = [(0, 1), (0, 2), (1, 1)]
    tags = [p.node_tags[asm_split][0], c_tag]
    try:
        split = search.find_split(rep, asm_split, restrs, hyps, i_seq_opts, j_seq_opts, 5, tags=[asm_tag, c_tag])
    except solver.SolverFailure, e:
        return None
    if not split or split[0] != "Split":
        trace("no split found (%s)." % repr(split))
        return None
    (_, split) = split
    rep = rep_graph.mk_graph_slice(p)
    checks = check.split_checks(p, (), hyps, split, tags=[asm_tag, c_tag])
    groups = check.proof_check_groups(checks)
    try:
        for group in groups:
            (res, el) = check.test_hyp_group(rep, group)
            if not res:
                trace("split check failed!")
                trace("failed at %s" % el)
                return None
    except solver.SolverFailure, e:
        return None
    (as_details, c_details, _, n, _) = split
    (c_split, (seq_start, step), _) = c_details
    c_bound = dict(c_bounds).get(p.loop_id(c_split))
    if not c_bound:
Exemple #45
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"
Exemple #46
0
 try:
     split = search.find_split(rep,
                               asm_split,
                               restrs,
                               hyps,
                               i_seq_opts,
                               j_seq_opts,
                               5,
                               tags=[asm_tag, c_tag])
 except solver.SolverFailure, e:
     return None
 if not split or split[0] != 'Split':
     trace('no split found (%s).' % repr(split))
     return None
 (_, split) = split
 rep = rep_graph.mk_graph_slice(p)
 checks = check.split_checks(p, (), hyps, split, tags=[asm_tag, c_tag])
 groups = check.proof_check_groups(checks)
 try:
     for group in groups:
         (res, el) = check.test_hyp_group(rep, group)
         if not res:
             trace('split check failed!')
             trace('failed at %s' % el)
             return None
 except solver.SolverFailure, e:
     return None
 (as_details, c_details, _, n, _) = split
 (c_split, (seq_start, step), _) = c_details
 c_bound = dict(c_bounds).get(p.loop_id(c_split))
 if not c_bound:
Exemple #47
0
def check_proof_report_rec(p,
                           restrs,
                           hyps,
                           proof,
                           step_num,
                           ctxt,
                           inducts,
                           do_check=True):
    printout('Step %d: %s' % (step_num, ctxt))
    if proof.kind == 'Restr':
        (kind, (x, y)) = proof.restr_range
        if kind == 'Offset':
            v = inducts[1][proof.point]
            rexpr = '{%s + %s ..< %s + %s}' % (v, x, v, y)
        else:
            rexpr = '{%s ..< %s}' % (x, y)
        printout('  Prove the number of visits to %d is in %s' %
                 (proof.point, rexpr))

        checks = proof_restr_checks(proof.point, proof.restr_range, p, restrs,
                                    hyps)
        cases = ['']
    elif proof.kind == 'SingleRevInduct':
        printout('  Proving a predicate by future induction.')
        (eqs, n) = proof.eqs_proof
        point = proof.point
        printout('    proving these invariants by %d-induction' % n)
        for x in eqs:
            printout('      %s (@ addr %s)' % (pretty_lambda(x), point))
        printout('    then establishing this predicate')
        (pred, n_bound) = proof.rev_proof
        printout('      %s (@ addr %s)' % (pretty_lambda(pred), point))
        printout('    at large iterations (%d) and by back induction.' %
                 n_bound)
        cases = ['']
        checks = all_rev_induct_checks(p, restrs, hyps, point, proof.eqs_proof,
                                       proof.rev_proof)
    elif proof.kind == 'Split':
        (l_dts, r_dts, eqs, n, lrmx) = proof.split
        v = next_induct_var(inducts[0])
        inducts = (inducts[0] + 1, dict(inducts[1]))
        inducts[1][l_dts[0]] = v
        inducts[1][r_dts[0]] = v
        printout('  prove %s related to %s' %
                 (pretty_vseq(l_dts), pretty_vseq(r_dts)))
        printout('    with equalities')
        for (x, y) in eqs:
            printout('      %s (@ addr %s)' % (pretty_lambda(x), l_dts[0]))
            printout('      = %s (@ addr %s)' % (pretty_lambda(y), r_dts[0]))
        printout('    and with invariants')
        for x in l_dts[2]:
            printout('      %s (@ addr %s)' % (pretty_lambda(x), l_dts[0]))
        for x in r_dts[2]:
            printout('      %s (@ addr %s)' % (pretty_lambda(x), r_dts[0]))
        checks = split_checks(p, restrs, hyps, proof.split)
        cases = [
            'case in (%d) where the length of the sequence < %d' %
            (step_num, n),
            'case in (%d) where the length of the sequence is %s + %s' %
            (step_num, v, n)
        ]
    elif proof.kind == 'Leaf':
        printout('  prove all verification conditions')
        checks = leaf_condition_checks(p, restrs, hyps)
        cases = []
    elif proof.kind == 'CaseSplit':
        printout('  case split on whether %d is visited' % proof.point)
        checks = []
        cases = [
            'case in (%d) where %d is visited' % (step_num, proof.point),
            'case in (%d) where %d is not visited' % (step_num, proof.point)
        ]

    if checks and do_check:
        groups = proof_check_groups(checks)
        for group in groups:
            rep = rep_graph.mk_graph_slice(p)
            detail = [0]
            (res, _) = test_hyp_group(rep, group, detail)
            if not res:
                printout('    .. failed to prove this.')
                printout('      (failure kind: %r)' % detail[0])
                return

        printout('    .. proven.')

    subproblems = proof_subproblems(p, proof.kind, proof.args, restrs, hyps,
                                    '')
    xs = logic.azip(subproblems, proof.subproofs)
    xs = logic.azip(xs, cases)
    step_num += 1
    for ((subprob, subproof), case) in xs:
        (restrs, hyps, _) = subprob
        res = check_proof_report_rec(p,
                                     restrs,
                                     hyps,
                                     subproof,
                                     step_num,
                                     case,
                                     inducts,
                                     do_check=do_check)
        if not res:
            return
        (step_num, induct_var_num) = res
        inducts = (induct_var_num, inducts[1])
    return (step_num, inducts[0])
Exemple #48
0
	p.cached_analysis[key] = va2
	return va2

last_asm_stack_depth_fun = [0]

def check_before_guess_asm_stack_depth (fun):
	from solver import smt_expr
	if not fun.entry:
		return None
	p = fun.as_problem (problem.Problem, name = 'Target')
	try:
		p.do_analysis ()
		p.check_no_inner_loops ()
	except problem.Abort, e:
		return None
	rep = rep_graph.mk_graph_slice (p, fast = True)
	try:
		rep.get_pc (default_n_vc (p, 'Ret'), 'Target')
		err_pc = rep.get_pc (default_n_vc (p, 'Err'), 'Target')
	except solver.EnvMiss, e:
		return None
	return p

def guess_asm_stack_depth (fun):
	p = check_before_guess_asm_stack_depth (fun)
	if not p:
		return (0, {})

	last_asm_stack_depth_fun[0] = fun.name

	entry = p.get_entry ('Target')
Exemple #49
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"
Exemple #50
0
def refute_function_arcs(call_stack, arcs, ctxt_arcs):
    last_refute_attempt[0] = (call_stack, arcs, ctxt_arcs)
    f = identify_function(call_stack,
                          [(addr, 0) for arc in arcs for addr in arc])

    # easy function limit refutations
    if not (ctxt_within_function_limits(call_stack)
            and function_reachable_within_limits(f)):
        verdicts.setdefault(f, [])
        if call_stack:
            vdct = (call_stack, [], 'impossible')
        else:
            min_addr = min([addr for arc in arcs for addr in arc])
            vdct = ([], [min_addr], 'impossible')
        verdicts[f].append(vdct)
        new_refutes[f] = True
        print 'added %s refutation %s: %s' % (f, vdct[0], vdct[1])
        return

    # ignore complex loops
    if has_complex_loop(f):
        print 'has complex loop: %s, skipping' % f
        return

    (top_loop, stack) = pick_stack_setup(call_stack)
    arc_extras = call_stack_parent_arc_extras(call_stack, ctxt_arcs,
                                              len(stack), top_loop)

    arcs = [
        arc for arc in arcs
        if previous_verdict(stack, f, add_arc_extras(arc, arc_extras)) == None
    ]
    if not arcs:
        return

    funs = [body_addrs[addr] for addr in stack] + [f]
    (p, hyps, addr_map, tag_pairs) = build_compound_problem(funs)

    focused_loops = {}
    if top_loop != None:
        top_loop_split = p.loop_id(addr_map[top_loop])
        top_loop_tag = p.node_tags[top_loop_split][0]
        assert top_loop_tag in tag_pairs[0][0].values()
        focused_loops[top_loop_tag] = top_loop_split

    rep = rep_graph.mk_graph_slice(p)
    call_tags = zip(tag_pairs[:-1], tag_pairs[1:])
    call_hyps = [
        get_call_link_hyps(p,
                           addr_map[n],
                           from_tp,
                           to_tp,
                           focused_loops=focused_loops)
        for (n, (from_tp, to_tp)) in zip(stack, call_tags)
    ]

    for arc in arcs:
        arc2 = add_arc_extras(arc, arc_extras)
        if previous_verdict(stack, f, arc2) != None:
            continue
        print 'fresh %s arc %s: %s' % (f, stack, arc)
        vis_pcs = [(get_pc_hyp_local(rep,
                                     addr_map[addr],
                                     focused_loops=focused_loops), (addr, i))
                   for (addr, i) in arc2]
        vis_pcs = dict(vis_pcs).items()

        res = refute_minimise_vis_hyps(rep, hyps, call_hyps, vis_pcs)
        if res == None:
            verdicts.setdefault(f, [])
            verdicts[f].append((stack, list(arc2), 'possible'))
            continue

        (used_call_hyps, used_vis_pcs) = res
        stack2 = stack[-len(used_call_hyps):]
        used_vis = [(addr, i) for (_, (addr, i)) in used_vis_pcs]
        verdicts.setdefault(f, [])
        if len(stack2) == len(stack) and top_loop != None:
            vdct = 'impossible_in_loop'
        else:
            vdct = 'impossible'
        verdicts[f].append((stack2, used_vis, vdct))
        new_refutes[f] = True
        print 'added %s refutation %s: %s' % (f, stack, used_vis)