-
Notifications
You must be signed in to change notification settings - Fork 12.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use pointer offset instead of deref for A/Rc::into_raw #67339
Conversation
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Oh right, fat pointers... (sorry for the number of force pushes: until I get fully moved over to my new PC the one I'm working on has some messed up dev environment and can't even build rustc fully anymore...) |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
r? @RalfJung |
This comment has been minimized.
This comment has been minimized.
(I'm sick and my backlog is already quite long, no promises when I'll be able to get around to this.) |
The general approach looks good to me, but I feel this is T-libs territory, so r? @SimonSapin |
Per r? @sfackler |
@bors r+ |
📌 Commit eb77f7e has been approved by |
Oops :D |
r? @sfackler |
Use pointer offset instead of deref for A/Rc::into_raw Internals thread: https://internals.rust-lang.org/t/rc-and-internal-mutability/11463/2?u=cad97 The current implementation of (`A`)`Rc::into_raw` uses the `Deref::deref` implementation to get the pointer-to-data that is returned. This is problematic in the proposed Stacked Borrow rules, as this only gets shared provenance over the data location. (Note that the strong/weak counts are `UnsafeCell` (`Cell`/`Atomic`) so shared provenance can still mutate them, but the data itself is not.) When promoted back to a real reference counted pointer, the restored pointer can be used for mutation through `::get_mut` (if it is the only surviving reference). However, this mutates through a pointer ultimately derived from a `&T` borrow, violating the Stacked Borrow rules. There are three known potential solutions to this issue: - Stacked Borrows is wrong, liballoc is correct. - Fully admit (`A`)`Rc` as an "internal mutability" type and store the data payload in an `UnsafeCell` like the strong/weak counts are. (Note: this is not needed generally since the `RcBox`/`ArcInner` is stored behind a shared `NonNull` which maintains shared write provenance as a raw pointer.) - Adjust `into_raw` to do direct manipulation of the pointer (like `from_raw`) so that it maintains write provenance and doesn't derive the pointer from a reference. This PR implements the third option, as recommended by @RalfJung. Potential future work: provide `as_raw` and `clone_raw` associated functions to allow the [`&T` -> (`A`)`Rc<T>` pattern](https://internals.rust-lang.org/t/rc-and-internal-mutability/11463/2?u=cad97) to be used soundly without creating (`A`)`Rc` from references.
☀️ Test successful - checks-azure |
Internals thread: https://internals.rust-lang.org/t/rc-and-internal-mutability/11463/2?u=cad97
The current implementation of (
A
)Rc::into_raw
uses theDeref::deref
implementation to get the pointer-to-data that is returned. This is problematic in the proposed Stacked Borrow rules, as this only gets shared provenance over the data location. (Note that the strong/weak counts areUnsafeCell
(Cell
/Atomic
) so shared provenance can still mutate them, but the data itself is not.) When promoted back to a real reference counted pointer, the restored pointer can be used for mutation through::get_mut
(if it is the only surviving reference). However, this mutates through a pointer ultimately derived from a&T
borrow, violating the Stacked Borrow rules.There are three known potential solutions to this issue:
A
)Rc
as an "internal mutability" type and store the data payload in anUnsafeCell
like the strong/weak counts are. (Note: this is not needed generally since theRcBox
/ArcInner
is stored behind a sharedNonNull
which maintains shared write provenance as a raw pointer.)into_raw
to do direct manipulation of the pointer (likefrom_raw
) so that it maintains write provenance and doesn't derive the pointer from a reference.This PR implements the third option, as recommended by @RalfJung.
Potential future work: provide
as_raw
andclone_raw
associated functions to allow the&T
-> (A
)Rc<T>
pattern to be used soundly without creating (A
)Rc
from references.