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

Allow arithmetic and certain bitwise ops on AtomicPtr #96935

Merged
merged 2 commits into from
Jul 6, 2022

Conversation

thomcc
Copy link
Member

@thomcc thomcc commented May 11, 2022

This is mainly to support migrating from AtomicUsize, for the strict provenance experiment.

This is a pretty dubious set of APIs, but it should be sufficient to allow code that's using AtomicUsize to manipulate a tagged pointer atomically. It's under a new feature gate, #![feature(strict_provenance_atomic_ptr)], but I'm not sure if it needs its own tracking issue. I'm happy to make one, but it's not clear that it's needed.

I'm unsure if it needs changes in the various non-LLVM backends. Because we just cast things to integers anyway (and were already doing so), I doubt it.

API change proposal: rust-lang/libs-team#60

Fixes #95492

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

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 r? rust-lang/libs-api @rustbot label +T-libs-api -T-libs to request review from a libs-api team reviewer. 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

@rust-highfive
Copy link
Collaborator

r? @kennytm

(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 May 11, 2022
@thomcc
Copy link
Member Author

thomcc commented May 11, 2022

This is a new unstable API, so I guess this is appropriate.

r? rust-lang/libs-api @rustbot label +T-libs-api -T-libs

These wouldn't stabilize separately from the rest of the strict provenance experiment, though, and at the moment are mostly to help test concurrent code under miri.

@rust-highfive rust-highfive assigned dtolnay and unassigned kennytm May 11, 2022
@rustbot rustbot added T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. and removed T-libs Relevant to the library team, which will review and decide on the PR/issue. labels May 11, 2022
@m-ou-se
Copy link
Member

m-ou-se commented May 11, 2022

I think fetch_add in this PR can easily be a footgun that I'd totally shoot myself with. For example, I might have an AtomicPtr to a 16-byte aligned struct, of which I use the lower 4 bits as some kind of counter. Then I'd probaly write a.fetch_add(1) assuming it'd add 1 to that counter instead of bumping the pointer 16 bytes over.

@WaffleLapkin
Copy link
Member

@m-ou-se Isn't the same applicable to <*const T>::add?

@m-ou-se
Copy link
Member

m-ou-se commented May 11, 2022

Not as much, because it's quite uncommon to do tricks like storing flags or counters inside a regular raw pointer. It's very common to do that with atomics though. There are many AtomicUsizes in the world that store a pointer and some flags, which could (should?) be upgraded tot AtomicPtr instead. Having AtomicPtr::atomic_add could be a big pitfall then.

@thomcc
Copy link
Member Author

thomcc commented May 14, 2022

I think fetch_add in this PR can easily be a footgun that I'd totally shoot myself with. For example, I might have an AtomicPtr to a 16-byte aligned struct, of which I use the lower 4 bits as some kind of counter.

I don't disagree, but on the other hand if we have fetch_add default to bytes, something like a.fetch_add(1, ord).add(1) will do the wrong thing.

It's a tricky API problem -- I'm open to suggestions. One option would be to only offer the bytewise versions.

@m-ou-se
Copy link
Member

m-ou-se commented May 14, 2022

I don't disagree, but on the other hand if we have fetch_add default to bytes

I'm not saying we should do that either. That's just as confusing.

@m-ou-se
Copy link
Member

m-ou-se commented May 14, 2022

Maybe we should have fetch_byte_add and fetch_ptr_add or something like that.

@thomcc
Copy link
Member Author

thomcc commented May 14, 2022

Maybe we should have fetch_byte_add and fetch_ptr_add or something like that.

I've gone ahead and renamed things along these lines.

@WaffleLapkin
Copy link
Member

I'm slightly worried that having an inconsistent naming scheme is worse, than having fetch_add on pointers be in units of T. To me fetch_ptr_add sounds like it takes *const T instead of an usize.

@thomcc
Copy link
Member Author

thomcc commented May 15, 2022

This problem is actually why it took so long for me to make this PR.

@thomcc
Copy link
Member Author

thomcc commented May 16, 2022

Not as much, because it's quite uncommon to do tricks like storing flags or counters inside a regular raw pointer

FWIW this isn't exactly true. Code like our std::io::Error isn't that rare, especially in contexts like virtual machines and language runtimes. It's not limited to stuff like that though, you also see similar tricks in the semver and string_cache crates. And this sort of thing is a common footgun for them too, when ported from using integers to pointers.

I'm not sure how much this matters, but it does make some case that this footgun would not be unprecedented (although I'm unsure how good of an argument that is in and of itself).

@JohnCSimon JohnCSimon added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jun 20, 2022
@thomcc
Copy link
Member Author

thomcc commented Jun 30, 2022

I probably need to update this after #97423. I'll take a look later today or tomorrow.

@m-ou-se m-ou-se added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jul 1, 2022
This is mainly to support migrating from AtomicUsize, for the strict
provenance experiment.

