Skip to content
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

Clarify and restrict when {Arc,Rc}::get_unchecked_mut is allowed. #101310

Merged
merged 4 commits into from
Nov 21, 2022

Conversation

zachs18
Copy link
Contributor

@zachs18 zachs18 commented Sep 2, 2022

(Tracking issue for {Arc,Rc}::get_unchecked_mut: #63292)

(I'm using Rc in this comment, but it applies for Arc all the same).

As currently documented, Rc::get_unchecked_mut can lead to unsoundness when multiple Rc/Weak pointers to the same allocation exist. The current documentation only requires that other Rc/Weak pointers to the same allocation "must not be dereferenced for the duration of the returned borrow". This can lead to unsoundness in (at least) two ways: variance, and Rc<str>/Rc<[u8]> aliasing. (playground link).

This PR changes the documentation of Rc::get_unchecked_mut to restrict usage to when all Rc<T>/Weak<T> have the exact same T (including lifetimes). I believe this is sufficient to prevent unsoundness, while still allowing get_unchecked_mut to be called on an aliased Rc as long as the safety contract is upheld by the caller.

Alternatives

  • A less strict, but still sound alternative would be to say that the caller must only write values which are valid for all aliased Rc/Weak inner types. (This was mentioned in the tracking issue). This may be too complicated to clearly express in the documentation.
  • A more strict alternative would be to say that there must not be any aliased Rc/Weak pointers, i.e. it is required that get_mut would return Some(_). (This was also mentioned in the tracking issue). There is at least one codebase that this would cause to become unsound (here, where additional locking is used to ensure unique access to an aliased Rc<T>; I saw this because it was linked on the tracking issue).

@rustbot rustbot added the T-libs Relevant to the library team, which will review and decide on the PR/issue. label Sep 2, 2022
@rust-highfive
Copy link
Collaborator

r? @joshtriplett

(rust-highfive has picked a reviewer for you, use r? to override)

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Sep 2, 2022
library/alloc/src/rc.rs Outdated Show resolved Hide resolved
library/alloc/src/sync.rs Outdated Show resolved Hide resolved
@rust-log-analyzer

This comment has been minimized.

@zachs18 zachs18 marked this pull request as ready for review September 2, 2022 08:01
@Kixunil
Copy link
Contributor

Kixunil commented Sep 2, 2022

TBH, I don't like allowing implicit shared mutability via Rc at all. People who need it should explicitly use Rc<UnsafeCell<T>> Then among other things we wouldn't have to explain these things for a bunch of types in std and just have it in the UnsafeCell doc.

@joshtriplett
Copy link
Member

cc @RalfJung: does this look reasonable to you?

@RalfJung
Copy link
Member

RalfJung commented Oct 3, 2022

This sounds reasonable, but might be good to get @CAD97 or @SimonSapin to take a look, who are more familiar with Rc/Arc internals than I am.

@CAD97
Copy link
Contributor

CAD97 commented Oct 3, 2022

I'm also iffy at this point on whether we should be treating Rc as exposing its (unchecked) internal mutability.

However, I do agree that this is sufficient to close the documented soundness hole, and that any looser use should probably be using UnsafeCell.

The only additional case I'd consider allowing intrinsically is when some Rcs are dyn Trait to the same concrete type (including lifetimes).


So to be explicit: this is a clear improvement to the current documentation/guarantees.

@rustbot
Copy link
Collaborator

rustbot commented Nov 18, 2022

Hey! It looks like you've submitted a new PR for the library teams!

If this PR contains changes to any rust-lang/rust public library APIs then please comment with @rustbot label +T-libs-api -T-libs to tag it appropriately. If this PR contains changes to any unstable APIs please edit the PR description to add a link to the relevant API Change Proposal or create one if you haven't already. If you're unsure where your change falls no worries, just leave it as is and the reviewer will take a look and make a decision to forward on if necessary.

Examples of T-libs-api changes:

  • Stabilizing library features
  • Introducing insta-stable changes such as new implementations of existing stable traits on existing stable types
  • Introducing new or changing existing unstable library APIs (excluding permanently unstable features / features without a tracking issue)
  • Changing public documentation in ways that create new stability guarantees
  • Changing observable runtime behavior of library APIs

@zachs18 zachs18 force-pushed the rc_get_unchecked_mut_docs_soundness branch from 548b0cb to 9e7df81 Compare November 18, 2022 18:50
@zachs18 zachs18 force-pushed the rc_get_unchecked_mut_docs_soundness branch from 9e7df81 to 734f724 Compare November 18, 2022 18:50
@RalfJung
Copy link
Member

r? libs

@SimonSapin
Copy link
Contributor

Given how finicky they are to use correctly, at this point I’d be in favor of removing these functions entirely and perhaps replace them with UniqueArc / UniqueRc types that would represent "Arc/Rc with strong_count == 1 && weak_count == 0", implement DerefMut, and have zero-cost conversion to Arc/Rc

@Mark-Simulacrum
Copy link
Member

@bors r+ rollup

This seems OK and we have some sign-offs from other folks, we can iterate on other designs (e.g., UniueArc/Rc) later.

@bors
Copy link
Contributor

bors commented Nov 20, 2022

📌 Commit 734f724 has been approved by Mark-Simulacrum

It is now in the queue for this repository.

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Nov 20, 2022
bors added a commit to rust-lang-ci/rust that referenced this pull request Nov 20, 2022
…iaskrgr

Rollup of 9 pull requests

Successful merges:

 - rust-lang#101310 (Clarify and restrict when `{Arc,Rc}::get_unchecked_mut` is allowed.)
 - rust-lang#104461 (Fix building of `aarch64-pc-windows-gnullvm`)
 - rust-lang#104487 (update ntapi dep to remove future-incompat warning)
 - rust-lang#104504 (Add a detailed note for missing comma typo w/ FRU syntax)
 - rust-lang#104581 (rustdoc: remove unused JS IIFE from main.js)
 - rust-lang#104632 (avoid non-strict-provenance casts in libcore tests)
 - rust-lang#104634 (move core::arch into separate file)
 - rust-lang#104641 (replace unusual grammar)
 - rust-lang#104643 (add examples to chunks remainder methods. )

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
@bors bors merged commit b4513ce into rust-lang:master Nov 21, 2022
@rustbot rustbot added this to the 1.67.0 milestone Nov 21, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-libs Relevant to the library team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.