Exemplo n.º 1
0
    def find_key_in_heap(
        self,
        ref: z3.ExprRef,
        typ: Type,
        proxy_generator: Callable[[Type], object],
        snapshot: SnapshotRef = SnapshotRef(-1)
    ) -> object:
        with self.framework():
            for (curref, curtyp,
                 curval) in itertools.chain(*self.heaps[snapshot:]):
                could_match = dynamic_typing.unify(curtyp, typ)
                if not could_match:
                    continue
                if self.smt_fork(curref == ref):
                    debug('HEAP key lookup ', ref, ': Found existing. ',
                          'type:', name_of_type(type(curval)), 'id:',
                          id(curval) % 1000)
                    return curval
            ret = proxy_generator(typ)
            debug('HEAP key lookup ', ref, ': Created new. ', 'type:',
                  name_of_type(type(ret)), 'id:',
                  id(ret) % 1000)

            #assert dynamic_typing.unify(python_type(ret), typ), 'proxy type was {} and type required was {}'.format(type(ret), typ)
            self.add_value_to_heaps(ref, typ, ret)
            return ret
Exemplo n.º 2
0
 def describe(self, include_postexec=False) -> str:
     ret = ""
     if self.exc:
         exc = self.exc
         exc_type = name_of_type(type(exc))
         tb = test_stack(exc.__traceback__)
         ret = f"exc={exc_type}: {str(exc)} {tb}"
     else:
         ret = f"ret={self.ret!r}"
     if include_postexec:
         a = [repr(a) for a in self.post_args]
         a += [f"{k}={v!r}" for k, v in self.post_kwargs.items()]
         ret += f'  post=({", ".join(a)})'
     return ret
Exemplo n.º 3
0
    def find_key_in_heap(
            self,
            ref: z3.ExprRef,
            typ: Type,
            proxy_generator: Callable[[Type], object],
            snapshot: SnapshotRef = SnapshotRef(-1),
    ) -> object:
        with NoTracing():
            for (curref, curtyp,
                 curval) in itertools.chain(*self.heaps[snapshot:]):
                could_match = dynamic_typing.unify(curtyp, typ)
                if not could_match:
                    continue
                if self.smt_fork(curref == ref):
                    debug(
                        "HEAP key lookup ",
                        ref,
                        ": Found existing. ",
                        "type:",
                        name_of_type(type(curval)),
                        "id:",
                        id(curval) % 1000,
                    )
                    return curval
            ret = proxy_generator(typ)
            debug(
                "HEAP key lookup ",
                ref,
                ": Created new. ",
                "type:",
                name_of_type(type(ret)),
                "id:",
                id(ret) % 1000,
            )

            self.add_value_to_heaps(ref, typ, ret)
            return ret
Exemplo n.º 4
0
def get_smt_proxy_type(cls: type) -> type:
    if issubclass(cls, SmtProxyMarker):
        return cls
    global _SMT_PROXY_TYPES
    cls_name = name_of_type(cls)
    if cls not in _SMT_PROXY_TYPES:
        def symbolic_init(self):
            self.__class__ = cls
        class_body = { '__init__': symbolic_init }
        try:
            proxy_cls = type(cls_name + '_proxy', (SmtProxyMarker, cls), class_body)
        except TypeError as e:
            if 'is not an acceptable base type' in str(e):
                raise CrosshairUnsupported(f'Cannot subclass {cls_name}')
            else:
                raise
        _SMT_PROXY_TYPES[cls] = proxy_cls
    return _SMT_PROXY_TYPES[cls]
