crosshair-tool 0.0.56__cp39-cp39-macosx_11_0_arm64.whl → 0.0.100__cp39-cp39-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.
Files changed (123) hide show
  1. _crosshair_tracers.cpython-39-darwin.so +0 -0
  2. crosshair/__init__.py +1 -1
  3. crosshair/_mark_stacks.h +51 -24
  4. crosshair/_tracers.h +9 -5
  5. crosshair/_tracers_test.py +19 -9
  6. crosshair/auditwall.py +9 -8
  7. crosshair/auditwall_test.py +31 -19
  8. crosshair/codeconfig.py +3 -2
  9. crosshair/condition_parser.py +17 -133
  10. crosshair/condition_parser_test.py +54 -96
  11. crosshair/conftest.py +1 -1
  12. crosshair/copyext.py +91 -22
  13. crosshair/copyext_test.py +33 -0
  14. crosshair/core.py +259 -203
  15. crosshair/core_and_libs.py +20 -0
  16. crosshair/core_regestered_types_test.py +82 -0
  17. crosshair/core_test.py +693 -664
  18. crosshair/diff_behavior.py +76 -21
  19. crosshair/diff_behavior_test.py +132 -23
  20. crosshair/dynamic_typing.py +128 -18
  21. crosshair/dynamic_typing_test.py +91 -4
  22. crosshair/enforce.py +1 -6
  23. crosshair/enforce_test.py +15 -23
  24. crosshair/examples/check_examples_test.py +2 -1
  25. crosshair/fnutil.py +2 -3
  26. crosshair/fnutil_test.py +0 -7
  27. crosshair/fuzz_core_test.py +70 -83
  28. crosshair/libimpl/arraylib.py +10 -7
  29. crosshair/libimpl/binascii_ch_test.py +30 -0
  30. crosshair/libimpl/binascii_test.py +67 -0
  31. crosshair/libimpl/binasciilib.py +150 -0
  32. crosshair/libimpl/bisectlib_test.py +5 -5
  33. crosshair/libimpl/builtinslib.py +1002 -682
  34. crosshair/libimpl/builtinslib_ch_test.py +108 -30
  35. crosshair/libimpl/builtinslib_test.py +431 -143
  36. crosshair/libimpl/codecslib.py +22 -2
  37. crosshair/libimpl/codecslib_test.py +41 -9
  38. crosshair/libimpl/collectionslib.py +44 -8
  39. crosshair/libimpl/collectionslib_test.py +108 -20
  40. crosshair/libimpl/copylib.py +1 -1
  41. crosshair/libimpl/copylib_test.py +18 -0
  42. crosshair/libimpl/datetimelib.py +84 -67
  43. crosshair/libimpl/datetimelib_ch_test.py +12 -7
  44. crosshair/libimpl/datetimelib_test.py +5 -6
  45. crosshair/libimpl/decimallib.py +5257 -0
  46. crosshair/libimpl/decimallib_ch_test.py +78 -0
  47. crosshair/libimpl/decimallib_test.py +76 -0
  48. crosshair/libimpl/encodings/_encutil.py +21 -11
  49. crosshair/libimpl/fractionlib.py +16 -0
  50. crosshair/libimpl/fractionlib_test.py +80 -0
  51. crosshair/libimpl/functoolslib.py +19 -7
  52. crosshair/libimpl/functoolslib_test.py +22 -6
  53. crosshair/libimpl/hashliblib.py +30 -0
  54. crosshair/libimpl/hashliblib_test.py +18 -0
  55. crosshair/libimpl/heapqlib.py +32 -5
  56. crosshair/libimpl/heapqlib_test.py +15 -12
  57. crosshair/libimpl/iolib.py +7 -4
  58. crosshair/libimpl/ipaddresslib.py +8 -0
  59. crosshair/libimpl/itertoolslib_test.py +1 -1
  60. crosshair/libimpl/mathlib.py +165 -2
  61. crosshair/libimpl/mathlib_ch_test.py +44 -0
  62. crosshair/libimpl/mathlib_test.py +59 -16
  63. crosshair/libimpl/oslib.py +7 -0
  64. crosshair/libimpl/pathliblib_test.py +10 -0
  65. crosshair/libimpl/randomlib.py +1 -0
  66. crosshair/libimpl/randomlib_test.py +6 -4
  67. crosshair/libimpl/relib.py +180 -59
  68. crosshair/libimpl/relib_ch_test.py +26 -2
  69. crosshair/libimpl/relib_test.py +77 -14
  70. crosshair/libimpl/timelib.py +35 -13
  71. crosshair/libimpl/timelib_test.py +13 -3
  72. crosshair/libimpl/typeslib.py +15 -0
  73. crosshair/libimpl/typeslib_test.py +36 -0
  74. crosshair/libimpl/unicodedatalib_test.py +3 -3
  75. crosshair/libimpl/weakreflib.py +13 -0
  76. crosshair/libimpl/weakreflib_test.py +69 -0
  77. crosshair/libimpl/zliblib.py +15 -0
  78. crosshair/libimpl/zliblib_test.py +13 -0
  79. crosshair/lsp_server.py +21 -10
  80. crosshair/main.py +48 -28
  81. crosshair/main_test.py +59 -14
  82. crosshair/objectproxy.py +39 -14
  83. crosshair/objectproxy_test.py +27 -13
  84. crosshair/opcode_intercept.py +212 -24
  85. crosshair/opcode_intercept_test.py +172 -18
  86. crosshair/options.py +0 -1
  87. crosshair/patch_equivalence_test.py +5 -21
  88. crosshair/path_cover.py +7 -5
  89. crosshair/path_search.py +6 -4
  90. crosshair/path_search_test.py +1 -2
  91. crosshair/pathing_oracle.py +53 -10
  92. crosshair/pathing_oracle_test.py +21 -0
  93. crosshair/pure_importer_test.py +5 -21
  94. crosshair/register_contract.py +16 -6
  95. crosshair/register_contract_test.py +2 -14
  96. crosshair/simplestructs.py +154 -85
  97. crosshair/simplestructs_test.py +16 -2
  98. crosshair/smtlib.py +24 -0
  99. crosshair/smtlib_test.py +14 -0
  100. crosshair/statespace.py +319 -196
  101. crosshair/statespace_test.py +45 -0
  102. crosshair/stubs_parser.py +0 -2
  103. crosshair/test_util.py +87 -25
  104. crosshair/test_util_test.py +26 -0
  105. crosshair/tools/check_init_and_setup_coincide.py +0 -3
  106. crosshair/tools/generate_demo_table.py +2 -2
  107. crosshair/tracers.py +141 -49
  108. crosshair/type_repo.py +11 -4
  109. crosshair/unicode_categories.py +1 -0
  110. crosshair/util.py +158 -76
  111. crosshair/util_test.py +13 -20
  112. crosshair/watcher.py +4 -4
  113. crosshair/z3util.py +1 -1
  114. {crosshair_tool-0.0.56.dist-info → crosshair_tool-0.0.100.dist-info}/METADATA +45 -36
  115. crosshair_tool-0.0.100.dist-info/RECORD +176 -0
  116. {crosshair_tool-0.0.56.dist-info → crosshair_tool-0.0.100.dist-info}/WHEEL +2 -1
  117. crosshair/examples/hypothesis/__init__.py +0 -2
  118. crosshair/examples/hypothesis/bugs_detected/simple_strategies.py +0 -74
  119. crosshair_tool-0.0.56.dist-info/RECORD +0 -152
  120. /crosshair/{examples/hypothesis/bugs_detected/__init__.py → py.typed} +0 -0
  121. {crosshair_tool-0.0.56.dist-info → crosshair_tool-0.0.100.dist-info}/entry_points.txt +0 -0
  122. {crosshair_tool-0.0.56.dist-info → crosshair_tool-0.0.100.dist-info/licenses}/LICENSE +0 -0
  123. {crosshair_tool-0.0.56.dist-info → crosshair_tool-0.0.100.dist-info}/top_level.txt +0 -0
