Skip to content
Free public beta until December 4, 2026: every course is open, no card needed. After that, the first chapter of each course stays free and full access is a one-time $39 ($19 for up to 100 founding members chosen for helpful feedback). Your progress is kept. How the beta works

Recipe

Review an unsafe block

Use when: a change adds or edits an unsafe block, unsafe fn or unsafe impl

Goal: each unsafe operation is necessary, documented, and valid for every input the safe code around it allows

Taught in Checking unsafe code

  1. 1

    Look for a safe standard-library function that does the same job (get_disjoint_mut, split_at_mut, to_bits, an atomic).

    Example

    A static mut counter: replace it with an AtomicU32, and the review is over.

    Why: the safest unsafe block is the one that isn't there.

  2. 2

    For every dereference, unsafe call or impl in the block, read the documented conditions.

    Example

    &mut *p.add(i): p.add(i) in bounds; the &mut valid, aligned, and not overlapping any other live reference.

    Why: the SAFETY comment can only be checked against a complete list.

  3. 3

    Every condition must be backed by a fact in the code: a check, a loop bound, a private invariant.

    Example

    "i and j are in bounds (checked above)", but nothing checks i != j: the review has found the missing condition.

    Why: a comment that names no checkable fact is a hope.

  4. 4

    Ask what safe arguments could reach the block: equal indices, empty slices, the largest length, public fields set to anything.

    Why: soundness means every safe caller, not only the ones in today's code.

  5. 5

    Add a test for each edge and run the tests with cargo +nightly miri test; for code calling C, use a sanitizer.

    Why: tools catch the cases where the argument was wrong, but only on paths a test reaches.

Common mistakes

  • Accepting "the tests pass" as the argument.
  • Reviewing only the lines inside unsafe { }, not the checks and fields around them.
  • Allowing a safe function whose soundness depends on how today's callers use it.