Skip to content

Commit

Permalink
test that we can see this weak behavior
Browse files Browse the repository at this point in the history
  • Loading branch information
RalfJung committed Jul 14, 2022
1 parent 07c3e42 commit b8a0c49
Showing 1 changed file with 48 additions and 3 deletions.
51 changes: 48 additions & 3 deletions tests/pass/weak_memory/weak.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
// Spurious failure is possible, if you are really unlucky with
// the RNG and always read the latest value from the store buffer.

use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering::*;
use std::sync::atomic::{fence, AtomicUsize};
use std::thread::spawn;

#[derive(Copy, Clone)]
Expand Down Expand Up @@ -70,7 +70,7 @@ fn seq_cst() -> bool {
r3 == 1
}

fn initialization_write() -> bool {
fn initialization_write(add_fence: bool) -> bool {
let x = static_atomic(11);
assert_eq!(x.load(Relaxed), 11); // work around https://github.com/rust-lang/miri/issues/2164

Expand All @@ -85,6 +85,9 @@ fn initialization_write() -> bool {

let j2 = spawn(move || {
reads_value(wait, 1);
if add_fence {
fence(AcqRel);
}
x.load(Relaxed)
});

Expand All @@ -94,6 +97,46 @@ fn initialization_write() -> bool {
r2 == 11
}

fn faa_replaced_by_load() -> bool {
// Example from https://github.com/llvm/llvm-project/issues/56450#issuecomment-1183695905
#[no_mangle]
pub fn rdmw(storing: &AtomicUsize, sync: &AtomicUsize, loading: &AtomicUsize) -> usize {
storing.store(1, Relaxed);
fence(Release);
// sync.fetch_add(0, Relaxed);
sync.load(Relaxed);
fence(Acquire);
loading.load(Relaxed)
}

let x = static_atomic(0);
assert_eq!(x.load(Relaxed), 0); // work around https://github.com/rust-lang/miri/issues/2164
let y = static_atomic(0);
assert_eq!(y.load(Relaxed), 0); // work around https://github.com/rust-lang/miri/issues/2164
let z = static_atomic(0);
assert_eq!(z.load(Relaxed), 0); // work around https://github.com/rust-lang/miri/issues/2164

// Since each thread is so short, we need to make sure that they truely run at the same time
// Otherwise t1 will finish before t2 even starts
let go = static_atomic(0);

let t1 = spawn(move || {
while go.load(Relaxed) == 0 {}
rdmw(y, x, z)
});

let t2 = spawn(move || {
while go.load(Relaxed) == 0 {}
rdmw(z, x, y)
});

go.store(1, Relaxed);

let a = t1.join().unwrap();
let b = t2.join().unwrap();
(a, b) == (0, 0)
}

/// Asserts that the function returns true at least once in 100 runs
fn assert_once(f: fn() -> bool) {
assert!(std::iter::repeat_with(|| f()).take(100).any(|x| x));
Expand All @@ -102,5 +145,7 @@ fn assert_once(f: fn() -> bool) {
pub fn main() {
assert_once(relaxed);
assert_once(seq_cst);
assert_once(initialization_write);
assert_once(|| initialization_write(false));
assert_once(|| initialization_write(true));
assert_once(faa_replaced_by_load);
}

0 comments on commit b8a0c49

Please sign in to comment.