Transmuting `&mut MaybeUninit::zeroed()` to `&mut [u8]` is unsound
- Dominant language
- Rust
- Stars
- 2.6k
- Forks
- 179
- Avg merge
- 1d 19h
- Merged PRs (30d)
- 29
Description
## Progress
- [x] Fix unsoundness in `FromBytes::read_from_io`
- #2320
- #2358
- [ ] Update documentation as described below
---
These days, `MaybeUninit::zeroed` is [pretty clear](https://doc.rust-lang.org/std/mem/union.MaybeUninit.html#method.zeroed) that you cannot expect all padding bytes to be zero in the output value (same for [`mem::zeroed`](https://doc.rust-lang.org/std/mem/fn.zeroed.html)). Zerocopy [mentions this](https://docs.rs/zerocopy/latest/zerocopy/trait.FromZeros.html#warning-padding-bytes), but it doesn't seem fully internalized by the library:
- `FromZeros::zero` contradicts this, stating that it's similar to `*self = Self::new_zeroed()` and that the difference is it doesn't semantically drop anything. This isn't the only difference! `zero` is capable of fully zeroing all of the bytes of an object until it is moved into, while `*self = Self::new_zeroed()` doesn't guarantee you can then soundly access as a byte slice unless that `Self: IntoBytes`.
- `FromZeros::new_zeroed` doesn't mention the same caveat as `MaybeUninit::zeroed` at all even though it applies.
- The [current implementation](https://github.com/google/zerocopy/blob/17e7e4d98c9d2cd49c94307e2276b7ce377aa74a/src/lib.rs#L4551) of `FromBytes::read_from_io` is unsound, since there may still be padding bytes for `!IntoBytes` types from `new_zeroed`. It should be constructing a `MaybeUninit::uninit()` then [zeroing its bytes](https://doc.rust-lang.org/std/ptr/fn.write_bytes.html) before casting to `&mut [u8]`.
I'll send a PR fixing the unsoundness issue. I'm also interested in improving the documentation to be more consistent and to provide clear working alternatives to documented unsound operations.
Contributor guide
Assessment
This issue has not been assessed yet.