25.10 Summary

Unsafe Rust is a necessary component of the language, providing the means to perform operations that are beyond the scope of the compiler’s static safety verification. It unlocks capabilities essential for systems programming, such as hardware interaction, FFI, low-level optimizations, and the implementation of foundational data structures.

Key points to remember:

  • The unsafe keyword enables five specific capabilities otherwise forbidden in safe Rust.
  • unsafe does not disable the borrow checker or other fundamental Rust safety rules like type checking. It only permits the five specified “superpowers.”
  • Programmers using unsafe take responsibility for manually upholding Rust’s safety invariants for the operations performed within unsafe contexts.
  • Use unsafe { ... } blocks to isolate specific unsafe operations within a function.
  • Use unsafe fn when a function requires the caller to guarantee certain preconditions for safe execution.
  • Raw pointers (*const T, *mut T) offer C-like pointer flexibility but require manual verification for validity, alignment, and aliasing rules before dereferencing or performing arithmetic.
  • FFI (extern "C") allows interaction with external code but is unsafe because Rust cannot verify the external code or the declared function signatures.
  • static mut provides mutable global variables but is inherently unsafe due to data race risks; prefer thread-safe alternatives like Mutex or atomics.
  • Accessing union fields is unsafe as the compiler doesn’t track the active field.
  • Implementing unsafe trait requires unsafe impl as the programmer must guarantee adherence to the trait’s safety contract.
  • Advanced features like std::mem::transmute and asm! are powerful but extremely dangerous and should be used sparingly and with great care.
  • Minimize Unsafe Code: Keep unsafe blocks as small and localized as possible.
  • Encapsulate Unsafety: Whenever feasible, wrap unsafe operations within safe abstraction layers (safe functions or methods).
  • Document Assumptions: Clearly document the invariants and safety conditions that must hold for any unsafe block or unsafe fn to be correct.
  • Verify Thoroughly: Use tools like Miri, code review, and rigorous testing (including fuzzing) to validate the correctness of unsafe code sections.

Unsafe Rust is a tool to be used judiciously. When employed carefully and correctly, it allows Rust to achieve the low-level control and performance characteristics required for systems programming, while the majority of the codebase benefits from the strong safety guarantees of safe Rust.

25.10.1 Further Reading

  • The Rustonomicon: The official guide to Unsafe Rust, delving into memory layout, undefined behavior, FFI details, concurrency, and more. Essential reading for serious unsafe usage.
  • Rust Standard Library Documentation: Key modules include std::ptr (raw pointers), std::mem (memory operations like transmute, size_of), std::ffi (foreign function interface), std::sync::atomic (atomic types), and std::arch (platform-specific intrinsics and assembly).
  • Rust Atomics and Locks by Mara Bos: An in-depth exploration of low-level concurrency primitives in Rust, heavily featuring unsafe code and concepts.