when an address gets reused, establish a happens-before link in the data race model
This commit is contained in:
parent
d261b53081
commit
48fd549cd3
8 changed files with 129 additions and 36 deletions
|
|
@ -0,0 +1,60 @@
|
|||
//! Regression test for <https://github.com/rust-lang/miri/issues/3450>:
|
||||
//! When the address gets reused, there should be a happens-before relation.
|
||||
#![feature(strict_provenance)]
|
||||
#![feature(sync_unsafe_cell)]
|
||||
|
||||
use std::cell::SyncUnsafeCell;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering::Relaxed};
|
||||
use std::thread;
|
||||
|
||||
static ADDR: AtomicUsize = AtomicUsize::new(0);
|
||||
static VAL: SyncUnsafeCell<i32> = SyncUnsafeCell::new(0);
|
||||
|
||||
fn addr() -> usize {
|
||||
let alloc = Box::new(42);
|
||||
<*const i32>::addr(&*alloc)
|
||||
}
|
||||
|
||||
fn thread1() {
|
||||
unsafe {
|
||||
VAL.get().write(42);
|
||||
}
|
||||
let alloc = addr();
|
||||
ADDR.store(alloc, Relaxed);
|
||||
}
|
||||
|
||||
fn thread2() -> bool {
|
||||
// We try to get an allocation at the same address as the global `ADDR`. If we fail too often,
|
||||
// just bail. `main` will try again with a different allocation.
|
||||
for _ in 0..16 {
|
||||
let alloc = addr();
|
||||
let addr = ADDR.load(Relaxed);
|
||||
if alloc == addr {
|
||||
// We got a reuse!
|
||||
// If the new allocation is at the same address as the old one, there must be a
|
||||
// happens-before relationship between them. Therefore, we can read VAL without racing
|
||||
// and must observe the write above.
|
||||
let val = unsafe { VAL.get().read() };
|
||||
assert_eq!(val, 42);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut success = false;
|
||||
while !success {
|
||||
let t1 = thread::spawn(thread1);
|
||||
let t2 = thread::spawn(thread2);
|
||||
t1.join().unwrap();
|
||||
success = t2.join().unwrap();
|
||||
|
||||
// Reset everything.
|
||||
ADDR.store(0, Relaxed);
|
||||
unsafe {
|
||||
VAL.get().write(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -37,6 +37,8 @@ fn relaxed() -> bool {
|
|||
let x = static_atomic(0);
|
||||
let j1 = spawn(move || {
|
||||
x.store(1, Relaxed);
|
||||
// Preemption is disabled, so the store above will never be the
|
||||
// latest store visible to another thread.
|
||||
x.store(2, Relaxed);
|
||||
});
|
||||
|
||||
|
|
@ -138,6 +140,7 @@ fn faa_replaced_by_load() -> bool {
|
|||
}
|
||||
|
||||
/// Asserts that the function returns true at least once in 100 runs
|
||||
#[track_caller]
|
||||
fn assert_once(f: fn() -> bool) {
|
||||
assert!(std::iter::repeat_with(|| f()).take(100).any(|x| x));
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue