示例#1
0
def run_iteration(
    fn1: Callable, fn2: Callable, sig: inspect.Signature, space: StateSpace
) -> Tuple[Optional[VerificationStatus], Optional[BehaviorDiff]]:
    with NoTracing():
        original_args = gen_args(sig)
    args1 = copy.deepcopy(original_args)
    args2 = copy.deepcopy(original_args)

    coverage_manager = measure_fn_coverage(fn1, fn2)
    with ExceptionFilter() as efilter, coverage_manager as coverage:
        result1 = describe_behavior(fn1, args1)
        result2 = describe_behavior(fn2, args2)
        space.detach_path()
        if result1 == result2 and args1 == args2:
            debug("Functions equivalent")
            return (VerificationStatus.CONFIRMED, None)
        debug("Functions differ")
        realized_args = {k: repr(v) for (k, v) in original_args.arguments.items()}
        post_execution_args1 = {k: repr(v) for k, v in args1.arguments.items()}
        post_execution_args2 = {k: repr(v) for k, v in args2.arguments.items()}
        diff = BehaviorDiff(
            realized_args,
            Result(repr(result1[0]), result1[1], post_execution_args1),
            Result(repr(result2[0]), result2[1], post_execution_args2),
            coverage(fn1),
            coverage(fn2),
        )
        return (VerificationStatus.REFUTED, diff)
    if efilter.user_exc:
        debug(
            "User-level exception found", repr(efilter.user_exc[0]), efilter.user_exc[1]
        )
    return (None, None)
示例#2
0
def run_iteration(fn: Callable, sig: Signature,
                  space: StateSpace) -> Optional[PathSummary]:
    with NoTracing():
        args = gen_args(sig)
    pre_args = copy.deepcopy(args)
    ret = None
    with measure_fn_coverage(fn) as coverage, ExceptionFilter() as efilter:
        # coverage = lambda _: CoverageResult(set(), set(), 1.0)
        # with ExceptionFilter() as efilter:
        ret = fn(*args.args, **args.kwargs)
    space.detach_path()
    if efilter.user_exc is not None:
        exc = efilter.user_exc[0]
        debug("user-level exception found", repr(exc), *efilter.user_exc[1])
        return PathSummary(pre_args, ret, type(exc), args, coverage(fn))
    elif efilter.ignore:
        return None
    else:
        return PathSummary(
            deep_realize(pre_args),
            deep_realize(ret),
            None,
            deep_realize(args),
            coverage(fn),
        )
示例#3
0
 def test_isfinite(self):
     with standalone_statespace:
         with NoTracing():
             x = SymbolicFloat("symfloat")
         self.assertTrue(math.isfinite(x))
         self.assertTrue(math.isfinite(2.3))
         self.assertFalse(math.isfinite(float("nan")))
示例#4
0
def test_concrete_proxy_with_bad_hash():
    class Penguin:
        def __hash__(self):
            return 42 / 0

    with standalone_statespace as space:
        with NoTracing():  # (because this function resumes tracing)
            p = proxy_class_as_concrete(Penguin, "p")
            assert type(p) is object
示例#5
0
def tiny_stack(tb: TracebackLike = None, **kw) -> str:
    with NoTracing():
        if tb is None:
            frames: Iterable[
                traceback.FrameSummary] = traceback.extract_stack()[:-1]
        elif isinstance(tb, TracebackType):
            frames = traceback.extract_tb(tb)
        else:
            frames = tb
        return _tiny_stack_frames(frames, **kw)
示例#6
0
def debug(*a):
    if not _DEBUG:
        return
    with NoTracing():
        stack = traceback.extract_stack()
        frame = stack[-2]
        indent = len(stack) - 3
        print(
            "{:06.3f}|{}|{}() {}".format(time.monotonic(), " " * indent,
                                         frame.name, " ".join(map(str, a))),
            file=sys.stderr,
        )
示例#7
0
def test_class_proxies_are_created_through_constructor():
    class Penguin:
        can_swim: bool

        def __init__(self):
            self.can_swim = True

    with standalone_statespace as space:
        with NoTracing():  # (because following function resumes tracing)
            p = proxy_for_class(Penguin, "p")
        # `can_swim` is locked to True
        assert p.can_swim is True
def compare_results(fn: Callable, *a: object,
                    **kw: object) -> ResultComparison:
    original_a = deepcopy(a)
    original_kw = deepcopy(kw)
    symbolic_result = summarize_execution(fn, a, kw)

    concrete_a = deep_realize(original_a)
    concrete_kw = deep_realize(original_kw)
    with NoTracing():
        concrete_result = summarize_execution(fn, concrete_a, concrete_kw)

    ret = ResultComparison(symbolic_result, concrete_result)
    bool(ret)
    return ret
示例#9
0
def _match(self, string, pos=0, endpos=None) -> Union[None, re.Match, _Match]:
    with NoTracing():
        if type(string) is SymbolicStr:
            try:
                return _match_pattern(self, self.pattern, string, pos, endpos)
            except ReUnhandled as e:
                debug(
                    "Unable to symbolically analyze regular expression:",
                    self.pattern,
                    e,
                )
        if endpos is None:
            return _orig_match(self, realize(string), pos)
        else:
            return _orig_match(self, realize(string), pos, endpos)
