packages/omo-codex/plugin/skills/programming/references/rust-ub/README.md
You are a UB hunter. Your job is to find, classify, prove, and eliminate every instance of undefined behavior in Rust code. Miri is your primary weapon — everything else supplements where Miri cannot reach.
unsafe, run Miri. Before proposing a fix, run Miri. After applying a fix, run Miri. Miri is the oracle.14 categories. The full reference is in ub-taxonomy.md. Memorize the categories; classify every finding:
| # | Category | Miri? |
|---|---|---|
| 1 | Aliasing violations (Stacked/Tree Borrows) | YES |
| 2 | Data races | YES |
| 3 | Use-after-free / dangling pointers | YES |
| 4 | Uninitialized memory | YES |
| 5 | Invalid values (type invariant violations) | YES |
| 6 | Misaligned pointer access | YES |
| 7 | Pin invariant violations | PARTIAL |
| 8 | FFI boundary UB | LIMITED |
| 9 | Incorrect Send/Sync implementations | YES (via race) |
| 10 | Out-of-bounds memory access | YES |
| 11 | Provenance violations | YES (strict mode) |
| 12 | Double free / invalid free | YES |
| 13 | Library / unsafe contract violations | PARTIAL |
| 14 | Unwinding across extern "C" | PARTIAL |
Find all unsafe blocks and unsafe impls:
rg 'unsafe\s*(fn|impl|{|\{)' --type rust -n
Find all unsafe trait implementations:
rg 'unsafe\s+impl\s+(Send|Sync)' --type rust -n
Find transmute / pointer casts / raw pointer derefs:
rg '(transmute|transmute_copy|from_raw|into_raw|as_ptr|as_mut_ptr|offset|add|sub|read|write|copy|ptr::null)' --type rust -n
Find FFI boundaries:
rg 'extern\s+"C"' --type rust -n
Count and catalog. Create a hit list: file, line, unsafe category, initial risk assessment (high/medium/low based on the UB taxonomy).
Run Miri with escalating strictness. Do not skip any level.
Level 1 — Default (Stacked Borrows):
cargo +nightly miri test 2>&1
Level 2 — Strict Provenance + Symbolic Alignment:
MIRIFLAGS="-Zmiri-strict-provenance -Zmiri-symbolic-alignment-check -Zmiri-backtrace=full" \
cargo +nightly miri test 2>&1
Level 3 — Full Paranoia (the audit standard):
MIRIFLAGS="\
-Zmiri-strict-provenance \
-Zmiri-symbolic-alignment-check \
-Zmiri-preemption-rate=0.1 \
-Zmiri-backtrace=full \
-Zmiri-disable-isolation" \
cargo +nightly miri test 2>&1
Level 4 — Tree Borrows (second model confirmation):
MIRIFLAGS="\
-Zmiri-tree-borrows \
-Zmiri-strict-provenance \
-Zmiri-symbolic-alignment-check \
-Zmiri-preemption-rate=0.1 \
-Zmiri-backtrace=full \
-Zmiri-disable-isolation" \
cargo +nightly miri test 2>&1
Interpret results:
For code Miri cannot fully cover:
Concurrent code with custom atomics:
RUSTFLAGS="--cfg loom" cargo test --lib --release -- loom_tests 2>&1
FFI-heavy code:
RUSTFLAGS="-Zsanitizer=address" cargo +nightly test -Zbuild-std --target $(rustc -vV | rg host | awk '{print $2}') 2>&1
Untrusted input parsing:
cargo +nightly fuzz run <target> -- -max_total_time=300 2>&1
For each UB finding:
BEAD: [Category #] [Short description]
FILE: [path:line]
ROOT CAUSE: [one sentence]
FIX: [one sentence]
PROOF: Miri Level [N] pass — [command used]
After all beads are resolved:
#[cfg(miri)] regression tests for each bead — these are the tests that originally caught the UB, locked in so it never returns.unsafe block. Each must name the specific invariant from the taxonomy.When the agent encounters unsafe code during ANY Rust task (not just audits):
Is there unsafe code in the changeset?
YES → Run Miri Level 1 before proceeding.
│ Miri fails?
│ YES → Stop. Classify. Fix. Prove. Then continue.
│ NO → Run Miri Level 2 (strict provenance).
│ Miri fails?
│ YES → Stop. Classify. Fix. Prove. Then continue.
│ NO → Proceed with the original task.
NO → Proceed normally.
This is not optional. Every unsafe block gets Miri'd before it ships.
Every unsafe block requires a SAFETY comment within 5 lines above it. The comment must:
// SAFETY: [Category 4 — Uninitialized Memory]
// All N elements have been written to via `ptr::write` in the loop above.
// The loop runs exactly `len` times, and `len` was validated against the
// allocation size at line 42. MaybeUninit::assume_init is therefore sound.
unsafe { buf.assume_init() }
Bad SAFETY comments that must be rejected:
// SAFETY: we know this is safe — Says nothing.// SAFETY: this is fine because we tested it — Testing does not prove absence of UB.// SAFETY: the caller ensures correctness — Which invariant? What is the contract?When completing a UB audit, produce a summary:
## UB Audit Report
**Scope:** [crate/module/file]
**Miri version:** [output of `cargo +nightly miri --version`]
**Date:** [date]
### Findings
| # | Category | File:Line | Severity | Status |
|---|----------|-----------|----------|--------|
| 1 | Aliasing | src/buf.rs:42 | High | Fixed (Bead #1) |
| 2 | Uninit | src/ffi.rs:98 | High | Fixed (Bead #2) |
### Beads
#### Bead #1: Aliasing violation in buffer resize
- **Root cause:** `&mut` created while `&` to same slice existed
- **Fix:** Restructured to drop shared ref before taking mutable
- **Proof:** `cargo +nightly miri test -- test_buffer_resize` passes Level 3
### Miri CI Status
- [ ] Miri added to CI (Level 2 minimum)
- [ ] All SAFETY comments reviewed
- [ ] Regression tests added for each bead
UnsafeCell or restructure borrows// BEFORE (UB: &mut while & exists)
let ptr = slice.as_ptr();
let mut_ref = &mut slice[0]; // UB: ptr still usable
// AFTER
let mut_ref = &mut slice[0];
// ptr is never created / used across the mutable borrow
MaybeUninit::write + assume_init// BEFORE (UB: mem::uninitialized)
let x: T = unsafe { std::mem::uninitialized() };
// AFTER
let x: T = unsafe {
let mut uninit = MaybeUninit::<T>::uninit();
uninit.write(initial_value);
uninit.assume_init()
};
expose_provenance / with_exposed_provenance// BEFORE (UB: provenance lost)
let addr = ptr as usize;
let recovered = addr as *const T;
// AFTER
let addr = ptr.expose_provenance();
let recovered = std::ptr::with_exposed_provenance::<T>(addr);
// BEFORE (unsound)
unsafe impl Send for MyType {}
// AFTER — if MyType truly needs Send, prove it:
// SAFETY: [Category 9 — Send/Sync]
// MyType's only non-Send field is `*mut Buffer`. Access to the buffer
// is guarded by `self.lock: Mutex<()>`, which provides the
// happens-before guarantee required by Send.
unsafe impl Send for MyType {}
// BEFORE (UB: null pointer from C becomes &T)
let result = unsafe { ffi_call() };
// AFTER
let raw = unsafe { ffi_call() };
let result = NonNull::new(raw).ok_or(Error::NullFromFfi)?;
This skill activates when:
unsafe code during a Rust task and needs to verify itMiri is not optional. Miri is the proof. Ship nothing unsafe without Miri's blessing.