Fixes rust-lang#95492
@rustbot
Copy link
Collaborator

rustbot commented Jul 1, 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

@thomcc
Copy link
Member Author

thomcc commented Jul 1, 2022

This didn't end up needing any changes, but I rebased it, and wrote a change proposal (bit of a long one, sorry if they should be shorter -- the semantics are just a bit subtle, so I tried to cover everything): rust-lang/libs-team#60

@bors ready

@thomcc
Copy link
Member Author

thomcc commented Jul 1, 2022

Err, hm. Wrong bot probably (oops). Either way:

@rustbot label -S-waiting-on-author +S-waiting-on-review

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jul 1, 2022
@RalfJung
Copy link
Member

RalfJung commented Jul 2, 2022

Btw, these operations will also need changes on the Miri side to be supported there.

Copy link
Member

@dtolnay dtolnay left a comment

Choose a reason for hiding this comment

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

This looks terrific to me. :) Thanks. I concur with all of the design decisions justified in rust-lang/libs-team#60:

  • the idea that these should exist at all, rather than doing CAS loops in the downstream code
  • element-sized offsetting by itself is not sufficient
  • byte-sized offsetting by itself would be annoying (but I'm sure we'll revisit this possibility when stabilizing)
  • the specific naming scheme fetch_ptr_add and fetch_byte_add
  • atomptr.fetch_ptr_add(n, ord).add(n) as the recommendation for non-wrapping semantics

The last would be good to document as an idiom in the part of the documentation that talks about fetch_ptr_add's relationship with wrapping_add, or maybe in the example code. r=me if you get to it before bors does, otherwise separate PR or leave to the stabilization PR.

@dtolnay
Copy link
Member

dtolnay commented Jul 6, 2022

@bors r+

@bors
Copy link
Contributor

bors commented Jul 6, 2022

📌 Commit e65ecee has been approved by dtolnay

@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 Jul 6, 2022
bors added a commit to rust-lang-ci/rust that referenced this pull request Jul 6, 2022
…laumeGomez

Rollup of 7 pull requests

Successful merges:

 - rust-lang#96935 (Allow arithmetic and certain bitwise ops on AtomicPtr)
 - rust-lang#98519 (Replace some `guess_head_span` with `def_span`)
 - rust-lang#98911 (rustdoc: filter '_ lifetimes from ty::Generics)
 - rust-lang#98939 (rustdoc: Add more semantic information to impl IDs)
 - rust-lang#98971 (Fix typo in file descriptor docs)
 - rust-lang#98983 (docs: Add overview of `rustc_middle::mir::TerminatorKind`)
 - rust-lang#98984 (Remove erroneous doc comment)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
@bors bors merged commit 4755173 into rust-lang:master Jul 6, 2022
@rustbot rustbot added this to the 1.64.0 milestone Jul 6, 2022
assert_eq!(atom.load(SeqCst), ptr.map_addr(|a| a | 0b1001));

assert_eq!(atom.fetch_and(MASK_PTR, SeqCst), ptr.map_addr(|a| a | 0b1001));
assert_eq!(atom.load(SeqCst), ptr);
Copy link
Member

@RalfJung RalfJung Jul 7, 2022

Choose a reason for hiding this comment

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

This test just compares the address of the pointer.

Would be good to also load from the pointer obtained via atom.load(), to ensure that it also has the provenance to actually access memory.

bors added a commit to rust-lang/miri that referenced this pull request Jul 7, 2022
rustup; ptr atomics

Adds support for the operations added in rust-lang/rust#96935.
I made the pointer-binops always return the provenance of the *left* argument; `@thomcc` I hope that is what you intended. I have honestly no idea if it has anything to do with what LLVM does...

I also simplified our pointer comparison code while I was at it -- now that *all* comparison operators support wide pointers, we can unify those branches.
@jonhoo
Copy link
Contributor

jonhoo commented Jul 7, 2022

This lists #95228 as the tracking issue. Should that issue be updated to also mention this new feature (strict_provenance_atomic_ptr that is), or should we open a new, different tracking issue specifically for these methods? It feels like there's a decent argument for landing those independently of the other strict provenance mechanisms.

@WaffleLapkin
Copy link
Member

I think opening a separate tracking issue would be a good idea, the "generic strict_provenance tracking issue" is already overloaded by itself.

#[cfg(not(bootstrap))]
// SAFETY: data races are prevented by atomic intrinsics.
unsafe {
atomic_add(self.p.get(), core::ptr::invalid_mut(val), order).cast()
Copy link
Member

Choose a reason for hiding this comment

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

If there's any chance that this could end up calling the intrinsic with a pointer type for the LHS and usize for the RHS, that would be great -- it would make it very clear from the types that it's only the left input that carries provenance.

@WaffleLapkin
Copy link
Member

I've opened a tracking issue for this feature: #99108

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-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[strict provenance] Close The Gap Between AtomicUsize and AtomicPtr