Exemplo n.º 5
0
def attempt_call(conditions: Conditions, fn: Callable,
                 short_circuit: ShortCircuitingContext,
                 enforced_conditions: EnforcedConditions) -> CallAnalysis:
    space = context_statespace()
    bound_args = gen_args(conditions.sig)

    msg_gen = MessageGenerator(fn)
    with space.framework():
        # TODO: looks wrong(-ish) to guard this with space.framework().
        # Copy on custom objects may require patched builtins. (datetime.timedelta is one such case)
        original_args = copy.deepcopy(bound_args)
    space.checkpoint()

    lcls: Mapping[str, object] = bound_args.arguments
    # In preconditions, __old__ exists but is just bound to the same args.
    # This lets people write class invariants using `__old__` to, for example,
    # demonstrate immutability.
    lcls = {'__old__': AttributeHolder(lcls), **lcls}
    expected_exceptions = conditions.raises
    for precondition in conditions.pre:
        with ExceptionFilter(expected_exceptions) as efilter:
            with enforced_conditions.enabled_enforcement(), short_circuit:
                precondition_ok = precondition.evaluate(lcls)
            if not precondition_ok:
                debug('Failed to meet precondition', precondition.expr_source)
                return CallAnalysis(failing_precondition=precondition)
        if efilter.ignore:
            debug('Ignored exception in precondition.', efilter.analysis)
            return efilter.analysis
        elif efilter.user_exc is not None:
            (user_exc, tb) = efilter.user_exc
            debug('Exception attempting to meet precondition',
                  precondition.expr_source, ':', user_exc, tb.format())
            return CallAnalysis(
                failing_precondition=precondition,
                failing_precondition_reason=
                f'it raised "{repr(user_exc)} at {tb.format()[-1]}"')

    with ExceptionFilter(expected_exceptions) as efilter:
        with enforced_conditions.enabled_enforcement(), short_circuit:
            assert not space.running_framework_code
            __return__ = fn(*bound_args.args, **bound_args.kwargs)
        lcls = {
            **bound_args.arguments, '__return__': __return__,
            '_': __return__,
            '__old__': AttributeHolder(original_args.arguments),
            fn.__name__: fn
        }

    if efilter.ignore:
        debug('Ignored exception in function.', efilter.analysis)
        return efilter.analysis
    elif efilter.user_exc is not None:
        space.check_deferred_assumptions()
        (e, tb) = efilter.user_exc
        detail = name_of_type(type(e)) + ': ' + str(e)
        frame_filename, frame_lineno = frame_summary_for_fn(tb, fn)
        debug('exception while evaluating function body:', detail,
              frame_filename, 'line', frame_lineno)
        detail += ' ' + get_input_description(fn.__name__, original_args,
                                              _MISSING)
        return CallAnalysis(VerificationStatus.REFUTED, [
            msg_gen.make(MessageType.EXEC_ERR, detail, frame_filename,
                         frame_lineno, ''.join(tb.format()))
        ])

    for argname, argval in bound_args.arguments.items():
        if (conditions.mutable_args is not None
                and argname not in conditions.mutable_args):
            old_val, new_val = original_args.arguments[argname], argval
            if not deep_eq(old_val, new_val, set()):
                space.check_deferred_assumptions()
                detail = 'Argument "{}" is not marked as mutable, but changed from {} to {}'.format(
                    argname, old_val, new_val)
                debug('Mutablity problem:', detail)
                return CallAnalysis(
                    VerificationStatus.REFUTED,
                    [msg_gen.make(MessageType.POST_ERR, detail, None, 0, '')])

    (post_condition, ) = conditions.post
    with ExceptionFilter(expected_exceptions) as efilter:
        # TODO: re-enable post-condition short circuiting. This will require refactoring how
        # enforced conditions and short curcuiting interact, so that post-conditions are
        # selectively run when, and only when, performing a short circuit.
        #with enforced_conditions.enabled_enforcement(), short_circuit:
        isok = bool(post_condition.evaluate(lcls))
    if efilter.ignore:
        debug('Ignored exception in postcondition.', efilter.analysis)
        return efilter.analysis
    elif efilter.user_exc is not None:
        space.check_deferred_assumptions()
        (e, tb) = efilter.user_exc
        detail = repr(e) + ' ' + get_input_description(
            fn.__name__, original_args, __return__,
            post_condition.addl_context)
        debug('exception while calling postcondition:', detail)
        failures = [
            msg_gen.make(MessageType.POST_ERR, detail, post_condition.filename,
                         post_condition.line, ''.join(tb.format()))
        ]
        return CallAnalysis(VerificationStatus.REFUTED, failures)
    if isok:
        debug('Postcondition confirmed.')
        return CallAnalysis(VerificationStatus.CONFIRMED)
    else:
        space.check_deferred_assumptions()
        detail = 'false ' + \
                 get_input_description(
                     fn.__name__, original_args, __return__, post_condition.addl_context)
        debug(detail)
        failures = [
            msg_gen.make(MessageType.POST_FAIL, detail,
                         post_condition.filename, post_condition.line, '')
        ]
        return CallAnalysis(VerificationStatus.REFUTED, failures)