Part 3 · 1 chapters · ~8 min
Memory and unsafe
Stack and heap, Box and allocation, drop order and RAII, the layout of Vec and String, slices and fat pointers, interior mutability, what unsafe permits and what it does not, building safe abstractions over unsafe code, FFI with C, and Miri for checking undefined behaviour.
6
Layout, RAII and unsafe
code
// RAII: resources released in Drop, deterministically, at end of scope
struct Lease { id: u64 }
impl Drop for Lease { fn drop(&mut self) { release_lease(self.id) } } // runs even on early return or panic unwind
// Vec<T> is (pointer, length, capacity) on the stack + a heap buffer; &[T] is a fat pointer (ptr, len)
let v: Vec<i64> = Vec::with_capacity(1_000); // one allocation up front
// unsafe unlocks five abilities only: dereference raw pointers, call unsafe fns, access mutable statics,
// implement unsafe traits, access union fields. The borrow checker still runs everywhere else.
fn first_unchecked(xs: &[i64]) -> i64 {
assert!(!xs.is_empty()); // the safe wrapper upholds the invariant...
unsafe { *xs.get_unchecked(0) } // ...that the unsafe call relies on
}
// FFI: call C
extern "C" { fn abs(x: i32) -> i32; }
let y = unsafe { abs(-3) };
cargo +nightly miri test # Miri interprets tests and reports undefined behaviour in unsafe codeThe rule: unsafe code is fine when it is small, documented with a // SAFETY: comment stating the invariant, and wrapped in a safe API that cannot be misused. Most application code never needs it; libraries such as Vec and Tokio contain it so you do not have to.