Skip to content

Use pointer offset instead of deref for A/Rc::into_raw #67339

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Merged
merged 2 commits into from
Jan 16, 2020

Conversation

CAD97
Copy link
Contributor

@CAD97 CAD97 commented Dec 15, 2019

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 to be used soundly without creating (A)Rc from references.

@rust-highfive

This comment has been minimized.

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Dec 15, 2019
@rust-highfive

This comment has been minimized.

@CAD97
Copy link
Contributor Author

CAD97 commented Dec 16, 2019

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...)

@rust-highfive

This comment has been minimized.

@rust-highfive

This comment has been minimized.

@Mark-Simulacrum
Copy link
Member

r? @RalfJung

@rust-highfive

This comment has been minimized.

@RalfJung
Copy link
Member

(I'm sick and my backlog is already quite long, no promises when I'll be able to get around to this.)

@RalfJung
Copy link
Member

The general approach looks good to me, but I feel this is T-libs territory, so r? @SimonSapin

@rust-highfive rust-highfive assigned SimonSapin and unassigned RalfJung Dec 22, 2019
@SimonSapin
Copy link
Contributor

Per curl https://raw.githubusercontent.com/rust-lang/highfive/master/highfive/configs/rust-lang/rust.json|jq .groups.libs|grep @|shuf -n1

r? @sfackler

@rust-highfive rust-highfive assigned sfackler and unassigned SimonSapin Jan 15, 2020
@sfackler
Copy link
Member

@bors r+

@bors
Copy link
Collaborator

bors commented Jan 15, 2020

📌 Commit eb77f7e has been approved by sfackler

@bors bors removed the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Jan 15, 2020
@bors bors added the S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. label Jan 15, 2020
@rust-highfive rust-highfive assigned KodrAus and unassigned sfackler Jan 15, 2020
@Dylan-DPC-zz
Copy link

Oops :D

@Dylan-DPC-zz
Copy link

r? @sfackler

@rust-highfive rust-highfive assigned sfackler and unassigned KodrAus Jan 15, 2020
@bors
Copy link
Collaborator

bors commented Jan 16, 2020

⌛ Testing commit eb77f7e with merge e02c475...

bors added a commit that referenced this pull request Jan 16, 2020
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.
@bors
Copy link
Collaborator

bors commented Jan 16, 2020

☀️ Test successful - checks-azure
Approved by: sfackler
Pushing e02c475 to master...

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
merged-by-bors This PR was explicitly merged by bors. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion.
Projects
None yet
Development

Successfully merging this pull request may close these issues.