Skip to content

Commit d1094ea

Browse files
authored
Merge pull request rust-lang#4076 from RalfJung/sc-fence
fix SC fence logic
2 parents a57d5fe + 016fb48 commit d1094ea

File tree

2 files changed

+51
-11
lines changed

2 files changed

+51
-11
lines changed

src/tools/miri/src/concurrency/data_race.rs

+8-4
Original file line numberDiff line numberDiff line change
@@ -874,23 +874,27 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> {
874874
// Either Acquire | AcqRel | SeqCst
875875
clocks.apply_acquire_fence();
876876
}
877-
if atomic != AtomicFenceOrd::Acquire {
878-
// Either Release | AcqRel | SeqCst
879-
clocks.apply_release_fence();
880-
}
881877
if atomic == AtomicFenceOrd::SeqCst {
882878
// Behave like an RMW on the global fence location. This takes full care of
883879
// all the SC fence requirements, including C++17 §32.4 [atomics.order]
884880
// paragraph 6 (which would limit what future reads can see). It also rules
885881
// out many legal behaviors, but we don't currently have a model that would
886882
// be more precise.
883+
// Also see the second bullet on page 10 of
884+
// <https://www.cs.tau.ac.il/~orilahav/papers/popl21_robustness.pdf>.
887885
let mut sc_fence_clock = data_race.last_sc_fence.borrow_mut();
888886
sc_fence_clock.join(&clocks.clock);
889887
clocks.clock.join(&sc_fence_clock);
890888
// Also establish some sort of order with the last SC write that happened, globally
891889
// (but this is only respected by future reads).
892890
clocks.write_seqcst.join(&data_race.last_sc_write_per_thread.borrow());
893891
}
892+
// The release fence is last, since both of the above could alter our clock,
893+
// which should be part of what is being released.
894+
if atomic != AtomicFenceOrd::Acquire {
895+
// Either Release | AcqRel | SeqCst
896+
clocks.apply_release_fence();
897+
}
894898

895899
// Increment timestamp in case of release semantics.
896900
interp_ok(atomic != AtomicFenceOrd::Acquire)

src/tools/miri/tests/pass/0weak_memory_consistency.rs

+43-7
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//@compile-flags: -Zmiri-ignore-leaks -Zmiri-disable-stacked-borrows -Zmiri-provenance-gc=10000
1+
//@compile-flags: -Zmiri-ignore-leaks -Zmiri-disable-stacked-borrows -Zmiri-disable-validation -Zmiri-provenance-gc=10000
22
// This test's runtime explodes if the GC interval is set to 1 (which we do in CI), so we
33
// override it internally back to the default frequency.
44

@@ -34,14 +34,10 @@ unsafe impl<T> Sync for EvilSend<T> {}
3434
// We can't create static items because we need to run each test
3535
// multiple times
3636
fn static_atomic(val: i32) -> &'static AtomicI32 {
37-
let ret = Box::leak(Box::new(AtomicI32::new(val)));
38-
ret.store(val, Relaxed); // work around https://github.com/rust-lang/miri/issues/2164
39-
ret
37+
Box::leak(Box::new(AtomicI32::new(val)))
4038
}
4139
fn static_atomic_bool(val: bool) -> &'static AtomicBool {
42-
let ret = Box::leak(Box::new(AtomicBool::new(val)));
43-
ret.store(val, Relaxed); // work around https://github.com/rust-lang/miri/issues/2164
44-
ret
40+
Box::leak(Box::new(AtomicBool::new(val)))
4541
}
4642

4743
// Spins until it acquires a pre-determined value.
@@ -365,6 +361,45 @@ fn test_cpp20_rwc_syncs() {
365361
assert!((b, c) != (0, 0));
366362
}
367363

364+
/// This checks that the *last* thing the SC fence does is act like a release fence.
365+
/// See <https://github.com/rust-lang/miri/pull/4057#issuecomment-2522296601>.
366+
fn test_sc_fence_release() {
367+
let x = static_atomic(0);
368+
let y = static_atomic(0);
369+
let z = static_atomic(0);
370+
let k = static_atomic(0);
371+
372+
let j1 = spawn(move || {
373+
x.store(1, Relaxed);
374+
fence(SeqCst);
375+
k.store(1, Relaxed);
376+
});
377+
let j2 = spawn(move || {
378+
y.store(1, Relaxed);
379+
fence(SeqCst);
380+
z.store(1, Relaxed);
381+
});
382+
383+
let j3 = spawn(move || {
384+
let kval = k.load(Acquire);
385+
let yval = y.load(Relaxed);
386+
(kval, yval)
387+
});
388+
let j4 = spawn(move || {
389+
let zval = z.load(Acquire);
390+
let xval = x.load(Relaxed);
391+
(zval, xval)
392+
});
393+
394+
j1.join().unwrap();
395+
j2.join().unwrap();
396+
let (kval, yval) = j3.join().unwrap();
397+
let (zval, xval) = j4.join().unwrap();
398+
399+
let bad = kval == 1 && yval == 0 && zval == 1 && xval == 0;
400+
assert!(!bad);
401+
}
402+
368403
pub fn main() {
369404
for _ in 0..50 {
370405
test_single_thread();
@@ -378,5 +413,6 @@ pub fn main() {
378413
test_iriw_sc_rlx();
379414
test_cpp20_sc_fence_fix();
380415
test_cpp20_rwc_syncs();
416+
test_sc_fence_release();
381417
}
382418
}

0 commit comments

Comments
 (0)