@@ -1,16 +1,179 @@
1
1
  import math
2
+ import sys
3
+ from numbers import Real
4
+
5
+ import z3 # type: ignore
2
6
 
3
7
  from crosshair import NoTracing, register_patch
4
- from crosshair.libimpl.builtinslib import SymbolicNumberAble
8
+ from crosshair.core import with_realized_args
9
+ from crosshair.libimpl.builtinslib import (
10
+ PreciseIeeeSymbolicFloat,
11
+ RealBasedSymbolicFloat,
12
+ SymbolicBool,
13
+ SymbolicIntable,
14
+ SymbolicValue,
15
+ smt_xor,
16
+ )
17
+ from crosshair.tracers import ResumedTracing
18
+ from crosshair.util import name_of_type
19
+ from crosshair.z3util import z3Not, z3Or
20
+
21
+
22
+ def _is_positive(x):
23
+ if isinstance(x, SymbolicValue):
24
+ if isinstance(x, PreciseIeeeSymbolicFloat):
25
+ return SymbolicBool(z3Not(z3.fpIsNegative(x.var)))
26
+ elif isinstance(x, RealBasedSymbolicFloat):
27
+ return SymbolicBool(x.var >= 0)
28
+ else:
29
+ with ResumedTracing():
30
+ return x >= 0
31
+ else:
32
+ return math.copysign(1, x) == 1
33
+
34
+
35
+ def _copysign(x, y):
36
+ if not isinstance(x, Real):
37
+ raise TypeError(f"must be real number, not {name_of_type(type(x))}")
38
+ if not isinstance(y, Real):
39
+ raise TypeError(f"must be real number, not {name_of_type(type(y))}")
40
+ with NoTracing():
41
+ x_is_positive = _is_positive(x)
42
+ y_is_positive = _is_positive(y)
43
+ # then invert as needed:
44
+ invert = smt_xor(x_is_positive, y_is_positive)
45
+ with NoTracing():
46
+ if isinstance(invert, SymbolicBool) and isinstance(
47
+ x, (PreciseIeeeSymbolicFloat, RealBasedSymbolicFloat)
48
+ ):
49
+ return type(x)(z3.If(invert.var, -x.var, x.var))
50
+ with ResumedTracing():
51
+ return -x if invert else x
52
+
53
+
54
+ if sys.version_info >= (3, 9):
55
+
56
+ def _gcd(a=0, b=0):
57
+ while b:
58
+ a, b = b, a % b
59
+ return abs(a)
60
+
61
+ else: # (arguments were required in Python <= 3.8)
62
+
63
+ def _gcd(a, b):
64
+ while b:
65
+ a, b = b, a % b
66
+ return abs(a)
5
67
 
6
68
 
7
69
  def _isfinite(x):
8
70
  with NoTracing():
9
- if isinstance(x, SymbolicNumberAble):
71
+ if isinstance(x, (SymbolicIntable, RealBasedSymbolicFloat)):
10
72
  return True
73
+ elif isinstance(x, PreciseIeeeSymbolicFloat):
74
+ return SymbolicBool(z3Not(z3Or(z3.fpIsNaN(x.var), z3.fpIsInf(x.var))))
11
75
  else:
12
76
  return math.isfinite(x)
13
77
 
14
78
 
79
+ def _isnan(x):
80
+ with NoTracing():
81
+ if isinstance(x, (SymbolicIntable, RealBasedSymbolicFloat)):
82
+ return False
83
+ elif isinstance(x, PreciseIeeeSymbolicFloat):
84
+ return SymbolicBool(z3.fpIsNaN(x.var))
85
+ else:
86
+ return math.isnan(x)
87
+
88
+
89
+ def _isinf(x):
90
+ with NoTracing():
91
+ if isinstance(x, (SymbolicIntable, RealBasedSymbolicFloat)):
92
+ return False
93
+ elif isinstance(x, PreciseIeeeSymbolicFloat):
94
+ return SymbolicBool(z3.fpIsInf(x.var))
95
+ else:
96
+ return math.isinf(x)
97
+
98
+
99
+ _FUNCTIONS_WITH_REALIZATION = [
100
+ # TODO: we could attempt to implement some of these in the SMT solver
101
+ "acos",
102
+ "acosh",
103
+ "asin",
104
+ "asinh",
105
+ "atan",
106
+ "atan2",
107
+ "atanh",
108
+ "ceil",
109
+ "comb",
110
+ "cos",
111
+ "cosh",
112
+ "degrees",
113
+ "dist",
114
+ "erf",
115
+ "erfc",
116
+ "exp",
117
+ "expm1",
118
+ "fabs",
119
+ "factorial",
120
+ "floor",
121
+ "fmod",
122
+ "frexp",
123
+ "fsum",
124
+ "gamma",
125
+ "hypot",
126
+ "isclose",
127
+ "isqrt",
128
+ "ldexp",
129
+ "lgamma",
130
+ "log",
131
+ "log10",
132
+ "log1p",
133
+ "log2",
134
+ "modf",
135
+ "perm",
136
+ "pow",
137
+ "prod",
138
+ "radians",
139
+ "remainder",
140
+ "sin",
141
+ "sinh",
142
+ "sqrt",
143
+ "tan",
144
+ "tanh",
145
+ "trunc",
146
+ ]
147
+
148
+ if sys.version_info >= (3, 9):
149
+ _FUNCTIONS_WITH_REALIZATION.extend(
150
+ [
151
+ "lcm",
152
+ "nextafter",
153
+ "ulp",
154
+ ]
155
+ )
156
+
157
+ if sys.version_info >= (3, 11):
158
+ _FUNCTIONS_WITH_REALIZATION.extend(
159
+ [
160
+ "cbrt",
161
+ "exp2",
162
+ ]
163
+ )
164
+
165
+ if sys.version_info >= (3, 12):
166
+ _FUNCTIONS_WITH_REALIZATION.append("sumprod")
167
+
168
+
15
169
  def make_registrations():
