crosshair-tool 0.0.95__cp311-cp311-macosx_11_0_arm64.whl → 0.0.96__cp311-cp311-macosx_11_0_arm64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of crosshair-tool might be problematic. Click here for more details.
- _crosshair_tracers.cpython-311-darwin.so +0 -0
- crosshair/__init__.py +1 -1
- crosshair/condition_parser_test.py +0 -2
- crosshair/core.py +2 -1
- crosshair/core_test.py +2 -3
- crosshair/diff_behavior_test.py +0 -2
- crosshair/libimpl/builtinslib.py +65 -16
- crosshair/libimpl/builtinslib_ch_test.py +12 -2
- crosshair/libimpl/builtinslib_test.py +36 -0
- crosshair/libimpl/collectionslib_test.py +4 -4
- crosshair/libimpl/functoolslib.py +8 -2
- crosshair/libimpl/functoolslib_test.py +22 -6
- crosshair/opcode_intercept.py +9 -17
- crosshair/path_cover.py +5 -1
- crosshair/pathing_oracle.py +41 -4
- crosshair/pathing_oracle_test.py +21 -0
- crosshair/statespace.py +73 -18
- crosshair/statespace_test.py +16 -0
- {crosshair_tool-0.0.95.dist-info → crosshair_tool-0.0.96.dist-info}/METADATA +1 -1
- {crosshair_tool-0.0.95.dist-info → crosshair_tool-0.0.96.dist-info}/RECORD +24 -23
- {crosshair_tool-0.0.95.dist-info → crosshair_tool-0.0.96.dist-info}/WHEEL +0 -0
- {crosshair_tool-0.0.95.dist-info → crosshair_tool-0.0.96.dist-info}/entry_points.txt +0 -0
- {crosshair_tool-0.0.95.dist-info → crosshair_tool-0.0.96.dist-info}/licenses/LICENSE +0 -0
- {crosshair_tool-0.0.95.dist-info → crosshair_tool-0.0.96.dist-info}/top_level.txt +0 -0
|
Binary file
|
crosshair/__init__.py
CHANGED
|
@@ -15,7 +15,7 @@ from crosshair.statespace import StateSpace
|
|
|
15
15
|
from crosshair.tracers import NoTracing, ResumedTracing
|
|
16
16
|
from crosshair.util import IgnoreAttempt, debug
|
|
17
17
|
|
|
18
|
-
__version__ = "0.0.
|
|
18
|
+
__version__ = "0.0.96" # Do not forget to update in setup.py!
|
|
19
19
|
__author__ = "Phillip Schanely"
|
|
20
20
|
__license__ = "MIT"
|
|
21
21
|
__status__ = "Alpha"
|
crosshair/core.py
CHANGED
|
@@ -377,7 +377,8 @@ def with_symbolic_self(symbolic_cls: Type, fn: Callable):
|
|
|
377
377
|
elif any(isinstance(a, CrossHairValue) for a in args) or (
|
|
378
378
|
kwargs and any(isinstance(a, CrossHairValue) for a in kwargs.values())
|
|
379
379
|
):
|
|
380
|
-
|
|
380
|
+
# NOTE: _ch_create_from_literal is suppoerted for very few types right now
|
|
381
|
+
self = symbolic_cls._ch_create_from_literal(self)
|
|
381
382
|
target_fn = getattr(symbolic_cls, fn.__name__)
|
|
382
383
|
else:
|
|
383
384
|
args = map(realize, args)
|
crosshair/core_test.py
CHANGED
|
@@ -5,7 +5,6 @@ import re
|
|
|
5
5
|
import sys
|
|
6
6
|
import time
|
|
7
7
|
from typing import *
|
|
8
|
-
from unittest import skipIf
|
|
9
8
|
|
|
10
9
|
import pytest # type: ignore
|
|
11
10
|
|
|
@@ -736,7 +735,7 @@ def test_newtype() -> None:
|
|
|
736
735
|
assert isinstance(x, SymbolicInt)
|
|
737
736
|
|
|
738
737
|
|
|
739
|
-
@
|
|
738
|
+
@pytest.mark.skipif(sys.version_info < (3, 12), reason="type statements added in 3.12")
|
|
740
739
|
def test_type_statement() -> None:
|
|
741
740
|
env: dict[str, Any] = {}
|
|
742
741
|
exec("type MyIntNew = int\n", env)
|
|
@@ -747,7 +746,7 @@ def test_type_statement() -> None:
|
|
|
747
746
|
assert isinstance(x, SymbolicInt)
|
|
748
747
|
|
|
749
748
|
|
|
750
|
-
@
|
|
749
|
+
@pytest.mark.skipif(sys.version_info < (3, 12), reason="type statements added in 3.12")
|
|
751
750
|
def test_parameterized_type_statement() -> None:
|
|
752
751
|
env: dict[str, Any] = {}
|
|
753
752
|
exec("type Pair[A, B] = tuple[B, A]\n", env)
|
crosshair/diff_behavior_test.py
CHANGED
crosshair/libimpl/builtinslib.py
CHANGED
|
@@ -346,7 +346,7 @@ class AtomicSymbolicValue(SymbolicValue):
|
|
|
346
346
|
raise CrossHairInternal(f"_pytype not implemented in {cls}")
|
|
347
347
|
|
|
348
348
|
@classmethod
|
|
349
|
-
def _smt_promote_literal(cls,
|
|
349
|
+
def _smt_promote_literal(cls, literal: object) -> Optional[z3.ExprRef]:
|
|
350
350
|
raise CrossHairInternal(f"_smt_promote_literal not implemented in {cls}")
|
|
351
351
|
|
|
352
352
|
@classmethod
|
|
@@ -1120,7 +1120,7 @@ class SymbolicBool(SymbolicIntable, AtomicSymbolicValue):
|
|
|
1120
1120
|
return bool
|
|
1121
1121
|
|
|
1122
1122
|
@classmethod
|
|
1123
|
-
def _smt_promote_literal(cls, literal) -> Optional[z3.
|
|
1123
|
+
def _smt_promote_literal(cls, literal) -> Optional[z3.ExprRef]:
|
|
1124
1124
|
if isinstance(literal, bool):
|
|
1125
1125
|
return z3.BoolVal(literal)
|
|
1126
1126
|
return None
|
|
@@ -1189,7 +1189,7 @@ class SymbolicInt(SymbolicIntable, AtomicSymbolicValue):
|
|
|
1189
1189
|
return int
|
|
1190
1190
|
|
|
1191
1191
|
@classmethod
|
|
1192
|
-
def _smt_promote_literal(cls, literal) -> Optional[z3.
|
|
1192
|
+
def _smt_promote_literal(cls, literal) -> Optional[z3.ExprRef]:
|
|
1193
1193
|
if isinstance(literal, int):
|
|
1194
1194
|
return z3IntVal(literal)
|
|
1195
1195
|
return None
|
|
@@ -1410,7 +1410,7 @@ class PreciseIeeeSymbolicFloat(SymbolicFloat):
|
|
|
1410
1410
|
return _PRECISE_IEEE_FLOAT_SORT
|
|
1411
1411
|
|
|
1412
1412
|
@classmethod
|
|
1413
|
-
def _smt_promote_literal(cls, literal) -> Optional[z3.
|
|
1413
|
+
def _smt_promote_literal(cls, literal) -> Optional[z3.ExprRef]:
|
|
1414
1414
|
if isinstance(literal, float):
|
|
1415
1415
|
return z3.FPVal(literal, cls._ch_smt_sort())
|
|
1416
1416
|
return None
|
|
@@ -1533,7 +1533,7 @@ class RealBasedSymbolicFloat(SymbolicFloat):
|
|
|
1533
1533
|
return z3.RealSort()
|
|
1534
1534
|
|
|
1535
1535
|
@classmethod
|
|
1536
|
-
def _smt_promote_literal(cls, literal) -> Optional[z3.
|
|
1536
|
+
def _smt_promote_literal(cls, literal) -> Optional[z3.ExprRef]:
|
|
1537
1537
|
if isinstance(literal, float) and isfinite(literal):
|
|
1538
1538
|
return z3.RealVal(literal)
|
|
1539
1539
|
return None
|
|
@@ -2447,7 +2447,7 @@ class SymbolicType(AtomicSymbolicValue, SymbolicValue, Untracable):
|
|
|
2447
2447
|
return type
|
|
2448
2448
|
|
|
2449
2449
|
@classmethod
|
|
2450
|
-
def _smt_promote_literal(cls, literal) -> Optional[z3.
|
|
2450
|
+
def _smt_promote_literal(cls, literal) -> Optional[z3.ExprRef]:
|
|
2451
2451
|
if isinstance(literal, type):
|
|
2452
2452
|
return context_statespace().extra(SymbolicTypeRepository).get_type(literal)
|
|
2453
2453
|
return None
|
|
@@ -2668,10 +2668,25 @@ class SymbolicCallable:
|
|
|
2668
2668
|
__annotations__: dict = {}
|
|
2669
2669
|
|
|
2670
2670
|
def __init__(self, values: list):
|
|
2671
|
+
"""
|
|
2672
|
+
A function that will ignore its arguments and produce return values
|
|
2673
|
+
from the list given.
|
|
2674
|
+
If the given list is exhausted, the function will just repeatedly
|
|
2675
|
+
return the final value in the list.
|
|
2676
|
+
|
|
2677
|
+
If `values` is concrete, it must be non-mepty.
|
|
2678
|
+
If `values` is a symbolic list, it will be forced to be non-empty
|
|
2679
|
+
(the caller must enure that's possible).
|
|
2680
|
+
"""
|
|
2671
2681
|
assert not is_tracing()
|
|
2672
2682
|
with ResumedTracing():
|
|
2673
|
-
|
|
2674
|
-
|
|
2683
|
+
has_values = len(values) > 0
|
|
2684
|
+
if isinstance(values, CrossHairValue):
|
|
2685
|
+
space = context_statespace()
|
|
2686
|
+
assert space.is_possible(has_values)
|
|
2687
|
+
space.add(has_values)
|
|
2688
|
+
else:
|
|
2689
|
+
assert has_values
|
|
2675
2690
|
self.values = values
|
|
2676
2691
|
self.idx = 0
|
|
2677
2692
|
|
|
@@ -2695,6 +2710,7 @@ class SymbolicCallable:
|
|
|
2695
2710
|
if idx >= len(values):
|
|
2696
2711
|
return values[-1]
|
|
2697
2712
|
else:
|
|
2713
|
+
self.idx += 1
|
|
2698
2714
|
return values[idx]
|
|
2699
2715
|
|
|
2700
2716
|
def __bool__(self):
|
|
@@ -3406,6 +3422,26 @@ class AnySymbolicStr(AbcString):
|
|
|
3406
3422
|
return "0" * fill_length + self
|
|
3407
3423
|
|
|
3408
3424
|
|
|
3425
|
+
def _unfindable_range(start: Optional[int], end: Optional[int], mylen: int) -> bool:
|
|
3426
|
+
"""
|
|
3427
|
+
Emulates some preliminary checks that CPython makes before searching
|
|
3428
|
+
for substrings within some bounds. (in e.g. str.find, str.startswith, etc)
|
|
3429
|
+
"""
|
|
3430
|
+
if start is None or start == 0 or start <= -mylen:
|
|
3431
|
+
return False
|
|
3432
|
+
|
|
3433
|
+
# At this point, we know that `start` is defined and points to an index after 0
|
|
3434
|
+
if end is None or end >= mylen:
|
|
3435
|
+
return start > mylen
|
|
3436
|
+
|
|
3437
|
+
# At this point, we know that `end` is defined and points to an index before the end of the string
|
|
3438
|
+
if start < 0:
|
|
3439
|
+
start += mylen
|
|
3440
|
+
if end < 0:
|
|
3441
|
+
end += mylen
|
|
3442
|
+
return end < start
|
|
3443
|
+
|
|
3444
|
+
|
|
3409
3445
|
class LazyIntSymbolicStr(AnySymbolicStr, CrossHairValue):
|
|
3410
3446
|
"""
|
|
3411
3447
|
A symbolic string that lazily generates SymbolicInt-based characters as needed.
|
|
@@ -3444,10 +3480,8 @@ class LazyIntSymbolicStr(AnySymbolicStr, CrossHairValue):
|
|
|
3444
3480
|
codepoints = tuple(self._codepoints)
|
|
3445
3481
|
return "".join(chr(realize(x)) for x in codepoints)
|
|
3446
3482
|
|
|
3447
|
-
# This is normally an AtomicSymbolicValue method, but sometimes it's used in a
|
|
3448
|
-
# duck-typing way.
|
|
3449
3483
|
@classmethod
|
|
3450
|
-
def
|
|
3484
|
+
def _ch_create_from_literal(cls, val: object) -> Optional[CrossHairValue]:
|
|
3451
3485
|
if isinstance(val, str):
|
|
3452
3486
|
return LazyIntSymbolicStr(list(map(ord, val)))
|
|
3453
3487
|
return None
|
|
@@ -3481,6 +3515,10 @@ class LazyIntSymbolicStr(AnySymbolicStr, CrossHairValue):
|
|
|
3481
3515
|
with NoTracing():
|
|
3482
3516
|
if not isinstance(i, (Integral, slice)):
|
|
3483
3517
|
raise TypeError(type(i))
|
|
3518
|
+
# This could/should? be symbolic by naming all the possibilities.
|
|
3519
|
+
# Note the slice case still must realize the return length.
|
|
3520
|
+
# Especially because we no longer explore realization trees except
|
|
3521
|
+
# as a last resort.
|
|
3484
3522
|
i = deep_realize(i)
|
|
3485
3523
|
with ResumedTracing():
|
|
3486
3524
|
newcontents = self._codepoints[i]
|
|
@@ -3561,11 +3599,15 @@ class LazyIntSymbolicStr(AnySymbolicStr, CrossHairValue):
|
|
|
3561
3599
|
return any(self.endswith(s, start, end) for s in substr)
|
|
3562
3600
|
if not isinstance(substr, str):
|
|
3563
3601
|
raise TypeError
|
|
3602
|
+
substrlen = len(substr)
|
|
3564
3603
|
if start is None and end is None:
|
|
3565
3604
|
matchable = self
|
|
3566
3605
|
else:
|
|
3567
3606
|
matchable = self[start:end]
|
|
3568
|
-
|
|
3607
|
+
if substrlen == 0:
|
|
3608
|
+
return not _unfindable_range(start, end, len(self))
|
|
3609
|
+
else:
|
|
3610
|
+
return matchable[-substrlen:] == substr
|
|
3569
3611
|
|
|
3570
3612
|
def startswith(self, substr, start=None, end=None):
|
|
3571
3613
|
if isinstance(substr, tuple):
|
|
@@ -3575,6 +3617,10 @@ class LazyIntSymbolicStr(AnySymbolicStr, CrossHairValue):
|
|
|
3575
3617
|
if start is None and end is None:
|
|
3576
3618
|
matchable = self
|
|
3577
3619
|
else:
|
|
3620
|
+
# Wacky special case: the empty string is findable off the left
|
|
3621
|
+
# side but not the right!
|
|
3622
|
+
if _unfindable_range(start, end, len(self)):
|
|
3623
|
+
return False
|
|
3578
3624
|
matchable = self[start:end]
|
|
3579
3625
|
return matchable[: len(substr)] == substr
|
|
3580
3626
|
|
|
@@ -3615,7 +3661,7 @@ class LazyIntSymbolicStr(AnySymbolicStr, CrossHairValue):
|
|
|
3615
3661
|
end += mylen
|
|
3616
3662
|
matchstr = self[start:end] if start != 0 or end is not mylen else self
|
|
3617
3663
|
if len(substr) == 0:
|
|
3618
|
-
#
|
|
3664
|
+
# An oddity of CPython. We can find the empty string when over-slicing
|
|
3619
3665
|
# off the left side of the string, but not off the right:
|
|
3620
3666
|
# ''.find('', 3, 4) == -1
|
|
3621
3667
|
# ''.find('', -4, -3) == 0
|
|
@@ -4790,14 +4836,17 @@ def _str_format_map(self, map) -> Union[AnySymbolicStr, str]:
|
|
|
4790
4836
|
|
|
4791
4837
|
|
|
4792
4838
|
def _str_startswith(self, substr, start=None, end=None) -> bool:
|
|
4793
|
-
if not isinstance(self, str):
|
|
4794
|
-
raise TypeError
|
|
4795
4839
|
with NoTracing():
|
|
4840
|
+
if isinstance(self, LazyIntSymbolicStr):
|
|
4841
|
+
with ResumedTracing():
|
|
4842
|
+
return self.startswith(substr, start, end)
|
|
4843
|
+
elif not isinstance(self, str):
|
|
4844
|
+
raise TypeError
|
|
4796
4845
|
# Handle native values with native implementation:
|
|
4797
4846
|
if type(substr) is str:
|
|
4798
4847
|
return self.startswith(substr, start, end)
|
|
4799
4848
|
if type(substr) is tuple:
|
|
4800
|
-
if all(type(
|
|
4849
|
+
if all(type(s) is str for s in substr):
|
|
4801
4850
|
return self.startswith(substr, start, end)
|
|
4802
4851
|
symbolic_self = LazyIntSymbolicStr([ord(c) for c in self])
|
|
4803
4852
|
return symbolic_self.startswith(substr, start, end)
|
|
@@ -606,9 +606,14 @@ def check_str_endswith(
|
|
|
606
606
|
string: str, suffix: str, start: Optional[int], end: Optional[int]
|
|
607
607
|
) -> ResultComparison:
|
|
608
608
|
"""post: _"""
|
|
609
|
+
# crosshair: max_uninteresting_iterations=100
|
|
610
|
+
|
|
611
|
+
for i in (len(string), len(suffix), start, end):
|
|
612
|
+
if i is not None and abs(i) >= 1:
|
|
613
|
+
pass
|
|
614
|
+
|
|
609
615
|
return compare_results(
|
|
610
|
-
lambda s, *a: s.endswith(*a),
|
|
611
|
-
string,
|
|
616
|
+
lambda s, *a, **kw: s.endswith(*a, **kw), string, suffix, start, end
|
|
612
617
|
)
|
|
613
618
|
|
|
614
619
|
|
|
@@ -825,6 +830,11 @@ def check_str_startswith(
|
|
|
825
830
|
end: Optional[int],
|
|
826
831
|
) -> ResultComparison:
|
|
827
832
|
"""post: _"""
|
|
833
|
+
# crosshair: max_uninteresting_iterations=100
|
|
834
|
+
|
|
835
|
+
for i in (len(string), len(prefix), start, end):
|
|
836
|
+
if i is not None and abs(i) >= 1:
|
|
837
|
+
pass
|
|
828
838
|
return compare_results(
|
|
829
839
|
lambda s, *a, **kw: s.startswith(*a, **kw), string, prefix, start, end
|
|
830
840
|
)
|
|
@@ -939,6 +939,31 @@ def test_str_replace_method() -> None:
|
|
|
939
939
|
check_states(f, POST_FAIL)
|
|
940
940
|
|
|
941
941
|
|
|
942
|
+
def test_str_startswith(space) -> None:
|
|
943
|
+
symbolic_char = proxy_for_type(str, "x")
|
|
944
|
+
symbolic_empty = proxy_for_type(str, "y")
|
|
945
|
+
with ResumedTracing():
|
|
946
|
+
space.add(len(symbolic_char) == 1)
|
|
947
|
+
space.add(len(symbolic_empty) == 0)
|
|
948
|
+
assert symbolic_char.startswith(symbolic_empty)
|
|
949
|
+
assert symbolic_char.startswith(symbolic_char)
|
|
950
|
+
assert symbolic_char.startswith(("foo", symbolic_empty))
|
|
951
|
+
assert not symbolic_char.startswith(("foo", "bar"))
|
|
952
|
+
assert symbolic_char.startswith(("", "bar"))
|
|
953
|
+
assert symbolic_char.startswith("")
|
|
954
|
+
assert symbolic_char.startswith(symbolic_empty, 1)
|
|
955
|
+
assert symbolic_char.startswith(symbolic_empty, 1, 1)
|
|
956
|
+
assert str.startswith(symbolic_char, symbolic_empty)
|
|
957
|
+
assert "foo".startswith(symbolic_empty)
|
|
958
|
+
assert not "".startswith(symbolic_char)
|
|
959
|
+
|
|
960
|
+
# Yes, the empty string is findable off the left side but not the right
|
|
961
|
+
assert "x".startswith("", -10, -9)
|
|
962
|
+
assert symbolic_char.startswith(symbolic_empty, -10, -9)
|
|
963
|
+
assert not "x".startswith("", 9, 10)
|
|
964
|
+
assert not symbolic_char.startswith(symbolic_empty, 9, 10)
|
|
965
|
+
|
|
966
|
+
|
|
942
967
|
@pytest.mark.demo
|
|
943
968
|
def test_str_index_method() -> None:
|
|
944
969
|
def f(a: str) -> int:
|
|
@@ -3134,6 +3159,17 @@ def test_callable_as_bool() -> None:
|
|
|
3134
3159
|
check_states(f, CONFIRMED)
|
|
3135
3160
|
|
|
3136
3161
|
|
|
3162
|
+
def test_callable_can_return_different_values(space) -> None:
|
|
3163
|
+
fn = proxy_for_type(Callable[[], int], "fn")
|
|
3164
|
+
with ResumedTracing():
|
|
3165
|
+
first_return = fn()
|
|
3166
|
+
second_return = fn()
|
|
3167
|
+
returns_are_equal = first_return == second_return
|
|
3168
|
+
returns_are_not_equal = first_return != second_return
|
|
3169
|
+
assert space.is_possible(returns_are_equal)
|
|
3170
|
+
assert space.is_possible(returns_are_not_equal)
|
|
3171
|
+
|
|
3172
|
+
|
|
3137
3173
|
@pytest.mark.smoke
|
|
3138
3174
|
def test_callable_repr() -> None:
|
|
3139
3175
|
def f(f1: Callable[[int], int]) -> int:
|
|
@@ -3,7 +3,7 @@ import sys
|
|
|
3
3
|
from collections import Counter, defaultdict, deque, namedtuple
|
|
4
4
|
from copy import deepcopy
|
|
5
5
|
from inspect import Parameter, Signature
|
|
6
|
-
from typing import Counter, DefaultDict, Deque, NamedTuple, Tuple
|
|
6
|
+
from typing import Callable, Counter, DefaultDict, Deque, Dict, NamedTuple, Tuple
|
|
7
7
|
|
|
8
8
|
import pytest
|
|
9
9
|
|
|
@@ -14,7 +14,7 @@ from crosshair.core import (
|
|
|
14
14
|
realize,
|
|
15
15
|
standalone_statespace,
|
|
16
16
|
)
|
|
17
|
-
from crosshair.libimpl.collectionslib import ListBasedDeque
|
|
17
|
+
from crosshair.libimpl.collectionslib import ListBasedDeque, PureDefaultDict
|
|
18
18
|
from crosshair.statespace import CANNOT_CONFIRM, CONFIRMED, POST_FAIL, MessageType
|
|
19
19
|
from crosshair.test_util import check_states
|
|
20
20
|
from crosshair.tracers import NoTracing, ResumedTracing
|
|
@@ -246,10 +246,10 @@ def test_defaultdict_default_fail(test_list) -> None:
|
|
|
246
246
|
|
|
247
247
|
|
|
248
248
|
def test_defaultdict_default_ok(test_list) -> None:
|
|
249
|
-
def f(a: DefaultDict[int, int],
|
|
249
|
+
def f(a: DefaultDict[int, int], k: int) -> DefaultDict[int, int]:
|
|
250
250
|
"""
|
|
251
251
|
pre: len(a) == 0 and a.default_factory is not None
|
|
252
|
-
post: _[
|
|
252
|
+
post: _[k] == _[k]
|
|
253
253
|
"""
|
|
254
254
|
return a
|
|
255
255
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from functools import _lru_cache_wrapper, partial, reduce
|
|
1
|
+
from functools import _lru_cache_wrapper, partial, reduce, update_wrapper, wraps
|
|
2
2
|
|
|
3
3
|
from crosshair.core import register_patch
|
|
4
4
|
|
|
@@ -7,7 +7,13 @@ from crosshair.core import register_patch
|
|
|
7
7
|
|
|
8
8
|
def _partial(func, *a1, **kw1):
|
|
9
9
|
if callable(func):
|
|
10
|
-
|
|
10
|
+
# We make a do-nothing wrapper to ensure that the tracer has a crack
|
|
11
|
+
# at this function when it is called.
|
|
12
|
+
def wrapper(*a2, **kw2):
|
|
13
|
+
return func(*a2, **kw2)
|
|
14
|
+
|
|
15
|
+
update_wrapper(wrapper, func)
|
|
16
|
+
return partial(wrapper, *a1, **kw1)
|
|
11
17
|
else:
|
|
12
18
|
raise TypeError
|
|
13
19
|
|
|
@@ -1,20 +1,36 @@
|
|
|
1
1
|
import functools
|
|
2
|
+
import inspect
|
|
2
3
|
|
|
3
4
|
from crosshair.core import proxy_for_type, standalone_statespace
|
|
4
5
|
from crosshair.libimpl.builtinslib import LazyIntSymbolicStr
|
|
5
|
-
from crosshair.tracers import NoTracing
|
|
6
|
+
from crosshair.tracers import NoTracing, ResumedTracing
|
|
6
7
|
|
|
7
8
|
|
|
8
|
-
def test_partial():
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
xyz = LazyIntSymbolicStr(list(map(ord, "xyz")))
|
|
9
|
+
def test_partial(space):
|
|
10
|
+
abc = LazyIntSymbolicStr(list(map(ord, "abc")))
|
|
11
|
+
xyz = LazyIntSymbolicStr(list(map(ord, "xyz")))
|
|
12
|
+
with ResumedTracing():
|
|
13
13
|
joiner = functools.partial(str.join, ",")
|
|
14
14
|
ret = joiner([abc, xyz])
|
|
15
15
|
assert ret == "abc,xyz"
|
|
16
16
|
|
|
17
17
|
|
|
18
|
+
def test_partial_is_interceptable(space):
|
|
19
|
+
x = proxy_for_type(str, "x")
|
|
20
|
+
y = proxy_for_type(str, "y")
|
|
21
|
+
with ResumedTracing():
|
|
22
|
+
joiner = functools.partial(str.startswith, x)
|
|
23
|
+
# Ensure we don't explode
|
|
24
|
+
list(map(joiner, ["foo", y]))
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def test_partial_arg_is_inspectable(space):
|
|
28
|
+
with ResumedTracing():
|
|
29
|
+
joiner = functools.partial(str.join, ",")
|
|
30
|
+
assert isinstance(joiner, functools.partial)
|
|
31
|
+
assert inspect.getdoc(joiner.func) == inspect.getdoc(str.join)
|
|
32
|
+
|
|
33
|
+
|
|
18
34
|
def test_reduce():
|
|
19
35
|
with standalone_statespace as space:
|
|
20
36
|
with NoTracing():
|
crosshair/opcode_intercept.py
CHANGED
|
@@ -5,7 +5,9 @@ from collections import defaultdict
|
|
|
5
5
|
from collections.abc import MutableMapping, Set
|
|
6
6
|
from sys import version_info
|
|
7
7
|
from types import CodeType, FrameType
|
|
8
|
-
from typing import Any, Callable, Iterable, Mapping, Tuple, Union
|
|
8
|
+
from typing import Any, Callable, Iterable, List, Mapping, Tuple, Union
|
|
9
|
+
|
|
10
|
+
from z3 import ExprRef
|
|
9
11
|
|
|
10
12
|
from crosshair.core import (
|
|
11
13
|
ATOMIC_IMMUTABLE_TYPES,
|
|
@@ -83,13 +85,6 @@ class MultiSubscriptableContainer:
|
|
|
83
85
|
if isinstance(container, Mapping):
|
|
84
86
|
kv_pairs: Iterable[Tuple[Any, Any]] = container.items()
|
|
85
87
|
else:
|
|
86
|
-
in_bounds = space.smt_fork(
|
|
87
|
-
z3Or(-len(container) <= key.var, key.var < len(container)),
|
|
88
|
-
desc=f"index_in_bounds",
|
|
89
|
-
probability_true=0.9,
|
|
90
|
-
)
|
|
91
|
-
if not in_bounds:
|
|
92
|
-
raise IndexError
|
|
93
88
|
kv_pairs = enumerate(container)
|
|
94
89
|
|
|
95
90
|
values_by_type = defaultdict(list)
|
|
@@ -118,7 +113,7 @@ class MultiSubscriptableContainer:
|
|
|
118
113
|
keys_by_value_id[id(cur_value)].append(cur_key)
|
|
119
114
|
for value_type, cur_pairs in values_by_type.items():
|
|
120
115
|
hypothetical_result = symbolic_for_pytype(value_type)(
|
|
121
|
-
"
|
|
116
|
+
"item_" + space.uniq(), value_type
|
|
122
117
|
)
|
|
123
118
|
with ResumedTracing():
|
|
124
119
|
condition_pairs = []
|
|
@@ -139,20 +134,17 @@ class MultiSubscriptableContainer:
|
|
|
139
134
|
space.add(any([all(pair) for pair in condition_pairs]))
|
|
140
135
|
return hypothetical_result
|
|
141
136
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
):
|
|
137
|
+
exprs_and_values: List[Tuple[ExprRef, object]] = []
|
|
138
|
+
for value_id, value in values_by_id.items():
|
|
145
139
|
keys_for_value = keys_by_value_id[value_id]
|
|
146
140
|
with ResumedTracing():
|
|
147
141
|
is_match = any([key == k for k in keys_for_value])
|
|
148
142
|
if isinstance(is_match, SymbolicBool):
|
|
149
|
-
|
|
150
|
-
is_match.var,
|
|
151
|
-
probability_true=probability_true,
|
|
152
|
-
):
|
|
153
|
-
return value
|
|
143
|
+
exprs_and_values.append((is_match.var, value))
|
|
154
144
|
elif is_match:
|
|
155
145
|
return value
|
|
146
|
+
if exprs_and_values:
|
|
147
|
+
return space.smt_fanout(exprs_and_values, desc="multi_subscript")
|
|
156
148
|
|
|
157
149
|
if type(container) is dict:
|
|
158
150
|
raise KeyError # ( f"Key {key} not found in dict")
|
crosshair/path_cover.py
CHANGED
|
@@ -133,7 +133,11 @@ def path_cover(
|
|
|
133
133
|
selected: List[PathSummary] = []
|
|
134
134
|
while paths:
|
|
135
135
|
next_best = max(
|
|
136
|
-
paths,
|
|
136
|
+
paths,
|
|
137
|
+
key=lambda p: (
|
|
138
|
+
len(p.coverage.offsets_covered - opcodes_found), # high coverage
|
|
139
|
+
-len(p.formatted_args), # with small input size
|
|
140
|
+
),
|
|
137
141
|
)
|
|
138
142
|
cur_offsets = next_best.coverage.offsets_covered
|
|
139
143
|
if coverage_type == CoverageType.OPCODE:
|
crosshair/pathing_oracle.py
CHANGED
|
@@ -2,7 +2,7 @@ import math
|
|
|
2
2
|
from collections import defaultdict
|
|
3
3
|
from typing import Counter, Dict, List, Optional, Sequence, Tuple
|
|
4
4
|
|
|
5
|
-
from z3 import ExprRef
|
|
5
|
+
from z3 import ExprRef
|
|
6
6
|
|
|
7
7
|
from crosshair.statespace import (
|
|
8
8
|
AbstractPathingOracle,
|
|
@@ -11,9 +11,11 @@ from crosshair.statespace import (
|
|
|
11
11
|
NodeLike,
|
|
12
12
|
RootNode,
|
|
13
13
|
SearchTreeNode,
|
|
14
|
+
StateSpace,
|
|
14
15
|
WorstResultNode,
|
|
15
16
|
)
|
|
16
17
|
from crosshair.util import CrossHairInternal, debug, in_debug
|
|
18
|
+
from crosshair.z3util import z3And, z3Not, z3Or
|
|
17
19
|
|
|
18
20
|
CodeLoc = Tuple[str, ...]
|
|
19
21
|
|
|
@@ -60,7 +62,8 @@ class CoveragePathingOracle(AbstractPathingOracle):
|
|
|
60
62
|
# (even just a 10% change could be much larger than it would be otherwise)
|
|
61
63
|
_delta_probabilities = {-1: 0.1, 0: 0.25, 1: 0.9}
|
|
62
64
|
|
|
63
|
-
def pre_path_hook(self,
|
|
65
|
+
def pre_path_hook(self, space: StateSpace) -> None:
|
|
66
|
+
root = space._root
|
|
64
67
|
visits = self.visits
|
|
65
68
|
_delta_probabilities = self._delta_probabilities
|
|
66
69
|
|
|
@@ -213,16 +216,50 @@ class PreferNegativeOracle(AbstractPathingOracle):
|
|
|
213
216
|
return 0.25
|
|
214
217
|
|
|
215
218
|
|
|
219
|
+
class ConstrainedOracle(AbstractPathingOracle):
|
|
220
|
+
"""
|
|
221
|
+
A pathing oracle that prefers to take a path that satisfies
|
|
222
|
+
explicitly provided constraints.
|
|
223
|
+
"""
|
|
224
|
+
|
|
225
|
+
def __init__(self, inner_oracle: AbstractPathingOracle):
|
|
226
|
+
self.inner_oracle = inner_oracle
|
|
227
|
+
self.exprs: List[ExprRef] = []
|
|
228
|
+
|
|
229
|
+
def prefer(self, expr: ExprRef):
|
|
230
|
+
self.exprs.append(expr)
|
|
231
|
+
|
|
232
|
+
def pre_path_hook(self, space: StateSpace) -> None:
|
|
233
|
+
self.space = space
|
|
234
|
+
self.exprs = []
|
|
235
|
+
self.inner_oracle.pre_path_hook(space)
|
|
236
|
+
|
|
237
|
+
def post_path_hook(self, path: Sequence["SearchTreeNode"]) -> None:
|
|
238
|
+
self.inner_oracle.post_path_hook(path)
|
|
239
|
+
|
|
240
|
+
def decide(
|
|
241
|
+
self, root, node: "WorstResultNode", engine_probability: Optional[float]
|
|
242
|
+
) -> float:
|
|
243
|
+
# We always run the inner oracle in case it's tracking something about the path.
|
|
244
|
+
default_probability = self.inner_oracle.decide(root, node, engine_probability)
|
|
245
|
+
if not self.space.is_possible(z3And(*[node.expr, *self.exprs])):
|
|
246
|
+
return 0.0
|
|
247
|
+
elif not self.space.is_possible(z3And(*[z3Not(node.expr), *self.exprs])):
|
|
248
|
+
return 1.0
|
|
249
|
+
else:
|
|
250
|
+
return default_probability
|
|
251
|
+
|
|
252
|
+
|
|
216
253
|
class RotatingOracle(AbstractPathingOracle):
|
|
217
254
|
def __init__(self, oracles: List[AbstractPathingOracle]):
|
|
218
255
|
self.oracles = oracles
|
|
219
256
|
self.index = -1
|
|
220
257
|
|
|
221
|
-
def pre_path_hook(self,
|
|
258
|
+
def pre_path_hook(self, space: StateSpace) -> None:
|
|
222
259
|
oracles = self.oracles
|
|
223
260
|
self.index = (self.index + 1) % len(oracles)
|
|
224
261
|
for oracle in oracles:
|
|
225
|
-
oracle.pre_path_hook(
|
|
262
|
+
oracle.pre_path_hook(space)
|
|
226
263
|
|
|
227
264
|
def post_path_hook(self, path: Sequence["SearchTreeNode"]) -> None:
|
|
228
265
|
for oracle in self.oracles:
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import random
|
|
2
|
+
|
|
3
|
+
import z3
|
|
4
|
+
|
|
5
|
+
from crosshair.pathing_oracle import ConstrainedOracle, PreferNegativeOracle
|
|
6
|
+
from crosshair.statespace import RootNode, SimpleStateSpace, WorstResultNode
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def test_constrained_oracle():
|
|
10
|
+
oracle = ConstrainedOracle(PreferNegativeOracle())
|
|
11
|
+
x = z3.Int("x")
|
|
12
|
+
root = RootNode()
|
|
13
|
+
space = SimpleStateSpace()
|
|
14
|
+
oracle.pre_path_hook(space)
|
|
15
|
+
oracle.prefer(x >= 7)
|
|
16
|
+
rand = random.Random()
|
|
17
|
+
assert oracle.decide(root, WorstResultNode(rand, x < 7, space.solver), None) == 0.0
|
|
18
|
+
assert oracle.decide(root, WorstResultNode(rand, x >= 3, space.solver), None) == 1.0
|
|
19
|
+
assert (
|
|
20
|
+
oracle.decide(root, WorstResultNode(rand, x == 7, space.solver), None) == 0.25
|
|
21
|
+
)
|
crosshair/statespace.py
CHANGED
|
@@ -46,7 +46,7 @@ from crosshair.util import (
|
|
|
46
46
|
in_debug,
|
|
47
47
|
name_of_type,
|
|
48
48
|
)
|
|
49
|
-
from crosshair.z3util import z3Aassert, z3Not, z3PopNot
|
|
49
|
+
from crosshair.z3util import z3Aassert, z3Not, z3Or, z3PopNot
|
|
50
50
|
|
|
51
51
|
|
|
52
52
|
@functools.total_ordering
|
|
@@ -219,7 +219,7 @@ class StateSpaceCounter(Counter):
|
|
|
219
219
|
|
|
220
220
|
|
|
221
221
|
class AbstractPathingOracle:
|
|
222
|
-
def pre_path_hook(self,
|
|
222
|
+
def pre_path_hook(self, space: "StateSpace") -> None:
|
|
223
223
|
pass
|
|
224
224
|
|
|
225
225
|
def post_path_hook(self, path: Sequence["SearchTreeNode"]) -> None:
|
|
@@ -350,6 +350,7 @@ def solver_is_sat(solver, *exprs) -> bool:
|
|
|
350
350
|
ret = solver.check(*exprs)
|
|
351
351
|
if ret == z3.unknown:
|
|
352
352
|
debug("Z3 Unknown satisfiability. Reason:", solver.reason_unknown())
|
|
353
|
+
debug("Call stack at time of unknown sat:", ch_stack())
|
|
353
354
|
if solver.reason_unknown() == "interrupted from keyboard":
|
|
354
355
|
raise KeyboardInterrupt
|
|
355
356
|
if exprs:
|
|
@@ -427,7 +428,7 @@ class RootNode(SinglePathNode):
|
|
|
427
428
|
)
|
|
428
429
|
from crosshair.pathing_oracle import CoveragePathingOracle # circular import
|
|
429
430
|
|
|
430
|
-
self.pathing_oracle = CoveragePathingOracle()
|
|
431
|
+
self.pathing_oracle: AbstractPathingOracle = CoveragePathingOracle()
|
|
431
432
|
self.iteration = 0
|
|
432
433
|
|
|
433
434
|
|
|
@@ -704,6 +705,17 @@ def debug_path_tree(node, highlights, prefix="") -> List[str]:
|
|
|
704
705
|
return [f"{prefix} -> {str(node)} {node.stats()}"]
|
|
705
706
|
|
|
706
707
|
|
|
708
|
+
def make_default_solver() -> z3.Solver:
|
|
709
|
+
"""Create a new solver with default settings."""
|
|
710
|
+
smt_tactic = z3.Tactic("smt")
|
|
711
|
+
solver = smt_tactic.solver()
|
|
712
|
+
solver.set("mbqi", True)
|
|
713
|
+
# turn off every randomization thing we can think of:
|
|
714
|
+
solver.set("random-seed", 42)
|
|
715
|
+
solver.set("smt.random-seed", 42)
|
|
716
|
+
return solver
|
|
717
|
+
|
|
718
|
+
|
|
707
719
|
class StateSpace:
|
|
708
720
|
"""Holds various information about the SMT solver's current state."""
|
|
709
721
|
|
|
@@ -717,18 +729,12 @@ class StateSpace:
|
|
|
717
729
|
model_check_timeout: float,
|
|
718
730
|
search_root: RootNode,
|
|
719
731
|
):
|
|
720
|
-
|
|
721
|
-
self.solver = smt_tactic.solver()
|
|
732
|
+
self.solver = make_default_solver()
|
|
722
733
|
if model_check_timeout < 1 << 63:
|
|
723
734
|
self.smt_timeout: Optional[int] = int(model_check_timeout * 1000 + 1)
|
|
724
735
|
self.solver.set(timeout=self.smt_timeout)
|
|
725
736
|
else:
|
|
726
737
|
self.smt_timeout = None
|
|
727
|
-
self.solver.set(mbqi=True)
|
|
728
|
-
# turn off every randomization thing we can think of:
|
|
729
|
-
self.solver.set("random-seed", 42)
|
|
730
|
-
self.solver.set("smt.random-seed", 42)
|
|
731
|
-
# self.solver.set('randomize', False)
|
|
732
738
|
self.choices_made: List[SearchTreeNode] = []
|
|
733
739
|
self.status_cap: Optional[VerificationStatus] = None
|
|
734
740
|
self.heaps: List[List[Tuple[z3.ExprRef, Type, object]]] = [[]]
|
|
@@ -745,7 +751,7 @@ class StateSpace:
|
|
|
745
751
|
self._deferred_assumptions = []
|
|
746
752
|
assert search_root.iteration is not None
|
|
747
753
|
search_root.iteration += 1
|
|
748
|
-
search_root.pathing_oracle.pre_path_hook(
|
|
754
|
+
search_root.pathing_oracle.pre_path_hook(self)
|
|
749
755
|
|
|
750
756
|
def add(self, expr) -> None:
|
|
751
757
|
with NoTracing():
|
|
@@ -1049,6 +1055,51 @@ class StateSpace:
|
|
|
1049
1055
|
self.next_uniq += 1
|
|
1050
1056
|
return "_{:x}".format(self.next_uniq)
|
|
1051
1057
|
|
|
1058
|
+
@assert_tracing(False)
|
|
1059
|
+
def smt_fanout(
|
|
1060
|
+
self,
|
|
1061
|
+
exprs_and_results: Sequence[Tuple[z3.ExprRef, object]],
|
|
1062
|
+
desc: str,
|
|
1063
|
+
weights: Optional[Sequence[float]] = None,
|
|
1064
|
+
none_of_the_above_weight: float = 0.0,
|
|
1065
|
+
):
|
|
1066
|
+
"""Performs a weighted binary search over the given SMT expressions."""
|
|
1067
|
+
exprs = [e for (e, _) in exprs_and_results]
|
|
1068
|
+
final_weights = [1.0] * len(exprs) if weights is None else weights
|
|
1069
|
+
if CROSSHAIR_EXTRA_ASSERTS:
|
|
1070
|
+
if len(final_weights) != len(exprs):
|
|
1071
|
+
raise CrossHairInternal("inconsistent smt_fanout exprs and weights")
|
|
1072
|
+
if not all(0 < w for w in final_weights):
|
|
1073
|
+
raise CrossHairInternal("smt_fanout weights must be greater than zero")
|
|
1074
|
+
if not self.is_possible(z3Or(*exprs)):
|
|
1075
|
+
raise CrossHairInternal(
|
|
1076
|
+
"no smt_fanout option is possible: " + repr(exprs)
|
|
1077
|
+
)
|
|
1078
|
+
if self.is_possible(z3Not(z3Or(*exprs))):
|
|
1079
|
+
raise CrossHairInternal(
|
|
1080
|
+
"smt_fanout options are not exhaustive: " + repr(exprs)
|
|
1081
|
+
)
|
|
1082
|
+
|
|
1083
|
+
def attempt(start: int, end: int):
|
|
1084
|
+
size = end - start
|
|
1085
|
+
if size == 1:
|
|
1086
|
+
return exprs_and_results[start][1]
|
|
1087
|
+
mid = (start + end) // 2
|
|
1088
|
+
left_exprs = exprs[start:mid]
|
|
1089
|
+
left_weight = sum(final_weights[start:mid])
|
|
1090
|
+
right_weight = sum(final_weights[mid:end])
|
|
1091
|
+
if self.smt_fork(
|
|
1092
|
+
z3Or(*left_exprs),
|
|
1093
|
+
probability_true=left_weight / (left_weight + right_weight),
|
|
1094
|
+
desc=f"{desc}_fan_size_{size}",
|
|
1095
|
+
):
|
|
1096
|
+
return attempt(start, mid)
|
|
1097
|
+
else:
|
|
1098
|
+
return attempt(mid, end)
|
|
1099
|
+
|
|
1100
|
+
return attempt(0, len(exprs))
|
|
1101
|
+
|
|
1102
|
+
@assert_tracing(False)
|
|
1052
1103
|
def smt_fork(
|
|
1053
1104
|
self,
|
|
1054
1105
|
expr: Optional[z3.ExprRef] = None,
|
|
@@ -1062,6 +1113,14 @@ class StateSpace:
|
|
|
1062
1113
|
def defer_assumption(self, description: str, checker: Callable[[], bool]) -> None:
|
|
1063
1114
|
self._deferred_assumptions.append((description, checker))
|
|
1064
1115
|
|
|
1116
|
+
def extend_timeouts(
|
|
1117
|
+
self, constant_factor: float = 0.0, smt_multiple: Optional[float] = None
|
|
1118
|
+
) -> None:
|
|
1119
|
+
self.execution_deadline += constant_factor
|
|
1120
|
+
if self.smt_timeout is not None and smt_multiple is not None:
|
|
1121
|
+
self.smt_timeout = int(self.smt_timeout * smt_multiple)
|
|
1122
|
+
self.solver.set(timeout=self.smt_timeout)
|
|
1123
|
+
|
|
1065
1124
|
def detach_path(self, currently_handling: Optional[BaseException] = None) -> None:
|
|
1066
1125
|
"""
|
|
1067
1126
|
Mark the current path exhausted.
|
|
@@ -1075,13 +1134,9 @@ class StateSpace:
|
|
|
1075
1134
|
if self.is_detached:
|
|
1076
1135
|
debug("Path is already detached")
|
|
1077
1136
|
return
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
self.execution_deadline += 4.0
|
|
1082
|
-
if self.smt_timeout is not None:
|
|
1083
|
-
self.smt_timeout = self.smt_timeout * 2
|
|
1084
|
-
self.solver.set(timeout=self.smt_timeout)
|
|
1137
|
+
# Give ourselves a time extension for deferred assumptions and
|
|
1138
|
+
# (likely) counterexample generation to follow.
|
|
1139
|
+
self.extend_timeouts(constant_factor=4.0, smt_multiple=2.0)
|
|
1085
1140
|
for description, checker in self._deferred_assumptions:
|
|
1086
1141
|
with ResumedTracing():
|
|
1087
1142
|
check_ret = checker()
|
crosshair/statespace_test.py
CHANGED
|
@@ -81,3 +81,19 @@ def test_model_value_to_python_AlgebraicNumRef():
|
|
|
81
81
|
rt2 = z3.simplify(z3.Sqrt(2))
|
|
82
82
|
assert type(rt2) == z3.AlgebraicNumRef
|
|
83
83
|
model_value_to_python(rt2)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def test_smt_fanout(space: SimpleStateSpace):
|
|
87
|
+
option1 = z3.Bool("option1")
|
|
88
|
+
option2 = z3.Bool("option2")
|
|
89
|
+
space.add(z3.Xor(option1, option2)) # Ensure exactly one option can be set
|
|
90
|
+
exprs_and_results = [(option1, "result1"), (option2, "result2")]
|
|
91
|
+
|
|
92
|
+
result = space.smt_fanout(exprs_and_results, desc="choose_one")
|
|
93
|
+
assert result in ("result1", "result2")
|
|
94
|
+
if result == "result1":
|
|
95
|
+
assert space.is_possible(option1)
|
|
96
|
+
assert not space.is_possible(option2)
|
|
97
|
+
else:
|
|
98
|
+
assert not space.is_possible(option1)
|
|
99
|
+
assert space.is_possible(option2)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
_crosshair_tracers.cpython-311-darwin.so,sha256=
|
|
1
|
+
_crosshair_tracers.cpython-311-darwin.so,sha256=BzcIAaJ9SDegvNOzM9oToPW5LFRG8N_JQJDn7OsB834,57048
|
|
2
2
|
crosshair/_tracers_pycompat.h,sha256=6IYnbQxrYkhBsLDAHSX25DPOwo1oYHCZUVWZ8c7YCnQ,14356
|
|
3
3
|
crosshair/pure_importer.py,sha256=-t4eowrZOQmfqK1N2tjI5POoaxRGavytwMmbRivelFg,878
|
|
4
4
|
crosshair/options.py,sha256=htQNgnrpoRjSNq6rfLBAF8nos-NNIwmP6tQYyI8ugsM,6775
|
|
@@ -6,6 +6,7 @@ crosshair/lsp_server_test.py,sha256=7LO1Qqxkper3Xt2krgOlGqF1O_uDObo76o4FZbIqykY,
|
|
|
6
6
|
crosshair/conftest.py,sha256=BkLszApkdy6FrvzaHO7xh8_BJrG9AfytFTse-HuQVvg,653
|
|
7
7
|
crosshair/copyext_test.py,sha256=uJzdC9m2FqMjqQ-ITFoP0MZg3OCiO8paU-d533KocD8,2108
|
|
8
8
|
crosshair/objectproxy.py,sha256=1cO_ApA0AKPfCRu6MIsxUOKUUEGn0b1U4IHxTC4nDGI,9790
|
|
9
|
+
crosshair/pathing_oracle_test.py,sha256=-6U-n1k6MahHYnQ6lvI9ahFjPr9vUfaUAnFThXR2k78,709
|
|
9
10
|
crosshair/objectproxy_test.py,sha256=UJuO_jUt8_OEUtgQWyhlekPOdvtM8IQ5M9I_1AqXPWM,1081
|
|
10
11
|
crosshair/stubs_parser.py,sha256=rlBTQus5BlZ3Ygg6Xzk5dbQbDtRpv6w9i2HQmGrPVmc,14240
|
|
11
12
|
crosshair/_preliminaries_test.py,sha256=r2PohNNMfIkDqsnvI6gKlJTbwBaZA9NQJueQfJMN2Eo,504
|
|
@@ -23,12 +24,12 @@ crosshair/fnutil.py,sha256=X80bD2Lh4QAh-rF561r3JRxjxcuZepF3hJaxaj1GG9s,13123
|
|
|
23
24
|
crosshair/unicode_categories.py,sha256=g4pnUPanx8KkpwI06ZUGx8GR8Myruf_EpTjyti_V4z8,333519
|
|
24
25
|
crosshair/copyext.py,sha256=GBGQP9YAHoezLXwb_M59Hh1VXSou5EQt4ZmmUA0T_og,4899
|
|
25
26
|
crosshair/_tracers_test.py,sha256=KpCGspjOUeZuhwTYgn_RxI4M4wMbT5rldusFDgneQ6M,3596
|
|
26
|
-
crosshair/__init__.py,sha256=
|
|
27
|
-
crosshair/core.py,sha256=
|
|
28
|
-
crosshair/path_cover.py,sha256=
|
|
27
|
+
crosshair/__init__.py,sha256=pX7dpKGv0frAXPUfHUH9_8CmbQ0ItGRkG9yPi7_uApI,936
|
|
28
|
+
crosshair/core.py,sha256=nUdmPCcEWxaYawkydj2AJ7VdXe8IIu7hVyDi83Bxwec,64262
|
|
29
|
+
crosshair/path_cover.py,sha256=TCofZ9D5q7hpEIOnifp53BvY_YyPpZZC-heZw_NuTOQ,6838
|
|
29
30
|
crosshair/enforce_test.py,sha256=C6CQ4P1FjkdIJeJg3aJynp1iLDCE6BFCEVtSqXbvmQk,4665
|
|
30
31
|
crosshair/test_util.py,sha256=D9-f-DdzJemfAUkQL0cwKxPL8RZ-5gkVmghyRcKlBJI,10367
|
|
31
|
-
crosshair/core_test.py,sha256=
|
|
32
|
+
crosshair/core_test.py,sha256=P-r-qzHPZ2yLmSBZByYPccJZfxYi2ZCwn9o1mEfzRe8,33019
|
|
32
33
|
crosshair/codeconfig.py,sha256=GgF-ND8Ha3FysSTQ-JuezHjlhGVBbo5aCJov1Ps3VSE,3959
|
|
33
34
|
crosshair/util_test.py,sha256=_KTQ0O4cLhF1pAeB8Y8Cyqbd0UyZf5KxJUaiA-ew-tE,4676
|
|
34
35
|
crosshair/watcher_test.py,sha256=Ef1YSwy68wWPR5nPjwvEKPqxltI9pE9lTbnesmDy3Bk,2764
|
|
@@ -36,7 +37,7 @@ crosshair/auditwall.py,sha256=sqOmfXQLgmGfWS7b8SmVv66eFM2owaGn-4Ppq453VLI,5138
|
|
|
36
37
|
crosshair/simplestructs_test.py,sha256=6uDdrSISHLhwnFuESkR8mUGw7m1llM6vCNDFChkfSs8,8639
|
|
37
38
|
crosshair/z3util_test.py,sha256=CZovn4S9mYcG_yQegcxm80VHrvUdvNei0gvGTF9TOrk,173
|
|
38
39
|
crosshair/diff_behavior.py,sha256=_5X_pTN0_-rSPrh8dfpODJG_phFMn7fWc-_zLgO3UTk,11253
|
|
39
|
-
crosshair/condition_parser_test.py,sha256=
|
|
40
|
+
crosshair/condition_parser_test.py,sha256=UcgxzqrBLUMScif_RrgHvrhjzWx1KUPgAQOEmfJw7lc,15500
|
|
40
41
|
crosshair/pure_importer_test.py,sha256=Xjtlwn1mj7g-6VA87lrvzfUADCjlmn1wgHtbrnc0uuY,421
|
|
41
42
|
crosshair/fnutil_test.py,sha256=wXtfIxAupRm0KUzKob8luEsNI4YegBQUfwz7msWbfHY,2186
|
|
42
43
|
crosshair/stubs_parser_test.py,sha256=0itTT0Udul_51RJXNv6KB97z44gYze6NZfKJL7yIDzA,1228
|
|
@@ -46,28 +47,28 @@ crosshair/abcstring.py,sha256=ROU8LzS7kfEU2L_D3QfhVxIjrYr1VctwUWfylC7KlCc,6549
|
|
|
46
47
|
crosshair/_mark_stacks.h,sha256=j86qubOUvVhoR19d74iQ084RrTEq8M6oT4wJsGQUySY,28678
|
|
47
48
|
crosshair/fuzz_core_test.py,sha256=q7WsZt6bj5OJrXaVsT3JaRYWWnL8X_1flSfty4Z7CcA,16903
|
|
48
49
|
crosshair/unicode_categories_test.py,sha256=ZAU37IDGm9PDvwy_CGFcrF9Waa8JuUNdI4aq74wkB6c,739
|
|
49
|
-
crosshair/statespace_test.py,sha256=
|
|
50
|
+
crosshair/statespace_test.py,sha256=Eq7LNpjradHyCoCKU91Fxmo9DUpK2Mk4PyxxiAEp-Yk,3211
|
|
50
51
|
crosshair/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
51
52
|
crosshair/lsp_server.py,sha256=j7SX4pdVwa2MrtkNIjajLilzl5CZTY6PrBQsa26cdNo,8670
|
|
52
53
|
crosshair/path_search.py,sha256=wwZjp-3E4dENnJa6BlnSq8FARkIx0PyUYc7kvH32A2k,5588
|
|
53
54
|
crosshair/auditwall_test.py,sha256=VPcw_OW3nl3BkOZY4wEEtVDyTamdgqD4IjRccI2p5vI,2030
|
|
54
55
|
crosshair/smtlib_test.py,sha256=edzEn19u2YYHxSzG9RrMiu2HTiEexAuehC3IlG9LuJM,511
|
|
55
56
|
crosshair/register_contract_test.py,sha256=DhvKIcF3LgQfHfUSCccoA11ctCdFaQR263Pc4YUuxyk,4970
|
|
56
|
-
crosshair/statespace.py,sha256=
|
|
57
|
+
crosshair/statespace.py,sha256=h1un79C-vkyKJ1iLAU4lQlVu3A6YqqbpcrqHGCsTsrg,43442
|
|
57
58
|
crosshair/opcode_intercept_test.py,sha256=Si3rJQR5cs5d4uB8uwE2K8MjP8rE1a4yHkjXzhfS10A,9241
|
|
58
59
|
crosshair/main_test.py,sha256=2xpgNqog__XcYffGcwPeEEmr0Vy4EgVZE8GCAjQnE8U,14834
|
|
59
60
|
crosshair/codeconfig_test.py,sha256=RnC-RnNpr6If4eHmOepDZ33MCmfyhup08dzHKCm5xWA,3350
|
|
60
61
|
crosshair/watcher.py,sha256=kCCMlLe2KhW5MbEbMmixNRjRAvu5CypIAGd1V_YZ9QM,10048
|
|
61
62
|
crosshair/test_util_test.py,sha256=_r8DtAI5b1Yn1ruv9o51FWHmARII3-WDkWWnnY1iaAw,943
|
|
62
|
-
crosshair/opcode_intercept.py,sha256=
|
|
63
|
+
crosshair/opcode_intercept.py,sha256=ZNePiOMX5xmREkA-x2t1MuM8fmHPbaogMOmGYn21NzU,21579
|
|
63
64
|
crosshair/simplestructs.py,sha256=CiZSuHH_j_bYitaW-n7vWd_42xSyV6Jh8es3BQLlcHk,34221
|
|
64
65
|
crosshair/tracers_test.py,sha256=EBK_ZCy2MsxqmEaGjo0uw9zAztW9O6fhCW_0PJxyTS8,3270
|
|
65
66
|
crosshair/smtlib.py,sha256=hh-P32KHoH9BCq3oDYGp2PfOeOb8CwDj8tTkgqroLD8,689
|
|
66
67
|
crosshair/main.py,sha256=TkaOr39tMV9ZHQXgfJobKFEVW60XpHUqdY520nMIWw8,34659
|
|
67
68
|
crosshair/path_cover_test.py,sha256=U46zw4-m7yAXhu8-3Xnhvf-_9Ov5ivfCAm5euGwpRFA,4089
|
|
68
69
|
crosshair/__main__.py,sha256=zw9Ylf8v2fGocE57o4FqvD0lc7U4Ld2GbeCGxRWrpqo,252
|
|
69
|
-
crosshair/pathing_oracle.py,sha256=
|
|
70
|
-
crosshair/diff_behavior_test.py,sha256=
|
|
70
|
+
crosshair/pathing_oracle.py,sha256=PvqX7396SaQK3m-bMpCwBKmHW9SYiioooUWNvmmEqNw,10497
|
|
71
|
+
crosshair/diff_behavior_test.py,sha256=nCpzOjrw0qsYgVhD2iCvKiNAt82SrfUWxWS5mPSE73w,7215
|
|
71
72
|
crosshair/core_and_libs.py,sha256=8FGL62GnyX6WHOqKh0rqJ0aJ_He5pwZm_zwPXTaPqhI,3963
|
|
72
73
|
crosshair/core_regestered_types_test.py,sha256=er3ianvu-l0RS-WrS46jmOWr4Jq06Cec9htAXGXJSNg,2099
|
|
73
74
|
crosshair/z3util.py,sha256=AkslxCSfzgSni6oWXUckWihWn3LuceQycR0X3D3ZhD8,1759
|
|
@@ -105,22 +106,22 @@ crosshair/libimpl/unicodedatalib.py,sha256=q5LoCaEbHJrUwVWtUrlS3n_X21yp15xTS42l-
|
|
|
105
106
|
crosshair/libimpl/datetimelib_test.py,sha256=v9Cg512AXIGy7_dsN2y_ZD7W7fqfSSz07eiCUZukM60,2659
|
|
106
107
|
crosshair/libimpl/heapqlib_test.py,sha256=NdwTihD0xGy4qIDaS5a9-t3q437rP47GNdtceEBquNA,537
|
|
107
108
|
crosshair/libimpl/binascii_test.py,sha256=LOBqLAJ77Kx8vorjVTaT3X0Z93zw4P5BvwUapMCiSLg,1970
|
|
108
|
-
crosshair/libimpl/collectionslib_test.py,sha256=
|
|
109
|
+
crosshair/libimpl/collectionslib_test.py,sha256=0qmCRQbxfX8vMZLaok1GS68NIocR--RyTVVDqbtHalU,9185
|
|
109
110
|
crosshair/libimpl/timelib.py,sha256=MXEFOZjFGa1-yLvmB3l3DFTLF9PSluOlmRK-ZJaA_oI,2409
|
|
110
111
|
crosshair/libimpl/jsonlib_test.py,sha256=U40WJf-69dtflz75sIsl5zA3IV5R6Ltc4Z9jv_Fh-Fw,1382
|
|
111
|
-
crosshair/libimpl/builtinslib.py,sha256=
|
|
112
|
+
crosshair/libimpl/builtinslib.py,sha256=j275QUgWqnq62immbBqUzlPesOq0t-oTb0C9WL7sIiA,173276
|
|
112
113
|
crosshair/libimpl/mathlib_test.py,sha256=QShLCXHdv3tx5PQxcSoR0MHeZ1huaiV6d3u7C2mGOn4,1861
|
|
113
114
|
crosshair/libimpl/fractionlib.py,sha256=qdbiAHHC480YdKq3wYK_piZ3UD7oT64YfuNclypMUfQ,458
|
|
114
115
|
crosshair/libimpl/binascii_ch_test.py,sha256=hFqSfF1Q8jl2LNBIWaQ6vBJIIshPOmSwrR0T1Ko4Leo,1009
|
|
115
116
|
crosshair/libimpl/jsonlib.py,sha256=xFTvqGKzQcCgPme1WIpNMjBPfNHVZBMNuNx0uKMYXj0,28805
|
|
116
117
|
crosshair/libimpl/typeslib_test.py,sha256=qCeUU_c-zmuvfwHEsaYqic9wdGzs9XbDZNr6bF2Xp58,1129
|
|
117
|
-
crosshair/libimpl/builtinslib_test.py,sha256=
|
|
118
|
+
crosshair/libimpl/builtinslib_test.py,sha256=jbN2t-zteWqF5TxA7oo4c9UsPrqklBY7wlEt16rxqtI,92230
|
|
118
119
|
crosshair/libimpl/zliblib.py,sha256=XymJTKYbplpYJZ-P7GKVSY3V_8HPy5lqRFsCH1zezIk,357
|
|
119
120
|
crosshair/libimpl/decimallib.py,sha256=zBKDrDZcg45oCKUkf6SIDuVpjA1Web7tD1MEQo5cjxI,177348
|
|
120
121
|
crosshair/libimpl/relib_ch_test.py,sha256=zvSBF82mNQR5yEOMwwcaBOh8OpJkQeiVl85pgYVvJRA,5235
|
|
121
|
-
crosshair/libimpl/functoolslib.py,sha256=
|
|
122
|
+
crosshair/libimpl/functoolslib.py,sha256=YD0g9UnC4v_wZXR3ekQa2gLrKJnr6dHdYtT9qIMUIGM,1009
|
|
122
123
|
crosshair/libimpl/collectionslib_ch_test.py,sha256=PYitnmXXEZfm25FzBodEX1hOpwqnDspbqt5aqzeVar0,5855
|
|
123
|
-
crosshair/libimpl/builtinslib_ch_test.py,sha256=
|
|
124
|
+
crosshair/libimpl/builtinslib_ch_test.py,sha256=Fyu2fZLXI-pUaS3gyyM6zMQhsTFdpRCnnp1rXwxKXwk,30854
|
|
124
125
|
crosshair/libimpl/randomlib_test.py,sha256=KuEgrih9JvstsFDwrgAuHZrlVjIvaNUxS8ftiGPrwHI,3322
|
|
125
126
|
crosshair/libimpl/weakreflib_test.py,sha256=CdGJhW32qJoxedn8QzPcMcKKmfl9Nv4FPDYebblIKmY,1812
|
|
126
127
|
crosshair/libimpl/mathlib.py,sha256=ci_byDulWf1VOitpD3C-TwToL6CRYKkJUVMxjAYzUH8,4256
|
|
@@ -156,7 +157,7 @@ crosshair/libimpl/heapqlib.py,sha256=TWH55dg-Hi5FRz2oZuXHcBU_xJzHjvhe9YQVvw7ZbfI
|
|
|
156
157
|
crosshair/libimpl/unicodedatalib_test.py,sha256=CJkAbiu8_2uhvjDIoYi3IJ8Nb_8sdjKVNvNhJCgPbZ0,1442
|
|
157
158
|
crosshair/libimpl/encodings_ch_test.py,sha256=0qLsioOuFUZkOjP4J9Wct4CGBaBY8BnHx9paZHnIofI,2513
|
|
158
159
|
crosshair/libimpl/hashliblib.py,sha256=Ki_cw28OnhZExgKbSoh5GaDbBfNRIOqH7O2aYQJGS3M,1234
|
|
159
|
-
crosshair/libimpl/functoolslib_test.py,sha256=
|
|
160
|
+
crosshair/libimpl/functoolslib_test.py,sha256=eaT_JWu-C3j8l9ekwDXd2dhPJvuB577T9DuXRohL0fc,1604
|
|
160
161
|
crosshair/libimpl/iolib_ch_test.py,sha256=yibR3CbYjd9Sf2UaAIQaWO8QXbsZgyDc9w10VEtQN-A,3623
|
|
161
162
|
crosshair/libimpl/weakreflib.py,sha256=By2JxeBHJCQP_Na5MBhE9YCc0O5NoKefKASoRBUNcW0,230
|
|
162
163
|
crosshair/libimpl/decimallib_test.py,sha256=393MkVB9-LPcA7JJK6wGAbDyd-YejkjwrXRaEDaVhjM,2238
|
|
@@ -167,9 +168,9 @@ crosshair/libimpl/encodings/ascii.py,sha256=Cz1xraTkXdQ5aBKDkorX4rAvrmf877_EqzC9
|
|
|
167
168
|
crosshair/libimpl/encodings/__init__.py,sha256=5LTEj1M-S00eZ4rfQWczAixg57vyh_9vZ5m5EKB5Ksc,680
|
|
168
169
|
crosshair/libimpl/encodings/latin_1.py,sha256=ftUsPjUb9L7UKXKi9P7OAqOl9FkNP98M9jMAvseXBCQ,1242
|
|
169
170
|
crosshair/libimpl/encodings/_encutil.py,sha256=nwVWqcGM1f7-hAC3Z46KnfrLzAjhfy4zaTa11uVBk6M,6828
|
|
170
|
-
crosshair_tool-0.0.
|
|
171
|
-
crosshair_tool-0.0.
|
|
172
|
-
crosshair_tool-0.0.
|
|
173
|
-
crosshair_tool-0.0.
|
|
174
|
-
crosshair_tool-0.0.
|
|
175
|
-
crosshair_tool-0.0.
|
|
171
|
+
crosshair_tool-0.0.96.dist-info/RECORD,,
|
|
172
|
+
crosshair_tool-0.0.96.dist-info/WHEEL,sha256=sunMa2yiYbrNLGeMVDqEA0ayyJbHlex7SCn1TZrEq60,136
|
|
173
|
+
crosshair_tool-0.0.96.dist-info/entry_points.txt,sha256=u5FIPVn1jqn4Kzg5K_iNnbP6L4hQw5FWjQ0UMezG2VE,96
|
|
174
|
+
crosshair_tool-0.0.96.dist-info/top_level.txt,sha256=2jLWtM-BWg_ZYNbNfrcds0HFZD62a6J7ZIbcgcQrRk4,29
|
|
175
|
+
crosshair_tool-0.0.96.dist-info/METADATA,sha256=XkqQh0ph4NN3is0V3zwd434hTKNQug9pOooY9FIrclg,6777
|
|
176
|
+
crosshair_tool-0.0.96.dist-info/licenses/LICENSE,sha256=NVyMvNqn1pH6RSHs6RWRcJyJvORnpgGFBlF73buqYJ0,4459
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|