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
crosshair/tracers.py CHANGED
@@ -3,7 +3,9 @@
3
3
  import ctypes
4
4
  import dataclasses
5
5
  import dis
6
+ import os
6
7
  import sys
8
+ import types
7
9
  from collections import defaultdict
8
10
  from sys import _getframe
9
11
  from types import CodeType
@@ -12,6 +14,7 @@ from typing import (
12
14
  Callable,
13
15
  DefaultDict,
14
16
  Dict,
17
+ FrozenSet,
15
18
  Iterable,
16
19
  List,
17
20
  Optional,
@@ -20,8 +23,11 @@ from typing import (
20
23
  TypeVar,
21
24
  )
22
25
 
23
- from _crosshair_tracers import CTracer, TraceSwap
26
+ from _crosshair_tracers import CTracer, TraceSwap, supported_opcodes # type: ignore
24
27
 
28
+ CROSSHAIR_EXTRA_ASSERTS = os.environ.get("CROSSHAIR_EXTRA_ASSERTS", "0") == "1"
29
+
30
+ SYS_MONITORING_TOOL_ID = 4
25
31
  USE_C_TRACER = True
26
32
 
27
33
  PyObjPtr = ctypes.POINTER(ctypes.py_object)
@@ -42,12 +48,12 @@ _debug_header: Tuple[Tuple[str, type], ...] = (
42
48
  from _crosshair_tracers import frame_stack_read, frame_stack_write
43
49
 
44
50
  CALL_FUNCTION = dis.opmap.get("CALL_FUNCTION", 256)
45
- CALL_FUNCTION_KW = dis.opmap.get("CALL_FUNCTION_KW", 256)
51
+ CALL_FUNCTION_KW = dis.opmap.get("CALL_FUNCTION_KW", 256) # Removed as of 3.11
46
52
  CALL_FUNCTION_EX = dis.opmap.get("CALL_FUNCTION_EX", 256)
47
53
  CALL_METHOD = dis.opmap.get("CALL_METHOD", 256)
48
54
  BUILD_TUPLE_UNPACK_WITH_CALL = dis.opmap.get("BUILD_TUPLE_UNPACK_WITH_CALL", 256)
49
55
  CALL = dis.opmap.get("CALL", 256)
50
- CALL_KW = dis.opmap.get("CALL_KW", 256)
56
+ CALL_KW = dis.opmap.get("CALL_KW", 256) # New in 3.13
51
57
 
52
58
 
53
59
  class RawNullPointer:
@@ -55,89 +61,113 @@ class RawNullPointer:
55
61
 
56
62
 
57
63
  NULL_POINTER = RawNullPointer()
64
+ CallStackInfo = (
65
+ Tuple[ # Information about the interpreter stack just before calling a function
66
+ int, # stack index of the callable
67
+ Callable, # the callable object itself
68
+ Optional[int], # index of kwargs dict (if used in this call)
69
+ ]
70
+ )
58
71
 
59
72
 
60
- def handle_build_tuple_unpack_with_call(frame) -> Optional[Tuple[int, Callable]]:
73
+ def handle_build_tuple_unpack_with_call(frame) -> CallStackInfo:
61
74
  idx = -(
62
75
  frame.f_code.co_code[frame.f_lasti + 1] + 1
63
76
  ) # TODO: account for EXTENDED_ARG, here and elsewhere
64
77
  try:
65
- return (idx, frame_stack_read(frame, idx))
78
+ return (idx, frame_stack_read(frame, idx), None)
66
79
  except ValueError:
67
80
  return (idx, NULL_POINTER) # type: ignore
68
81
 
69
82
 
70
- def handle_call_3_11(frame) -> Optional[Tuple[int, Callable]]:
83
+ def handle_call_3_11(frame) -> CallStackInfo:
71
84
  idx = -(frame.f_code.co_code[frame.f_lasti + 1] + 1)
72
85
  try:
73
- ret = (idx - 1, frame_stack_read(frame, idx - 1))
86
+ ret = (idx - 1, frame_stack_read(frame, idx - 1), None)
74
87
  except ValueError:
75
- ret = (idx, frame_stack_read(frame, idx))
88
+ ret = (idx, frame_stack_read(frame, idx), None)
76
89
  return ret
77
90
 
78
91
 
79
- def handle_call_3_13(frame) -> Optional[Tuple[int, Callable]]:
92
+ def handle_call_3_13(frame) -> CallStackInfo:
80
93
  idx = -(frame.f_code.co_code[frame.f_lasti + 1] + 2)
81
- return (idx, frame_stack_read(frame, idx))
94
+ return (idx, frame_stack_read(frame, idx), None)
82
95
 
83
96
 
84
- def handle_call_function(frame) -> Optional[Tuple[int, Callable]]:
97
+ def handle_call_function(frame) -> CallStackInfo:
85
98
  idx = -(frame.f_code.co_code[frame.f_lasti + 1] + 1)
86
99
  try:
87
- return (idx, frame_stack_read(frame, idx))
100
+ return (idx, frame_stack_read(frame, idx), None)
88
101
  except ValueError:
89
102
  return (idx, NULL_POINTER) # type: ignore
90
103
 
91
104
 
92
- def handle_call_function_kw(frame) -> Optional[Tuple[int, Callable]]:
105
+ def handle_call_function_kw(frame) -> CallStackInfo:
93
106
  idx = -(frame.f_code.co_code[frame.f_lasti + 1] + 2)
94
107
  try:
95
- return (idx, frame_stack_read(frame, idx))
108
+ return (idx, frame_stack_read(frame, idx), None)
96
109
  except ValueError:
97
110
  return (idx, NULL_POINTER) # type: ignore
98
111
 
99
112
 
100
- def handle_call_kw(frame) -> Optional[Tuple[int, Callable]]:
113
+ def handle_call_kw(frame) -> CallStackInfo:
101
114
  idx = -(frame.f_code.co_code[frame.f_lasti + 1] + 3)
102
- return (idx, frame_stack_read(frame, idx))
115
+ return (idx, frame_stack_read(frame, idx), None)
103
116
 
104
117
 
105
- def handle_call_function_ex_3_6(frame) -> Optional[Tuple[int, Callable]]:
106
- idx = -((frame.f_code.co_code[frame.f_lasti + 1] & 1) + 2)
118
+ def handle_call_function_ex_3_6(frame) -> CallStackInfo:
119
+ has_kwargs = frame.f_code.co_code[frame.f_lasti + 1] & 1
120
+ idx = -(has_kwargs + 2)
121
+ kwargs_idx = -1 if has_kwargs else None
107
122
  try:
108
- # print("fetch @ idx", idx)
109
- return (idx, frame_stack_read(frame, idx))
123
+ return (idx, frame_stack_read(frame, idx), kwargs_idx)
110
124
  except ValueError:
111
- return (idx, NULL_POINTER) # type: ignore
125
+ return (idx, NULL_POINTER, kwargs_idx) # type: ignore
112
126
 
113
127
 
114
- def handle_call_function_ex_3_13(frame) -> Optional[Tuple[int, Callable]]:
115
- idx = -((frame.f_code.co_code[frame.f_lasti + 1] & 1) + 3)
128
+ def handle_call_function_ex_3_13(frame) -> CallStackInfo:
129
+ has_kwargs = frame.f_code.co_code[frame.f_lasti + 1] & 1
130
+ idx = -(has_kwargs + 3)
131
+ kwargs_idx = -1 if has_kwargs else None
116
132
  try:
117
- return (idx, frame_stack_read(frame, idx))
133
+ return (idx, frame_stack_read(frame, idx), kwargs_idx)
118
134
  except ValueError:
119
- return (idx, NULL_POINTER) # type: ignore
135
+ return (idx, NULL_POINTER, kwargs_idx) # type: ignore
136
+
137
+
138
+ def handle_call_function_ex_3_14(frame) -> CallStackInfo:
139
+ callable_idx, kwargs_idx = -4, -1
140
+ try:
141
+ return (callable_idx, frame_stack_read(frame, callable_idx), kwargs_idx)
142
+ except ValueError:
143
+ return (callable_idx, NULL_POINTER, kwargs_idx) # type: ignore
120
144
 
121
145
 
122
- def handle_call_method(frame) -> Optional[Tuple[int, Callable]]:
146
+ def handle_call_method(frame) -> CallStackInfo:
123
147
  idx = -(frame.f_code.co_code[frame.f_lasti + 1] + 2)
124
148
  try:
125
- return (idx, frame_stack_read(frame, idx))
149
+ return (idx, frame_stack_read(frame, idx), None)
126
150
  except ValueError:
127
151
  # not a sucessful method lookup; no call happens here
128
152
  idx += 1
129
- return (idx, frame_stack_read(frame, idx))
153
+ return (idx, frame_stack_read(frame, idx), None)
130
154
 
131
155
 
132
- _CALL_HANDLERS: Dict[int, Callable[[object], Optional[Tuple[int, Callable]]]] = {
156
+ _CALL_HANDLERS: Dict[int, Callable[[object], CallStackInfo]] = {
133
157
  BUILD_TUPLE_UNPACK_WITH_CALL: handle_build_tuple_unpack_with_call,
134
158
  CALL: handle_call_3_13 if sys.version_info >= (3, 13) else handle_call_3_11,
135
159
  CALL_KW: handle_call_kw,
136
160
  CALL_FUNCTION: handle_call_function,
137
161
  CALL_FUNCTION_KW: handle_call_function_kw,
138
- CALL_FUNCTION_EX: handle_call_function_ex_3_13
139
- if sys.version_info >= (3, 13)
140
- else handle_call_function_ex_3_6,
162
+ CALL_FUNCTION_EX: (
163
+ handle_call_function_ex_3_14
164
+ if sys.version_info >= (3, 14)
165
+ else (
166
+ handle_call_function_ex_3_13
167
+ if sys.version_info >= (3, 13)
168
+ else handle_call_function_ex_3_6
169
+ )
170
+ ),
141
171
  CALL_METHOD: handle_call_method,
142
172
  }
143
173
 
@@ -152,6 +182,35 @@ class TraceException(BaseException):
152
182
  pass
153
183
 
154
184
 
185
+ def check_opcode_support(opcodes: FrozenSet[int]):
186
+ if sys.version_info < (3, 12):
187
+ return
188
+ missing_opcodes = opcodes - set(supported_opcodes())
189
+ if missing_opcodes:
190
+ raise TraceException(
191
+ f"The C-level tracer does not support these opcodes: {','.join(map(dis.opname.__getitem__, missing_opcodes))}"
192
+ )
193
+
194
+
195
+ check_opcode_support(frozenset(_CALL_HANDLERS.keys()))
196
+
197
+
198
+ wrapper_descriptor_type = type(int.__bool__)
199
+ assert str(wrapper_descriptor_type) == "<class 'wrapper_descriptor'>"
200
+
201
+ _NORMAL_CALLABLE_TYPES = (
202
+ type,
203
+ types.FunctionType, #': <class 'function'>,
204
+ types.MethodDescriptorType, #': <class 'method_descriptor'>,
205
+ types.MethodType, #': <class 'method'>,
206
+ types.MethodWrapperType, #': <class 'method-wrapper'>}
207
+ types.BuiltinFunctionType, #': <class 'builtin_function_or_method'>,
208
+ types.BuiltinMethodType, #: <class 'builtin_function_or_method'>,
209
+ types.ClassMethodDescriptorType, #': <class 'classmethod_descriptor'>,
210
+ wrapper_descriptor_type,
211
+ )
212
+
213
+
155
214
  class TracingModule:
156
215
  # override these!:
157
216
  opcodes_wanted = frozenset(_CALL_HANDLERS.keys())
@@ -165,18 +224,21 @@ class TracingModule:
165
224
  call_handler = _CALL_HANDLERS.get(opcodenum)
166
225
  if not call_handler:
167
226
  return None
168
- maybe_call_info = call_handler(frame)
169
- if maybe_call_info is None:
170
- # TODO: this cannot happen?
171
- return None
172
- (fn_idx, target) = maybe_call_info
227
+ (fn_idx, target, kwargs_idx) = call_handler(frame)
173
228
  binding_target = None
174
229
 
230
+ __self = None
175
231
  try:
176
232
  __self = object.__getattribute__(target, "__self__")
177
233
  except AttributeError:
178
234
  pass
179
- else:
235
+ if (__self is None) and (not isinstance(target, _NORMAL_CALLABLE_TYPES)):
236
+ try:
237
+ target = object.__getattribute__(target, "__call__")
238
+ __self = object.__getattribute__(target, "__self__")
239
+ except AttributeError:
240
+ pass
241
+ if __self is not None:
180
242
  try:
181
243
  __func = object.__getattribute__(target, "__func__")
182
244
  except AttributeError:
@@ -190,6 +252,27 @@ class TracingModule:
190
252
  binding_target = __self
191
253
  target = __func
192
254
 
255
+ if kwargs_idx is not None:
256
+ try:
257
+ kwargs_dict = frame_stack_read(frame, kwargs_idx)
258
+ except ValueError:
259
+ pass
260
+ else:
261
+ replacement_kwargs = {}
262
+ for key, val in kwargs_dict.items():
263
+ if isinstance(key, str):
264
+ replacement_kwargs[key] = val
265
+ continue
266
+ # circular import:
267
+ from crosshair.libimpl.builtinslib import AnySymbolicStr
268
+
269
+ if isinstance(key, AnySymbolicStr):
270
+ # NOTE: We need to ensure symbolic strings don't need tracing for realization
271
+ replacement_kwargs[key.__ch_realize__()] = val
272
+ else:
273
+ raise TypeError("keywords must be strings")
274
+ frame_stack_write(frame, kwargs_idx, replacement_kwargs)
275
+
193
276
  if isinstance(target, Untracable):
194
277
  return None
195
278
  replacement = self.trace_call(frame, target, binding_target)
@@ -222,7 +305,6 @@ class PatchingModule(TracingModule):
222
305
  def __init__(
223
306
  self,
224
307
  overrides: Optional[Dict[Callable, Callable]] = None,
225
- fn_type_overrides: Optional[Dict[type, Callable]] = None,
226
308
  ):
227
309
  # NOTE: you might imagine that we should use an IdKeyedDict for self.overrides
228
310
  # However, some builtin bound methods have no way to get identity for their code:
@@ -234,11 +316,13 @@ class PatchingModule(TracingModule):
234
316
  self.nextfn: Dict[object, Callable] = {} # code object to next, lower layer
235
317
  if overrides:
236
318
  self.add(overrides)
237
- self.fn_type_overrides = fn_type_overrides or {}
238
319
 
239
320
  def add(self, new_overrides: Dict[Callable, Callable]):
240
321
  for orig, new_override in new_overrides.items():
241
322
  prev_override = self.overrides.get(orig, orig)
323
+ assert (
324
+ prev_override is not new_override
325
+ ), f"Function patch {new_override} has already been applied"
242
326
  self.nextfn[(new_override.__code__, orig)] = prev_override
243
327
  self.overrides[orig] = new_override
244
328
 
@@ -265,11 +349,7 @@ class PatchingModule(TracingModule):
265
349
  # not properly unbound by `TracingModule.trace_op`.
266
350
  return None
267
351
  if target is None:
268
- fn_type_override = self.fn_type_overrides.get(type(fn))
269
- if fn_type_override is None:
270
- return None
271
- else:
272
- target = fn_type_override(fn)
352
+ return None
273
353
  caller_code = frame.f_code
274
354
  if caller_code.co_name == "_crosshair_wrapper":
275
355
  return None
@@ -306,7 +386,7 @@ class CompositeTracer:
306
386
 
307
387
  def __enter__(self) -> object:
308
388
  self.ctracer.push_module(self.patching_module)
309
- tool_id = 4
389
+ tool_id = SYS_MONITORING_TOOL_ID
310
390
  sys.monitoring.use_tool_id(tool_id, "CrossHair")
311
391
  sys.monitoring.register_callback(
312
392
  tool_id,
@@ -321,7 +401,7 @@ class CompositeTracer:
321
401
  return self
322
402
 
323
403
  def __exit__(self, _etype, exc, _etb):
324
- tool_id = 4
404
+ tool_id = SYS_MONITORING_TOOL_ID
325
405
  sys.monitoring.register_callback(
326
406
  tool_id, sys.monitoring.events.INSTRUCTION, None
327
407
  )
@@ -380,6 +460,9 @@ class CoverageResult:
380
460
  class CoverageTracingModule(TracingModule):
381
461
  opcodes_wanted = frozenset(i for i in range(256))
382
462
 
463
+ # TODO: this needs to be moved into a separate kind of monitor to
464
+ # support threading (sys.monitoring probes are global)
465
+
383
466
  def __init__(self, *fns: Callable):
384
467
  assert not is_tracing()
385
468
  self.fns = fns
@@ -431,8 +514,17 @@ def NoTracing():
431
514
  return TraceSwap(COMPOSITE_TRACER.ctracer, True)
432
515
 
433
516
 
434
- def ResumedTracing():
435
- return TraceSwap(COMPOSITE_TRACER.ctracer, False)
517
+ if CROSSHAIR_EXTRA_ASSERTS:
518
+
519
+ def ResumedTracing():
520
+ if COMPOSITE_TRACER.ctracer.is_handling():
521
+ raise TraceException("Cannot resume tracing while opcode handling")
522
+ return TraceSwap(COMPOSITE_TRACER.ctracer, False)
523
+
524
+ else:
525
+
526
+ def ResumedTracing():
527
+ return TraceSwap(COMPOSITE_TRACER.ctracer, False)
436
528
 
437
529
 
438
530
  _T = TypeVar("_T")
crosshair/type_repo.py CHANGED
@@ -5,6 +5,8 @@ from typing import Dict, List, Optional, Type
5
5
 
6
6
  import z3 # type: ignore
7
7
 
8
+ from crosshair.tracers import NoTracing
9
+ from crosshair.util import CrossHairInternal, CrossHairValue, is_hashable
8
10
  from crosshair.z3util import z3Eq, z3Not
9
11
 
10
12
  _MAP: Optional[Dict[type, List[type]]] = None
@@ -18,6 +20,8 @@ _IGNORED_MODULE_ROOTS = {
18
20
  "pkg_resources",
19
21
  "pytest",
20
22
  "py", # (part of pytest)
23
+ # Disabled because the import attempt can cause problems:
24
+ "numpy", # importing numpy/testing/_private/utils.py attempts a subprocess call
21
25
  }
22
26
 
23
27
 
@@ -48,7 +52,7 @@ def get_subclass_map() -> Dict[type, List[type]]:
48
52
  Crawl all types presently in memory and makes a map from parent to child classes.
49
53
 
50
54
  Only direct children are included.
51
- Does not yet handle "protocol" subclassing (eg "Iterator", "Mapping", etc).
55
+ TODO: Does not yet handle "protocol" subclassing (eg "Iterator", "Mapping", etc).
52
56
  """
53
57
  global _MAP
54
58
  if _MAP is None:
@@ -57,15 +61,13 @@ def get_subclass_map() -> Dict[type, List[type]]:
57
61
  if module_name.split(".", 1)[0] in _IGNORED_MODULE_ROOTS:
58
62
  continue
59
63
  if module is None:
60
- # We set the internal _datetime module to None, ensuring that
61
- # we don't load the C implementation.
62
64
  continue
63
65
  try:
64
66
  module_classes = inspect.getmembers(module, inspect.isclass)
65
67
  except ImportError:
66
68
  continue
67
69
  for _, cls in module_classes:
68
- if _class_known_to_be_copyable(cls):
70
+ if _class_known_to_be_copyable(cls) and is_hashable(cls):
69
71
  classes.add(cls)
70
72
  subclass = collections.defaultdict(list)
71
73
  for cls in classes:
@@ -120,6 +122,11 @@ class SymbolicTypeRepository:
120
122
  return SMT_SUBTYPE_FN(typ1, typ2) == MAYBE_SORT.yes
121
123
 
122
124
  def get_type(self, typ: Type) -> z3.ExprRef:
125
+ with NoTracing():
126
+ if issubclass(typ, CrossHairValue):
127
+ raise CrossHairInternal(
128
+ "Type repo should not be queried with a symbolic"
129
+ )
123
130
  pytype_to_smt = self.pytype_to_smt
124
131
  if typ not in pytype_to_smt:
125
132
  stmts = []