170
+ register_patch(math.copysign, _copysign)
171
+ register_patch(math.gcd, _gcd)
16
172
  register_patch(math.isfinite, _isfinite)
173
+ register_patch(math.isnan, _isnan)
174
+ register_patch(math.isinf, _isinf)
175
+ for fn_name in _FUNCTIONS_WITH_REALIZATION:
176
+ fn = getattr(math, fn_name)
177
+ register_patch(
178
+ fn, with_realized_args(fn, deep=True)
179
+ ) # deep realization needed for Fraction instances
@@ -0,0 +1,44 @@
1
+ import math
2
+ import sys
3
+ from typing import Union
4
+
5
+ import pytest # type: ignore
6
+
7
+ from crosshair.core import realize
8
+ from crosshair.core_and_libs import MessageType, analyze_function, run_checkables
9
+ from crosshair.options import AnalysisOptionSet
10
+ from crosshair.test_util import compare_results
11
+
12
+
13
+ def check_copysign(
14
+ a: Union[int, float], b: Union[int, float], realize_a: bool, realize_b: bool
15
+ ):
16
+ """post: _"""
17
+ if realize_a:
18
+ a = realize(a)
19
+ if realize_b:
20
+ b = realize(b)
21
+ return compare_results(math.copysign, a, b)
22
+
23
+
24
+ def check_gcd(a: int, b: int):
25
+ """
26
+ pre: all([-10 < a, a < 10, -10 < b, b < 10]) # for performance
27
+ post: _
28
+ """
29
+ return compare_results(math.gcd, a, b)
30
+
31
+
32
+ # This is the only real test definition.
33
+ # It runs crosshair on each of the "check" functions defined above.
34
+ @pytest.mark.parametrize("fn_name", [fn for fn in dir() if fn.startswith("check_")])
35
+ def test_builtin(fn_name: str) -> None:
36
+ this_module = sys.modules[__name__]
37
+ messages = run_checkables(
38
+ analyze_function(
39
+ getattr(this_module, fn_name),
40
+ AnalysisOptionSet(max_uninteresting_iterations=50),
41
+ )
42
+ )
43
+ errors = [m for m in messages if m.state > MessageType.PRE_UNSAT]
44
+ assert errors == []
@@ -1,24 +1,67 @@
1
1
  import math
2
2
  import sys
3
- import unittest
4
3
 
5
- from crosshair.core import standalone_statespace
6
- from crosshair.libimpl.builtinslib import SymbolicFloat
7
- from crosshair.tracers import NoTracing
4
+ import pytest
5
+
6
+ from crosshair.core import proxy_for_type, standalone_statespace
7
+ from crosshair.libimpl.builtinslib import (
8
+ ModelingDirector,
9
+ PreciseIeeeSymbolicFloat,
10
+ RealBasedSymbolicFloat,
11
+ )
12
+ from crosshair.statespace import POST_FAIL
13
+ from crosshair.test_util import check_states
14
+ from crosshair.tracers import NoTracing, ResumedTracing
8
15
  from crosshair.util import set_debug
9
16
 
10
17
 
