Miri
An interpreter for Rust’s Mid-level Intermediate Representation (MIR). Runs your program on an abstract machine and detects Undefined Behaviour that a normal compiler would happily emit.
What Miri catches:
- Out-of-bounds pointer arithmetic and derefs.
- Use-after-free.
- Violations of Rust’s aliasing model (Stacked Borrows / Tree Borrows): the exact rules
&mut Tis supposed to guarantee. - Invalid values (e.g. a
boolthat’s not 0 or 1, a&Tthat’s null). - Data races.
- Uninitialized reads.
Use:
rustup +nightly component add miri
cargo +nightly miri test
Runs your test suite under the interpreter. It’s slow (expect 10–100×), so you don’t use it on full integration tests, but on unit tests for unsafe code it’s invaluable.
Especially important when writing unsafe. The borrow checker steps aside in unsafe blocks; Miri enforces the rules dynamically instead. If your unsafe passes Miri with a good test suite, you’ve caught most of the ways it could be wrong.
From ECE459 L28
Shares a name with the 1960s Star Trek episode. In this course the most common unsafe use is launching a GPU kernel, so Miri’s utility is limited there.
Profiling with Miri [Bra22]
Miri can also produce flamegraph-style output via measureme → crox → Chrome dev tools:
MIRIFLAGS="-Zmiri-disable-isolation -Zmiri-measureme=crox" cargo +nightly miri run
Caveat from the article’s comments: Miri runs the debug/interpreter version, so what it flags as hot may not be hot in a release build; optimizing for Miri can actually regress real performance. Useful as an idea generator in the change-run-evaluate loop, not as ground truth.
War story: running Miri on the producer-consumer-opt code required dropping items-per-thread to 10 to finish in reasonable time. The resulting graph showed that initializing the RNG dominated thread 1’s early time; subsequent uses were quick.