TRT
Sign in
mediumExpertdebugging

What are the exact rules for writing sound `unsafe` Rust (aliasing, alignment, `MaybeUninit`, `catch_unwind` across FFI), how does `cargo miri` detect.

Detail the 5 `unsafe` operations, Stacked/Tree Borrows in `Miri`, `MaybeUninit`T``, `extern "C-unwind"` panic safety, and C11/Rust memory orderings.

TRT practice prompt — not a verified question from a named employer.

The Runtime Theory Team2 min read

A strong answer

Writing expert systems Rust requires mastering the exact boundary between safe and unsafe Rust: (1) unsafe does NOT turn off the borrow checker—it only unlocks 5 superpowers (dereferencing raw pointers *const T/*mut T, calling unsafe fn, implementing unsafe trait like Send/Sync, accessing static mut, and accessing union fields), shifting the burden of proving zero Undefined Behavior (UB) onto the author's // SAFETY: invariant! Even when len == 0, std::slice::from_raw_parts(ptr, 0) requires ptr to be non-null and properly aligned (NonNull::dangling())! (2) cargo miri runs your tests inside an interpreter for Rust's Mid-level Intermediate Representation (MIR) implementing Stacked Borrows / Tree Borrows, deterministically catching every invalid pointer alignment, null slice, uninitialized read (MaybeUninit), or aliasing violation (&mut T overlapping &T)! (3) Lock-Free Acquire / Release Atomics: On weakly ordered CPUs (ARM64), the CPU and compiler can reorder independent memory writes! When Producer writes data = 42 and publishes ready.store(true, Ordering::Release), and Consumer reads if ready.load(Ordering::Acquire) { read(data) }, the Release–Acquire pair forms a happens-before synchronization edge: every memory write before the Release store is guaranteed visible after the Acquire load!

A Release store on atomic variable $A$ in Thread 1 synchronizes-with an Acquire load on $A$ in Thread 2 that observes the stored value, establishing a happens-before ordering for all memory writes performed by Thread 1 prior to the Release store. On x86-64 (Total Store Order, TSO), regular loads and stores already preserve Acquire/Release ordering in hardware (so Acquire/Release compiles to plain mov with a compiler reordering barrier!); on ARM64, the compiler emits stlr (Store-Release) and ldar (Load-Acquire) instructions so hardware store buffers flush in order.

Using Acquire/Release instead of SeqCst (Ordering::SeqCst) avoids full memory-fence instructions (mfence / lock on x86, double barriers on ARM), running at maximum L1 cache speed while guaranteeing lock-free publication safety. In production systems (crossbeam lock-free channels/epoch GC, tokio task queues, Bytemuck / zerocopy safe byte-casting traits, and cargo miri in CI across the Rust standard library and major crates.), engineers monitor these exact trade-offs to keep p99 latency predictable and prevent resource exhaustion under peak load.

What the interviewer is listening for

  • Traces how sound unsafe encapsulation, Miri UB verification, and Acquire/Release atomic memory ordering operates in memory step by step rather than giving a vague textbook definition.
  • States the core correctness invariant and explains why edge cases do not violate it.
  • Quantifies time, space, and hardware costs (Ordering::Relaxed, Ordering::Acquire / Release) with concrete numbers.
  • Identifies real-world failure modes (Creating two &mut T references to the same address in unsafe code (let a = &mut *p; let b = &mut *p; *a = 1; *b = 2;)) and explains how production systems mitigate them.

Common mistakes

  • Treating sound unsafe encapsulation, Miri UB verification, and Acquire/Release atomic memory ordering as a black box without explaining the underlying memory or state transitions.
  • Ignoring worst-case tail latency or memory overhead (Passing a C NULL pointer with len = 0 into std::slice::from_raw_parts(ptr, len)).
  • Forgetting boundary conditions and error recovery (Casting a &[u8] byte slice directly to &MyHeaderStruct with unsafe { &*(bytes.as_ptr() as *const MyHeaderStruct) } without checking alignment or padding).

This answer walks

Practice follow-ups

  1. 01Why is unwinding a Rust `panic!` across an `extern "C"` FFI boundary into C or Python Undefined Behavior, and how does `std::panic::catch_unwind` prevent it?
  2. 02When is `Ordering::Relaxed` actually safe and sufficient (e.g., an isolated metric counter `requests_total.fetch_add(1, Ordering::Relaxed)` that does not guard any other memory)?

Not started

Sign in to save your learning progress.

Sign in to save