crosshair-tool 0.0.85__cp313-cp313-macosx_10_13_x86_64.whl → 0.0.86__cp313-cp313-macosx_10_13_x86_64.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-313-darwin.so +0 -0
- crosshair/__init__.py +1 -1
- crosshair/libimpl/builtinslib.py +4 -260
- crosshair/libimpl/builtinslib_test.py +1 -1
- crosshair/libimpl/typeslib_test.py +2 -1
- crosshair/opcode_intercept.py +110 -41
- crosshair/opcode_intercept_test.py +85 -5
- crosshair/statespace.py +9 -4
- crosshair/util.py +3 -1
- {crosshair_tool-0.0.85.dist-info → crosshair_tool-0.0.86.dist-info}/METADATA +1 -1
- {crosshair_tool-0.0.85.dist-info → crosshair_tool-0.0.86.dist-info}/RECORD +15 -15
- {crosshair_tool-0.0.85.dist-info → crosshair_tool-0.0.86.dist-info}/WHEEL +1 -0
- {crosshair_tool-0.0.85.dist-info → crosshair_tool-0.0.86.dist-info}/entry_points.txt +0 -0
- {crosshair_tool-0.0.85.dist-info → crosshair_tool-0.0.86.dist-info}/licenses/LICENSE +0 -0
- {crosshair_tool-0.0.85.dist-info → crosshair_tool-0.0.86.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.86" # Do not forget to update in setup.py!
|
|
19
19
|
__author__ = "Phillip Schanely"
|
|
20
20
|
__license__ = "MIT"
|
|
21
21
|
__status__ = "Alpha"
|
crosshair/libimpl/builtinslib.py
CHANGED
|
@@ -402,6 +402,10 @@ def crosshair_types_for_python_type(
|
|
|
402
402
|
return _PYTYPE_TO_WRAPPER_TYPE.get(origin, ())
|
|
403
403
|
|
|
404
404
|
|
|
405
|
+
def python_types_using_atomic_symbolics() -> Iterable[Type[AtomicSymbolicValue]]:
|
|
406
|
+
return _PYTYPE_TO_WRAPPER_TYPE.keys()
|
|
407
|
+
|
|
408
|
+
|
|
405
409
|
class ModelingDirector:
|
|
406
410
|
def __init__(self, *a) -> None:
|
|
407
411
|
# Maps python type to the symbolic type we've chosen to represent it (on this iteration)
|
|
@@ -3488,10 +3492,6 @@ class LazyIntSymbolicStr(AnySymbolicStr, CrossHairValue):
|
|
|
3488
3492
|
otherpoints = [ord(ch) for ch in other]
|
|
3489
3493
|
with ResumedTracing():
|
|
3490
3494
|
return mypoints.__eq__(otherpoints)
|
|
3491
|
-
elif isinstance(other, SeqBasedSymbolicStr):
|
|
3492
|
-
with ResumedTracing():
|
|
3493
|
-
otherpoints = [ord(ch) for ch in other]
|
|
3494
|
-
return mypoints.__eq__(otherpoints)
|
|
3495
3495
|
else:
|
|
3496
3496
|
return NotImplemented
|
|
3497
3497
|
|
|
@@ -3660,257 +3660,6 @@ class LazyIntSymbolicStr(AnySymbolicStr, CrossHairValue):
|
|
|
3660
3660
|
return self._find(substr, start, end, from_right=True)
|
|
3661
3661
|
|
|
3662
3662
|
|
|
3663
|
-
class SeqBasedSymbolicStr(AtomicSymbolicValue, SymbolicSequence, AnySymbolicStr):
|
|
3664
|
-
def __init__(self, smtvar: Union[str, z3.ExprRef], typ: Type = str):
|
|
3665
|
-
assert typ == str
|
|
3666
|
-
SymbolicValue.__init__(self, smtvar, typ)
|
|
3667
|
-
self.item_pytype = str
|
|
3668
|
-
if isinstance(smtvar, str):
|
|
3669
|
-
# Constrain fresh strings to valid codepoints
|
|
3670
|
-
space = context_statespace()
|
|
3671
|
-
idxvar = z3.Int("idxvar" + space.uniq())
|
|
3672
|
-
z3seq = self.var
|
|
3673
|
-
space.add(
|
|
3674
|
-
z3.ForAll(
|
|
3675
|
-
[idxvar], z3.And(0 <= z3seq[idxvar], z3seq[idxvar] <= maxunicode)
|
|
3676
|
-
)
|
|
3677
|
-
)
|
|
3678
|
-
|
|
3679
|
-
@classmethod
|
|
3680
|
-
def _ch_smt_sort(cls) -> z3.SortRef:
|
|
3681
|
-
return z3.SeqSort(z3.IntSort())
|
|
3682
|
-
|
|
3683
|
-
@classmethod
|
|
3684
|
-
def _pytype(cls) -> Type:
|
|
3685
|
-
return str
|
|
3686
|
-
|
|
3687
|
-
@classmethod
|
|
3688
|
-
def _smt_promote_literal(cls, literal) -> Optional[z3.SortRef]:
|
|
3689
|
-
if isinstance(literal, str):
|
|
3690
|
-
if len(literal) <= 1:
|
|
3691
|
-
if len(literal) == 0:
|
|
3692
|
-
return z3.Empty(z3.SeqSort(z3.IntSort()))
|
|
3693
|
-
return z3.Unit(z3IntVal(ord(literal)))
|
|
3694
|
-
return z3.Concat([z3.Unit(z3IntVal(ord(ch))) for ch in literal])
|
|
3695
|
-
return None
|
|
3696
|
-
|
|
3697
|
-
def __ch_realize__(self) -> object:
|
|
3698
|
-
codepoints = context_statespace().find_model_value(self.var)
|
|
3699
|
-
return "".join(chr(x) for x in codepoints)
|
|
3700
|
-
|
|
3701
|
-
def __copy__(self):
|
|
3702
|
-
return SeqBasedSymbolicStr(self.var)
|
|
3703
|
-
|
|
3704
|
-
def __hash__(self):
|
|
3705
|
-
return hash(self.__str__())
|
|
3706
|
-
|
|
3707
|
-
@staticmethod
|
|
3708
|
-
def _concat_strings(
|
|
3709
|
-
a: Union[str, "SeqBasedSymbolicStr"], b: Union[str, "SeqBasedSymbolicStr"]
|
|
3710
|
-
) -> Union[str, "SeqBasedSymbolicStr"]:
|
|
3711
|
-
assert not is_tracing()
|
|
3712
|
-
# Assumes at least one argument is symbolic and not tracing
|
|
3713
|
-
if isinstance(a, SeqBasedSymbolicStr) and isinstance(b, SeqBasedSymbolicStr):
|
|
3714
|
-
return SeqBasedSymbolicStr(a.var + b.var)
|
|
3715
|
-
elif isinstance(a, str) and isinstance(b, SeqBasedSymbolicStr):
|
|
3716
|
-
return SeqBasedSymbolicStr(
|
|
3717
|
-
SeqBasedSymbolicStr._coerce_to_smt_sort(a) + b.var
|
|
3718
|
-
)
|
|
3719
|
-
else:
|
|
3720
|
-
assert isinstance(a, SeqBasedSymbolicStr)
|
|
3721
|
-
assert isinstance(b, str)
|
|
3722
|
-
return SeqBasedSymbolicStr(
|
|
3723
|
-
a.var + SeqBasedSymbolicStr._coerce_to_smt_sort(b)
|
|
3724
|
-
)
|
|
3725
|
-
|
|
3726
|
-
def __add__(self, other):
|
|
3727
|
-
with NoTracing():
|
|
3728
|
-
if isinstance(other, (SeqBasedSymbolicStr, str)):
|
|
3729
|
-
return SeqBasedSymbolicStr._concat_strings(self, other)
|
|
3730
|
-
if isinstance(other, AnySymbolicStr):
|
|
3731
|
-
return NotImplemented
|
|
3732
|
-
raise TypeError
|
|
3733
|
-
|
|
3734
|
-
def __radd__(self, other):
|
|
3735
|
-
with NoTracing():
|
|
3736
|
-
if isinstance(other, (SeqBasedSymbolicStr, str)):
|
|
3737
|
-
return SeqBasedSymbolicStr._concat_strings(other, self)
|
|
3738
|
-
if isinstance(other, AnySymbolicStr):
|
|
3739
|
-
return NotImplemented
|
|
3740
|
-
raise TypeError
|
|
3741
|
-
|
|
3742
|
-
def __mul__(self, other):
|
|
3743
|
-
if isinstance(other, Integral):
|
|
3744
|
-
if other <= 1:
|
|
3745
|
-
return self if other == 1 else ""
|
|
3746
|
-
# Note that in SymbolicInt, we attempt string multiplication via regex.
|
|
3747
|
-
# Z3 cannot do much with a symbolic regex, so we case-split on
|
|
3748
|
-
# the repetition count.
|
|
3749
|
-
return SeqBasedSymbolicStr(z3.Concat(*[self.var for _ in range(other)]))
|
|
3750
|
-
return NotImplemented
|
|
3751
|
-
|
|
3752
|
-
__rmul__ = __mul__
|
|
3753
|
-
|
|
3754
|
-
def __mod__(self, other):
|
|
3755
|
-
return self.__str__() % realize(other)
|
|
3756
|
-
|
|
3757
|
-
def __contains__(self, other):
|
|
3758
|
-
with NoTracing():
|
|
3759
|
-
forced = force_to_smt_sort(other, SeqBasedSymbolicStr)
|
|
3760
|
-
return SymbolicBool(z3.Contains(self.var, forced))
|
|
3761
|
-
|
|
3762
|
-
def __getitem__(self, i: Union[int, slice]):
|
|
3763
|
-
with NoTracing():
|
|
3764
|
-
idx_or_pair = process_slice_vs_symbolic_len(
|
|
3765
|
-
context_statespace(), i, z3.Length(self.var)
|
|
3766
|
-
)
|
|
3767
|
-
if isinstance(idx_or_pair, tuple):
|
|
3768
|
-
(start, stop) = idx_or_pair
|
|
3769
|
-
smt_result = z3.Extract(self.var, start, stop - start)
|
|
3770
|
-
else:
|
|
3771
|
-
smt_result = z3.Unit(self.var[idx_or_pair])
|
|
3772
|
-
return SeqBasedSymbolicStr(smt_result)
|
|
3773
|
-
|
|
3774
|
-
def endswith(self, substr):
|
|
3775
|
-
with NoTracing():
|
|
3776
|
-
smt_substr = force_to_smt_sort(substr, SeqBasedSymbolicStr)
|
|
3777
|
-
return SymbolicBool(z3.SuffixOf(smt_substr, self.var))
|
|
3778
|
-
|
|
3779
|
-
def find(self, substr, start=None, end=None):
|
|
3780
|
-
if not isinstance(substr, str):
|
|
3781
|
-
raise TypeError
|
|
3782
|
-
with NoTracing():
|
|
3783
|
-
space = context_statespace()
|
|
3784
|
-
smt_my_len = z3.Length(self.var)
|
|
3785
|
-
if start is None and end is None:
|
|
3786
|
-
smt_start = z3IntVal(0)
|
|
3787
|
-
smt_end = smt_my_len
|
|
3788
|
-
smt_str = self.var
|
|
3789
|
-
if len(substr) == 0:
|
|
3790
|
-
return 0
|
|
3791
|
-
else:
|
|
3792
|
-
(smt_start, smt_end) = flip_slice_vs_symbolic_len(
|
|
3793
|
-
space, slice(start, end, None), smt_my_len
|
|
3794
|
-
)
|
|
3795
|
-
if len(substr) == 0:
|
|
3796
|
-
# Add oddity of CPython. We can find the empty string when over-slicing
|
|
3797
|
-
# off the left side of the string, but not off the right:
|
|
3798
|
-
# ''.find('', 3, 4) == -1
|
|
3799
|
-
# ''.find('', -4, -3) == 0
|
|
3800
|
-
if space.smt_fork(smt_start > smt_my_len):
|
|
3801
|
-
return -1
|
|
3802
|
-
elif space.smt_fork(smt_start > 0):
|
|
3803
|
-
return SymbolicInt(smt_start)
|
|
3804
|
-
else:
|
|
3805
|
-
return 0
|
|
3806
|
-
(smt_start, smt_end) = clip_range_to_symbolic_len(
|
|
3807
|
-
space, smt_start, smt_end, smt_my_len
|
|
3808
|
-
)
|
|
3809
|
-
smt_str = z3.SubString(self.var, smt_start, smt_end - smt_start)
|
|
3810
|
-
|
|
3811
|
-
smt_sub = force_to_smt_sort(substr, SeqBasedSymbolicStr)
|
|
3812
|
-
if space.smt_fork(z3.Contains(smt_str, smt_sub)):
|
|
3813
|
-
return SymbolicInt(z3.IndexOf(smt_str, smt_sub, 0) + smt_start)
|
|
3814
|
-
else:
|
|
3815
|
-
return -1
|
|
3816
|
-
|
|
3817
|
-
def partition(self, sep: str):
|
|
3818
|
-
if not isinstance(sep, str):
|
|
3819
|
-
raise TypeError
|
|
3820
|
-
if len(sep) == 0:
|
|
3821
|
-
raise ValueError
|
|
3822
|
-
with NoTracing():
|
|
3823
|
-
space = context_statespace()
|
|
3824
|
-
smt_str = self.var
|
|
3825
|
-
smt_sep = force_to_smt_sort(sep, SeqBasedSymbolicStr)
|
|
3826
|
-
if space.smt_fork(z3.Contains(smt_str, smt_sep)):
|
|
3827
|
-
uniq = space.uniq()
|
|
3828
|
-
# Divide my contents into 4 concatenated parts:
|
|
3829
|
-
prefix = SeqBasedSymbolicStr(f"prefix{uniq}")
|
|
3830
|
-
match1 = SeqBasedSymbolicStr(
|
|
3831
|
-
f"match1{uniq}"
|
|
3832
|
-
) # the first character of the match
|
|
3833
|
-
match_tail = SeqBasedSymbolicStr(f"match_tail{uniq}")
|
|
3834
|
-
suffix = SeqBasedSymbolicStr(f"suffix{uniq}")
|
|
3835
|
-
space.add(z3.Length(match1.var) == 1)
|
|
3836
|
-
space.add(smt_sep == z3.Concat(match1.var, match_tail.var))
|
|
3837
|
-
space.add(smt_str == z3.Concat(prefix.var, smt_sep, suffix.var))
|
|
3838
|
-
space.add(
|
|
3839
|
-
z3.Not(z3.Contains(z3.Concat(match_tail.var, suffix.var), smt_sep))
|
|
3840
|
-
)
|
|
3841
|
-
return (prefix, sep, suffix)
|
|
3842
|
-
else:
|
|
3843
|
-
return (self, "", "")
|
|
3844
|
-
|
|
3845
|
-
def rfind(self, substr, start=None, end=None) -> Union[int, SymbolicInt]:
|
|
3846
|
-
if not isinstance(substr, str):
|
|
3847
|
-
raise TypeError
|
|
3848
|
-
with NoTracing():
|
|
3849
|
-
space = context_statespace()
|
|
3850
|
-
smt_my_len = z3.Length(self.var)
|
|
3851
|
-
if start is None and end is None:
|
|
3852
|
-
smt_start = z3IntVal(0)
|
|
3853
|
-
smt_end = smt_my_len
|
|
3854
|
-
smt_str = self.var
|
|
3855
|
-
if len(substr) == 0:
|
|
3856
|
-
return SymbolicInt(smt_my_len)
|
|
3857
|
-
else:
|
|
3858
|
-
(smt_start, smt_end) = flip_slice_vs_symbolic_len(
|
|
3859
|
-
space, slice(start, end, None), smt_my_len
|
|
3860
|
-
)
|
|
3861
|
-
if len(substr) == 0:
|
|
3862
|
-
# Add oddity of CPython. We can find the empty string when over-slicing
|
|
3863
|
-
# off the left side of the string, but not off the right:
|
|
3864
|
-
# ''.find('', 3, 4) == -1
|
|
3865
|
-
# ''.find('', -4, -3) == 0
|
|
3866
|
-
if space.smt_fork(smt_start > smt_my_len):
|
|
3867
|
-
return -1
|
|
3868
|
-
elif space.smt_fork(smt_end < 0):
|
|
3869
|
-
return 0
|
|
3870
|
-
elif space.smt_fork(smt_end < smt_my_len):
|
|
3871
|
-
return SymbolicInt(smt_end)
|
|
3872
|
-
else:
|
|
3873
|
-
return SymbolicInt(smt_my_len)
|
|
3874
|
-
(smt_start, smt_end) = clip_range_to_symbolic_len(
|
|
3875
|
-
space, smt_start, smt_end, smt_my_len
|
|
3876
|
-
)
|
|
3877
|
-
smt_str = z3.SubString(self.var, smt_start, smt_end - smt_start)
|
|
3878
|
-
smt_sub = force_to_smt_sort(substr, SeqBasedSymbolicStr)
|
|
3879
|
-
if space.smt_fork(z3.Contains(smt_str, smt_sub)):
|
|
3880
|
-
uniq = space.uniq()
|
|
3881
|
-
# Divide my contents into 4 concatenated parts:
|
|
3882
|
-
prefix = SeqBasedSymbolicStr(f"prefix{uniq}")
|
|
3883
|
-
match1 = SeqBasedSymbolicStr(f"match1{uniq}")
|
|
3884
|
-
match_tail = SeqBasedSymbolicStr(f"match_tail{uniq}")
|
|
3885
|
-
suffix = SeqBasedSymbolicStr(f"suffix{uniq}")
|
|
3886
|
-
space.add(z3.Length(match1.var) == 1)
|
|
3887
|
-
space.add(smt_sub == z3.Concat(match1.var, match_tail.var))
|
|
3888
|
-
space.add(smt_str == z3.Concat(prefix.var, smt_sub, suffix.var))
|
|
3889
|
-
space.add(
|
|
3890
|
-
z3.Not(z3.Contains(z3.Concat(match_tail.var, suffix.var), smt_sub))
|
|
3891
|
-
)
|
|
3892
|
-
return SymbolicInt(smt_start + z3.Length(prefix.var))
|
|
3893
|
-
else:
|
|
3894
|
-
return -1
|
|
3895
|
-
|
|
3896
|
-
def rpartition(self, sep: str):
|
|
3897
|
-
result = self.rsplit(sep, maxsplit=1)
|
|
3898
|
-
if len(result) == 1:
|
|
3899
|
-
return ("", "", self)
|
|
3900
|
-
elif len(result) == 2:
|
|
3901
|
-
return (result[0], sep, result[1])
|
|
3902
|
-
|
|
3903
|
-
def startswith(self, substr, start=None, end=None):
|
|
3904
|
-
if isinstance(substr, tuple):
|
|
3905
|
-
return any(self.startswith(s, start, end) for s in substr)
|
|
3906
|
-
smt_substr = force_to_smt_sort(substr, SeqBasedSymbolicStr)
|
|
3907
|
-
if start is not None or end is not None:
|
|
3908
|
-
# TODO: "".startswith("", 1) should be False, not True
|
|
3909
|
-
return self[start:end].startswith(substr)
|
|
3910
|
-
with NoTracing():
|
|
3911
|
-
return SymbolicBool(z3.PrefixOf(smt_substr, self.var))
|
|
3912
|
-
|
|
3913
|
-
|
|
3914
3663
|
def buffer_to_byte_seq(obj: object) -> Optional[Sequence[int]]:
|
|
3915
3664
|
if isinstance(obj, (bytes, bytearray)):
|
|
3916
3665
|
return list(obj)
|
|
@@ -4822,11 +4571,6 @@ def _ord(c: str) -> int:
|
|
|
4822
4571
|
with NoTracing():
|
|
4823
4572
|
if isinstance(c, LazyIntSymbolicStr):
|
|
4824
4573
|
return c._codepoints[0]
|
|
4825
|
-
elif isinstance(c, SeqBasedSymbolicStr):
|
|
4826
|
-
space = context_statespace()
|
|
4827
|
-
ret = SymbolicInt("ord" + space.uniq())
|
|
4828
|
-
space.add(c.var == z3.Unit(ret.var))
|
|
4829
|
-
return ret
|
|
4830
4574
|
return ord(realize(c))
|
|
4831
4575
|
|
|
4832
4576
|
|
|
@@ -30,6 +30,7 @@ def test_mappingproxy_deep_realize(space):
|
|
|
30
30
|
assert type(copy) is MappingProxyType
|
|
31
31
|
with ResumedTracing():
|
|
32
32
|
val_from_orig = orig[key]
|
|
33
|
-
|
|
33
|
+
realized_key = deep_realize(key)
|
|
34
|
+
val_from_copy = copy[realized_key]
|
|
34
35
|
assert type(val_from_orig) is SymbolicInt
|
|
35
36
|
assert type(val_from_copy) is int
|
crosshair/opcode_intercept.py
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import dis
|
|
2
2
|
import sys
|
|
3
3
|
import weakref
|
|
4
|
+
from collections import defaultdict
|
|
4
5
|
from collections.abc import MutableMapping, Set
|
|
5
6
|
from sys import version_info
|
|
6
7
|
from types import CodeType, FrameType
|
|
7
|
-
from typing import Callable
|
|
8
|
+
from typing import Any, Callable, Iterable, Mapping, Tuple, Union
|
|
8
9
|
|
|
9
10
|
from crosshair.core import (
|
|
10
11
|
ATOMIC_IMMUTABLE_TYPES,
|
|
@@ -13,20 +14,29 @@ from crosshair.core import (
|
|
|
13
14
|
)
|
|
14
15
|
from crosshair.libimpl.builtinslib import (
|
|
15
16
|
AnySymbolicStr,
|
|
17
|
+
AtomicSymbolicValue,
|
|
18
|
+
ModelingDirector,
|
|
16
19
|
SymbolicBool,
|
|
17
20
|
SymbolicInt,
|
|
18
21
|
SymbolicList,
|
|
22
|
+
python_types_using_atomic_symbolics,
|
|
19
23
|
)
|
|
20
24
|
from crosshair.simplestructs import LinearSet, ShellMutableSet, SimpleDict, SliceView
|
|
21
25
|
from crosshair.statespace import context_statespace
|
|
22
26
|
from crosshair.tracers import (
|
|
23
27
|
COMPOSITE_TRACER,
|
|
24
28
|
NoTracing,
|
|
29
|
+
ResumedTracing,
|
|
25
30
|
TracingModule,
|
|
26
31
|
frame_stack_read,
|
|
27
32
|
frame_stack_write,
|
|
28
33
|
)
|
|
29
|
-
from crosshair.util import
|
|
34
|
+
from crosshair.util import (
|
|
35
|
+
CROSSHAIR_EXTRA_ASSERTS,
|
|
36
|
+
CrossHairInternal,
|
|
37
|
+
CrossHairValue,
|
|
38
|
+
debug,
|
|
39
|
+
)
|
|
30
40
|
from crosshair.z3util import z3Not, z3Or
|
|
31
41
|
|
|
32
42
|
BINARY_SUBSCR = dis.opmap.get("BINARY_SUBSCR", 256)
|
|
@@ -60,13 +70,100 @@ _DEEPLY_CONCRETE_KEY_TYPES = (
|
|
|
60
70
|
)
|
|
61
71
|
|
|
62
72
|
|
|
73
|
+
class MultiSubscriptableContainer:
|
|
74
|
+
"""Used for indexing a symbolic (non-slice) key into a concrete container"""
|
|
75
|
+
|
|
76
|
+
def __init__(self, container: Union[list, tuple, dict]):
|
|
77
|
+
self.container = container
|
|
78
|
+
|
|
79
|
+
def __getitem__(self, key: AtomicSymbolicValue) -> object:
|
|
80
|
+
with NoTracing():
|
|
81
|
+
space = context_statespace()
|
|
82
|
+
container = self.container
|
|
83
|
+
if isinstance(container, Mapping):
|
|
84
|
+
kv_pairs: Iterable[Tuple[Any, Any]] = container.items()
|
|
85
|
+
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
|
+
kv_pairs = enumerate(container)
|
|
94
|
+
|
|
95
|
+
values_by_type = defaultdict(list)
|
|
96
|
+
values_by_id = {}
|
|
97
|
+
keys_by_value_id = defaultdict(list)
|
|
98
|
+
symbolic_for_pytype = space.extra(ModelingDirector).choose
|
|
99
|
+
for cur_key, cur_value in kv_pairs:
|
|
100
|
+
if (
|
|
101
|
+
isinstance(cur_value, AtomicSymbolicValue)
|
|
102
|
+
or type(cur_value) in python_types_using_atomic_symbolics()
|
|
103
|
+
):
|
|
104
|
+
pytype = (
|
|
105
|
+
cur_value._pytype()
|
|
106
|
+
if isinstance(cur_value, AtomicSymbolicValue)
|
|
107
|
+
else type(cur_value)
|
|
108
|
+
)
|
|
109
|
+
# Some types like real-based float and symbolic types don't cover all values:
|
|
110
|
+
if (
|
|
111
|
+
symbolic_for_pytype(pytype)._smt_promote_literal(cur_value)
|
|
112
|
+
is not None
|
|
113
|
+
):
|
|
114
|
+
values_by_type[pytype].append((cur_key, cur_value))
|
|
115
|
+
continue
|
|
116
|
+
# No symbolics cover this value, but we might still find repeated values:
|
|
117
|
+
values_by_id[id(cur_value)] = cur_value
|
|
118
|
+
keys_by_value_id[id(cur_value)].append(cur_key)
|
|
119
|
+
for value_type, cur_pairs in values_by_type.items():
|
|
120
|
+
hypothetical_result = symbolic_for_pytype(value_type)(
|
|
121
|
+
"item_at_" + space.uniq(), value_type
|
|
122
|
+
)
|
|
123
|
+
with ResumedTracing():
|
|
124
|
+
condition_pairs = []
|
|
125
|
+
for cur_key, cur_val in cur_pairs:
|
|
126
|
+
keys_equal = key == cur_key
|
|
127
|
+
values_equal = hypothetical_result == cur_val
|
|
128
|
+
with NoTracing():
|
|
129
|
+
if isinstance(keys_equal, SymbolicBool):
|
|
130
|
+
condition_pairs.append((keys_equal, values_equal))
|
|
131
|
+
elif keys_equal is False:
|
|
132
|
+
pass
|
|
133
|
+
else:
|
|
134
|
+
# (because the key must be symbolic, we don't ever expect raw True)
|
|
135
|
+
raise CrossHairInternal(
|
|
136
|
+
f"key comparison type: {type(keys_equal)} {keys_equal}"
|
|
137
|
+
)
|
|
138
|
+
if any(keys_equal for keys_equal, _ in condition_pairs):
|
|
139
|
+
space.add(any([all(pair) for pair in condition_pairs]))
|
|
140
|
+
return hypothetical_result
|
|
141
|
+
|
|
142
|
+
for (value_id, value), probability_true in with_uniform_probabilities(
|
|
143
|
+
values_by_id.items()
|
|
144
|
+
):
|
|
145
|
+
keys_for_value = keys_by_value_id[value_id]
|
|
146
|
+
with ResumedTracing():
|
|
147
|
+
is_match = any([key == k for k in keys_for_value])
|
|
148
|
+
if isinstance(is_match, SymbolicBool):
|
|
149
|
+
if space.smt_fork(
|
|
150
|
+
is_match.var,
|
|
151
|
+
probability_true=probability_true,
|
|
152
|
+
):
|
|
153
|
+
return value
|
|
154
|
+
elif is_match:
|
|
155
|
+
return value
|
|
156
|
+
|
|
157
|
+
if type(container) is dict:
|
|
158
|
+
raise KeyError # ( f"Key {key} not found in dict")
|
|
159
|
+
else:
|
|
160
|
+
raise IndexError # (f"Index {key} out of range for list/tuple of length {len(container)}")
|
|
161
|
+
|
|
162
|
+
|
|
63
163
|
class SymbolicSubscriptInterceptor(TracingModule):
|
|
64
164
|
opcodes_wanted = frozenset([BINARY_SUBSCR, BINARY_OP])
|
|
65
165
|
|
|
66
166
|
def trace_op(self, frame, codeobj, codenum):
|
|
67
|
-
# Note that because this is called from inside a Python trace handler, tracing
|
|
68
|
-
# is automatically disabled, so there's no need for a `with NoTracing():` guard.
|
|
69
|
-
|
|
70
167
|
if codenum == BINARY_OP:
|
|
71
168
|
oparg = frame_op_arg(frame)
|
|
72
169
|
if oparg != 26: # subscript operator, NB_SUBSCR
|
|
@@ -78,7 +175,14 @@ class SymbolicSubscriptInterceptor(TracingModule):
|
|
|
78
175
|
# If we got this far, the index is likely symbolic (or perhaps a slice object)
|
|
79
176
|
container = frame_stack_read(frame, -2)
|
|
80
177
|
container_type = type(container)
|
|
81
|
-
if
|
|
178
|
+
if isinstance(key, AtomicSymbolicValue) and type(container) in (
|
|
179
|
+
tuple,
|
|
180
|
+
list,
|
|
181
|
+
dict,
|
|
182
|
+
):
|
|
183
|
+
wrapped_container = MultiSubscriptableContainer(container)
|
|
184
|
+
frame_stack_write(frame, -2, wrapped_container)
|
|
185
|
+
elif container_type is dict:
|
|
82
186
|
# SimpleDict won't hash the keys it's given!
|
|
83
187
|
wrapped_dict = SimpleDict(list(container.items()))
|
|
84
188
|
frame_stack_write(frame, -2, wrapped_dict)
|
|
@@ -90,41 +194,6 @@ class SymbolicSubscriptInterceptor(TracingModule):
|
|
|
90
194
|
if isinstance(start, SymbolicInt) or isinstance(stop, SymbolicInt):
|
|
91
195
|
view_wrapper = SliceView(container, 0, len(container))
|
|
92
196
|
frame_stack_write(frame, -2, SymbolicList(view_wrapper))
|
|
93
|
-
elif container_type is list or container_type is tuple:
|
|
94
|
-
if not isinstance(key, SymbolicInt):
|
|
95
|
-
return
|
|
96
|
-
# We can't stay symbolic with a concrete list and symbolic numeric index.
|
|
97
|
-
# But we can make the choice evenly and combine duplicate values, if any.
|
|
98
|
-
|
|
99
|
-
space = context_statespace()
|
|
100
|
-
in_bounds = space.smt_fork(
|
|
101
|
-
z3Or(-len(container) <= key.var, key.var < len(container)),
|
|
102
|
-
desc=f"index_in_bounds",
|
|
103
|
-
probability_true=0.9,
|
|
104
|
-
)
|
|
105
|
-
if not in_bounds:
|
|
106
|
-
return
|
|
107
|
-
# TODO: `container` should be the same (per path node) on every run;
|
|
108
|
-
# it would be great to cache this computation somehow.
|
|
109
|
-
indices = {}
|
|
110
|
-
for idx, value in enumerate(container):
|
|
111
|
-
value_id = id(value)
|
|
112
|
-
if value_id in indices:
|
|
113
|
-
indices[value_id].append(idx)
|
|
114
|
-
else:
|
|
115
|
-
indices[value_id] = [idx]
|
|
116
|
-
for value_id, probability_true in with_uniform_probabilities(
|
|
117
|
-
indices.keys()
|
|
118
|
-
):
|
|
119
|
-
indices_with_value = indices[value_id]
|
|
120
|
-
if space.smt_fork(
|
|
121
|
-
z3Or(*[key.var == i for i in indices_with_value]),
|
|
122
|
-
desc=f"index_to_{'_or_'.join(map(str, indices_with_value))}",
|
|
123
|
-
probability_true=probability_true,
|
|
124
|
-
):
|
|
125
|
-
# avoids realization of `key` in case `container` has duplicates
|
|
126
|
-
frame_stack_write(frame, -1, indices_with_value[0])
|
|
127
|
-
break
|
|
128
197
|
|
|
129
198
|
|
|
130
199
|
class SymbolicSliceInterceptor(TracingModule):
|
|
@@ -1,10 +1,19 @@
|
|
|
1
|
+
import math
|
|
1
2
|
import sys
|
|
3
|
+
from abc import ABCMeta
|
|
2
4
|
from typing import List, Set
|
|
3
5
|
|
|
4
6
|
import pytest
|
|
5
7
|
|
|
6
8
|
from crosshair.core_and_libs import NoTracing, proxy_for_type, standalone_statespace
|
|
7
|
-
from crosshair.
|
|
9
|
+
from crosshair.libimpl.builtinslib import (
|
|
10
|
+
ModelingDirector,
|
|
11
|
+
RealBasedSymbolicFloat,
|
|
12
|
+
SymbolicBool,
|
|
13
|
+
SymbolicInt,
|
|
14
|
+
SymbolicType,
|
|
15
|
+
)
|
|
16
|
+
from crosshair.statespace import POST_FAIL
|
|
8
17
|
from crosshair.test_util import check_states
|
|
9
18
|
from crosshair.tracers import ResumedTracing
|
|
10
19
|
from crosshair.z3util import z3And
|
|
@@ -23,7 +32,73 @@ def test_dict_index():
|
|
|
23
32
|
check_states(numstr, POST_FAIL)
|
|
24
33
|
|
|
25
34
|
|
|
26
|
-
def
|
|
35
|
+
def test_dict_index_without_realization(space):
|
|
36
|
+
class WithMeta(metaclass=ABCMeta):
|
|
37
|
+
pass
|
|
38
|
+
|
|
39
|
+
space.extra(ModelingDirector).global_representations[float] = RealBasedSymbolicFloat
|
|
40
|
+
a = {
|
|
41
|
+
-1: WithMeta,
|
|
42
|
+
# ^ tests regression: isinstance(WithMeta(), type) but type(WithMeta) != type
|
|
43
|
+
0: list,
|
|
44
|
+
1.0: 10.0,
|
|
45
|
+
2: 20,
|
|
46
|
+
3: 30,
|
|
47
|
+
4: 40,
|
|
48
|
+
("complex", "key"): 50,
|
|
49
|
+
6: math.inf,
|
|
50
|
+
7: math.inf,
|
|
51
|
+
}
|
|
52
|
+
int_key = proxy_for_type(int, "int_key")
|
|
53
|
+
int_key2 = proxy_for_type(int, "int_key2")
|
|
54
|
+
int_key3 = proxy_for_type(int, "int_key3")
|
|
55
|
+
float_key = RealBasedSymbolicFloat("float_key")
|
|
56
|
+
float_key2 = RealBasedSymbolicFloat("float_key2")
|
|
57
|
+
with ResumedTracing():
|
|
58
|
+
# Try some concrete values out first:
|
|
59
|
+
assert a[("complex", "key")] == 50
|
|
60
|
+
assert a[6] == float("inf")
|
|
61
|
+
try:
|
|
62
|
+
a[42]
|
|
63
|
+
assert False, "Expected KeyError for missing key 42"
|
|
64
|
+
except KeyError:
|
|
65
|
+
pass
|
|
66
|
+
|
|
67
|
+
space.add(2 <= int_key)
|
|
68
|
+
space.add(int_key <= 4)
|
|
69
|
+
int_result = a[int_key]
|
|
70
|
+
assert space.is_possible(int_result == 20)
|
|
71
|
+
assert space.is_possible(int_result == 40)
|
|
72
|
+
assert not space.is_possible(int_result == 10)
|
|
73
|
+
space.add(float_key == 1.0)
|
|
74
|
+
float_result = a[float_key]
|
|
75
|
+
assert space.is_possible(float_result == 10.0)
|
|
76
|
+
assert not space.is_possible(float_result == 42.0)
|
|
77
|
+
space.add(float_key2 == 2.0)
|
|
78
|
+
float_result2 = a[float_key2]
|
|
79
|
+
assert space.is_possible(float_result2 == 20)
|
|
80
|
+
space.add(int_key2 == 0)
|
|
81
|
+
int_result2 = a[int_key2]
|
|
82
|
+
assert int_result2 == list
|
|
83
|
+
space.add(any([int_key3 == 6, int_key3 == 7]))
|
|
84
|
+
inf_result = a[int_key3]
|
|
85
|
+
assert inf_result is math.inf
|
|
86
|
+
assert isinstance(int_result, SymbolicInt)
|
|
87
|
+
assert isinstance(float_result, RealBasedSymbolicFloat)
|
|
88
|
+
assert isinstance(float_result2, SymbolicInt)
|
|
89
|
+
assert isinstance(int_result2, SymbolicType)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def test_dict_symbolic_index_miss(space):
|
|
93
|
+
a = {6: 60, 7: 70}
|
|
94
|
+
x = proxy_for_type(int, "x")
|
|
95
|
+
with ResumedTracing():
|
|
96
|
+
space.add(x <= 4)
|
|
97
|
+
with pytest.raises(KeyError):
|
|
98
|
+
result = a[x]
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def test_concrete_list_with_symbolic_index_simple(space):
|
|
27
102
|
haystack = [False] * 13 + [True] + [False] * 11
|
|
28
103
|
|
|
29
104
|
idx = proxy_for_type(int, "idx")
|
|
@@ -31,8 +106,12 @@ def test_concrete_list_with_symbolic_index_deduplicates_values(space):
|
|
|
31
106
|
space.add(0 <= idx)
|
|
32
107
|
space.add(idx < len(haystack))
|
|
33
108
|
ret = haystack[idx]
|
|
34
|
-
|
|
35
|
-
|
|
109
|
+
assert isinstance(ret, SymbolicBool)
|
|
110
|
+
with ResumedTracing():
|
|
111
|
+
assert space.is_possible(idx == 13)
|
|
112
|
+
assert space.is_possible(idx == 12)
|
|
113
|
+
space.add(ret)
|
|
114
|
+
assert not space.is_possible(idx == 12)
|
|
36
115
|
|
|
37
116
|
|
|
38
117
|
def test_concrete_list_with_symbolic_index_unhashable_values(space):
|
|
@@ -204,5 +283,6 @@ def test_identity_operator_does_not_realize_on_differing_types():
|
|
|
204
283
|
b1 = proxy_for_type(bool, "b1")
|
|
205
284
|
choices_made_at_start = len(space.choices_made)
|
|
206
285
|
space.add(b1)
|
|
207
|
-
|
|
286
|
+
fourty_two = 42 # assignment just to avoid lint errors
|
|
287
|
+
b1 is fourty_two
|
|
208
288
|
assert len(space.choices_made) == choices_made_at_start
|
crosshair/statespace.py
CHANGED
|
@@ -743,11 +743,13 @@ class StateSpace:
|
|
|
743
743
|
model_check_timeout: float,
|
|
744
744
|
search_root: RootNode,
|
|
745
745
|
):
|
|
746
|
-
smt_timeout = model_check_timeout * 1000 + 1
|
|
747
746
|
smt_tactic = z3.Tactic("smt")
|
|
748
|
-
if smt_timeout < 1 << 63:
|
|
749
|
-
smt_tactic = z3.TryFor(smt_tactic, int(smt_timeout))
|
|
750
747
|
self.solver = smt_tactic.solver()
|
|
748
|
+
if model_check_timeout < 1 << 63:
|
|
749
|
+
self.smt_timeout: Optional[int] = int(model_check_timeout * 1000 + 1)
|
|
750
|
+
self.solver.set(timeout=self.smt_timeout)
|
|
751
|
+
else:
|
|
752
|
+
self.smt_timeout = None
|
|
751
753
|
self.solver.set(mbqi=True)
|
|
752
754
|
# turn off every randomization thing we can think of:
|
|
753
755
|
self.solver.set("random-seed", 42)
|
|
@@ -1097,7 +1099,10 @@ class StateSpace:
|
|
|
1097
1099
|
else:
|
|
1098
1100
|
# Give ourselves a time extension for deferred assumptions and
|
|
1099
1101
|
# (likely) counterexample generation to follow.
|
|
1100
|
-
self.execution_deadline +=
|
|
1102
|
+
self.execution_deadline += 4.0
|
|
1103
|
+
if self.smt_timeout is not None:
|
|
1104
|
+
self.smt_timeout = self.smt_timeout * 2
|
|
1105
|
+
self.solver.set(timeout=self.smt_timeout)
|
|
1101
1106
|
for description, checker in self._deferred_assumptions:
|
|
1102
1107
|
with ResumedTracing():
|
|
1103
1108
|
check_ret = checker()
|
crosshair/util.py
CHANGED
|
@@ -180,7 +180,9 @@ class IdKeyedDict(collections.abc.MutableMapping):
|
|
|
180
180
|
return self.inner.__delitem__(id(k))
|
|
181
181
|
|
|
182
182
|
def __iter__(self):
|
|
183
|
-
|
|
183
|
+
raise NotImplementedError
|
|
184
|
+
# No use cases for this yet, but we could do something like this:
|
|
185
|
+
# return (actual_key_object for actual_key_object, _ in self.inner.values())
|
|
184
186
|
|
|
185
187
|
def __len__(self):
|
|
186
188
|
return len(self.inner)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
_crosshair_tracers.cpython-313-darwin.so,sha256=
|
|
1
|
+
_crosshair_tracers.cpython-313-darwin.so,sha256=S6wfN7eGUhzJWCEJJ1_HwxCpRs3aD7uj9or1cw7noXs,49912
|
|
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
|
|
@@ -13,7 +13,7 @@ crosshair/dynamic_typing_test.py,sha256=oyg94OXjF_2jNFy33UJjkfWnDXKnM4or2TXbxrOq
|
|
|
13
13
|
crosshair/enforce.py,sha256=FsZx3D-KtGrhb8xdAZbPUtwvVmEu8IAn7rwf7tmkrRY,10010
|
|
14
14
|
crosshair/path_search_test.py,sha256=7cqzAMXUYAtA00mq9XR5AaZChqeQyXyCfuuv53_51pk,1692
|
|
15
15
|
crosshair/condition_parser.py,sha256=oquaht026eZUigh2lyaFLXYDbmENdBKjddszx0a-B3w,42647
|
|
16
|
-
crosshair/util.py,sha256=
|
|
16
|
+
crosshair/util.py,sha256=eddHHvkn9NnsfYahpuIF4Xp03kIiQ8EJUaliFEO4XG4,22124
|
|
17
17
|
crosshair/dynamic_typing.py,sha256=jbI9FXv5-WXREQjeDtlDQladv-xCW21TUOM3qErJaJ4,11998
|
|
18
18
|
crosshair/register_contract.py,sha256=EnDAxngJhKvJLFdw5kVgqaYDQ5hAZXKwAGBdXpot-AQ,10386
|
|
19
19
|
crosshair/tracers.py,sha256=_jaSDgZ_pYdqacWE_msXn7W7CoSdQ_-7hlrxa891oHo,17139
|
|
@@ -23,7 +23,7 @@ crosshair/fnutil.py,sha256=X80bD2Lh4QAh-rF561r3JRxjxcuZepF3hJaxaj1GG9s,13123
|
|
|
23
23
|
crosshair/unicode_categories.py,sha256=g4pnUPanx8KkpwI06ZUGx8GR8Myruf_EpTjyti_V4z8,333519
|
|
24
24
|
crosshair/copyext.py,sha256=GBGQP9YAHoezLXwb_M59Hh1VXSou5EQt4ZmmUA0T_og,4899
|
|
25
25
|
crosshair/_tracers_test.py,sha256=KpCGspjOUeZuhwTYgn_RxI4M4wMbT5rldusFDgneQ6M,3596
|
|
26
|
-
crosshair/__init__.py,sha256=
|
|
26
|
+
crosshair/__init__.py,sha256=BqE2fB9um9PltLa0yX7EVsyAzVpgDe5EBvIiEhQ2exI,936
|
|
27
27
|
crosshair/core.py,sha256=K7147xrvcvtrP1T9oIRywq2uHMMsIu8ZwFZWBQXPozg,63634
|
|
28
28
|
crosshair/path_cover.py,sha256=wV0Vy8IPDzqXQ2VI8a94FxltS9p-Y1oF17OKePjvpgs,6710
|
|
29
29
|
crosshair/enforce_test.py,sha256=C6CQ4P1FjkdIJeJg3aJynp1iLDCE6BFCEVtSqXbvmQk,4665
|
|
@@ -53,13 +53,13 @@ crosshair/path_search.py,sha256=wwZjp-3E4dENnJa6BlnSq8FARkIx0PyUYc7kvH32A2k,5588
|
|
|
53
53
|
crosshair/auditwall_test.py,sha256=VPcw_OW3nl3BkOZY4wEEtVDyTamdgqD4IjRccI2p5vI,2030
|
|
54
54
|
crosshair/smtlib_test.py,sha256=edzEn19u2YYHxSzG9RrMiu2HTiEexAuehC3IlG9LuJM,511
|
|
55
55
|
crosshair/register_contract_test.py,sha256=DhvKIcF3LgQfHfUSCccoA11ctCdFaQR263Pc4YUuxyk,4970
|
|
56
|
-
crosshair/statespace.py,sha256=
|
|
57
|
-
crosshair/opcode_intercept_test.py,sha256=
|
|
56
|
+
crosshair/statespace.py,sha256=KeIIBwBKxDgQO0ML2LvYXhS5DgmelaYF-RRXopR9lqA,41794
|
|
57
|
+
crosshair/opcode_intercept_test.py,sha256=hBf04VwhaIzPdoAaqQmQJfx36yaznD9sm9x1Lb9VDm8,8790
|
|
58
58
|
crosshair/main_test.py,sha256=DFXtE--616vCF1WAS576SHXO19K0LsDPzJIWNT5vuXM,14383
|
|
59
59
|
crosshair/codeconfig_test.py,sha256=RnC-RnNpr6If4eHmOepDZ33MCmfyhup08dzHKCm5xWA,3350
|
|
60
60
|
crosshair/watcher.py,sha256=kCCMlLe2KhW5MbEbMmixNRjRAvu5CypIAGd1V_YZ9QM,10048
|
|
61
61
|
crosshair/test_util_test.py,sha256=FIOWVBMiF-zyq0pGsDQ8W6lB6_E9sGpD80dioHHETyQ,512
|
|
62
|
-
crosshair/opcode_intercept.py,sha256=
|
|
62
|
+
crosshair/opcode_intercept.py,sha256=z4Yb9prYE2UK21AxhjAeXyXAk5IriDuCSSCeNhbDu2A,21880
|
|
63
63
|
crosshair/simplestructs.py,sha256=CiZSuHH_j_bYitaW-n7vWd_42xSyV6Jh8es3BQLlcHk,34221
|
|
64
64
|
crosshair/tracers_test.py,sha256=EBK_ZCy2MsxqmEaGjo0uw9zAztW9O6fhCW_0PJxyTS8,3270
|
|
65
65
|
crosshair/smtlib.py,sha256=hh-P32KHoH9BCq3oDYGp2PfOeOb8CwDj8tTkgqroLD8,689
|
|
@@ -107,13 +107,13 @@ crosshair/libimpl/binascii_test.py,sha256=LOBqLAJ77Kx8vorjVTaT3X0Z93zw4P5BvwUapM
|
|
|
107
107
|
crosshair/libimpl/collectionslib_test.py,sha256=3h7XTToKWauMhjrEwLXVI0jT8FZKBlkvlw0oiPMmuKM,9164
|
|
108
108
|
crosshair/libimpl/timelib.py,sha256=MXEFOZjFGa1-yLvmB3l3DFTLF9PSluOlmRK-ZJaA_oI,2409
|
|
109
109
|
crosshair/libimpl/jsonlib_test.py,sha256=U40WJf-69dtflz75sIsl5zA3IV5R6Ltc4Z9jv_Fh-Fw,1382
|
|
110
|
-
crosshair/libimpl/builtinslib.py,sha256=
|
|
110
|
+
crosshair/libimpl/builtinslib.py,sha256=9qAV1xZ2oZrIrpfWQ3BXgnY0nK2Gjov4v207x43lTq4,171629
|
|
111
111
|
crosshair/libimpl/mathlib_test.py,sha256=QShLCXHdv3tx5PQxcSoR0MHeZ1huaiV6d3u7C2mGOn4,1861
|
|
112
112
|
crosshair/libimpl/fractionlib.py,sha256=qdbiAHHC480YdKq3wYK_piZ3UD7oT64YfuNclypMUfQ,458
|
|
113
113
|
crosshair/libimpl/binascii_ch_test.py,sha256=hFqSfF1Q8jl2LNBIWaQ6vBJIIshPOmSwrR0T1Ko4Leo,1009
|
|
114
114
|
crosshair/libimpl/jsonlib.py,sha256=xFTvqGKzQcCgPme1WIpNMjBPfNHVZBMNuNx0uKMYXj0,28805
|
|
115
|
-
crosshair/libimpl/typeslib_test.py,sha256=
|
|
116
|
-
crosshair/libimpl/builtinslib_test.py,sha256=
|
|
115
|
+
crosshair/libimpl/typeslib_test.py,sha256=qCeUU_c-zmuvfwHEsaYqic9wdGzs9XbDZNr6bF2Xp58,1129
|
|
116
|
+
crosshair/libimpl/builtinslib_test.py,sha256=Q0DvH7Q_Ja0Tg83enhB_y_Pdau_S-bA6ztorjvgl4Mw,90275
|
|
117
117
|
crosshair/libimpl/zliblib.py,sha256=XymJTKYbplpYJZ-P7GKVSY3V_8HPy5lqRFsCH1zezIk,357
|
|
118
118
|
crosshair/libimpl/decimallib.py,sha256=zBKDrDZcg45oCKUkf6SIDuVpjA1Web7tD1MEQo5cjxI,177348
|
|
119
119
|
crosshair/libimpl/relib_ch_test.py,sha256=zvSBF82mNQR5yEOMwwcaBOh8OpJkQeiVl85pgYVvJRA,5235
|
|
@@ -166,9 +166,9 @@ crosshair/libimpl/encodings/ascii.py,sha256=Cz1xraTkXdQ5aBKDkorX4rAvrmf877_EqzC9
|
|
|
166
166
|
crosshair/libimpl/encodings/__init__.py,sha256=5LTEj1M-S00eZ4rfQWczAixg57vyh_9vZ5m5EKB5Ksc,680
|
|
167
167
|
crosshair/libimpl/encodings/latin_1.py,sha256=ftUsPjUb9L7UKXKi9P7OAqOl9FkNP98M9jMAvseXBCQ,1242
|
|
168
168
|
crosshair/libimpl/encodings/_encutil.py,sha256=nwVWqcGM1f7-hAC3Z46KnfrLzAjhfy4zaTa11uVBk6M,6828
|
|
169
|
-
crosshair_tool-0.0.
|
|
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.
|
|
169
|
+
crosshair_tool-0.0.86.dist-info/RECORD,,
|
|
170
|
+
crosshair_tool-0.0.86.dist-info/WHEEL,sha256=D5oYZcu7xsHPQ1lvRcEfimRZkYr_RmvD7J5S2QmS8s0,138
|
|
171
|
+
crosshair_tool-0.0.86.dist-info/entry_points.txt,sha256=u5FIPVn1jqn4Kzg5K_iNnbP6L4hQw5FWjQ0UMezG2VE,96
|
|
172
|
+
crosshair_tool-0.0.86.dist-info/top_level.txt,sha256=2jLWtM-BWg_ZYNbNfrcds0HFZD62a6J7ZIbcgcQrRk4,29
|
|
173
|
+
crosshair_tool-0.0.86.dist-info/METADATA,sha256=8n0ualxjh4y_waUzDZfliJjet2bID8tHk6kQIiwX2-M,6717
|
|
174
|
+
crosshair_tool-0.0.86.dist-info/licenses/LICENSE,sha256=NVyMvNqn1pH6RSHs6RWRcJyJvORnpgGFBlF73buqYJ0,4459
|
|
File without changes
|
|
File without changes
|
|
File without changes
|