def symbolic_run( self, fn: Callable[[TrackingStateSpace], bool] ) -> Tuple[object, Optional[BaseException]]: search_root = SinglePathNode(True) patched_builtins = PatchedBuiltins(contracted_builtins.__dict__, enabled=lambda: True) with patched_builtins: for itr in range(1, 200): debug('iteration', itr) space = TrackingStateSpace(time.time() + 10.0, 1.0, search_root=search_root) try: return (realize(fn(space)), None) except IgnoreAttempt as e: debug('ignore iteration attempt: ', str(e)) pass except BaseException as e: #traceback.print_exc() return (None, e) top_analysis, space_exhausted = space.bubble_status( CallAnalysis()) if space_exhausted: return ( None, CrosshairInternal(f'exhausted after {itr} iterations')) return (None, CrosshairInternal( 'Unable to find a successful symbolic execution'))
def run_iteration( fn1: Callable, fn2: Callable, sig: inspect.Signature, space: TrackingStateSpace) -> Tuple[ Optional[VerificationStatus], List[str]]: original_args = gen_args(sig) args1 = copy.deepcopy(original_args) args2 = copy.deepcopy(original_args) try: with ExceptionFilter() as efilter: ret1, exc1 = describe_behavior(fn1, args1) ret2, exc2 = describe_behavior(fn2, args2) err1, err2 = str(exc1), str(exc2) if ret1 == ret2 and err1 == err2: debug('Functions equivalent') return (VerificationStatus.CONFIRMED, []) debug('Functions differ') inputs = ', '.join(f'{k}={v!r}' for k,v in original_args.arguments.items()) output = [f' given: ({inputs})'] if ret1 != ret2: output.append(f'- returns: {ret1}') output.append(f'+ returns: {ret2}') if err1 != err2: output.append(f'- raises: {err1}') output.append(f'+ raises: {err2}') space.check_deferred_assumptions() return (VerificationStatus.REFUTED, output) if efilter.user_exc: debug('User-level exception found', *efilter.user_exc) except UnexploredPath: pass return (None, [])
def symbolic_run( self, fn: Callable[[TrackingStateSpace], object] ) -> Tuple[object, Optional[BaseException], TrackingStateSpace]: search_root = SinglePathNode(True) with Patched(enabled=lambda: True): for itr in range(1, 200): debug('iteration', itr) space = TrackingStateSpace(time.monotonic() + 10.0, 1.0, search_root=search_root) try: with StateSpaceContext(space): ret = (realize(fn(space)), 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, e, space) top_analysis, space_exhausted = space.bubble_status( CallAnalysis()) if space_exhausted: return ( None, CrosshairInternal(f'exhausted after {itr} iterations'), space) return (None, CrosshairInternal( 'Unable to find a successful symbolic execution'), space)
def symbolic_run( self, fn: Callable[[TrackingStateSpace], bool] ) -> Tuple[object, Optional[BaseException]]: search_root = SinglePathNode(True) itr = 0 for _ in range(200): itr += 1 space = TrackingStateSpace(time.time() + 10.0, 1.0, search_root=search_root) try: return (realize(fn(space)), None) except IgnoreAttempt: pass except BaseException as e: #import traceback #traceback.print_exc() return (None, e) top_analysis, space_exhausted = space.bubble_status(CallAnalysis()) if space_exhausted: return (None, CrosshairInternal(f'exhausted after {itr} iterations')) return (None, CrosshairInternal( 'Unable to find a successful symbolic execution'))
def diff_behavior_with_signature( fn1: Callable, fn2: Callable, sig: inspect.Signature, options: AnalysisOptions) -> Iterable[str]: 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: yield f'(stopping due to --per_condition_timeout={options.per_condition_timeout})' break space = TrackingStateSpace( execution_deadline=itr_start + options.per_path_timeout, model_check_timeout=options.per_path_timeout / 2, search_root=search_root) with StateSpaceContext(space): (verification_status, output) = run_iteration(fn1, fn2, sig, space) 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: break yield from output
def analyze_calltree(options: AnalysisOptions, conditions: Conditions) -> CallTreeAnalysis: fn = conditions.fn debug('Begin analyze calltree ', fn.__name__) all_messages = MessageCollector() search_root = SinglePathNode(True) space_exhausted = False failing_precondition: Optional[ ConditionExpr] = conditions.pre[0] if conditions.pre else None failing_precondition_reason: str = '' num_confirmed_paths = 0 _ = get_subclass_map() # ensure loaded short_circuit = ShortCircuitingContext() top_analysis: Optional[CallAnalysis] = None enforced_conditions = EnforcedConditions( options.condition_parser(), fn_globals(fn), builtin_patches(), interceptor=short_circuit.make_interceptor) def in_symbolic_mode(): space = optional_context_statespace() return space and not space.running_framework_code patched = Patched(in_symbolic_mode) with enforced_conditions, patched, enforced_conditions.disabled_enforcement( ): for i in itertools.count(1): start = time.monotonic() if start > options.deadline: debug('Exceeded condition timeout, stopping') break options.incr('num_paths') debug('Iteration ', i) space = TrackingStateSpace( execution_deadline=start + options.per_path_timeout, model_check_timeout=options.per_path_timeout / 2, search_root=search_root) try: # The real work happens here!: with StateSpaceContext(space): call_analysis = attempt_call(conditions, fn, short_circuit, enforced_conditions) if failing_precondition is not None: cur_precondition = call_analysis.failing_precondition if cur_precondition is None: if call_analysis.verification_status is not None: # We escaped the all the pre conditions on this try: failing_precondition = None elif (cur_precondition.line == failing_precondition.line and call_analysis.failing_precondition_reason): failing_precondition_reason = call_analysis.failing_precondition_reason elif cur_precondition.line > failing_precondition.line: failing_precondition = cur_precondition failing_precondition_reason = call_analysis.failing_precondition_reason except UnexploredPath: call_analysis = CallAnalysis(VerificationStatus.UNKNOWN) except IgnoreAttempt: call_analysis = CallAnalysis() status = call_analysis.verification_status if status == VerificationStatus.CONFIRMED: num_confirmed_paths += 1 top_analysis, space_exhausted = space.bubble_status(call_analysis) overall_status = top_analysis.verification_status if top_analysis else None debug('Iter complete. Worst status found so far:', overall_status.name if overall_status else 'None') if space_exhausted or top_analysis == VerificationStatus.REFUTED: break top_analysis = search_root.child.get_result() if top_analysis.messages: #log = space.execution_log() all_messages.extend( replace( m, #execution_log=log, test_fn=fn.__qualname__, condition_src=conditions.post[0].expr_source) for m in top_analysis.messages) if top_analysis.verification_status is None: top_analysis.verification_status = VerificationStatus.UNKNOWN if failing_precondition: assert num_confirmed_paths == 0 addl_ctx = ' ' + failing_precondition.addl_context if failing_precondition.addl_context else '' message = f'Unable to meet precondition{addl_ctx}' if failing_precondition_reason: message += f' (possibly because {failing_precondition_reason}?)' all_messages.extend([ AnalysisMessage(MessageType.PRE_UNSAT, message + '.', failing_precondition.filename, failing_precondition.line, 0, '') ]) top_analysis = CallAnalysis(VerificationStatus.REFUTED) assert top_analysis.verification_status is not None debug( ('Exhausted' if space_exhausted else 'Aborted'), ' calltree search with', top_analysis.verification_status.name, 'and', len(all_messages.get()), 'messages.', 'Number of iterations: ', i) return CallTreeAnalysis( messages=all_messages.get(), verification_status=top_analysis.verification_status, num_confirmed_paths=num_confirmed_paths)