Under The Hood
backend rust Rust 1.x

Unsafe Rust: Raw Pointers (*const T, *mut T), Undefined Behavior, Miri

Last updated
Prerequisites:
Rust ownership, references, and lifetimes
Understanding of memory safety
  • rust
  • unsafe
  • raw-pointers
  • undefined-behavior
  • miri
  • soundness

Read at your depth

The practical view

unsafe blocks let you do things the compiler cannot verify: dereference raw pointers, call unsafe functions (FFI), access/modify static mut, implement unsafe traits, call unsafe methods. Raw pointers: *const T and *mut T. They can be null, dangling, and ignore borrow rules. Creating a raw pointer is safe; DEREFERENCING it is unsafe (must be in an unsafe block). Unsafe does NOT disable the borrow checker — it only unlocks these specific operations. Rules: ensure the pointer is valid and aligned, the data is initialized, and no aliasing rules are violated (unless using interior mutability properly). Use unsafe sparingly and document the invariants.

The same idea in other frameworks

react equivalent
N/A — Rust language feature.

Legacy vs modern

Safe reference API vs raw-pointer unsafe API

Safe code uses references with compiler guarantees; raw pointers require manual validity/aliasing checks inside unsafe blocks.

before → after
Dereferencing a raw pointer without validation
let p: *const i32 = ptr; // ❌ OLD: no check that it's valid
Validated dereference with documented invariants
// ✅ NEW: check null/alignment, document the lifetime contract
if !p.is_null() && (p as usize) % align_of::<i32>() == 0 {
    let v = unsafe { *p }; // ✅ NEW: invariants upheld
}

Interview gotchas

Context

This tests the UB contract — interviewers want the optimizer's assumption model, not just 'it crashes', because UB can silently corrupt behavior under optimization.

The mechanical answer

Undefined behavior is a set of actions the Rust abstract machine declares as having NO defined semantics: dereferencing null/dangling/misaligned pointers, reading uninitialized memory, creating invalid values (e.g. a bool that is neither 0 nor 1), violating aliasing rules (two &mut to the same location), data races, and calling functions with wrong ABIs. The danger: the compiler is allowed to assume UB never happens. Given that assumption, the optimizer can transform code in ways that are correct only if the assumption holds — so a subtle UB (like a dangling pointer in a cold path) can cause bizarre miscompilation in unrelated code, not just a crash. This is why UB is a soundness issue, not a reliability issue: it invalidates the entire program's guarantees. Miri and sanitizers exist to find it in testing before it ships.

Trap

The naive answer is 'UB means it might crash'. UB means the compiler may assume it never happens and optimize accordingly — behavior is entirely unpredictable. Another trap: thinking a small unsafe block 'contains' the danger — UB from unsafe code can make even safe code behave wrongly because the optimizer's assumptions were violated globally. Candidates who explain the optimizer-assumption model show real soundness understanding.

Under The Hood — a multi-depth technical interview hub.

Third-party licenses Press ⌘ K to search.