-
Notifications
You must be signed in to change notification settings - Fork 352
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
Miri false positive data race due to incorrect handling of fences #2192
Comments
Cc @JCTyblaidd who wrote our data race detector |
Here's a simple test based on the crossbeam-channel case: use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering, fence};
use std::time::Duration;
use std::thread;
#[test]
fn data_race() {
static mut V: u32 = 0;
let a = Arc::new(AtomicUsize::default());
let b = a.clone();
thread::spawn(move || {
unsafe { V = 1 }
b.store(1, Ordering::SeqCst);
});
thread::sleep(Duration::from_millis(100));
fence(Ordering::SeqCst);
a.load(Ordering::Relaxed);
unsafe { V = 2 }
} When executed with
|
But to tell the truth, I'm still in doubt that this is a false positive. As far as the documentation goes (both for the And if we change fence(Ordering::SeqCst);
a.load(Ordering::Relaxed); to a.load(Ordering::Relaxed);
fence(Ordering::SeqCst); // It can be Acquire the data race warning is gone. But maybe I'm missing something here. |
I think there is a race here in both cases (i.e., also the one where the warning is gone)? You are completely ignoring the result of the load, so a possible execution is
|
I guess you meant something more like this where we check that the load loads 1. But in that case, we still have this valid execution:
The load at (4) is relaxed so it doesn't pick up any synchronization. Therefore the two accesses to V are not synchronized and I would say this is a data race. |
@alygin You're right. The correct use of the fence passes miri while having it before the load doesn't. fn main() {
use std::{
sync::atomic::{fence, AtomicUsize, Ordering},
sync::Arc,
thread,
};
static mut V: u32 = 0;
let a = Arc::new(AtomicUsize::default());
let b = a.clone();
thread::spawn(move || {
unsafe { V = 1 };
b.store(1, Ordering::SeqCst);
});
loop {
if a.load(Ordering::Relaxed) == 1 {
fence(Ordering::SeqCst);
return unsafe { V = 2 };
} else {
thread::yield_now(); // for miri
}
}
} After some thought, the crossbeam code is fine to race as drop() isn't necessarily a synchronization point (which the test case was trying to use as such). |
Closing as works-as-intended then. And I'll add this as a testcase. :) |
add interesting data race test This interesting testcase came up in #2192.
add interesting data race test This interesting testcase came up in #2192.
I don't actually understand any of what's going on in this case, just reporting this: crossbeam-rs/crossbeam#838 (comment)
cc @kprotty in case I've summarized this wrong or you have a simple test case for this on hand
The text was updated successfully, but these errors were encountered: