25.1 Overview
In safe Rust, the compiler prevents issues like data races, invalid memory access, and dangling pointers. However, there are situations where the compiler cannot confirm that an operation is safe—even if, in reality, it is correct when used carefully. This is when unsafe Rust comes into play.
Unsafe Rust allows five operations that safe Rust forbids:
- Dereferencing raw pointers (
*const T
and*mut T
). - Calling unsafe functions (including foreign C functions).
- Accessing and modifying mutable static variables.
- Implementing unsafe traits.
- Accessing union fields.
Aside from these operations, Rust’s usual rules regarding ownership, borrowing, and type checking still apply. Unsafe Rust does not turn off all safety checks; it only relaxes restrictions on the five operations listed above.
25.1.1 Why Do We Need Unsafe Code?
Rust is designed to support low-level systems programming while maintaining high safety standards. Nevertheless, certain scenarios require unsafe code:
- Hardware Interaction: Accessing memory-mapped I/O or device registers is inherently unsafe.
- Foreign Function Interface (FFI): Interoperating with C or other languages that lack Rust’s safety invariants.
- Advanced Data Structures: Intrusive linked lists or lock-free structures may need operations not expressible in safe Rust.
- Performance Optimizations: Specialized optimizations can involve pointer arithmetic or custom memory layouts that go beyond safe abstractions.
Because the compiler cannot verify correctness in these contexts, you must manually ensure that your code preserves all necessary safety properties.