about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2024-08-07 14:50:34 +0200
committerRalf Jung <post@ralfj.de>2024-09-28 12:05:29 +0200
commited417f44f81f7096bfe135e7d84092f2a7fecaa6 (patch)
treecc57de698427f1187d0a44edec5c6dbdca93b99c
parent76bce58b7ae52890d83edc5486c1427c3ab3c546 (diff)
downloadrust-ed417f44f81f7096bfe135e7d84092f2a7fecaa6.tar.gz
rust-ed417f44f81f7096bfe135e7d84092f2a7fecaa6.zip
miri: no longer complain about read-read races
-rw-r--r--src/tools/miri/src/concurrency/data_race.rs23
-rw-r--r--src/tools/miri/tests/fail/data_race/read_read_race1.rs30
-rw-r--r--src/tools/miri/tests/fail/data_race/read_read_race1.stderr22
-rw-r--r--src/tools/miri/tests/fail/data_race/read_read_race2.rs30
-rw-r--r--src/tools/miri/tests/fail/data_race/read_read_race2.stderr22
-rw-r--r--src/tools/miri/tests/pass/concurrency/data_race.rs38
6 files changed, 43 insertions, 122 deletions
diff --git a/src/tools/miri/src/concurrency/data_race.rs b/src/tools/miri/src/concurrency/data_race.rs
index b5b43f589f6..558a032d0bc 100644
--- a/src/tools/miri/src/concurrency/data_race.rs
+++ b/src/tools/miri/src/concurrency/data_race.rs
@@ -499,7 +499,7 @@ impl MemoryCellClocks {
         Ok(())
     }
 
