Skip to content

Commit a3bd578

Browse files
committed
make Stacked Borrows retags act like data races
1 parent a7f7221 commit a3bd578

32 files changed

+164
-45
lines changed

src/tools/miri/src/stacked_borrows/mod.rs

+20-3
Original file line numberDiff line numberDiff line change
@@ -874,8 +874,8 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
874874
// We need a frozen-sensitive reborrow.
875875
// We have to use shared references to alloc/memory_extra here since
876876
// `visit_freeze_sensitive` needs to access the global state.
877-
let extra = this.get_alloc_extra(alloc_id)?;
878-
let mut stacked_borrows = extra
877+
let alloc_extra = this.get_alloc_extra(alloc_id)?;
878+
let mut stacked_borrows = alloc_extra
879879
.stacked_borrows
880880
.as_ref()
881881
.expect("we should have Stacked Borrows data")
@@ -910,7 +910,16 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
910910
);
911911
stacked_borrows.for_each(range, dcx, |stack, dcx, exposed_tags| {
912912
stack.grant(orig_tag, item, access, &global, dcx, exposed_tags)
913-
})
913+
})?;
914+
drop(global);
915+
if let Some(access) = access {
916+
assert!(access == AccessKind::Read);
917+
// Make sure the data race model also knows about this.
918+
if let Some(data_race) = alloc_extra.data_race.as_ref() {
919+
data_race.read(alloc_id, range, &this.machine)?;
920+
}
921+
}
922+
Ok(())
914923
})?;
915924
return Ok(Some(alloc_id));
916925
}
@@ -938,6 +947,14 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
938947
stacked_borrows.for_each(range, dcx, |stack, dcx, exposed_tags| {
939948
stack.grant(orig_tag, item, access, &global, dcx, exposed_tags)
940949
})?;
950+
drop(global);
951+
if let Some(access) = access {
952+
assert!(access == AccessKind::Write);
953+
// Make sure the data race model also knows about this.
954+
if let Some(data_race) = alloc_extra.data_race.as_mut() {
955+
data_race.write(alloc_id, range, machine)?;
956+
}
957+
}
941958

942959
Ok(Some(alloc_id))
943960
}

src/tools/miri/tests/fail/data_race/alloc_read_race.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0
1+
//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
22
#![feature(new_uninit)]
33

44
use std::mem::MaybeUninit;

src/tools/miri/tests/fail/data_race/alloc_write_race.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0
1+
//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
22
#![feature(new_uninit)]
33

44
use std::ptr::null_mut;

src/tools/miri/tests/fail/data_race/atomic_read_na_write_race1.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
// We want to control preemption here.
2-
//@compile-flags: -Zmiri-preemption-rate=0
1+
// We want to control preemption here. Stacked borrows interferes by having its own accesses.
2+
//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
33

44
use std::sync::atomic::{AtomicUsize, Ordering};
55
use std::thread::spawn;

src/tools/miri/tests/fail/data_race/atomic_read_na_write_race2.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
// We want to control preemption here.
2-
//@compile-flags: -Zmiri-preemption-rate=0
1+
// We want to control preemption here. Stacked borrows interferes by having its own accesses.
2+
//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
33

44
use std::sync::atomic::AtomicUsize;
55
use std::sync::atomic::Ordering;

src/tools/miri/tests/fail/data_race/atomic_write_na_read_race1.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
// We want to control preemption here.
2-
//@compile-flags: -Zmiri-preemption-rate=0
1+
// We want to control preemption here. Stacked borrows interferes by having its own accesses.
2+
//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
33

44
use std::sync::atomic::AtomicUsize;
55
use std::sync::atomic::Ordering;

src/tools/miri/tests/fail/data_race/atomic_write_na_read_race2.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
// We want to control preemption here.
2-
//@compile-flags: -Zmiri-preemption-rate=0
1+
// We want to control preemption here. Stacked borrows interferes by having its own accesses.
2+
//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
33

44
use std::sync::atomic::{AtomicUsize, Ordering};
55
use std::thread::spawn;

src/tools/miri/tests/fail/data_race/atomic_write_na_write_race1.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
// We want to control preemption here.
2-
//@compile-flags: -Zmiri-preemption-rate=0
1+
// We want to control preemption here. Stacked borrows interferes by having its own accesses.
2+
//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
33

44
use std::sync::atomic::{AtomicUsize, Ordering};
55
use std::thread::spawn;

src/tools/miri/tests/fail/data_race/atomic_write_na_write_race2.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
// We want to control preemption here.
2-
//@compile-flags: -Zmiri-preemption-rate=0
1+
// We want to control preemption here. Stacked borrows interferes by having its own accesses.
2+
//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
33

