-
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
Clarify provenance of {Arc, Rc}::as_ptr pointer #104337
Conversation
Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @Mark-Simulacrum (or someone else) soon. Please see the contribution instructions for more information. |
Hey! It looks like you've submitted a new PR for the library teams! If this PR contains changes to any Examples of
|
r? libs-api I think we likely want to run this past UCG -- in particular we don't really have much normative documentation about validity for reads/writes on raw pointers like this yet (at least to my awareness). This seems broadly correct but may not be something we want to add yet. |
I agree that we should be careful with how we document this. I think this new documentation leaves edge cases unanswered. E.g. what about a situation with a non-zero weak counter? (Using some other mechanism to make sure the weak pointers aren't upgraded while writing through the |
/// 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). | ||
/// |
There was a problem hiding this comment.
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
.)
There was a problem hiding this comment.
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 withArc::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 caseArc::as_ptr
is probably the right thing to use, because it doesn't go through an intermediate reference, unlikeArc::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.
@y21 |
Sorry! I've been a bit busy the past few weeks so I forgot about this PR.
I'm not sure I understand this concern. The PR guarantees that writes are valid if and only if the strong count is 1 and weak count is 0. So, for a non-zero weak counter, writes are not valid. My concern is that this "conflicts" with the documentation of
Is it fine for the guarantees here to be different from |
Ping from triage: I'm closing this due to inactivity, Please reopen when you are ready to continue with this. @rustbot label: +S-inactive |
Fixes #87862.
This spawned off of a discussion in the Rust discord server last year about whether the following code is valid:
That is, can you mutate the returned
*const T
fromRc::as_ptr
(if theRc
is unique).Looking at the function signature, one might think that mutating the
*const T
is illegal because it comes from&Rc<T>
(effectively a&T
->&mut T
transmute), howeverRc
does not directly store theT
; instead it is stored inRcBox
that theRc
always has a*mut
to. This has always been an implementation detail up until now and one would rely on implementation details when writing to the returned pointer.It is even noted in the function body of
Rc::as_ptr
that the provenance must be retained such that methods like{Rc, Arc}::get_mut
could create a&mut T
to the contained item using this function (if I understand correctly).rust/library/alloc/src/rc.rs
Lines 860 to 866 in cd12888
This PR documents/guarantees the ability to write to the pointer