Hacker News new | ask | show | jobs
by mkeeter 1597 days ago
The article says

> A mutable reference must also never point to an invalid object, so doing let role = &mut *uninit.as_mut_ptr() if that object is not fully initialized is also wrong.

I'm curious who's right here, because I've seen your pattern in code recently!

2 comments

The docs for as_mut_ptr: https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.h...

> Incorrect usage of this method:

  let mut x = MaybeUninit::<Vec<u32>>::uninit();
  let x_vec = unsafe { &mut *x.as_mut_ptr() };
  // We have created a reference to an uninitialized vector! This is undefined behavior.
Also, above, it explicitly describes the intended API for partially initializing a struct: https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.h...
Thanks Steve!

It turns out I had misremembered; the cast I was thinking of is

https://github.com/oxidecomputer/hubris/blob/master/sys/kern...

from &mut MaybeUninit<[T]> to &mut [MaybeUninit<T>], which doesn't construct a reference to something uninitialized.

Aren't all the `(*role)` in their code "mutable references" too?

    (*role).name = "basic";
No, this is specifically not creating a mutable reference. So it's fine except for the fact that writing via assignment like this calls the destructor/drop for the old value, if the type has a Drop implementation. That's why &str is fine but String is not, since it will call Drop on a zeroed String (Which is not guaranteed to work) or on an uninitialized String. Using ptr::write instead explicitly does not Drop the old value that is being overwritten.

Basically, if you have something like

    let v = vec![1,2,3];
    v = vec![4,5,6]; // Here vec![1,2,3] is dropped otherwise we would be leaking
Do you have a source/explanation for *role not being a mutable reference? What is this expression's type then?

You mention ptr::write() but it is not used here, and I don't see how you could use it to write to a field?

(*role) is not a reference at all, it is a value. its type is Role.
lvalue not mutable reference, got it. I'm surprised there are contexts where one is fine but the other is UB, but I understand the rule.