make Stacked Borrows retags act like data races

This commit is contained in:
Ralf Jung 2022-11-26 14:46:06 +01:00
parent a7f72218c8
commit a3bd57823f
32 changed files with 164 additions and 45 deletions

View File

@ -874,8 +874,8 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
// We need a frozen-sensitive reborrow.
// We have to use shared references to alloc/memory_extra here since
// `visit_freeze_sensitive` needs to access the global state.
let extra = this.get_alloc_extra(alloc_id)?;
let mut stacked_borrows = extra
let alloc_extra = this.get_alloc_extra(alloc_id)?;
let mut stacked_borrows = alloc_extra
.stacked_borrows
.as_ref()
.expect("we should have Stacked Borrows data")
@ -910,7 +910,16 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
);
stacked_borrows.for_each(range, dcx, |stack, dcx, exposed_tags| {
stack.grant(orig_tag, item, access, &global, dcx, exposed_tags)
})
})?;
drop(global);
if let Some(access) = access {
assert!(access == AccessKind::Read);
// Make sure the data race model also knows about this.
if let Some(data_race) = alloc_extra.data_race.as_ref() {
data_race.read(alloc_id, range, &this.machine)?;
}
}
Ok(())
})?;
return Ok(Some(alloc_id));
}
@ -938,6 +947,14 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
stacked_borrows.for_each(range, dcx, |stack, dcx, exposed_tags| {
stack.grant(orig_tag, item, access, &global, dcx, exposed_tags)
})?;
drop(global);
if let Some(access) = access {
assert!(access == AccessKind::Write);
// Make sure the data race model also knows about this.
if let Some(data_race) = alloc_extra.data_race.as_mut() {
data_race.write(alloc_id, range, machine)?;
}
}
Ok(Some(alloc_id))
}

View File

@ -1,4 +1,4 @@
//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0
//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
#![feature(new_uninit)]
use std::mem::MaybeUninit;

View File

@ -1,4 +1,4 @@
//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0
//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
#![feature(new_uninit)]
use std::ptr::null_mut;

View File

@ -1,5 +1,5 @@
// We want to control preemption here.
//@compile-flags: -Zmiri-preemption-rate=0
// We want to control preemption here. Stacked borrows interferes by having its own accesses.
//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
use std::sync::atomic::{AtomicUsize, Ordering};
use std::thread::spawn;

View File

@ -1,5 +1,5 @@
// We want to control preemption here.
//@compile-flags: -Zmiri-preemption-rate=0
// We want to control preemption here. Stacked borrows interferes by having its own accesses.
//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering;

View File

@ -1,5 +1,5 @@
// We want to control preemption here.
//@compile-flags: -Zmiri-preemption-rate=0
// We want to control preemption here. Stacked borrows interferes by having its own accesses.
//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering;

View File

@ -1,5 +1,5 @@
// We want to control preemption here.
//@compile-flags: -Zmiri-preemption-rate=0
// We want to control preemption here. Stacked borrows interferes by having its own accesses.
//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
use std::sync::atomic::{AtomicUsize, Ordering};
use std::thread::spawn;

View File

@ -1,5 +1,5 @@
// We want to control preemption here.
//@compile-flags: -Zmiri-preemption-rate=0
// We want to control preemption here. Stacked borrows interferes by having its own accesses.
//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
use std::sync::atomic::{AtomicUsize, Ordering};
use std::thread::spawn;

View File

@ -1,5 +1,5 @@
// We want to control preemption here.
//@compile-flags: -Zmiri-preemption-rate=0
// We want to control preemption here. Stacked borrows interferes by having its own accesses.
//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering;

View File

@ -1,5 +1,5 @@
// We want to control preemption here.
//@compile-flags: -Zmiri-disable-isolation -Zmiri-preemption-rate=0
// We want to control preemption here. Stacked borrows interferes by having its own accesses.
//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
use std::mem;
use std::thread::{sleep, spawn};

View File

@ -1,5 +1,5 @@
// We want to control preemption here.
//@compile-flags: -Zmiri-disable-isolation -Zmiri-preemption-rate=0
// We want to control preemption here. Stacked borrows interferes by having its own accesses.
//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
use std::mem;
use std::thread::{sleep, spawn};

View File

@ -1,5 +1,5 @@
// We want to control preemption here.
//@compile-flags: -Zmiri-preemption-rate=0
// We want to control preemption here. Stacked borrows interferes by having its own accesses.
//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
use std::thread::spawn;

View File

@ -1,5 +1,5 @@
// We want to control preemption here.
//@compile-flags: -Zmiri-preemption-rate=0
// We want to control preemption here. Stacked borrows interferes by having its own accesses.
//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
use std::thread::spawn;

View File

@ -1,4 +1,4 @@
//@compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0
//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
use std::ptr::null_mut;
use std::sync::atomic::{AtomicPtr, Ordering};

View File

@ -1,5 +1,5 @@
// We want to control preemption here.
//@compile-flags: -Zmiri-preemption-rate=0
// We want to control preemption here. Stacked borrows interferes by having its own accesses.
//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
use std::thread::spawn;

View File

@ -1,5 +1,5 @@
// We want to control preemption here.
//@compile-flags: -Zmiri-preemption-rate=0
// We want to control preemption here. Stacked borrows interferes by having its own accesses.
//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
use std::thread::spawn;

View File

@ -1,4 +1,4 @@
//@compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0
//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
use std::ptr::null_mut;
use std::sync::atomic::{AtomicPtr, Ordering};

View File

@ -1,5 +1,5 @@
// We want to control preemption here.
//@compile-flags: -Zmiri-preemption-rate=0
// We want to control preemption here. Stacked borrows interferes by having its own accesses.
//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
use std::thread::spawn;

View File

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

View File

@ -1,5 +1,5 @@
// We want to control preemption here.
//@compile-flags: -Zmiri-preemption-rate=0
// We want to control preemption here. Stacked borrows interferes by having its own accesses.
//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
use std::thread::spawn;

View File

@ -1,4 +1,4 @@
//@compile-flags: -Zmiri-disable-isolation -Zmir-opt-level=0 -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0
//@compile-flags: -Zmir-opt-level=0 -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
// Note: mir-opt-level set to 0 to prevent the read of stack_var in thread 1
// from being optimized away and preventing the detection of the data-race.

View File

@ -1,4 +1,4 @@
//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0
//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
use std::sync::atomic::{AtomicUsize, Ordering};
use std::thread::spawn;

View File

@ -1,4 +1,4 @@
//@compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0
//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
use std::sync::atomic::{AtomicUsize, Ordering};
use std::thread::{sleep, spawn};

View File

@ -1,4 +1,4 @@
//@compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0
//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
use std::sync::atomic::{AtomicUsize, Ordering};
use std::thread::spawn;

View File

@ -1,4 +1,4 @@
//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0
//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
use std::sync::atomic::{AtomicUsize, Ordering};
use std::thread::spawn;

View File

@ -1,4 +1,4 @@
//@compile-flags: -Zmiri-preemption-rate=0
//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
use std::thread;
#[derive(Copy, Clone)]

View File

@ -1,5 +1,5 @@
// We want to control preemption here.
//@compile-flags: -Zmiri-preemption-rate=0
//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
use std::thread::spawn;

View File

@ -1,4 +1,4 @@
//@compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0
//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
use std::ptr::null_mut;
use std::sync::atomic::{AtomicPtr, Ordering};

View File

@ -0,0 +1,31 @@
//! Make sure that a retag acts like a write for the data race model.
//@compile-flags: -Zmiri-preemption-rate=0
#[derive(Copy, Clone)]
struct SendPtr(*mut u8);
unsafe impl Send for SendPtr {}
fn thread_1(p: SendPtr) {
let p = p.0;
unsafe {
let _r = &*p;
}
}
fn thread_2(p: SendPtr) {
let p = p.0;
unsafe {
*p = 5; //~ ERROR: Data race detected between Write on thread `<unnamed>` and Read on thread `<unnamed>`
}
}
fn main() {
let mut x = 0;
let p = std::ptr::addr_of_mut!(x);
let p = SendPtr(p);
let t1 = std::thread::spawn(move || thread_1(p));
let t2 = std::thread::spawn(move || thread_2(p));
let _ = t1.join();
let _ = t2.join();
}

View File

@ -0,0 +1,20 @@
error: Undefined Behavior: Data race detected between Write on thread `<unnamed>` and Read on thread `<unnamed>` at ALLOC
--> $DIR/retag_data_race_read.rs:LL:CC
|
LL | *p = 5;
| ^^^^^^ Data race detected between Write on thread `<unnamed>` and Read on thread `<unnamed>` at ALLOC
|
= 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:
= note: inside `thread_2` at $DIR/retag_data_race_read.rs:LL:CC
note: inside closure at $DIR/retag_data_race_read.rs:LL:CC
--> $DIR/retag_data_race_read.rs:LL:CC
|
LL | let t2 = std::thread::spawn(move || thread_2(p));
| ^^^^^^^^^^^
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
error: aborting due to previous error

View File

@ -0,0 +1,31 @@
//! Make sure that a retag acts like a write for the data race model.
//@compile-flags: -Zmiri-preemption-rate=0
#[derive(Copy, Clone)]
struct SendPtr(*mut u8);
unsafe impl Send for SendPtr {}
fn thread_1(p: SendPtr) {
let p = p.0;
unsafe {
let _r = &mut *p;
}
}
fn thread_2(p: SendPtr) {
let p = p.0;
unsafe {
*p = 5; //~ ERROR: Data race detected between Write on thread `<unnamed>` and Write on thread `<unnamed>`
}
}
fn main() {
let mut x = 0;
let p = std::ptr::addr_of_mut!(x);
let p = SendPtr(p);
let t1 = std::thread::spawn(move || thread_1(p));
let t2 = std::thread::spawn(move || thread_2(p));
let _ = t1.join();
let _ = t2.join();
}

View File

@ -0,0 +1,20 @@
error: Undefined Behavior: Data race detected between Write on thread `<unnamed>` and Write on thread `<unnamed>` at ALLOC
--> $DIR/retag_data_race_write.rs:LL:CC
|
LL | *p = 5;
| ^^^^^^ Data race detected between Write on thread `<unnamed>` and Write on thread `<unnamed>` at ALLOC
|
= 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:
= note: inside `thread_2` at $DIR/retag_data_race_write.rs:LL:CC
note: inside closure at $DIR/retag_data_race_write.rs:LL:CC
--> $DIR/retag_data_race_write.rs:LL:CC
|
LL | let t2 = std::thread::spawn(move || thread_2(p));
| ^^^^^^^^^^^
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
error: aborting due to previous error