-    /// Detect data-races with an atomic read, caused by a non-atomic access that does
+    /// Detect data-races with an atomic read, caused by a non-atomic write that does
     /// not happen-before the atomic-read.
     fn atomic_read_detect(
         &mut self,
@@ -510,12 +510,8 @@ impl MemoryCellClocks {
         trace!("Atomic read with vectors: {:#?} :: {:#?}", self, thread_clocks);
         let atomic = self.atomic_access(thread_clocks, access_size)?;
         atomic.read_vector.set_at_index(&thread_clocks.clock, index);
-        // Make sure the last non-atomic write and all non-atomic reads were before this access.
-        if self.write_was_before(&thread_clocks.clock) && self.read <= thread_clocks.clock {
-            Ok(())
-        } else {
-            Err(DataRace)
-        }
+        // Make sure the last non-atomic write was before this access.
+        if self.write_was_before(&thread_clocks.clock) { Ok(()) } else { Err(DataRace) }
     }
 
     /// Detect data-races with an atomic write, either with a non-atomic read or with
@@ -552,11 +548,9 @@ impl MemoryCellClocks {
         }
         thread_clocks.clock.index_mut(index).set_read_type(read_type);
         if self.write_was_before(&thread_clocks.clock) {
+            // We must be ordered-after all atomic writes.
             let race_free = if let Some(atomic) = self.atomic() {
-                // We must be ordered-after all atomic accesses, reads and writes.
-                // This ensures we don't mix atomic and non-atomic accesses.
                 atomic.write_vector <= thread_clocks.clock
-                    && atomic.read_vector <= thread_clocks.clock
             } else {
                 true
             };
@@ -957,9 +951,7 @@ impl VClockAlloc {
         let mut other_size = None; // if `Some`, this was a size-mismatch race
         let write_clock;
         let (other_access, other_thread, other_clock) =
-            // First check the atomic-nonatomic cases. If it looks like multiple
-            // cases apply, this one should take precedence, else it might look like
-            // we are reporting races between two non-atomic reads.
+            // First check the atomic-nonatomic cases.
             if !access.is_atomic() &&
                 let Some(atomic) = mem_clocks.atomic() &&
                 let Some(idx) = Self::find_gt_index(&atomic.write_vector, &active_clocks.clock)
@@ -1007,10 +999,7 @@ impl VClockAlloc {
             assert!(!involves_non_atomic);
             Some("overlapping unsynchronized atomic accesses must use the same access size")
         } else if access.is_read() && other_access.is_read() {
-            assert!(involves_non_atomic);
-            Some(
-                "overlapping atomic and non-atomic accesses must be synchronized, even if both are read-only",
-            )
+            panic!("there should be no same-size read-read races")
         } else {
             None
         };
diff --git a/src/tools/miri/tests/fail/data_race/read_read_race1.rs b/src/tools/miri/tests/fail/data_race/read_read_race1.rs
deleted file mode 100644
index 02aa4e4b716..00000000000
--- a/src/tools/miri/tests/fail/data_race/read_read_race1.rs
+++ /dev/null
@@ -1,30 +0,0 @@
-//@compile-flags: -Zmiri-preemption-rate=0.0
-// Avoid accidental synchronization via address reuse inside `thread::spawn`.
-//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0
-
-use std::sync::atomic::{AtomicU16, Ordering};
-use std::thread;
-
-// Make sure races between atomic and non-atomic reads are detected.
-// This seems harmless but C++ does not allow them, so we can't allow them for now either.
-// This test coverse the case where the non-atomic access come first.
-fn main() {
-    let a = AtomicU16::new(0);
-
-    thread::scope(|s| {
-        s.spawn(|| {
-            let ptr = &a as *const AtomicU16 as *mut u16;
-            unsafe { ptr.read() };
-        });
-        s.spawn(|| {
-            thread::yield_now();
-
-            // We also put a non-atomic access here, but that should *not* be reported.
-            let ptr = &a as *const AtomicU16 as *mut u16;
-            unsafe { ptr.read() };
-            // Then do the atomic access.
-            a.load(Ordering::SeqCst);
-            //~^ ERROR: Data race detected between (1) non-atomic read on thread `unnamed-1` and (2) atomic load on thread `unnamed-2`
-        });
-    });
-}
diff --git a/src/tools/miri/tests/fail/data_race/read_read_race1.stderr b/src/tools/miri/tests/fail/data_race/read_read_race1.stderr
deleted file mode 100644
index e97c4a4fdcb..00000000000
--- a/src/tools/miri/tests/fail/data_race/read_read_race1.stderr
+++ /dev/null
@@ -1,22 +0,0 @@
-error: Undefined Behavior: Data race detected between (1) non-atomic read on thread `unnamed-ID` and (2) atomic load on thread `unnamed-ID` at ALLOC. (2) just happened here
-  --> tests/fail/data_race/read_read_race1.rs:LL:CC
-   |
-LL |             a.load(Ordering::SeqCst);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between (1) non-atomic read on thread `unnamed-ID` and (2) atomic load on thread `unnamed-ID` at ALLOC. (2) just happened here
-   |
-help: and (1) occurred earlier here
-  --> tests/fail/data_race/read_read_race1.rs:LL:CC
-   |
-LL |             unsafe { ptr.read() };
-   |                      ^^^^^^^^^^
-   = help: overlapping atomic and non-atomic accesses must be synchronized, even if both are read-only
-   = help: see https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#memory-model-for-atomic-accesses for more information about the Rust memory model
-   = 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 (of the first span) on thread `unnamed-ID`:
-   = note: inside closure at tests/fail/data_race/read_read_race1.rs:LL:CC
-
-note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
-
-error: aborting due to 1 previous error
-
diff --git a/src/tools/miri/tests/fail/data_race/read_read_race2.rs b/src/tools/miri/tests/fail/data_race/read_read_race2.rs
deleted file mode 100644
index 3b94c9143f3..00000000000
--- a/src/tools/miri/tests/fail/data_race/read_read_race2.rs
+++ /dev/null
@@ -1,30 +0,0 @@
-//@compile-flags: -Zmiri-preemption-rate=0.0
-// Avoid accidental synchronization via address reuse inside `thread::spawn`.
-//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0
-
-use std::sync::atomic::{AtomicU16, Ordering};
-use std::thread;
-
-// Make sure races between atomic and non-atomic reads are detected.
-// This seems harmless but C++ does not allow them, so we can't allow them for now either.
-// This test coverse the case where the atomic access come first.
-fn main() {
-    let a = AtomicU16::new(0);
-
-    thread::scope(|s| {
-        s.spawn(|| {
-            // We also put a non-atomic access here, but that should *not* be reported.
-            let ptr = &a as *const AtomicU16 as *mut u16;
-            unsafe { ptr.read() };
-            // Then do the atomic access.
-            a.load(Ordering::SeqCst);
-        });
-        s.spawn(|| {
-            thread::yield_now();
-
-            let ptr = &a as *const AtomicU16 as *mut u16;
-            unsafe { ptr.read() };
-            //~^ ERROR: Data race detected between (1) atomic load on thread `unnamed-1` and (2) non-atomic read on thread `unnamed-2`
-        });
-    });
-}
diff --git a/src/tools/miri/tests/fail/data_race/read_read_race2.stderr b/src/tools/miri/tests/fail/data_race/read_read_race2.stderr
deleted file mode 100644
index d64032db7b3..00000000000
--- a/src/tools/miri/tests/fail/data_race/read_read_race2.stderr
+++ /dev/null
@@ -1,22 +0,0 @@
-error: Undefined Behavior: Data race detected between (1) atomic load on thread `unnamed-ID` and (2) non-atomic read on thread `unnamed-ID` at ALLOC. (2) just happened here
-  --> tests/fail/data_race/read_read_race2.rs:LL:CC
-   |
-LL |             unsafe { ptr.read() };
-   |                      ^^^^^^^^^^ Data race detected between (1) atomic load on thread `unnamed-ID` and (2) non-atomic read on thread `unnamed-ID` at ALLOC. (2) just happened here
-   |
-help: and (1) occurred earlier here
-  --> tests/fail/data_race/read_read_race2.rs:LL:CC
-   |
-LL |             a.load(Ordering::SeqCst);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^
-   = help: overlapping atomic and non-atomic accesses must be synchronized, even if both are read-only
-   = help: see https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#memory-model-for-atomic-accesses for more information about the Rust memory model
-   = 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 (of the first span) on thread `unnamed-ID`:
-   = note: inside closure at tests/fail/data_race/read_read_race2.rs:LL:CC
-
-note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
-
-error: aborting due to 1 previous error
-
diff --git a/src/tools/miri/tests/pass/concurrency/data_race.rs b/src/tools/miri/tests/pass/concurrency/data_race.rs
index 34380dfa504..adf5a37891f 100644
--- a/src/tools/miri/tests/pass/concurrency/data_race.rs
+++ b/src/tools/miri/tests/pass/concurrency/data_race.rs
@@ -1,7 +1,7 @@
 //@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0
 
 use std::sync::atomic::*;
-use std::thread::spawn;
+use std::thread::{self, spawn};
 
 #[derive(Copy, Clone)]
 struct EvilSend<T>(pub T);
@@ -143,10 +143,46 @@ fn test_local_variable_lazy_write() {
     assert_eq!(val, 127);
 }
 
+// This test coverse the case where the non-atomic access come first.
+fn test_read_read_race1() {
+    let a = AtomicU16::new(0);
+
+    thread::scope(|s| {
+        s.spawn(|| {
+            let ptr = &a as *const AtomicU16 as *mut u16;
+            unsafe { ptr.read() };
+        });
+        s.spawn(|| {
+            thread::yield_now();
+
+            a.load(Ordering::SeqCst);
+        });
+    });
+}
+
+// This test coverse the case where the atomic access come first.
+fn test_read_read_race2() {
+    let a = AtomicU16::new(0);
+
+    thread::scope(|s| {
+        s.spawn(|| {
+            a.load(Ordering::SeqCst);
+        });
+        s.spawn(|| {
+            thread::yield_now();
+
+            let ptr = &a as *const AtomicU16 as *mut u16;
+            unsafe { ptr.read() };
+        });
+    });
+}
+
 pub fn main() {
     test_fence_sync();
     test_multiple_reads();
     test_rmw_no_block();
     test_simple_release();
     test_local_variable_lazy_write();
+    test_read_read_race1();
+    test_read_read_race2();
 }