crosshair-tool 0.0.94__tar.gz → 0.0.96__tar.gz
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_tool-0.0.94 → crosshair_tool-0.0.96}/PKG-INFO +1 -1
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/__init__.py +1 -1
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/condition_parser_test.py +0 -2
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/core.py +2 -1
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/core_test.py +2 -3
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/diff_behavior_test.py +0 -2
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/builtinslib.py +65 -28
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/builtinslib_ch_test.py +12 -2
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/builtinslib_test.py +36 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/collectionslib_test.py +4 -4
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/functoolslib.py +8 -2
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/functoolslib_test.py +22 -6
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/objectproxy.py +38 -13
- crosshair_tool-0.0.96/crosshair/objectproxy_test.py +41 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/opcode_intercept.py +9 -17
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/path_cover.py +5 -1
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/pathing_oracle.py +41 -4
- crosshair_tool-0.0.96/crosshair/pathing_oracle_test.py +21 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/statespace.py +73 -18
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/statespace_test.py +16 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair_tool.egg-info/PKG-INFO +1 -1
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair_tool.egg-info/SOURCES.txt +1 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/setup.py +1 -1
- crosshair_tool-0.0.94/crosshair/objectproxy_test.py +0 -23
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/LICENSE +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/README.md +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/__main__.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/_mark_stacks.h +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/_preliminaries_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/_tracers.c +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/_tracers.h +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/_tracers_pycompat.h +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/_tracers_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/abcstring.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/auditwall.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/auditwall_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/codeconfig.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/codeconfig_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/condition_parser.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/conftest.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/copyext.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/copyext_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/core_and_libs.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/core_regestered_types_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/diff_behavior.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/dynamic_typing.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/dynamic_typing_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/enforce.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/enforce_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/examples/PEP316/__init__.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/examples/PEP316/bugs_detected/__init__.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/examples/PEP316/bugs_detected/getattr_magic.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/examples/PEP316/bugs_detected/hash_consistent_with_equals.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/examples/PEP316/bugs_detected/shopping_cart.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/examples/PEP316/bugs_detected/showcase.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/examples/PEP316/correct_code/__init__.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/examples/PEP316/correct_code/arith.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/examples/PEP316/correct_code/chess.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/examples/PEP316/correct_code/nesting_inference.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/examples/PEP316/correct_code/numpy_examples.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/examples/PEP316/correct_code/rolling_average.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/examples/PEP316/correct_code/showcase.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/examples/__init__.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/examples/check_examples_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/examples/deal/__init__.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/examples/icontract/__init__.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/examples/icontract/bugs_detected/__init__.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/examples/icontract/bugs_detected/showcase.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/examples/icontract/bugs_detected/wrong_sign.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/examples/icontract/correct_code/__init__.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/examples/icontract/correct_code/arith.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/examples/icontract/correct_code/showcase.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/fnutil.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/fnutil_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/fuzz_core_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/__init__.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/arraylib.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/binascii_ch_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/binascii_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/binasciilib.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/bisectlib_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/codecslib.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/codecslib_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/collectionslib.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/collectionslib_ch_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/copylib.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/copylib_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/datetimelib.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/datetimelib_ch_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/datetimelib_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/decimallib.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/decimallib_ch_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/decimallib_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/encodings/__init__.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/encodings/_encutil.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/encodings/ascii.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/encodings/latin_1.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/encodings/utf_8.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/encodings_ch_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/fractionlib.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/fractionlib_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/hashliblib.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/hashliblib_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/heapqlib.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/heapqlib_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/importliblib.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/importliblib_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/iolib.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/iolib_ch_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/iolib_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/ipaddresslib.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/itertoolslib.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/itertoolslib_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/jsonlib.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/jsonlib_ch_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/jsonlib_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/mathlib.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/mathlib_ch_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/mathlib_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/oslib.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/pathliblib_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/randomlib.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/randomlib_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/relib.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/relib_ch_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/relib_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/timelib.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/timelib_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/typeslib.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/typeslib_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/unicodedatalib.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/unicodedatalib_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/urlliblib.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/urlliblib_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/weakreflib.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/weakreflib_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/zliblib.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/zliblib_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/lsp_server.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/lsp_server_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/main.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/main_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/opcode_intercept_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/options.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/options_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/patch_equivalence_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/path_cover_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/path_search.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/path_search_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/pure_importer.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/pure_importer_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/py.typed +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/register_contract.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/register_contract_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/simplestructs.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/simplestructs_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/smtlib.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/smtlib_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/stubs_parser.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/stubs_parser_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/test_util.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/test_util_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/tools/__init__.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/tools/check_help_in_doc.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/tools/check_init_and_setup_coincide.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/tools/generate_demo_table.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/tracers.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/tracers_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/type_repo.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/unicode_categories.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/unicode_categories_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/util.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/util_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/watcher.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/watcher_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/z3util.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/z3util_test.py +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair_tool.egg-info/dependency_links.txt +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair_tool.egg-info/entry_points.txt +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair_tool.egg-info/requires.txt +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair_tool.egg-info/top_level.txt +0 -0
- {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/setup.cfg +0 -0
|
@@ -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"
|
|
@@ -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)
|
|
@@ -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)
|
|
@@ -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
|
|
@@ -2611,18 +2611,6 @@ class SymbolicObject(ObjectProxy, CrossHairValue, Untracable):
|
|
|
2611
2611
|
return object()
|
|
2612
2612
|
return proxy_for_type(pytype, varname, allow_subtypes=False)
|
|
2613
2613
|
|
|
2614
|
-
def _wrapped(self):
|
|
2615
|
-
with NoTracing():
|
|
2616
|
-
inner = _MISSING
|
|
2617
|
-
try:
|
|
2618
|
-
inner = object.__getattribute__(self, "_inner")
|
|
2619
|
-
except AttributeError:
|
|
2620
|
-
pass
|
|
2621
|
-
if inner is _MISSING:
|
|
2622
|
-
inner = self._realize()
|
|
2623
|
-
object.__setattr__(self, "_inner", inner)
|
|
2624
|
-
return inner
|
|
2625
|
-
|
|
2626
2614
|
def __ch_realize__(self):
|
|
2627
2615
|
return realize(self._wrapped())
|
|
2628
2616
|
|
|
@@ -2680,10 +2668,25 @@ class SymbolicCallable:
|
|
|
2680
2668
|
__annotations__: dict = {}
|
|
2681
2669
|
|
|
2682
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
|
+
"""
|
|
2683
2681
|
assert not is_tracing()
|
|
2684
2682
|
with ResumedTracing():
|
|
2685
|
-
|
|
2686
|
-
|
|
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
|
|
2687
2690
|
self.values = values
|
|
2688
2691
|
self.idx = 0
|
|
2689
2692
|
|
|
@@ -2707,6 +2710,7 @@ class SymbolicCallable:
|
|
|
2707
2710
|
if idx >= len(values):
|
|
2708
2711
|
return values[-1]
|
|
2709
2712
|
else:
|
|
2713
|
+
self.idx += 1
|
|
2710
2714
|
return values[idx]
|
|
2711
2715
|
|
|
2712
2716
|
def __bool__(self):
|
|
@@ -3418,6 +3422,26 @@ class AnySymbolicStr(AbcString):
|
|
|
3418
3422
|
return "0" * fill_length + self
|
|
3419
3423
|
|
|
3420
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
|
+
|
|
3421
3445
|
class LazyIntSymbolicStr(AnySymbolicStr, CrossHairValue):
|
|
3422
3446
|
"""
|
|
3423
3447
|
A symbolic string that lazily generates SymbolicInt-based characters as needed.
|
|
@@ -3456,10 +3480,8 @@ class LazyIntSymbolicStr(AnySymbolicStr, CrossHairValue):
|
|
|
3456
3480
|
codepoints = tuple(self._codepoints)
|
|
3457
3481
|
return "".join(chr(realize(x)) for x in codepoints)
|
|
3458
3482
|
|
|
3459
|
-
# This is normally an AtomicSymbolicValue method, but sometimes it's used in a
|
|
3460
|
-
# duck-typing way.
|
|
3461
3483
|
@classmethod
|
|
3462
|
-
def
|
|
3484
|
+
def _ch_create_from_literal(cls, val: object) -> Optional[CrossHairValue]:
|
|
3463
3485
|
if isinstance(val, str):
|
|
3464
3486
|
return LazyIntSymbolicStr(list(map(ord, val)))
|
|
3465
3487
|
return None
|
|
@@ -3493,6 +3515,10 @@ class LazyIntSymbolicStr(AnySymbolicStr, CrossHairValue):
|
|
|
3493
3515
|
with NoTracing():
|
|
3494
3516
|
if not isinstance(i, (Integral, slice)):
|
|
3495
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.
|
|
3496
3522
|
i = deep_realize(i)
|
|
3497
3523
|
with ResumedTracing():
|
|
3498
3524
|
newcontents = self._codepoints[i]
|
|
@@ -3573,11 +3599,15 @@ class LazyIntSymbolicStr(AnySymbolicStr, CrossHairValue):
|
|
|
3573
3599
|
return any(self.endswith(s, start, end) for s in substr)
|
|
3574
3600
|
if not isinstance(substr, str):
|
|
3575
3601
|
raise TypeError
|
|
3602
|
+
substrlen = len(substr)
|
|
3576
3603
|
if start is None and end is None:
|
|
3577
3604
|
matchable = self
|
|
3578
3605
|
else:
|
|
3579
3606
|
matchable = self[start:end]
|
|
3580
|
-
|
|
3607
|
+
if substrlen == 0:
|
|
3608
|
+
return not _unfindable_range(start, end, len(self))
|
|
3609
|
+
else:
|
|
3610
|
+
return matchable[-substrlen:] == substr
|
|
3581
3611
|
|
|
3582
3612
|
def startswith(self, substr, start=None, end=None):
|
|
3583
3613
|
if isinstance(substr, tuple):
|
|
@@ -3587,6 +3617,10 @@ class LazyIntSymbolicStr(AnySymbolicStr, CrossHairValue):
|
|
|
3587
3617
|
if start is None and end is None:
|
|
3588
3618
|
matchable = self
|
|
3589
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
|
|
3590
3624
|
matchable = self[start:end]
|
|
3591
3625
|
return matchable[: len(substr)] == substr
|
|
3592
3626
|
|
|
@@ -3627,7 +3661,7 @@ class LazyIntSymbolicStr(AnySymbolicStr, CrossHairValue):
|
|
|
3627
3661
|
end += mylen
|
|
3628
3662
|
matchstr = self[start:end] if start != 0 or end is not mylen else self
|
|
3629
3663
|
if len(substr) == 0:
|
|
3630
|
-
#
|
|
3664
|
+
# An oddity of CPython. We can find the empty string when over-slicing
|
|
3631
3665
|
# off the left side of the string, but not off the right:
|
|
3632
3666
|
# ''.find('', 3, 4) == -1
|
|
3633
3667
|
# ''.find('', -4, -3) == 0
|
|
@@ -4802,14 +4836,17 @@ def _str_format_map(self, map) -> Union[AnySymbolicStr, str]:
|
|
|
4802
4836
|
|
|
4803
4837
|
|
|
4804
4838
|
def _str_startswith(self, substr, start=None, end=None) -> bool:
|
|
4805
|
-
if not isinstance(self, str):
|
|
4806
|
-
raise TypeError
|
|
4807
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
|
|
4808
4845
|
# Handle native values with native implementation:
|
|
4809
4846
|
if type(substr) is str:
|
|
4810
4847
|
return self.startswith(substr, start, end)
|
|
4811
4848
|
if type(substr) is tuple:
|
|
4812
|
-
if all(type(
|
|
4849
|
+
if all(type(s) is str for s in substr):
|
|
4813
4850
|
return self.startswith(substr, start, end)
|
|
4814
4851
|
symbolic_self = LazyIntSymbolicStr([ord(c) for c in self])
|
|
4815
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():
|
|
@@ -10,11 +10,36 @@ from crosshair.tracers import NoTracing
|
|
|
10
10
|
# (which is BSD licenced)
|
|
11
11
|
#
|
|
12
12
|
|
|
13
|
+
_MISSING = object()
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def proxy_inplace_op(proxy, op, *args):
|
|
17
|
+
my_original_value = proxy._wrapped()
|
|
18
|
+
my_new_value = op(my_original_value, *args)
|
|
19
|
+
# We need to return our own identity if (and only if!) the underlying value does.
|
|
20
|
+
if my_new_value is my_original_value:
|
|
21
|
+
return proxy
|
|
22
|
+
else:
|
|
23
|
+
object.__setattr__(proxy, "_inner", my_new_value)
|
|
24
|
+
return my_new_value
|
|
25
|
+
|
|
13
26
|
|
|
14
27
|
class ObjectProxy:
|
|
15
|
-
def
|
|
28
|
+
def _realize(self):
|
|
16
29
|
raise NotImplementedError
|
|
17
30
|
|
|
31
|
+
def _wrapped(self):
|
|
32
|
+
with NoTracing():
|
|
33
|
+
inner = _MISSING
|
|
34
|
+
try:
|
|
35
|
+
inner = object.__getattribute__(self, "_inner")
|
|
36
|
+
except AttributeError:
|
|
37
|
+
pass
|
|
38
|
+
if inner is _MISSING:
|
|
39
|
+
inner = self._realize()
|
|
40
|
+
object.__setattr__(self, "_inner", inner)
|
|
41
|
+
return inner
|
|
42
|
+
|
|
18
43
|
def __get_module__(self) -> str:
|
|
19
44
|
return self._wrapped().__module__
|
|
20
45
|
|
|
@@ -233,40 +258,40 @@ class ObjectProxy:
|
|
|
233
258
|
return other | self._wrapped()
|
|
234
259
|
|
|
235
260
|
def __iadd__(self, other):
|
|
236
|
-
return operator.iadd
|
|
261
|
+
return proxy_inplace_op(self, operator.iadd, other)
|
|
237
262
|
|
|
238
263
|
def __isub__(self, other):
|
|
239
|
-
return operator.isub
|
|
264
|
+
return proxy_inplace_op(self, operator.isub, other)
|
|
240
265
|
|
|
241
266
|
def __imul__(self, other):
|
|
242
|
-
return operator.imul
|
|
267
|
+
return proxy_inplace_op(self, operator.imul, other)
|
|
243
268
|
|
|
244
269
|
def __itruediv__(self, other):
|
|
245
|
-
return operator.itruediv
|
|
270
|
+
return proxy_inplace_op(self, operator.itruediv, other)
|
|
246
271
|
|
|
247
272
|
def __ifloordiv__(self, other):
|
|
248
|
-
return
|
|
273
|
+
return proxy_inplace_op(self, operator.ifloordiv, other)
|
|
249
274
|
|
|
250
275
|
def __imod__(self, other):
|
|
251
|
-
return operator.imod
|
|
276
|
+
return proxy_inplace_op(self, operator.imod, other)
|
|
252
277
|
|
|
253
278
|
def __ipow__(self, other, *args):
|
|
254
|
-
return operator.ipow
|
|
279
|
+
return proxy_inplace_op(self, operator.ipow, other, *args)
|
|
255
280
|
|
|
256
281
|
def __ilshift__(self, other):
|
|
257
|
-
return operator.ilshift
|
|
282
|
+
return proxy_inplace_op(self, operator.ilshift, other)
|
|
258
283
|
|
|
259
284
|
def __irshift__(self, other):
|
|
260
|
-
return operator.irshift
|
|
285
|
+
return proxy_inplace_op(self, operator.irshift, other)
|
|
261
286
|
|
|
262
287
|
def __iand__(self, other):
|
|
263
|
-
return operator.iand
|
|
288
|
+
return proxy_inplace_op(self, operator.iand, other)
|
|
264
289
|
|
|
265
290
|
def __ixor__(self, other):
|
|
266
|
-
return operator.ixor
|
|
291
|
+
return proxy_inplace_op(self, operator.ixor, other)
|
|
267
292
|
|
|
268
293
|
def __ior__(self, other):
|
|
269
|
-
return operator.ior
|
|
294
|
+
return proxy_inplace_op(self, operator.ior, other)
|
|
270
295
|
|
|
271
296
|
def __neg__(self):
|
|
272
297
|
return -self._wrapped()
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
3
|
+
from crosshair.objectproxy import ObjectProxy
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ObjectWrap(ObjectProxy):
|
|
7
|
+
def __init__(self, obj):
|
|
8
|
+
object.__setattr__(self, "_o", obj)
|
|
9
|
+
|
|
10
|
+
def _realize(self):
|
|
11
|
+
return object.__getattribute__(self, "_o")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class TestObjectProxy:
|
|
15
|
+
def test_object_proxy_over_list(self) -> None:
|
|
16
|
+
i = [1, 2, 3]
|
|
17
|
+
proxy = ObjectWrap(i)
|
|
18
|
+
assert i == proxy
|
|
19
|
+
proxy.append(4)
|
|
20
|
+
assert [1, 2, 3, 4] == proxy
|
|
21
|
+
assert [1, 2, 3, 4, 5] == proxy + [5]
|
|
22
|
+
assert [2, 3] == proxy[1:3]
|
|
23
|
+
assert [1, 2, 3, 4] == proxy
|
|
24
|
+
|
|
25
|
+
def test_inplace_identities(self) -> None:
|
|
26
|
+
proxy = ObjectWrap(3.0)
|
|
27
|
+
orig_proxy = proxy
|
|
28
|
+
proxy += 1.0
|
|
29
|
+
assert proxy is not orig_proxy
|
|
30
|
+
proxy = ObjectWrap([1, 2])
|
|
31
|
+
orig_proxy = proxy
|
|
32
|
+
proxy += [3, 4]
|
|
33
|
+
assert proxy is orig_proxy
|
|
34
|
+
|
|
35
|
+
def test_object_proxy_over_float(self) -> None:
|
|
36
|
+
proxy = ObjectWrap(4.5)
|
|
37
|
+
proxy //= 2.0
|
|
38
|
+
assert 2.0 == proxy
|
|
39
|
+
proxy = ObjectWrap(5.0)
|
|
40
|
+
proxy /= 2.0
|
|
41
|
+
assert 2.5 == proxy
|
|
@@ -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")
|
|
@@ -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:
|