Confused by `UnsafeCell` casting rules
⚓ Rust 📅 2025-12-03 👤 surdeus 👁️ 1I was reading the UnsafeCell documentation and noticed this remark:
Note that the only valid way to obtain a
*mut Tpointer to the contents of a sharedUnsafeCell<T>is through.get()or.raw_get(). A&mut Treference can be obtained by either dereferencing this pointer or by calling.get_mut()on an exclusiveUnsafeCell<T>. Even thoughTandUnsafeCell<T>have the same memory layout, the following is not allowed and undefined behavior:unsafe fn not_allowed<T>(ptr: &UnsafeCell<T>) -> &mut T { let t = ptr as *const UnsafeCell<T> as *mut T; // This is undefined behavior, because the `*mut T` pointer // was not obtained through `.get()` nor `.raw_get()`: unsafe { &mut *t } }
Essentially it seems to state that using pointer casting to convert &UnsafeCell<T> to &mut T is unsound, but it does not explain why. Intuitively, every step of the conversion in the code sample appears sound to me, assuming that the rest of the code does not access the contents of the cell.
I ran this code through Miri, hoping it would produce a more concrete error, but it turns out Miri produces no errors for this code, even with -Zmiri-strict-provenance enabled.
So my question is why exactly is this code considered unsound? What specific rule does it violate?
3 posts - 2 participants
🏷️ Rust_feed