def warm_pc_env_cache (self, n_vc, tag): 'this is to avoid recursion limits and spot bugs' prev_chain = [] for i in range (5000): prevs = self.prevs (n_vc) try: prevs = [p for p in prevs if (tag, p[0], p[1]) not in self.node_pc_envs if self.get_tag_vcount (p, None) == (tag, n_vc[1])] except self.TooGeneral: break if not prevs: break n_vc = prevs[0] prev_chain.append(n_vc) if not (len (prev_chain) < 5000): printout ([n for (n, vc) in prev_chain]) assert len (prev_chain) < 5000, (prev_chain[:10], prev_chain[-10:]) prev_chain.reverse () for n_vc in prev_chain: self.get_node_pc_env (n_vc, tag, request = False)
def mk_stack_pairings (pairing_tups, stack_bounds_fname = None, quiet = True): """build the stack-aware calling-convention-aware logical pairings once a collection of function pairs have been read.""" # simplifies interactive testing of this function pre_pairings.clear () for (asm_f, c_f) in pairing_tups: pair = {'ASM': asm_f, 'C': c_f} assert c_f not in pre_pairings assert asm_f not in pre_pairings pre_pairings[c_f] = pair pre_pairings[asm_f] = pair fn_hash = hash (tuple (sorted ([(f, hash (functions[f])) for f in functions]))) prev_hash = read_fn_hash (stack_bounds_fname) if prev_hash == fn_hash: f = open (stack_bounds_fname) f.readline () stack_bounds = deserialise_stack_bounds (f) f.close () else: printout ('Computing stack bounds.') stack_bounds = compute_stack_bounds (quiet = quiet) f = open (stack_bounds_fname, 'w') f.write ('FunctionHash %s\n' % fn_hash) for line in serialise_stack_bounds (stack_bounds): f.write(line) f.close () return mk_pairings (stack_bounds)
def check_no_symbols(nodes): import pseudo_compile symbs = pseudo_compile.nodes_symbols(nodes) if not symbs: return printout('Aborting %s: undefined symbols %s' % (self.name, symbs)) raise Abort()
def mk_stack_pairings(pairing_tups, stack_bounds_fname=None, quiet=True): """build the stack-aware calling-convention-aware logical pairings once a collection of function pairs have been read.""" # simplifies interactive testing of this function pre_pairings.clear() for (asm_f, c_f) in pairing_tups: pair = {'ASM': asm_f, 'C': c_f} assert c_f not in pre_pairings assert asm_f not in pre_pairings pre_pairings[c_f] = pair pre_pairings[asm_f] = pair fn_hash = hash(tuple(sorted([(f, hash(functions[f])) for f in functions]))) prev_hash = read_fn_hash(stack_bounds_fname) if prev_hash == fn_hash: f = open(stack_bounds_fname) f.readline() stack_bounds = deserialise_stack_bounds(f) f.close() else: printout('Computing stack bounds.') stack_bounds = compute_stack_bounds(quiet=quiet) f = open(stack_bounds_fname, 'w') f.write('FunctionHash %s\n' % fn_hash) for line in serialise_stack_bounds(stack_bounds): f.write(line) f.close() problematic_synthetic() return mk_pairings(stack_bounds)
def check_no_inner_loop(p, head): subs = loop_inner_loops(p, head) if subs: printout('Aborting %s, complex loop' % p.name) trace(' sub-loops %s of loop at %s' % (subs, head)) for (h, _) in subs: trace(' head %d tagged %s' % (h, p.node_tags[h])) raise Abort()
def get_loop_virtual_stack_analysis(p, tag): """computes variable liveness etc analyses with stack slots treated as virtual variables.""" cache_key = ('loop_stack_analysis', tag) if cache_key in p.cached_analysis: return p.cached_analysis[cache_key] (ent, fname, _) = p.get_entry_details(tag) (_, sp) = get_stack_sp(p, tag) cc = get_asm_calling_convention(fname) rets = list( set([ ptr for arg in cc['rets'] for (ptr, _) in stack_virtualise_expr(arg, None)[0] ])) rets = [adjust_ret_ptr(ret) for ret in rets] renames = p.entry_exit_renames(tags=[tag]) r = renames[tag + '_OUT'] rets = [syntax.rename_expr(ret, r) for ret in rets] ns = [n for n in p.nodes if p.node_tags[n][0] == tag] loop_ns = logic.minimal_loop_node_set(p) ptrs = list( set([(n, ptr) for n in ns for ptr in (stack_virtualise_node(p.nodes[n], None))[0]])) ptrs += [(n, (sp, 'StackPointer')) for n in ns if n in loop_ns] offs = get_ptr_offsets(p, [(n, ptr) for (n, (ptr, _)) in ptrs], [(ent, sp, 'stack')] + [(ent, ptr, 'indirect_ret') for ptr in rets[:1]]) ptr_offs = {} rep_offs = {} upd_offsets = {} for ((n, ptr), off, k) in offs: off = norm_int(off, 32) ptr_offs.setdefault(n, {}) rep_offs.setdefault(n, {}) ptr_offs[n][ptr] = (k, off) rep_offs[n][k] = (ptr, -off) for (n, (ptr, kind)) in ptrs: if kind == 'MemUpdate' and n in loop_ns: loop = p.loop_id(n) (k, off) = ptr_offs[n][ptr] upd_offsets.setdefault(loop, set()) upd_offsets[loop].add((k, off)) loc_offs = mk_get_local_offs(p, tag, rep_offs) adj_nodes = {} for n in ns: try: (_, node) = stack_virtualise_node(p.nodes[n], ptr_offs.get(n, {})) except StackOffsMissing, e: printout("Stack analysis issue at (%d, %s)." % (n, p.node_tags[n])) node = p.nodes[n] adj_nodes[n] = node
def build_proof (p): init_hyps = check.init_point_hyps (p) proof = build_proof_rec (default_searcher, p, (), list (init_hyps)) trace ('Built proof for %s' % p.name) printout (repr (proof)) last_proof[0] = proof return proof
def check_all (omit_set = set (), loops = True, tags = None, report_mode = False): pairs = list (set ([pair for f in pairings for pair in pairings[f] if omit_set.isdisjoint (pair.funs.values ()) if not tags or tags.issubset (set (pair.tags))])) omitted = list (set ([pair for f in pairings for pair in pairings[f] if not omit_set.isdisjoint (pair.funs.values())])) random.shuffle (pairs) r = check_pairs (pairs, loops = loops, report_mode = report_mode) if omitted: printout (' - %d pairings omitted: %s' % (len (omitted), [pair.name for pair in omitted])) return r
def check_deps (fname, report_mode = False): frontier = set ([fname]) funs = set () while frontier: fname = frontier.pop () if fname in funs: continue funs.add (fname) frontier.update (functions[fname].function_calls ()) funs = sorted (funs) funs = [fun for fun in funs if fun in pairings] printout ('Testing functions: %s' % funs) pairs = [pair for f in funs for pair in pairings[f]] return check_pairs (pairs, report_mode = report_mode)
def problematic_synthetic(): synth = [ s for s in target_objects.symbols if '.clone.' in s or '.part.' in s or '.constprop.' in s ] synth = ['_'.join(s.split('.')) for s in synth] if not synth: return printout('Synthetic symbols: %s' % synth) synth_calls = set( [f for f in synth if f in functions if functions[f].function_calls()]) printout('Synthetic symbols which make function calls: %s' % synth_calls) if not synth_calls: return synth_stack = set([ f for f in synth_calls if [ node for node in functions[f].nodes.itervalues() if node.kind == 'Basic' if ('r13', word32T) in node.get_lvals() ] ]) printout('Synthetic symbols which call and move sp: %s' % synth_stack) synth_problems = set([ f for f in synth_stack if [ f2 for f2 in functions if f in functions[f2].function_calls() if len(set(functions[f2].function_calls())) > 1 ] ]) printout('Problematic synthetics: %s' % synth_problems) return synth_problems
def check_all (omit_set = set (), loops = True, tags = None, report_mode = False, only_build_problem = False): pairs = list (set ([pair for f in pairings for pair in pairings[f] if omit_set.isdisjoint (pair.funs.values ()) if not tags or tags.issubset (set (pair.tags))])) omitted = list (set ([pair for f in pairings for pair in pairings[f] if not omit_set.isdisjoint (pair.funs.values())])) random.shuffle (pairs) r = check_pairs (pairs, loops = loops, report_mode = report_mode, only_build_problem = only_build_problem) if omitted: printout (' - %d pairings omitted: %s' % (len (omitted), [pair.name for pair in omitted])) return r
def problematic_instructions(): add_inst_specs(report_problematic=False) unhandled = {} for f in functions: for f2 in functions[f].function_calls(): if "instruction'" not in f2: continue if functions[f2].entry: continue unhandled.setdefault(f, []) unhandled[f].append(f2) for f in unhandled: printout('Function %r contains unhandled instructions:' % f) printout(' %s' % unhandled[f]) return unhandled
def compute_recursion_idents(group, extra_unfolds): idents = {} group = set(group) recursion_trace.append('Computing for group %s' % group) printout('Doing recursion analysis for function group:') printout(' %s' % list(group)) prevs = set([ f for f in functions if [f2 for f2 in functions[f].function_calls() if f2 in group] ]) for f in prevs - group: recursion_trace.append(' checking for %s' % f) trace('Checking idents for %s' % f) while add_recursion_ident(f, group, idents, extra_unfolds): pass return idents
def build_compound_problem(fnames): """mirrors build_problem from check for multiple functions""" printout('Building compound problem for %s' % fnames) last_compound_problem_req[0] = list(fnames) p = problem.Problem(None, name=', '.join(fnames)) fun_tag_pairs = [] all_tags = {} for (i, fn) in enumerate(fnames): i = len(fnames) - i [pair] = pairings[fn] next_tags = {} scripts = get_problem_inline_scripts(pair) for (pair_tag, fname) in pair.funs.items(): tag = '%s_%d_%s' % (fname, i, pair_tag) tag = syntax.fresh_name(tag, all_tags) next_tags[pair_tag] = tag p.add_entry_function(functions[fname], tag) p.hook_tag_hints[tag] = pair_tag p.replay_inline_script(tag, scripts[pair_tag]) fun_tag_pairs.append((next_tags, pair)) p.pad_merge_points() p.do_analysis() free_hyps = [] for (tags, pair) in fun_tag_pairs: (inp_eqs, _) = pair.eqs free_hyps += check.inst_eqs(p, (), inp_eqs, tags) err_vis_opts = rep_graph.vc_options([0, 1, 2], [1]) err_vis_vc = tuple([(n, err_vis_opts) for n in p.loop_heads() if p.node_tags[n][0] == tags['C']]) err_vis = (('Err', err_vis_vc), tags['C']) free_hyps.append(rep_graph.pc_false_hyp(err_vis)) addr_map = {} for n in p.nodes: if not p.node_tags[n][0].endswith('_ASM'): continue if type(p.node_tags[n][1]) == tuple: (fname, data) = p.node_tags[n][1] if (logic.is_int(data) and is_addr(data) and not fname.startswith("instruction'")): assert data not in addr_map, data addr_map[data] = n return (p, free_hyps, addr_map, fun_tag_pairs)
def build_compound_problem (fnames): """mirrors build_problem from check for multiple functions""" printout ('Building compound problem for %s' % fnames) last_compound_problem_req[0] = list (fnames) p = problem.Problem (None, name = ', '.join(fnames)) fun_tag_pairs = [] all_tags = {} for (i, fn) in enumerate (fnames): i = len (fnames) - i [pair] = pairings[fn] next_tags = {} scripts = get_problem_inline_scripts (pair) for (pair_tag, fname) in pair.funs.items (): tag = '%s_%d_%s' % (fname, i, pair_tag) tag = syntax.fresh_name (tag, all_tags) next_tags[pair_tag] = tag p.add_entry_function (functions[fname], tag) p.hook_tag_hints[tag] = pair_tag p.replay_inline_script (tag, scripts[pair_tag]) fun_tag_pairs.append ((next_tags, pair)) p.pad_merge_points () p.do_analysis () free_hyps = [] for (tags, pair) in fun_tag_pairs: (inp_eqs, _) = pair.eqs free_hyps += check.inst_eqs (p, (), inp_eqs, tags) err_vis_opts = rep_graph.vc_options ([0, 1, 2], [1]) err_vis_vc = tuple ([(n, err_vis_opts) for n in p.loop_heads () if p.node_tags[n][0] == tags['C']]) err_vis = (('Err', err_vis_vc), tags['C']) free_hyps.append (rep_graph.pc_false_hyp (err_vis)) addr_map = {} for n in p.nodes: if not p.node_tags[n][0].endswith ('_ASM'): continue if type (p.node_tags[n][1]) == tuple: (fname, data) = p.node_tags[n][1] if (logic.is_int (data) and is_addr (data) and not fname.startswith ("instruction'")): assert data not in addr_map, data addr_map[data] = n return (p, free_hyps, addr_map, fun_tag_pairs)
def compute_stack_bounds (quiet = False): prev_tracer = target_objects.tracer[0] if quiet: target_objects.tracer[0] = lambda s, n: () c_fs = get_functions_with_tag ('C') idents = get_recursion_identifiers (c_fs) asm_idents = convert_recursion_idents (idents) asm_fs = get_functions_with_tag ('ASM') printout ('Computed recursion limits.') bounds = compute_asm_stack_bounds (asm_idents, asm_fs) printout ('Computed stack bounds.') if quiet: target_objects.tracer[0] = prev_tracer return bounds
def compute_immediate_stack_bounds(idents, names): from syntax import true_term immed = {} names = sorted(names) for (i, fname) in enumerate(names): printout('Doing stack analysis for %r. (%d of %d)' % (fname, i + 1, len(names))) fun = functions[fname] (offs, fn_offs) = guess_asm_stack_depth(fun) callables = ident_callables(fname, fn_offs.keys(), idents) for ident in idents.get(fname, [true_term]): calls = [((fname2, ident2), fn_offs[fname2]) for fname2 in fn_offs for ident2 in idents.get(fname2, [true_term]) if callables[(ident, fname2, ident2)]] immed[(fname, ident)] = (offs, dict(calls)) last_immediate_stack_bounds[0] = immed return immed
def add_function(self, fun, tag, node_renames, loop_id=None): if not fun.entry: printout("Aborting %s: underspecified %s" % (self.name, fun.name)) raise Abort() node_renames.setdefault("Ret", "Ret") node_renames.setdefault("Err", "Err") new_node_renames = {} vs = syntax.get_vars(fun) vs = dict([(v, fresh_name(v, self.vs, vs[v])) for v in vs]) ns = fun.reachable_nodes() for n in ns: assert n not in node_renames node_renames[n] = self.alloc_node(tag, (fun.name, n), loop_id=loop_id, hint=n) new_node_renames[n] = node_renames[n] for n in ns: self.nodes[node_renames[n]] = syntax.copy_rename(fun.nodes[n], (vs, node_renames)) return (new_node_renames, vs)
def compute_immediate_stack_bounds (idents, names): from syntax import true_term immed = {} names = sorted (names) for (i, fname) in enumerate (names): printout ('Doing stack analysis for %r. (%d of %d)' % (fname, i + 1, len (names))) fun = functions[fname] (offs, fn_offs) = guess_asm_stack_depth (fun) callables = ident_callables (fname, fn_offs.keys (), idents) for ident in idents.get (fname, [true_term]): calls = [((fname2, ident2), fn_offs[fname2]) for fname2 in fn_offs for ident2 in idents.get (fname2, [true_term]) if callables[(ident, fname2, ident2)]] immed[(fname, ident)] = (offs, dict (calls)) last_immediate_stack_bounds[0] = immed return immed
def compute_stack_bounds(quiet=False): prev_tracer = target_objects.tracer[0] if quiet: target_objects.tracer[0] = lambda s, n: () try: c_fs = get_functions_with_tag('C') idents = get_recursion_identifiers(c_fs) asm_idents = convert_recursion_idents(idents) asm_fs = get_functions_with_tag('ASM') printout('Computed recursion limits.') bounds = compute_asm_stack_bounds(asm_idents, asm_fs) printout('Computed stack bounds.') except Exception, e: if quiet: target_objects.tracer[0] = prev_tracer raise
def aligned_address_sanity (functions, symbols, radix): for (f, func) in functions.iteritems (): if f not in symbols: # happens for static or invented functions sometimes continue if func.entry: addr = first_aligned_address (func.nodes, radix) if addr == None: printout ('Warning: %s: no aligned instructions' % f) continue addr2 = symbols[f][0] if addr != addr2: printout ('target mismatch on func %s' % f) printout (' (starts at 0x%x not 0x%x)' % (addr, addr2)) return False addr3 = entry_aligned_address (func, radix) if addr3 != addr2: printout ('entry mismatch on func %s' % f) printout (' (enters at 0x%x not 0x%x)' % (addr3, addr2)) return False return True
def add_function(self, fun, tag, node_renames, loop_id=None): if not fun.entry: printout('Aborting %s: underspecified %s' % (self.name, fun.name)) raise Abort() node_renames.setdefault('Ret', 'Ret') node_renames.setdefault('Err', 'Err') new_node_renames = {} vs = syntax.get_vars(fun) vs = dict([(v, fresh_name(v, self.vs, vs[v])) for v in vs]) ns = fun.reachable_nodes() check_no_symbols([fun.nodes[n] for n in ns]) for n in ns: assert n not in node_renames node_renames[n] = self.alloc_node(tag, (fun.name, n), loop_id=loop_id, hint=n) new_node_renames[n] = node_renames[n] for n in ns: self.nodes[node_renames[n]] = syntax.copy_rename( fun.nodes[n], (vs, node_renames)) return (new_node_renames, vs)
def mk_asm_inst_spec(fname): if not fname.startswith("asm_instruction'"): return if functions[fname].entry: return (_, ident) = fname.split("'", 1) (args, ident) = split_inst_name_regs(ident) if not all([arg.startswith('%') for arg in args]): printout('Warning: asm instruction name: formatting: %r' % fname) return base_ident = ident.split("_")[0] if base_ident not in instruction_fun_specs: return (impl_fname, regspecs) = instruction_fun_specs[base_ident] add_impl_fun(impl_fname, regspecs) (iscs, imems, _) = logic.split_scalar_pairs(functions[fname].inputs) (oscs, omems, _) = logic.split_scalar_pairs(functions[fname].outputs) call = syntax.Node('Call', 'Ret', ('r_' + impl_fname, iscs + [syntax.mk_token(ident)] + imems, [(v.name, v.typ) for v in oscs + omems])) assert not functions[fname].nodes functions[fname].nodes[1] = call functions[fname].entry = 1
def check_pairs (pairs, loops = True, report_mode = False): num_pairs = len (pairs) results = [toplevel_check_wname (pair, check_loops = loops, report_mode = report_mode, count = (i, num_pairs)) for (i, pair) in enumerate (pairs)] printout ('Result summary: %s' % results) count = len ([1 for (_, r) in results if r == 'True']) printout (' - %d proofs checked' % count) count = len ([1 for (_, r) in results if r in ['ProofAbort', 'None']]) printout (' - %d proofs skipped' % count) fails = [(nm, r) for (nm, r) in results if r not in ['True', 'ProofAbort', 'None']] printout (' - failures: %s' % fails) return syntax.foldr1 (comb_results, ['True'] + [r for (nm, r) in results])
def check_all (omit_set = set (), loops = True, tags = None, report_mode = False): pairs = list (set ([pair for f in pairings for pair in pairings[f] if omit_set.isdisjoint (pair.funs.values ()) if not tags or tags.issubset (set (pair.tags))])) num_pairs = len (pairs) omitted = list (set ([pair for f in pairings for pair in pairings[f] if not omit_set.isdisjoint (pair.funs.values())])) random.shuffle (pairs) results = [toplevel_check_wname (pair, check_loops = loops, report_mode = report_mode, count = (i, num_pairs)) for (i, pair) in enumerate (pairs)] printout ('Result summary: %s' % results) count = len ([1 for (_, r) in results if r == 'True']) printout (' - %d proofs checked' % count) count = len ([1 for (_, r) in results if r in ['ProofAbort', None]]) printout (' - %d proofs skipped' % count) fails = [(nm, r) for (nm, r) in results if r not in ['True', 'ProofAbort', None]] printout (' - failures: %s' % fails) if omitted: printout (' - %d pairings omitted: %s' % (len (omitted), omitted))
def print_coverage_report (skipped_pairs, covered_pairs): try: from trace_refute import addrs_covered, funs_sort_by_num_addrs covered_fs = set ([f for pair in covered_pairs for f in [pair.l_f, pair.r_f]]) coverage = addrs_covered (covered_fs) printout (' - %.2f%% instructions covered' % (coverage * 100)) skipped_fs = set ([f for pair in skipped_pairs for f in [pair.l_f, pair.r_f]]) fs = funs_sort_by_num_addrs (set (skipped_fs)) if not fs: return lrg_msgs = ['%s (%.2f%%)' % (f, addrs_covered ([f]) * 100) for f in reversed (fs[-3:])] printout (' - largest skipped functions:') printout (' %s' % ', '.join (lrg_msgs)) except Exception, e: pass
else: printout ('Refinement NOT proven.') except solver.SolverFailure, e: printout ('Solver timeout/failure in proof check.') result = 'CheckSolverFailure' except Exception, e: trace ('EXCEPTION in checking %s:' % p.name) exception = sys.exc_info () result = 'CheckEXCEPT' except problem.Abort: result = 'ProofAbort' except search.NoSplit: result = 'ProofNoSplit' except solver.SolverFailure, e: printout ('Solver timeout/failure in proof search.') result = 'ProofSolverFailure' except Exception, e: trace ('EXCEPTION in handling %s:' % pair) exception = sys.exc_info () result = 'ProofEXCEPT' end_time = time.time () tracer[0] = prev_tracer if exception: (etype, evalue, tb) = exception traceback.print_exception (etype, evalue, tb, file = sys.stdout) if not report:
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): 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') (_, sp) = get_stack_sp(p, 'Target') nodes = get_asm_reachable_nodes(p, tag_set=['Target'])
def toplevel_check (pair, check_loops = True, report = False, count = None, only_build_problem = False): if not only_build_problem: printout ('Testing Function pair %s' % pair) if count and not only_build_problem: (i, n) = count printout (' (function pairing %d of %d)' % (i + 1, n)) for (tag, fname) in pair.funs.iteritems (): if not functions[fname].entry: printout ('Skipping %s, underspecified %s' % (pair, tag)) return 'None' prev_tracer = tracer[0] if report: tracer[0] = lambda s, n: () exception = None trace (time.asctime ()) start_time = time.time() sys.stdout.flush () try: p = check.build_problem (pair) if only_build_problem: tracer[0] = prev_tracer return 'True' if report: printout (' .. built problem, finding proof') if not check_loops and p.loop_data: printout ('Problem has loop!') tracer[0] = prev_tracer return 'Loop' if check_loops == 'only' and not p.loop_data: printout ('No loop in problem.') tracer[0] = prev_tracer return 'NoLoop' proof = search.build_proof (p) if report: printout (' .. proof found.') try: if report: result = check.check_proof_report (p, proof) else: result = check.check_proof (p, proof) if result: printout ('Refinement proven.') else: printout ('Refinement NOT proven.') except solver.SolverFailure, e: printout ('Solver timeout/failure in proof check.') result = 'CheckSolverFailure' except Exception, e: trace ('EXCEPTION in checking %s:' % p.name) exception = sys.exc_info () result = 'CheckEXCEPT'
def check_proof_report_rec (p, restrs, hyps, proof, step_num, ctxt, inducts): import sys 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 == '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: groups = proof_check_groups (checks) for group in groups: rep = rep_graph.mk_graph_slice (p) (res, _) = test_hyp_group (rep, group) if not res: printout (' .. failed to prove this.') sys.stdout.flush () return printout (' .. proven.') sys.stdout.flush () 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) if not res: return (step_num, induct_var_num) = res inducts = (induct_var_num, inducts[1]) return (step_num, inducts[0])
def toplevel_check (pair, check_loops = True, report = False, count = None): printout ('Testing Function pair %s' % pair) if count: (i, n) = count printout (' (function pairing %d of %d)' % (i + 1, n)) for (tag, fname) in pair.funs.iteritems (): if not functions[fname].entry: printout ('Skipping %s, underspecified %s' % (pair, tag)) return 'None' prev_tracer = tracer[0] if report: tracer[0] = lambda s, n: () exception = None trace (time.asctime ()) start_time = time.time() sys.stdout.flush () try: p = check.build_problem (pair) if report: printout (' .. built problem, finding proof') if not check_loops and p.loop_data: printout ('Problem has loop!') tracer[0] = prev_tracer return 'Loop' if check_loops == 'only' and not p.loop_data: printout ('No loop in problem.') tracer[0] = prev_tracer return 'NoLoop' proof = search.build_proof (p) if report: printout (' .. proof found.') try: if report: result = check.check_proof_report (p, proof) else: result = check.check_proof (p, proof) if result: printout ('Refinement proven.') else: printout ('Refinement NOT proven.') except solver.SolverFailure, e: printout ('Solver timeout/failure in proof check.') result = 'CheckSolverFailure' except Exception, e: trace ('EXCEPTION in checking %s:' % p.name) exception = sys.exc_info () result = 'CheckEXCEPT'
else: printout ('Refinement NOT proven.') except solver.SolverFailure, e: printout ('Solver timeout/failure in proof check.') result = 'CheckSolverFailure' except Exception, e: trace ('EXCEPTION in checking %s:' % p.name) exception = sys.exc_info () result = 'CheckEXCEPT' except problem.Abort: result = 'ProblemAbort' except search.NoSplit: result = 'ProofNoSplit' except solver.SolverFailure, e: printout ('Solver timeout/failure in proof search.') result = 'ProofSolverFailure' except Exception, e: trace ('EXCEPTION in handling %s:' % pair) exception = sys.exc_info () result = 'ProofEXCEPT' end_time = time.time () tracer[0] = prev_tracer if exception: (etype, evalue, tb) = exception traceback.print_exception (etype, evalue, tb, file = sys.stdout) if not only_build_problem:
def check_pairs (pairs, loops = True, report_mode = False, only_build_problem = False): num_pairs = len (pairs) printout ('Checking %d function pair problems' % len (pairs)) results = [(pair, toplevel_check (pair, check_loops = loops, report = report_mode, count = (i, num_pairs), only_build_problem = only_build_problem)) for (i, pair) in enumerate (pairs)] result_dict = logic.dict_list ([(result_codes[r][1], pair) for (pair, r) in results]) if not only_build_problem: printout ('Results: %s' % [(pair.name, r) for (pair, r) in results]) printout ('Result summary:') success = result_dict.get ('Success', []) if only_build_problem: printout (' - %d problems build' % len (success)) else: printout (' - %d proofs checked' % len (success)) skipped = result_dict.get ('Skipped', []) printout (' - %d proofs skipped' % len (skipped)) fails = [pair.name for pair in result_dict.get ('Failed', [])] print_coverage_report (set (skipped), set (success + fails)) printout (' - failures: %s' % fails) return syntax.foldr1 (comb_results, ['True'] + [r for (_, r) in results])
else: printout ('Refinement NOT proven.') except solver.SolverFailure, e: printout ('Solver timeout/failure in proof check.') result = 'CheckSolverFailure' except Exception, e: trace ('EXCEPTION in checking %s:' % p.name) exception = sys.exc_info () result = 'CheckEXCEPT' except problem.Abort: result = 'ProofAbort' except search.NoSplit: result = 'ProofNoSplit' except solver.SolverFailure, e: printout ('Solver timeout/failure in proof search.') result = 'ProofSolverFailure' except Exception, e: trace ('EXCEPTION in handling %s:' % pair) exception = sys.exc_info () result = 'ProofEXCEPT' end_time = time.time () tracer[0] = prev_tracer if exception: (etype, evalue, tb) = exception traceback.print_exception (etype, evalue, tb, file = sys.stdout) printout ('Result %s for pair %s, time taken: %f'
def build_proof_rec (searcher, p, restrs, hyps, name = "problem"): trace ('doing build proof rec with restrs = %r, hyps = %r' % (restrs, hyps)) (kind, details) = searcher (p, restrs, hyps) last_searcher_results.append ((p, restrs, hyps, kind, details, name)) del last_searcher_results[:-10] if kind == 'Restr': (restr_kind, restr_points) = details printout ("Discovered that points [%s] can be bounded" % ', '.join ([restr_point_name (p, n) for n in restr_points])) printout (" (in %s)" % name) return build_proof_rec_with_restrs (restr_points, restr_kind, searcher, p, restrs, hyps, name = name) elif kind == 'Leaf': return ProofNode ('Leaf', None, ()) assert kind in ['CaseSplit', 'Split'] split = details if kind == 'CaseSplit': (split, hints) = details [(_, hyps1, nm1), (_, hyps2, nm2)] = check.proof_subproblems (p, kind, split, restrs, hyps, name) if kind == 'CaseSplit': printout ("Decided to case split at %s" % str (split)) printout (" (in %s)" % name) restr_points = hints kinds = ['Number', 'Number'] else: restr_points = check.split_heads (split) kinds = ['Number', 'Offset'] printout ("Discovered a loop relation for split points %s" % list (restr_points)) printout (" (in %s)" % name) subpfs = [build_proof_rec_with_restrs (restr_points, k, searcher, p, restrs, hyps_i, must_find = False, name = nm) for (nm, hyps_i, k) in [(nm1, hyps1, kinds[0]), (nm2, hyps2, kinds[1])]] return ProofNode (kind, split, subpfs)
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])