Esempio n. 1
0
 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'))
Esempio n. 2
0
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, [])
Esempio n. 3
0
 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)
Esempio n. 4
0
 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'))
Esempio n. 5
0
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
Esempio n. 6
0
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)