CrossHair
CrossHair is an analysis tool for Python that utilizes symbolic execution to blur the line between traditional testing and type systems. It works by repeatedly calling functions with symbolic inputs and employing an SMT solver to explore execution paths, finding counterexamples to contracts defined within docstrings. The library currently stands at version 0.0.102 and has a fairly active release cadence with frequent minor updates.
Common errors
-
CrossHair finds counterexamples for `float('nan')` or `float('inf')` where none were expected before.cause As of version 0.0.102, CrossHair proactively tests float arguments with `math.nan`, `math.inf`, and `-math.inf` to find more robust counterexamples.fixIf your function is not expected to handle these special float values, add a precondition like `pre: math.isfinite(x)` to the function's contract. Alternatively, set the environment variable `CROSSHAIR_ONLY_FINITE_FLOATS=1` to disable this behavior. -
The `crosshair cover` command with `--example_output_format=argument_dictionary` doesn't produce a dictionary output or gives a warning.
cause The option name for dictionary output was fixed/renamed in version 0.0.38.fixUse the corrected option name: `crosshair cover --example_output_format=arg_dictionary`. -
CrossHair analysis seems to ignore my function's `lru_cache` or `cache` decorator, leading to unexpected results or performance characteristics.
cause CrossHair intentionally disables `lru_cache` and `cache` decorators during symbolic execution to avoid non-deterministic behavior that can arise from caching in a symbolic context.fixAdjust your contracts and expectations, recognizing that the caching mechanism will not be active during CrossHair's analysis. Ensure your function's core logic is correct without relying on the cache during formal verification. -
Installation of `crosshair-tool` via pip is taking an unusually long time, seemingly stuck.
cause During installation, CrossHair often compiles its underlying SMT solver, Z3, from source. This process can be CPU-intensive and time-consuming on various platforms.fixThis is expected behavior. Allow sufficient time for the Z3 solver to compile. Ensure your system has a C++ compiler and related build tools installed, as these are typically required for the compilation.
Warnings
- breaking CrossHair now tests float arguments with `math.nan`, `math.inf`, and `-math.inf` by default. This change in version 0.0.102 is likely to uncover new counterexamples in existing codebases that previously assumed finite float inputs.
- breaking The default stopping conditions have been fully re-worked. The `--per_condition_timeout` option is no longer the default. Instead, `--max_uninteresting_iterations=5` is used when no other stopping criteria are specified.
- deprecated The `--example_output_format=argument_dictionary` option for the `cover` command has been fixed and renamed to `--example_output_format=arg_dictionary`. The old option will issue a warning and be removed in future releases.
- gotcha CrossHair automatically disables `functools.lru_cache` and `functools.cache` decorators during analysis to prevent non-deterministic errors. Code relying on these caches for functional correctness might exhibit different behavior under analysis.
- gotcha Installation of `crosshair-tool` can take a significant amount of time on some platforms. This is due to the underlying Z3 SMT solver being compiled from source as part of the installation process.
Install
-
pip install crosshair-tool
Imports
- CLI tool
crosshair watch my_module.py
Quickstart
# my_code.py
def divide(a: int, b: int) -> float:
"""
post: __return__ == a / b
"""
return a / b
# Run CrossHair from your terminal:
# crosshair watch my_code.py