44
use std::sync::atomic::AtomicUsize;
55
use std::sync::atomic::Ordering;

src/tools/miri/tests/fail/data_race/dangling_thread_async_race.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
// We want to control preemption here.
2-
//@compile-flags: -Zmiri-disable-isolation -Zmiri-preemption-rate=0
1+
// We want to control preemption here. Stacked borrows interferes by having its own accesses.
2+
//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
33

44
use std::mem;
55
use std::thread::{sleep, spawn};

src/tools/miri/tests/fail/data_race/dangling_thread_race.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
// We want to control preemption here.
2-
//@compile-flags: -Zmiri-disable-isolation -Zmiri-preemption-rate=0
1+
// We want to control preemption here. Stacked borrows interferes by having its own accesses.
2+
//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
33

44
use std::mem;
55
use std::thread::{sleep, spawn};

src/tools/miri/tests/fail/data_race/dealloc_read_race1.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
// We want to control preemption here.
2-
//@compile-flags: -Zmiri-preemption-rate=0
1+
// We want to control preemption here. Stacked borrows interferes by having its own accesses.
2+
//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
33

44
use std::thread::spawn;
55

src/tools/miri/tests/fail/data_race/dealloc_read_race2.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
// We want to control preemption here.
2-
//@compile-flags: -Zmiri-preemption-rate=0
1+
// We want to control preemption here. Stacked borrows interferes by having its own accesses.
2+
//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
33

44
use std::thread::spawn;
55

src/tools/miri/tests/fail/data_race/dealloc_read_race_stack.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//@compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0
1+
//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
22

33
use std::ptr::null_mut;
44
use std::sync::atomic::{AtomicPtr, Ordering};

src/tools/miri/tests/fail/data_race/dealloc_write_race1.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
// We want to control preemption here.
2-
//@compile-flags: -Zmiri-preemption-rate=0
1+
// We want to control preemption here. Stacked borrows interferes by having its own accesses.
2+
//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
33

44
use std::thread::spawn;
55

src/tools/miri/tests/fail/data_race/dealloc_write_race2.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
// We want to control preemption here.
2-
//@compile-flags: -Zmiri-preemption-rate=0
1+
// We want to control preemption here. Stacked borrows interferes by having its own accesses.
2+
//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
33

44
use std::thread::spawn;
55

src/tools/miri/tests/fail/data_race/dealloc_write_race_stack.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//@compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0
1+
//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
22

33
use std::ptr::null_mut;
44
use std::sync::atomic::{AtomicPtr, Ordering};

src/tools/miri/tests/fail/data_race/enable_after_join_to_main.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
// We want to control preemption here.
2-
//@compile-flags: -Zmiri-preemption-rate=0
1+
// We want to control preemption here. Stacked borrows interferes by having its own accesses.
2+
//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
33

44
use std::thread::spawn;
55

src/tools/miri/tests/fail/data_race/fence_after_load.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
// We want to control preemption here.
2-
//@compile-flags: -Zmiri-disable-isolation -Zmiri-preemption-rate=0
1+
// We want to control preemption here. Stacked borrows interferes by having its own accesses.
2+
//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
33
use std::sync::atomic::{fence, AtomicUsize, Ordering};
44
use std::sync::Arc;
55
use std::thread;

src/tools/miri/tests/fail/data_race/read_write_race.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
// We want to control preemption here.
2-
//@compile-flags: -Zmiri-preemption-rate=0
1+
// We want to control preemption here. Stacked borrows interferes by having its own accesses.
2+
//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
33

44
use std::thread::spawn;
55

src/tools/miri/tests/fail/data_race/read_write_race_stack.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//@compile-flags: -Zmiri-disable-isolation -Zmir-opt-level=0 -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0
1+
//@compile-flags: -Zmir-opt-level=0 -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
22

33
// Note: mir-opt-level set to 0 to prevent the read of stack_var in thread 1
44
// from being optimized away and preventing the detection of the data-race.

src/tools/miri/tests/fail/data_race/relax_acquire_race.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0
1+
//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
22

33
use std::sync::atomic::{AtomicUsize, Ordering};
44
use std::thread::spawn;

src/tools/miri/tests/fail/data_race/release_seq_race.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//@compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0
1+
//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
22

33
use std::sync::atomic::{AtomicUsize, Ordering};
44
use std::thread::{sleep, spawn};

src/tools/miri/tests/fail/data_race/release_seq_race_same_thread.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//@compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0
1+
//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
22

33
use std::sync::atomic::{AtomicUsize, Ordering};
44
use std::thread::spawn;

src/tools/miri/tests/fail/data_race/rmw_race.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0
1+
//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
22