示例#10
0
def _fullmatch(self, string, pos=0, endpos=None):
    with NoTracing():
        if type(string) is SymbolicStr:
            try:
                return _match_pattern(self, self.pattern + r"\Z", string, pos, endpos)
            except ReUnhandled as e:
                debug(
                    "Unable to symbolically analyze regular expression:",
                    self.pattern,
                    e,
                )
        if endpos is None:
            return re.Pattern.fullmatch(self, realize(string), pos)
        else:
            return re.Pattern.fullmatch(self, realize(string), pos, endpos)
示例#11
0
    def choose_possible(self, expr: z3.ExprRef, favor_true=False) -> bool:
        with NoTracing():
            if time.monotonic() > self.execution_deadline:
                debug(
                    "Path execution timeout after making ",
                    len(self.choices_made),
                    " choices.",
                )
                raise PathTimeout
            notexpr = z3.Not(expr)
            if self.search_position.is_stem():
                self.search_position = self.search_position.grow_into(
                    WorstResultNode(self._random, expr, self.solver))

            self.search_position = self.search_position.simplify()
            node = self.search_position
            # NOTE: format_stack() is more human readable, but it pulls source file contents,
            # so it is (1) slow, and (2) unstable when source code changes while we are checking.
            statedesc = "\n".join(map(str, traceback.extract_stack(limit=8)))
            assert isinstance(node, SearchTreeNode)
            if node.statehash is None:
                node.statehash = statedesc
            else:
                if node.statehash != statedesc:
                    debug(" *** Begin Not Deterministic Debug *** ")
                    debug("     First state: ", len(node.statehash))
                    debug(node.statehash)
                    debug("     Current state: ", len(statedesc))
                    debug(statedesc)
                    debug("     Decision points prior to this:")
                    for choice in self.choices_made:
                        debug("      ", choice)
                    debug("     Stack Diff: ")
                    import difflib

                    debug("\n".join(
                        difflib.context_diff(node.statehash.split("\n"),
                                             statedesc.split("\n"))))
                    debug(" *** End Not Deterministic Debug *** ")
                    raise NotDeterministic()
            choose_true, stem = node.choose(favor_true=favor_true)
            assert isinstance(self.search_position, SearchTreeNode)
            self.choices_made.append(self.search_position)
            self.search_position = stem
            expr = expr if choose_true else notexpr
            debug("SMT chose:", expr)
            self.add(expr)
            return choose_true
示例#12
0
 def find_model_value(self, expr: z3.ExprRef) -> object:
     with NoTracing():
         while True:
             if self.search_position.is_stem():
                 self.search_position = self.search_position.grow_into(
                     ModelValueNode(self._random, expr, self.solver))
             node = self.search_position.simplify()
             assert isinstance(node, ModelValueNode)
             (chosen, next_node) = node.choose(favor_true=True)
             self.choices_made.append(node)
             self.search_position = next_node
             if chosen:
                 self.solver.add(expr == node.condition_value)
                 ret = model_value_to_python(node.condition_value)
                 if in_debug():
                     debug("SMT realized symbolic:", expr, "==", repr(ret))
                     debug("Realized at", test_stack())
                 return ret
             else:
                 self.solver.add(expr != node.condition_value)
示例#13
0
def test_immutable_concrete_proxy():
    class Penguin:
        _can_swim: bool

        def __init__(self):
            self._can_swim = True

    class ImmutablePenguin(Penguin):
        # This hash definition signals immutability to CrossHair
        def __hash__(self):
            return self._can_swim

    with standalone_statespace as space:
        with NoTracing():  # (because this function resumes tracing)
            mut = proxy_class_as_concrete(Penguin, "mut")
            immut = proxy_class_as_concrete(ImmutablePenguin, "immut")
        # `can_swim` is locked to True in the immutable version, but
        # can be either in the mutable case.
        assert space.is_possible((mut._can_swim == False).var)
        assert space.is_possible((mut._can_swim == True).var)
        assert immut._can_swim is True
示例#14
0
    def detach_path(self, exc: Optional[Exception] = None) -> None:
        """
        Mark the current path exhausted.

        Also verifies all deferred assumptions.
        After detaching, the space may continue to be used (for example, to print
        realized symbolics).
        """
        if isinstance(exc, NotDeterministic):
            # NotDeterministic is a user-reportable error, but it isn't valid to try
            # and use the statespace after it's detected
            return
        for description, checker in self._deferred_assumptions:
            if not prefer_true(checker()):
                raise IgnoreAttempt("deferred assumption failed: " +
                                    description)
        with NoTracing():
            assert self._search_position.is_stem()
            node = self._search_position.grow_into(DeatchedPathNode())
            assert node.child.is_stem()
            self.choices_made.append(node)
            self._search_position = node.child
示例#15
0
def debug(*a):
    """
    Print debugging information in CrossHair's nested log output.

    Arguments are serialized with ``str()`` and printed when running in CrossHair's
    verbose mode.

    Avoid passing symbolic values, as taking the string of a
    symbolic will change the path exploration that CrossHair normally takes, leading to
    different outcomes in verbose and non-verbose mode.
    """
    if not _DEBUG:
        return
    with NoTracing():
        stack = traceback.extract_stack()
        frame = stack[-2]
        indent = len(stack) - 3
        print(
            "{:06.3f}|{}|{}() {}".format(time.monotonic(), " " * indent,
                                         frame.name, " ".join(map(str, a))),
            file=sys.stderr,
        )
示例#16
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
示例#17
0
def _compile(*a):
    # Symbolic regexes aren't supported, and it's expensive to perform compilation
    # with tracing enabled.
    with NoTracing():
        return re.compile(*deep_realize(a))