A Rust port of the core symbolic execution engine from
Angr. The work lives on the rust-symex branch
of a fork of angr/angr rather than in a standalone repository, since it
replaces the engine in place.
The design goal was for analysis to be initialized in Python and then hand off execution to Rust, with Rust as the source of truth for analysis state and callbacks into Python only for unhandled external calls. Users can still extend the engine in Python without writing any Rust, while the common path stays in native code. Two architectural decisions carry most of that:
RustStateProxy: a lightweight(manager, state_id)handle instead of syncing a fullSimState. The realSimStateis only constructed when a SimProcedure actually needs one.- A single solver of record: the Rust solver owns constraints with no
bidirectional sync; Python solver failures fall back to Rust via
eval_with_fallback. A minimal z3-rs patch lets Rust borrow Python’s Z3 context so AST pointers pass through without translation.
Results
As of April 2026, on 16 CTF binaries from angr-examples, the Rust engine
matched or beat the Python original on 13, with a 12.7x speedup on the largest
benchmark, and recovered the same flag as Python on every benchmark it solved.
A later run over a wider set reported 17 of 22 faster.
These are notional single-run numbers and at some point, I plan to do more rigorous benchmarking.
How it was built
This is by a wide margin the largest thing I have built this way — over 160K LoC — and it is the project that drove the tooling around it. Two earlier attempts failed before I pivoted to agent loops with persistent memory, combining beads for cross-session state with a Ralph-style loop. That loop started as a bash script, became a Go tool driven by a clean/dirty + plan/implement/review state machine, and has since run over 2,500 iterations against this codebase.
The agent’s accumulated memories grew large enough to need pruning of their own; the forgotten entries are archived at angr-memories and browsable.
Links: