Common Unsafe Patterns in Rust and When They're Justified

Unsafe Rust is justified for low-level operations like raw pointers and FFI when you manually verify safety invariants the compiler cannot check.

Unsafe Rust is justified when you need to perform operations the borrow checker cannot verify, such as calling C functions, manipulating raw pointers, or accessing mutable static variables. You must wrap these operations in an unsafe block or function to explicitly acknowledge the risk of undefined behavior. Use unsafe only when you have manually verified the safety invariants, such as ensuring a raw pointer is valid and not dangling before dereferencing it.

unsafe fn read_raw_pointer(ptr: *const i32) -> i32 {
    // Manually verify ptr is valid before dereferencing
    *ptr
}

fn main() {
    let x = 10;
    let ptr = &x as *const i32;
    let value = unsafe { read_raw_pointer(ptr) };
    println!("Value: {}", value);
}