Skip to content

Commit 95c99b2

Browse files
committed
Detect races between atomic and non-atomic accesses of a variable,
previously only data races between two non-atomic accesses were detected.
1 parent fe2e857 commit 95c99b2

File tree

8 files changed

+463
-78
lines changed

8 files changed

+463
-78
lines changed

src/data_race.rs

Lines changed: 273 additions & 77 deletions
Large diffs are not rendered by default.

src/shims/posix/linux/sync.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,10 @@ pub fn futex<'tcx>(
7878
// Read an `i32` through the pointer, regardless of any wrapper types.
7979
// It's not uncommon for `addr` to be passed as another type than `*mut i32`, such as `*const AtomicI32`.
8080
// FIXME: this fails if `addr` is not a pointer type.
81-
let futex_val = this.read_scalar_at_offset(addr.into(), 0, this.machine.layouts.i32)?.to_i32()?;
81+
// FIXME: what form of atomic operation should the `futex` use to load the value?
82+
let futex_val = this.read_scalar_at_offset_atomic(
83+
addr.into(), 0, this.machine.layouts.i32, AtomicReadOp::Acquire
84+
)?.to_i32()?;
8285
if val == futex_val {
8386
// The value still matches, so we block the trait make it wait for FUTEX_WAKE.
8487
this.block_thread(thread);
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// ignore-windows: Concurrency on Windows is not supported yet.
2+
#![feature(core_intrinsics)]
3+
4+
use std::thread::spawn;
5+
use std::sync::atomic::AtomicUsize;
6+
use std::intrinsics::atomic_load;
7+
8+
#[derive(Copy, Clone)]
9+
struct EvilSend<T>(pub T);
10+
11+
unsafe impl<T> Send for EvilSend<T> {}
12+
unsafe impl<T> Sync for EvilSend<T> {}
13+
14+
pub fn main() {
15+
let mut a = AtomicUsize::new(0);
16+
let b = &mut a as *mut AtomicUsize;
17+
let c = EvilSend(b);
18+
unsafe {
19+
let j1 = spawn(move || {
20+
*(c.0 as *mut usize) = 32;
21+
});
22+
23+
let j2 = spawn(move || {
24+
//Equivalent to: (&*c.0).load(Ordering::SeqCst)
25+
atomic_load(c.0 as *mut usize) //~ ERROR Data race
26+
});
27+
28+
j1.join().unwrap();
29+
j2.join().unwrap();
30+
}
31+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// ignore-windows: Concurrency on Windows is not supported yet.
2+
3+
use std::thread::spawn;
4+
use std::sync::atomic::AtomicUsize;
5+
use std::sync::atomic::Ordering;
6+
7+
#[derive(Copy, Clone)]
8+
struct EvilSend<T>(pub T);
9+
10+
unsafe impl<T> Send for EvilSend<T> {}
11+
unsafe impl<T> Sync for EvilSend<T> {}
12+
13+
pub fn main() {
14+
let mut a = AtomicUsize::new(0);
15+
let b = &mut a as *mut AtomicUsize;
16+
let c = EvilSend(b);
17+
unsafe {
18+
let j1 = spawn(move || {
19+
let atomic_ref = &mut *c.0;
20+
atomic_ref.load(Ordering::SeqCst)
21+
});
22+
23+
let j2 = spawn(move || {
24+
let atomic_ref = &mut *c.0;
25+
*atomic_ref.get_mut() = 32; //~ ERROR Data race
26+
});
27+
28+
j1.join().unwrap();
29+
j2.join().unwrap();
30+
}
31+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// ignore-windows: Concurrency on Windows is not supported yet.
2+
3+
use std::thread::spawn;
4+
use std::sync::atomic::AtomicUsize;
5+
use std::sync::atomic::Ordering;
6+
7+
#[derive(Copy, Clone)]
8+
struct EvilSend<T>(pub T);
9+
10+
unsafe impl<T> Send for EvilSend<T> {}
11+
unsafe impl<T> Sync for EvilSend<T> {}
12+
13+
pub fn main() {
14+
let mut a = AtomicUsize::new(0);
15+
let b = &mut a as *mut AtomicUsize;
16+
let c = EvilSend(b);
17+
unsafe {
18+
let j1 = spawn(move || {
19+
let atomic_ref = &mut *c.0;
20+
atomic_ref.store(32, Ordering::SeqCst)
21+
});
22+
23+
let j2 = spawn(move || {
24+
let atomic_ref = &mut *c.0;
25+
*atomic_ref.get_mut() //~ ERROR Data race
26+
});
27+
28+
j1.join().unwrap();
29+
j2.join().unwrap();
30+
}
31+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// ignore-windows: Concurrency on Windows is not supported yet.
2+
#![feature(core_intrinsics)]
3+
4+
use std::thread::spawn;
5+
use std::sync::atomic::AtomicUsize;
6+
use std::intrinsics::atomic_store;
7+
8+
#[derive(Copy, Clone)]
9+
struct EvilSend<T>(pub T);
10+
11+
unsafe impl<T> Send for EvilSend<T> {}
12+
unsafe impl<T> Sync for EvilSend<T> {}
13+
14+
pub fn main() {
15+
let mut a = AtomicUsize::new(0);
16+
let b = &mut a as *mut AtomicUsize;
17+
let c = EvilSend(b);
18+
unsafe {
19+
let j1 = spawn(move || {
20+
*(c.0 as *mut usize)
21+
});
22+
23+
let j2 = spawn(move || {
24+
//Equivalent to: (&*c.0).store(32, Ordering::SeqCst)
25+
atomic_store(c.0 as *mut usize, 32); //~ ERROR Data race
26+
});
27+
28+
j1.join().unwrap();
29+
j2.join().unwrap();
30+
}
31+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// ignore-windows: Concurrency on Windows is not supported yet.
2+
#![feature(core_intrinsics)]
3+
4+
use std::thread::spawn;
5+
use std::sync::atomic::AtomicUsize;
6+
use std::intrinsics::atomic_store;
7+
8+
#[derive(Copy, Clone)]
9+
struct EvilSend<T>(pub T);
10+
11+
unsafe impl<T> Send for EvilSend<T> {}
12+
unsafe impl<T> Sync for EvilSend<T> {}
13+
14+
pub fn main() {
15+
let mut a = AtomicUsize::new(0);
16+
let b = &mut a as *mut AtomicUsize;
17+
let c = EvilSend(b);
18+
unsafe {
19+
let j1 = spawn(move || {
20+
*(c.0 as *mut usize) = 32;
21+
});
22+
23+
let j2 = spawn(move || {
24+
//Equivalent to: (&*c.0).store(64, Ordering::SeqCst)
25+
atomic_store(c.0 as *mut usize, 64); //~ ERROR Data race
26+
});
27+
28+
j1.join().unwrap();
29+
j2.join().unwrap();
30+
}
31+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// ignore-windows: Concurrency on Windows is not supported yet.
2+
3+
use std::thread::spawn;
4+
use std::sync::atomic::AtomicUsize;
5+
use std::sync::atomic::Ordering;
6+
7+
#[derive(Copy, Clone)]
8+
struct EvilSend<T>(pub T);
9+
10+
unsafe impl<T> Send for EvilSend<T> {}
11+
unsafe impl<T> Sync for EvilSend<T> {}
12+
13+
pub fn main() {
14+
let mut a = AtomicUsize::new(0);
15+
let b = &mut a as *mut AtomicUsize;
16+
let c = EvilSend(b);
17+
unsafe {
18+
let j1 = spawn(move || {
19+
let atomic_ref = &mut *c.0;
20+
atomic_ref.store(64, Ordering::SeqCst);
21+
});
22+
23+
let j2 = spawn(move || {
24+
let atomic_ref = &mut *c.0;
25+
*atomic_ref.get_mut() = 32; //~ ERROR Data race
26+
});
27+
28+
j1.join().unwrap();
29+
j2.join().unwrap();
30+
}
31+
}

0 commit comments

Comments
 (0)