33
use std::sync::atomic::{AtomicUsize, Ordering};
44
use std::thread::spawn;

src/tools/miri/tests/fail/data_race/stack_pop_race.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//@compile-flags: -Zmiri-preemption-rate=0
1+
//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
22
use std::thread;
33

44
#[derive(Copy, Clone)]

src/tools/miri/tests/fail/data_race/write_write_race.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// We want to control preemption here.
2-
//@compile-flags: -Zmiri-preemption-rate=0
2+
//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
33

44
use std::thread::spawn;
55

src/tools/miri/tests/fail/data_race/write_write_race_stack.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//@compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0
1+
//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
22

33
use std::ptr::null_mut;
44
use std::sync::atomic::{AtomicPtr, Ordering};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
//! Make sure that a retag acts like a write for the data race model.
2+
//@compile-flags: -Zmiri-preemption-rate=0
3+
#[derive(Copy, Clone)]
4+
struct SendPtr(*mut u8);
5+
6+
unsafe impl Send for SendPtr {}
7+
8+
fn thread_1(p: SendPtr) {
9+
let p = p.0;
10+
unsafe {
11+
let _r = &*p;
12+
}
13+
}
14+
15+
fn thread_2(p: SendPtr) {
16+
let p = p.0;
17+
unsafe {
18+
*p = 5; //~ ERROR: Data race detected between Write on thread `<unnamed>` and Read on thread `<unnamed>`
19+
}
20+
}
21+
22+
fn main() {
23+
let mut x = 0;
24+
let p = std::ptr::addr_of_mut!(x);
25+
let p = SendPtr(p);
26+
27+
let t1 = std::thread::spawn(move || thread_1(p));
28+
let t2 = std::thread::spawn(move || thread_2(p));
29+
let _ = t1.join();
30+
let _ = t2.join();
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error: Undefined Behavior: Data race detected between Write on thread `<unnamed>` and Read on thread `<unnamed>` at ALLOC
2+
--> $DIR/retag_data_race_read.rs:LL:CC
3+
|
4+
LL | *p = 5;
5+
| ^^^^^^ Data race detected between Write on thread `<unnamed>` and Read on thread `<unnamed>` at ALLOC
6+
|
7+
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
8+
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
9+
= note: BACKTRACE:
10+
= note: inside `thread_2` at $DIR/retag_data_race_read.rs:LL:CC
11+
note: inside closure at $DIR/retag_data_race_read.rs:LL:CC
12+
--> $DIR/retag_data_race_read.rs:LL:CC
13+
|
14+
LL | let t2 = std::thread::spawn(move || thread_2(p));
15+
| ^^^^^^^^^^^
16+
17+
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
18+
19+
error: aborting due to previous error
20+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
//! Make sure that a retag acts like a write for the data race model.
2+
//@compile-flags: -Zmiri-preemption-rate=0
3+
#[derive(Copy, Clone)]
4+
struct SendPtr(*mut u8);
5+
6+
unsafe impl Send for SendPtr {}
7+
8+
fn thread_1(p: SendPtr) {
9+
let p = p.0;
10+
unsafe {
11+
let _r = &mut *p;
12+
}
13+
}
14+
15+
fn thread_2(p: SendPtr) {
16+
let p = p.0;
17+
unsafe {
18+
*p = 5; //~ ERROR: Data race detected between Write on thread `<unnamed>` and Write on thread `<unnamed>`
19+
}
20+
}
21+
22+
fn main() {
23+
let mut x = 0;
24+
let p = std::ptr::addr_of_mut!(x);
25+
let p = SendPtr(p);
26+
27+
let t1 = std::thread::spawn(move || thread_1(p));
28+
let t2 = std::thread::spawn(move || thread_2(p));
29+
let _ = t1.join();
30+
let _ = t2.join();
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error: Undefined Behavior: Data race detected between Write on thread `<unnamed>` and Write on thread `<unnamed>` at ALLOC
2+
--> $DIR/retag_data_race_write.rs:LL:CC
3+
|
4+
LL | *p = 5;
5+
| ^^^^^^ Data race detected between Write on thread `<unnamed>` and Write on thread `<unnamed>` at ALLOC
6+
|
7+
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
8+
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
9+
= note: BACKTRACE:
10+
= note: inside `thread_2` at $DIR/retag_data_race_write.rs:LL:CC
11+
note: inside closure at $DIR/retag_data_race_write.rs:LL:CC
12+
--> $DIR/retag_data_race_write.rs:LL:CC
13+
|
14+
LL | let t2 = std::thread::spawn(move || thread_2(p));
15+
| ^^^^^^^^^^^
16+
17+
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
18+
19+
error: aborting due to previous error
20+

0 commit comments

Comments
 (0)