How to cast immutable to mutable reference with UnsafeCell

Since Rust 1.73.0 I have troubles compiling the following code:

    fn not_working(&self, slab: &Slab) {
        let foo: &mut String = unsafe { &mut *(&slab.ps.char_buf as *const _ as *mut _) };
    }

How can I solve this using UnsafeCell as it is suggested by the compiler?

You have to put the UnsafeCell around the char_buf or the ps. However, you need some kind of synchronization logic to ensure that there is only one mutable reference to it at a time. Do you have that?

1 Like

Casting from &Type to &mut Type is always[1] UB, you cannot do it. Going from &Slab to &mut String is valid iff Slab (transitively) contains UnsafeCell<String>.

To a useful first approximation, can your use case be written using RwLock, at the cost of doing a bunch of extra runtime checks?

  • Yes: you can use UnsafeCell as an unchecked RwLock. If the lock would have blocked, you have a race and UB.
  • No: you cannot use UnsafeCell to accomplish what you're trying to do.

  1. Sometimes it isn't LLVM UB. It might not even be immediate Miri UB if UnsafeCell or UnsafePinned cover all of the bytes of Type. If you understand all that you don't need me to tell you this and you also understand that it's still terribly unsound. ↩ī¸Ž

17 Likes

A similar but slightly different way of framing this is that it has the same safety properties of using RwLock only by doing .try_read().unwrap_unchecked() and .try_write().unwrap_unchecked()

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.