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
def symbolic_run( self, fn: Callable[[StateSpace, Dict[str, object]], object], typed_args: Dict[str, type], ) -> Tuple[object, # return value Optional[Dict[str, object]], # arguments after execution Optional[BaseException], # exception thrown, if any StateSpace, ]: search_root = SinglePathNode(True) with COMPOSITE_TRACER, Patched(): for itr in range(1, 200): debug("iteration", itr) space = StateSpace(time.monotonic() + 10.0, 1.0, search_root=search_root) symbolic_args = {} try: with StateSpaceContext(space): symbolic_args = { name: proxy_for_type(typ, name) for name, typ in typed_args.items() } ret = fn(space, symbolic_args) ret = (deep_realize(ret), symbolic_args, None, space) space.check_deferred_assumptions() return ret except IgnoreAttempt as e: debug("ignore iteration attempt: ", str(e)) pass except BaseException as e: debug(traceback.format_exc()) return (None, symbolic_args, e, space) top_analysis, space_exhausted = space.bubble_status( CallAnalysis()) if space_exhausted: return ( None, symbolic_args, CrosshairInternal(f"exhausted after {itr} iterations"), space, ) return ( None, None, CrosshairInternal( "Unable to find a successful symbolic execution"), space, )
def diff_behavior_with_signature( fn1: Callable, fn2: Callable, sig: inspect.Signature, options: AnalysisOptions ) -> Iterable[BehaviorDiff]: search_root = SinglePathNode(True) condition_start = time.monotonic() 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, ) return options.incr("num_paths") space = StateSpace( execution_deadline=itr_start + options.per_path_timeout, model_check_timeout=options.per_path_timeout / 2, search_root=search_root, ) with StateSpaceContext(space): output = None try: (verification_status, output) = run_iteration(fn1, fn2, sig, space) except UnexploredPath: verification_status = VerificationStatus.UNKNOWN debug("Verification status:", verification_status) top_analysis, space_exhausted = space.bubble_status( CallAnalysis(verification_status) ) if ( top_analysis and top_analysis.verification_status == VerificationStatus.CONFIRMED ): debug("Stopping due to code path exhaustion. (yay!)") options.incr("exhaustion") break if output: yield output