11
- class MathLibTests(unittest.TestCase):
12
- def test_isfinite(self):
13
- with standalone_statespace:
14
- with NoTracing():
15
- x = SymbolicFloat("symfloat")
16
- self.assertTrue(math.isfinite(x))
17
- self.assertTrue(math.isfinite(2.3))
18
- self.assertFalse(math.isfinite(float("nan")))
18
+ def test_copysign_e2e():
19
+ def can_find_minus_zero(x: float):
20
+ """post: math.copysign(1, _) == 1"""
21
+ if x == 0:
22
+ return x
23
+ return 1
24
+
25
+ check_states(can_find_minus_zero, POST_FAIL)
26
+
27
+
28
+ @pytest.mark.parametrize(
29
+ "FloatType", [PreciseIeeeSymbolicFloat, RealBasedSymbolicFloat]
30
+ )
31
+ def test_copysign_symbolics(FloatType, space):
32
+ space.extra(ModelingDirector).global_representations[float] = FloatType
33
+ x = FloatType("x")
34
+ y = FloatType("y")
35
+ with ResumedTracing():
36
+ assert not space.is_possible(math.copysign(x, -0.0) > 0.0)
37
+ assert space.is_possible(math.copysign(x, y) > 0.0)
38
+ assert space.is_possible(math.copysign(x, y) < 0.0)
39
+
40
+
41
+ def test_isfinite():
42
+ with standalone_statespace:
43
+ with NoTracing():
44
+ x = RealBasedSymbolicFloat("symfloat")
45
+ assert math.isfinite(x)
46
+ assert math.isfinite(2.3)
47
+ assert not math.isfinite(float("nan"))
48
+
49
+
50
+ def test_isinf():
51
+ with standalone_statespace:
52
+ with NoTracing():
53
+ x = RealBasedSymbolicFloat("symfloat")
54
+ assert not math.isinf(x)
55
+ assert not math.isinf(float("nan"))
56
+ assert math.isinf(float("-inf"))
19
57
 
20
58
 
21
- if __name__ == "__main__":
22
- if ("-v" in sys.argv) or ("--verbose" in sys.argv):
23
- set_debug(True)
24
- unittest.main()
59
+ def test_log():
60
+ with standalone_statespace as space:
61
+ with NoTracing():
62
+ i = proxy_for_type(int, "i")
63
+ f = proxy_for_type(float, "f")
64
+ space.add(i > 0)
65
+ space.add(f > 0)
66
+ math.log(i)
67
+ math.log(f)
@@ -0,0 +1,7 @@
1
+ import os
2
+
3
+ from crosshair.core import register_patch
4
+
5
+
6
+ def make_registrations():
7
+ register_patch(os.fspath, os._fspath)
@@ -0,0 +1,10 @@
1
+ from pathlib import PurePath
2
+
3
+ from crosshair.core import proxy_for_type
4
+ from crosshair.tracers import ResumedTracing
5
+
6
+
7
+ def test_PurePath___init__(space):
8
+ pathstr = proxy_for_type(str, "pathstr")
9
+ with ResumedTracing():
10
+ PurePath(pathstr)
@@ -76,6 +76,7 @@ class ExplicitRandom(random.Random):
76
76
 
77
77
 
78
78
  def genint(factory: SymbolicFactory, cap: int):
79
+ # TODO: conditionally use SymbolicBoundedInt here and below
79
80
  with NoTracing():
80
81
  symbolic_int = SymbolicInt(factory.varname + factory.space.uniq(), int)
81
82
  factory.space.add(0 <= symbolic_int.var)
@@ -7,6 +7,7 @@ from crosshair.core_and_libs import proxy_for_type, standalone_statespace
7
7
  from crosshair.libimpl.randomlib import ExplicitRandom
8
8
  from crosshair.statespace import CANNOT_CONFIRM, CONFIRMED, POST_FAIL, MessageType
9
9
  from crosshair.test_util import check_states
10
+ from crosshair.tracers import ResumedTracing
10
11
 
11
12
 
12
13
  def test_ExplicitRandom():
@@ -31,9 +32,10 @@ def test_proxy_random():
31
32
  with standalone_statespace as space:
32
33
  rng = proxy_for_type(random.Random, "rng")
33
34
  i = rng.randrange(5, 10)
34
- assert space.is_possible(i.var == 5)
35
- assert space.is_possible(i.var == 9)
36
- assert not space.is_possible(i.var == 4)
35
+ with ResumedTracing():
36
+ assert space.is_possible(i == 5)
37
+ assert space.is_possible(i == 9)
38
+ assert not space.is_possible(i == 4)
37
39
 
38
40
 
39
41
  def test_global_randrange():
@@ -105,7 +107,7 @@ def test_global_uniform_inverted_args():
105
107
  """post: -2.0 <= _ <= 10.0"""
106
108
  return random.uniform(10, -2)
107
109
 
108
- check_states(f, CANNOT_CONFIRM)
110
+ check_states(f, CONFIRMED)
109
111
 
110
112
 
111
113
  def test_global_getrandbits():