Join GitHub today
GitHub is home to over 50 million developers working together to host and review code, manage projects, and build software together.
Sign upDocument that casting &mut T to &mut MaybeUninit<T> is not safe #66699
Comments
|
In the example you are already required to wrap the code in |
|
@jannickj if you try to write a safe wrapper around FWIW, there's at least one crate in the wild that is unsound because of this mistake. Hey @danielhenrymantilla you probably want to fix it. I wrote you an e-mail regarding other stuff, no reply yet. |
|
@Kixunil yes, thanks for the e-mail, I've been quite busy lately so I have not had much time to address this (or answer the e-mail So, to summarize the issue, it turns out that Which, when |
|
Yes, I believe that's sound. Since I didn't get the answer to the e-mail I started creating a new crate from scratch that's addressing my needs. :) It's not published yet, but has bunch of other cool stuff. (Solves the same problem for slices, has tons of helper methods, iterator, safe cursor...) We can still cooperate if you want. |
|
FYI, here's the crate: https://crates.io/crates/possibly_uninit I hope it will help prevent these kinds of bugs. |
|
Interestingly |
|
How hard would it be to add some basic abstractions into |
|
To me this looks like someone mistakenly assumed But, sure, if someone has a good suggestions for where in the |
|
@Kixunil Having a user-defined
See #63569. However, what you are asking for is not "something for slices and mutable references to |
|
Thanks for recommendation, good point, I will change it (that's why I called it "preview" :)). Is the name |
|
However, note that there is AFAIK no way to implement safe |
|
OK, I will rename it to Yes, the lack of enforcing is something I noticed. It's the primary reason I added It is totally true that " |
…om_init`
Well, that's weird. I've had a safety comment:
```rust
// `MaybeUninit<T>` is guaranteed to have the same ABI as `T`, so
// it's safe to cast `&mut [T]` to `&mut [MaybeUninit<T>]`
```
But it's wrong. `&mut T` and `T` isn't the same thing. While it's true that `T => MaybeUninit<T>`
or the same for an owned container (array, box, etc) should be fine, for an unique borrowed
container (`&mut _`, `&mut [_]`) it is definitely **not fine**, because the original owned value
remains `T`. Example of such a UB in safe code:
```rust
let mut a = ["string"];
<_>::from_init_mut(&mut a[..])[0] = MaybeUninit::uninit();
println!("{}", a); // segfault
```
You can also think of `MaybeUninit<T>` as a supertype of `T` and
then note that `&mut T` is invariant over `T`: https://doc.rust-lang.org/nomicon/subtyping.html#variance
The weirdest part of all of this is that I haven't tested those functions.
There aren't any tests. There aren't any test for safe function with unsafe in it!
I am ashamed...
A related issue in `rust-lang` repo, about documenting unsoundness
of `&mut T => &mut MaybeUninit<T>`: rust-lang/rust#66699

As discussed on Reddit, it turns out that casting
&mut Tto&mut MaybeUninit<T>is not a safe operation, since it allows UB in safe code.Playground example demonstrating the UB: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=93dd41cf851bfc0de2233e0a83b4b778
It is probably a good idea to explicitly point that out in MaybeUninit docs.