unsafe Rust and the soundness contract
Sometimes the borrow checker's rules, which are necessarily conservative, reject code that is actually correct — talking to hardware, calling a C library, implementing a fast data structure that needs two pointers into one buffer. Safe Rust would make these impossible. So Rust provides an escape hatch, the unsafe keyword, which does not turn checking off everywhere; it unlocks a small, specific set of extra powers in a marked region and asks YOU to uphold the rules the compiler can no longer verify. unsafe is not 'Rust without safety'; it is 'Rust where you take on a few obligations the checker hands back to you'.
Concretely, an unsafe block (or unsafe fn) unlocks exactly five things and nothing more: dereferencing a raw pointer (*const T or *mut T), calling an unsafe function or a foreign (FFI) function, accessing or modifying a mutable static, reading the fields of a union, and implementing an unsafe trait (like Send or Sync by hand). That is the whole list. Crucially, inside an unsafe block the ordinary borrow checker, type checker, and all other safety analyses still run exactly as before — unsafe does not let you alias mutably, ignore lifetimes, or skip type checks. It only grants those five operations, each of which has a precondition the compiler cannot check. The soundness contract is the deal: you may use these powers, but you must guarantee that doing so never causes undefined behaviour — no use-after-free, no out-of-bounds access, no creating two &mut to the same data, no data race. If you keep that promise, your unsafe code is 'sound', and code that calls it through a safe interface can never trigger UB no matter what it does. If you break it, you have undefined behaviour, with all the silent-corruption consequences of C.
Why this matters: unsafe is how Rust's safe abstractions are built — Vec, Mutex, Rc, and the standard library are full of audited unsafe inside, wrapped in safe APIs that you can use without ever writing unsafe yourself. The honest framing, and the one most often oversold, is this: Rust's safety guarantee covers the SAFE subset, and it holds precisely because every unsafe block keeps its end of the contract. A single unsound unsafe block can reintroduce exactly the bugs Rust promises to prevent, including ones that corrupt memory used by far-away safe code. So 'Rust is memory-safe' is true and important, but it means 'safe Rust cannot cause UB, AND the unsafe blocks underneath have been written to uphold the contract' — never 'Rust has no undefined behaviour'. Write as little unsafe as possible, keep each block tiny and reviewed, and check it with Miri.
// unsafe unlocks raw-pointer deref; YOU must ensure it points at valid data. let x = 5; let p: *const i32 = &x; // making a raw pointer is SAFE let v = unsafe { *p }; // dereferencing it is UNSAFE: you promise p is valid println!("{v}"); // 5 // The contract: if `p` were dangling, *p would be undefined behaviour — // not a guaranteed crash, possibly silent corruption, exactly as in C.
unsafe grants five specific powers; in return you promise no UB. Break that promise and you get C-style silent corruption inside a Rust program.
unsafe does not disable the borrow checker; it unlocks five operations the compiler cannot verify and hands you their preconditions. Rust's safety claim holds only because each unsafe block upholds the soundness contract — one unsound block can reintroduce exactly the UB Rust prevents.