diff options
Diffstat (limited to 'src/tools/miri/tests')
| -rw-r--r-- | src/tools/miri/tests/pass/concurrency/address_reuse_happens_before.rs | 60 | ||||
| -rw-r--r-- | src/tools/miri/tests/pass/weak_memory/weak.rs | 3 |
2 files changed, 63 insertions, 0 deletions
diff --git a/src/tools/miri/tests/pass/concurrency/address_reuse_happens_before.rs b/src/tools/miri/tests/pass/concurrency/address_reuse_happens_before.rs new file mode 100644 index 00000000000..c0de1b48263 --- /dev/null +++ b/src/tools/miri/tests/pass/concurrency/address_reuse_happens_before.rs @@ -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); + } + } +} diff --git a/src/tools/miri/tests/pass/weak_memory/weak.rs b/src/tools/miri/tests/pass/weak_memory/weak.rs index e10ccc277f6..dac63eeeb0b 100644 --- a/src/tools/miri/tests/pass/weak_memory/weak.rs +++ b/src/tools/miri/tests/pass/weak_memory/weak.rs @@ -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)); } |
