`Arc::strong_count` memory ordering is a potential footgun
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 119k
- Forks
- 16.2k
- PR merge metrics
- PR metrics pending
Description
In https://github.com/rust-lang/rust/pull/115546 the memory ordering of {Arc,Weak}::{strong,weak}_count got changed to Relaxed, which can cause some hard to debug race bugs.
I tried this code:
use std::cell::UnsafeCell;
use std::sync::Arc;
use std::thread;
struct SendMe<T>(T);
unsafe impl<T> Send for SendMe<T> {}
fn main() {
let a = Arc::new(UnsafeCell::new(0i32));
let b = SendMe(a.clone());
thread::spawn(move || {
let b = b;
for _ in 0..100 {
unsafe { *b.0.get() += 1; }
}
});
while Arc::strong_count(&a) != 1 {}
// core::sync::atomic::fence(core::sync::atomic::Ordering::Acquire);
unsafe { *a.get() += 1; }
}
I expected to see this happen: I expected the check strong_count == 0 to be strong enough to avoid a data race in this program. My intuition was that this check implies that no other thread can access the data concurrently.
Instead, this happened: With the fence commented out, the above program has undefined behavior. Miri outputs:
error: Undefined Behavior: Data race detected between (1) Write on thread `<unnamed>` and (2) Read on thread `main` at alloc826+0x10. (2) just happened here
--> src/main.rs:19:14
|
19 | unsafe { *a.get() += 1; }
| ^^^^^^^^^^^^^ Data race detected between (1) Write on thread `<unnamed>` and (2) Read on thread `main` at alloc826+0x10. (2) just happened here
|
help: and (1) occurred earlier here
--> src/main.rs:14:22
|
14 | unsafe { *b.0.get() += 1; }
| ^^^^^^^^^^^^^^^
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
= note: BACKTRACE (of the first span):
= note: inside `main` at src/main.rs:19:14: 19:27
I think we should either put the Acquire ordering back or add a warning to the docs that such code requires a manual fence.
Meta
1.74 = current beta
cc @SUPERCILEX author of https://github.com/rust-lang/rust/pull/115546
@rustbot label T-libs A-atomic
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Review Rust PR #115546 and reproduce the supplied Arc::strong_count example with Miri, including the commented Acquire fence. Determine whether the API's memory ordering or its documentation should change, and validate the chosen resolution against the reported data-race behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- operating-systems
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 25/100