Under The Hood
backend rust Rust 1.x

Drop Checker, Drop Glue, ManuallyDrop<T>, and std::mem::forget

Last updated
Prerequisites:
Rust ownership and lifetimes
Understanding of RAII and destructors
  • rust
  • drop
  • drop-checker
  • manuallydrop
  • mem-forget
  • destructor

Read at your depth

The practical view

In Rust, values are dropped automatically at the end of their scope (RAII): the Drop trait's drop() runs when the value goes out of scope. Box, Vec, MutexGuard, File all free resources on drop. ManuallyDrop<T> is a wrapper that prevents the compiler from dropping the inner value automatically — you take manual control (e.g. for FFI where the C side owns the memory). std::mem::forget(v) prevents v's destructor from running (v is 'leaked' deliberately). The drop checker is part of the borrow checker that verifies drop ordering doesn't cause use-after-free (e.g. dropping a reference to a value that drops earlier).

The same idea in other frameworks

react equivalent
N/A — Rust language feature.

Legacy vs modern

Automatic drop vs ManuallyDrop / mem::forget

RAII cleans up automatically; ManuallyDrop/mem::forget suppress the cleanup for cases where ownership moves outside Rust's rules.

before → after
Forgetting to clean up (relying on manual)
let file = File::open(path)?;
// ❌ OLD: if code forgets to close, the OS file handle leaks
ManuallyDrop for FFI ownership transfer
let mut md = ManuallyDrop::new(raw_ptr_holder); // ✅ NEW

Interview gotchas

Context

This tests the borrow-checker integration — interviewers want the drop-ordering analysis and the classic pattern it used to reject.

The mechanical answer

The drop checker is the part of the borrow checker that verifies values are not dropped while still borrowed (which would create a use-after-free when the borrow is later used, or when a destructor reads a dropped value). Historically (pre-NLL), it was conservative: it examined the drop order of locals and the lifetimes of borrows, and rejected code where a value that might be dropped at scope end was borrowed with a lifetime that extended to the end. The classic rejected pattern: a struct containing a reference to a field of another struct being dropped in the same scope, where the reference's lifetime outlived the field's drop. NLL (non-lexical lifetimes) made the analysis much more precise: borrows are considered live only where actually used, so many previously-rejected (but actually-safe) patterns now compile, and genuinely-unsafe drop orderings are still caught.

Trap

The naive answer is 'the drop checker prevents memory leaks'. It prevents use-after-free from drop-ordering, not leaks (leaks are prevented by RAII discipline, not the checker). Another trap: thinking NLL removed the drop checker — it made it more precise; the analysis still exists and still rejects unsound code. Candidates who describe the drop-order/liveness analysis show real understanding.

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

Third-party licenses Press ⌘ K to search.