Confused by `UnsafeCell` casting rules

I was reading the UnsafeCell documentation and noticed this remark:

Note that the only valid way to obtain a *mut T pointer to the contents of a shared UnsafeCell<T> is through .get() or .raw_get(). A &mut T reference can be obtained by either dereferencing this pointer or by calling .get_mut() on an exclusive UnsafeCell<T> . Even though T and UnsafeCell<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?

1 Like

It's giving the language devs space to make a final decision later.

  • Doc PR and clarification PR
  • Zulip thread about it

    I hope the final aliasing model will allow users to inline get, but we're not ready to promise that.

  • UCG issue about it

    That comment exists out of abundance of caution, since we do not yet have an official aliasing model for Rust. The comment gives the aliasing model the freedom to not just make UnsafeCell special, but to make UnsafeCell::get special. Stacked Borrows does not use that freedom, but until we have an official aliasing model and can say for sure that we do not need this freedom, I'd advise for taking the comment seriously and keeping it around, even if Miri cannot check that you are complying by it.

4 Likes

I also hope that the final aliasing model allows inlining UnsafeCell::get. The idea that UnsafeCell::get in particular is special, instead of UnsafeCell overall, makes the mental model more complicated (at least for me). Anyway, thanks for the info.