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

Atomics must be mutable #2464

Merged
merged 5 commits into from
Aug 9, 2022
Merged

Conversation

RalfJung
Copy link
Member

@RalfJung RalfJung commented Aug 5, 2022

@RalfJung RalfJung added the S-blocked-on-rust Status: Blocked on landing a Rust PR label Aug 5, 2022
@RalfJung RalfJung changed the title Atomic must be mutable Atomics must be mutable Aug 5, 2022
let (alloc_id, _offset, _prov) =
this.ptr_try_get_alloc_id(place.ptr).expect("there are no zero-sized atomic accesses");
if this.get_alloc_mutability(alloc_id)? == Mutability::Not {
throw_ub_format!("atomic operations cannot be performed on read-only memory");
Copy link
Member

Choose a reason for hiding this comment

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

Is it worth noting that this is target/size-specific for atomic loads? Or maybe there's a way to phrase it less strictly?

The guidance I've always been given for dealing with cross-process shared memory is that this is that atomics must be used if another process may write to it and that raw pointers (since obviously references are out of the question) would be UB (even if volatile were used), as it would still be a data race.

I do sympathize with not writing to add the target-specific logic for when this is broken to miri (it seems fragile and gross), but my concern is that encouraging people to not use atomics for this would lead them to perform worse UB.

(Unless we want to consider it not a data race?)

Copy link
Member

@taiki-e taiki-e Aug 7, 2022

Choose a reason for hiding this comment

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

AFAIK, the following are cases where atomic loads perform operations that could be problematic on read-only memory. 1

EDIT: pre-v6 arm issue is not Linux only.
EDIT: see rust-lang/unsafe-code-guidelines#355 (comment) for the emulator's case.

Considering the above, I think it is ok to allow atomic load on read-only memory when all of the following are met. (assuming we don't want to do complex and fragile target-specific processing)

  • size is pointer-width or smaller. 2
  • ordering is relaxed (or unordered).

And the error message would probably be something like:

atomic load operations with non-relaxed ordering or grater than pointer-width cannot be performed on read-only memory

Also, even if Miri does not allow them, I agree that additional notes would be helpful.

Footnotes

  1. armv6+'s 64-bit load is ldrexd, powerpc64 and s390x have 128-bit atomic load instructions, and RISC-V and MIPS don't have double-width atomics, so those platforms are fine. I don't know about 32-bit powerpc/sparc's 64-bit atomic load -- IIRC LLVM does not support the former, and the latter is a tier 3 target.

  2. However, on 64-bit architecture's ILP32 ABIs, such as x86_64's X32 ABI, 64-bit load is definitely okay, so if Miri or rustc is aware of the architecture's pointer width, we may want to allow those as well.

Copy link
Member Author

Choose a reason for hiding this comment

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

Considering the above, I think it is ok to allow atomic load on read-only memory when all of the following are met. (assuming we don't want to do complex and fragile target-specific processing)

That's hoping we don't find further exceptions to these rules later? :D

We can possibly relax this rule later if there is consensus that all targets supported by Rust will support relaxed atomic loads of pointer size and smaller on read-only memory, but how sure are we no targets will violate this in the future?

Note that Miri anyway does not support sharing memory with other processes, so read-only memory here refers to static without interior mutability. Due to rust-lang/unsafe-code-guidelines#303, this PR does not change behavior on any program that Miri currently accepts.

Copy link
Member Author

Choose a reason for hiding this comment

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

Also let's discuss the Miri implementation here; the spec is being discussed at rust-lang/unsafe-code-guidelines#355.

@RalfJung
Copy link
Member Author

RalfJung commented Aug 9, 2022

@bors r+

@bors
Copy link
Collaborator

bors commented Aug 9, 2022

📌 Commit a1f5a75 has been approved by RalfJung

It is now in the queue for this repository.

@bors
Copy link
Collaborator

bors commented Aug 9, 2022

⌛ Testing commit a1f5a75 with merge 5aef34c...

@bors
Copy link
Collaborator

bors commented Aug 9, 2022

☀️ Test successful - checks-actions
Approved by: RalfJung
Pushing 5aef34c to master...

@bors bors merged commit 5aef34c into rust-lang:master Aug 9, 2022
@RalfJung RalfJung deleted the atomic-must-be-mutable branch August 10, 2022 11:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-blocked-on-rust Status: Blocked on landing a Rust PR
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Make Atomic RMWs always fail on read-only memory
4 participants