rust-lang / unsafe-code-guidelines

Forum for discussion about what unsafe code can and can't do
https://rust-lang.github.io/unsafe-code-guidelines
Apache License 2.0
659 stars 57 forks source link

Is it sound to produce `&[u8]` and `&UnsafeCell` to the same memory so long as the latter isn't "used"? #455

Open joshlf opened 1 year ago

joshlf commented 1 year ago

Is it sound to produce a &[u8] and a &UnsafeCell which refer to the same region of memory and are live at the same time so long as no code performs mutation operations via the latter reference?

If this is sound, then it's possible to write a wrapper type which "disables" interior mutability by simply not exposing it, which is useful for caes such as https://github.com/google/zerocopy/issues/5 (specifically, we are running into issues with how to define the MaybeValid type).

RalfJung commented 1 year ago

This is intended to be sound but Stacked Borrows has issues with it, see https://github.com/rust-lang/unsafe-code-guidelines/issues/303.

joshlf commented 1 year ago

Gotcha. Sounds like the current state of things is that:

Is it the case that, as is mentioned in the issue you linked, replacing &UnsafeCell with &MaybeUninit<UnsafeCell> makes it so that this is guaranteed to be sound? Or, as is speculated in the issue thread, is that just a limitation of Miri being able to see through MaybeUninit?

RalfJung commented 1 year ago

The issue mentions replacing UnsafeCell<T> with MaybeUninit<T>. That is unsound, &MaybeUninit<T> must be read-only like all shared references. I have no idea what the person in the issue meant when they said using MaybeUninit could help; it shouldn't make a difference (and we never got an example of it making a difference, so I think they were just confused and there are other things that changed at the same time).

RalfJung commented 1 year ago

Gotcha. Sounds like the current state of things is that:

To add to the list: under Tree Borrows, this is sound.

joshlf commented 1 year ago

The issue mentions replacing UnsafeCell<T> with MaybeUninit<T>. That is unsound, &MaybeUninit<T> must be read-only like all shared references. I have no idea what the person in the issue meant when they said using MaybeUninit could help; it shouldn't make a difference (and we never got an example of it making a difference, so I think they were just confused and there are other things that changed at the same time).

Ah gotcha. I'm asking a slightly different question, which is: Does stacked borrows consider it insta-UB to have &[u8] and &MaybeUninit<UnsafeCell> live at the same time? In other words, does MaybeUninit (or really any similarly-shaped union) serve as the hypothetical "disable interior mutability" type I was referring to in the original comment?

Unfortunately, I answered my own question in the negative (that code is adapted from the code in #303).

RalfJung commented 1 year ago

Yeah there is no way to mask / disable interior mutability.