Skip to content

Clarify provenance of {Arc, Rc}::as_ptr pointer #104337

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

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions library/alloc/src/rc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -845,6 +845,9 @@ impl<T: ?Sized> Rc<T> {
/// The counts are not affected in any way and the `Rc` is not consumed. The pointer is valid
/// for as long there are strong counts in the `Rc`.
///
/// Note that even though the returned pointer is a `*const T`, it is also valid for writes
/// so long as this `Rc` remains unique (i.e. strong count is 1 and weak count is 0).
///
/// # Examples
///
/// ```
Expand Down
3 changes: 3 additions & 0 deletions library/alloc/src/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -852,6 +852,9 @@ impl<T: ?Sized> Arc<T> {
/// The counts are not affected in any way and the `Arc` is not consumed. The pointer is valid for
/// as long as there are strong counts in the `Arc`.
///
/// Note that even though the returned pointer is a `*const T`, it is also valid for writes
/// so long as this `Arc` remains unique (i.e. strong count is 1 and weak count is 0).
///
Comment on lines +855 to +857
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Arc type currently has no way to check that condition atomically. There is no public is_unique. Only weak_count and strong_count, which leave space for a race condition when called separately.

(Well it has one way: Arc::get_mut(). But if you call that then you can just use the resulting &mut T instead of the *const T.)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, so this would act more like Arc::get_mut_unchecked in that it can only be used for code sections where it's statically known that the Arc is unique. Anyway, I don't think I had a use case for Arc in mind when I created this PR, but I thought it would make sense to have the read/write validity guarantees of Rc::as_ptr match with Arc::as_ptr for symmetry (and I couldn't find a reason for why we shouldn't guarantee this for Arc also).

Well it has one way: Arc::get_mut(). But if you call that then you can just use the resulting &mut T instead of the *const T.

Now thinking about it, I'm having a bit of a hard time coming up with cases where Arc::as_ptr is needed for mutation and Arc::get_mut(_unchecked) wouldn't do. I tried to search for Arc::as_ptr on GitHub and most of the uses boil down to:

  • Comparing/hashing the pointer (no mutation involved)
  • Immediately turning it into a &mut T (which is technically not allowed without this guarantee, but this could be done with Arc::get_mut_unchecked, too)
  • Storing it as a *mut T somewhere and mutating it later on when uniqueness is logically/statically guaranteed in some other way (in which case Arc::as_ptr is probably the right thing to use, because it doesn't go through an intermediate reference, unlike Arc::get_mut(_unchecked))

There are some cases (like this one) where a *mut T is passed to FFI and it's not so obvious what happens to it (and not obvious if get_mut(_unchecked) could work, because that one goes through a &mut). In these cases, it's probably good to have the guarantee that the pointer returned by Arc::as_ptr is valid for writes if unique.

/// # Examples
///
/// ```
Expand Down