Course contentsShow
← Rust
Lesson 1025 of 1,9109. Smart Pointers and Interior MutabilityFree lesson

The Contract of UnsafeCell

Adhere to Rust's aliasing rules when manually managing memory safety.

In this lesson, you will learn how to honor the strict memory aliasing rules required when using UnsafeCell<T> to bypass Rust's standard borrow checker.

UnsafeCell<T> is the foundational building block for all interior mutability in Rust. While Cell and RefCell provide safe interfaces, UnsafeCell gives you raw, unchecked access to its inner data. However, the compiler assumes that your code obeys the fundamental aliasing rules: you may have many immutable references to data, or exactly one mutable reference, but never both at the same time.

When you use UnsafeCell<T>::get() to retrieve a pointer, you are essentially telling the compiler, "I promise to handle the safety contract manually."

The Contract in Practice

If you obtain a pointer via UnsafeCell, you must ensure that you never create a mutable reference (&mut T) while an immutable reference (&T) exists that points to the same memory. Even if the data is wrapped in UnsafeCell, creating an &mut T implies exclusive access. If you concurrently hold an &T elsewhere, the compiler's optimizer may assume the data behind the &T is constant. If you modify the memory via your pointer, you trigger Undefined Behavior (UB).

use std::cell::UnsafeCell;

fn main() {
    let u = UnsafeCell::new(5);
    
    // We get two raw pointers to the same memory
    let ptr1 = u.get();
    let ptr2 = u.get();
    
    unsafe {
        // This is safe only if we don't violate aliasing.
        // We must ensure no &T exists if we are writing via *ptr1.
        *ptr1 += 1;
        
        // This is valid as long as we aren't simultaneously
        // dereferencing an &T to the same data.
        println!("Value: {}", *ptr2);
    }
}

The "contract" is simply this: UnsafeCell does not turn off the rules of aliasing; it merely provides the mechanism to perform mutation that the borrow checker cannot verify. You are personally responsible for proving that no aliasing violation occurs at the moment of mutation. If you treat UnsafeCell as a license to ignore Rust's exclusivity requirements, you will introduce subtle, non-deterministic bugs that the compiler cannot detect for you.

Key Takeaway: UnsafeCell allows you to obtain mutable pointers to data, but you remain strictly bound by Rust’s aliasing rules; you must guarantee that no immutable references exist whenever you perform a write.