Is it safe to "hide" a &(mut) T inside a &mut T?

Basically, I'd like to know if the below is safe (and why). If it's not safe, is there an easy way to make it safe?

What about if do_it required &mut self instead of &self? Conceptually, it still seems to me that it should be safe, because the two references cannot touch the same memory.

playground

pub struct Container<T> {
    thing: T, // thing is private
    pub data: i32,
}

// Assume that this is only implemented outside this module, 
// so implementors cannot see the `thing` field.
pub trait Thing: Sized {
    fn do_it(&self, c: &mut Container<Self>);
}

impl<T: Thing> Container<T> {
    fn run(&mut self) {
        let ptr = &self.thing as *const T;
        let thing = unsafe { ptr.as_ref() };
        thing.unwrap().do_it(self);
    }
}

It's not safe for &self and &mut Container<Self> to alias the same memory. It doesn't really matter that the T: Thing can't see that inner thing field, because it could still call a Container method that does mutate that field. Or even more basic, it could modify c entirely with something like mem::replace or mem::take, and this indirectly modifies &self.

It doesn't really matter whether you actually do such things, but you could, and the compiler would have to do whole-program analysis to prove that you don't. Fundamentally, &mut must have unique access, and it's undefined behavior for that to alias/overlap any other references.

2 Likes

Argh! Good point, they could blow it all away by assigning.

I'll go with the safe alternative, which should cost very little extra:

thing: Option<Box<T>>,
...
fn run(&mut self) {
    let thing = self.thing.take();
    thing.as_ref().unwrap().do_it(self);
    self.thing = thing;
}

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.