def diff_behavior(ctxfn1: FunctionInfo, ctxfn2: FunctionInfo, options: AnalysisOptions) -> Union[str, List[BehaviorDiff]]: fn1, sig1 = ctxfn1.callable() fn2, sig2 = ctxfn2.callable() debug("Resolved signature:", sig1) all_diffs: List[BehaviorDiff] = [] half1, half2 = options.split_limits(0.5) with condition_parser(options.analysis_kind), Patched(): # We attempt both orderings of functions. This helps by: # (1) avoiding code path explosions in one of the functions # (2) using both signatures (in case they differ) all_diffs.extend(diff_behavior_with_signature(fn1, fn2, sig1, half1)) all_diffs.extend( diff.reverse() for diff in diff_behavior_with_signature(fn2, fn1, sig2, half2)) debug("diff candidates:", all_diffs) # greedily pick results: result_diffs = [] opcodeset1 = set(i.offset for i in dis.get_instructions(fn1.__code__)) opcodeset2 = set(i.offset for i in dis.get_instructions(fn2.__code__)) while all_diffs: scorer = diff_scorer(opcodeset1, opcodeset2) selection = max(all_diffs, key=scorer) (num_opcodes, _) = scorer(selection) debug("Considering input", selection.args, " num opcodes=", num_opcodes) if num_opcodes == 0: break all_diffs.remove(selection) result_diffs.append(selection) coverage1, coverage2 = selection.coverage1, selection.coverage2 if coverage1 is not None and coverage2 is not None: opcodeset1 -= coverage1.offsets_covered opcodeset2 -= coverage2.offsets_covered return result_diffs
def path_cover(ctxfn: FunctionInfo, options: AnalysisOptions, coverage_type: CoverageType) -> List[PathSummary]: fn, sig = ctxfn.callable() search_root = SinglePathNode(True) condition_start = time.monotonic() paths: List[PathSummary] = [] for i in range(1, options.max_iterations): debug("Iteration ", i) itr_start = time.monotonic() if itr_start > condition_start + options.per_condition_timeout: debug( "Stopping due to --per_condition_timeout=", options.per_condition_timeout, ) break space = StateSpace( execution_deadline=itr_start + options.per_path_timeout, model_check_timeout=options.per_path_timeout / 2, search_root=search_root, ) with condition_parser(options.analysis_kind), Patched( ), COMPOSITE_TRACER, StateSpaceContext(space): summary = None try: summary = run_iteration(fn, sig, space) verification_status = VerificationStatus.CONFIRMED except UnexploredPath: verification_status = VerificationStatus.UNKNOWN debug("Verification status:", verification_status) top_analysis, exhausted = space.bubble_status( CallAnalysis(verification_status)) debug("Path tree stats", search_root.stats()) if summary: paths.append(summary) if exhausted: debug("Stopping due to code path exhaustion. (yay!)") break opcodes_found: Set[int] = set() selected: List[PathSummary] = [] while paths: next_best = max( paths, key=lambda p: len(p.coverage.offsets_covered - opcodes_found)) cur_offsets = next_best.coverage.offsets_covered if coverage_type == CoverageType.OPCODE: if len(cur_offsets - opcodes_found) == 0: break selected.append(next_best) opcodes_found |= cur_offsets paths = [p for p in paths if p is not next_best] return selected