about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-04-25 08:14:58 +0000
committerbors <bors@rust-lang.org>2024-04-25 08:14:58 +0000
commit97132949f7f5f707fa4460447289efe432d6ffca (patch)
treebf07f062fa6dbabb7f23e704b1f3db1d6c21161c
parente22a73c6d0c1173b8f3309bae43b9bea1df3c36b (diff)
parent247e82cb8391765cef976d0a23d7bdc3e509a978 (diff)
Auto merge of #3501 - RalfJung:tls-many-seeds, r=RalfJung
add a test for the TLS memory leak

This is a regression test for https://github.com/rust-lang/rust/issues/123583.
-rwxr-xr-xsrc/tools/miri/ci/ci.sh18
-rw-r--r--src/tools/miri/src/concurrency/weak_memory.rs4
-rw-r--r--src/tools/miri/src/diagnostics.rs11
-rw-r--r--src/tools/miri/tests/many-seeds/tls-leak.rs26
4 files changed, 47 insertions, 12 deletions
diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh
index f8ba612750e..ad0c795315e 100755
--- a/src/tools/miri/ci/ci.sh
+++ b/src/tools/miri/ci/ci.sh
@@ -128,16 +128,18 @@ function run_tests_minimal {
 ## Main Testing Logic ##
 
 # In particular, fully cover all tier 1 targets.
+# We also want to run the many-seeds tests on all tier 1 targets.
 case $HOST_TARGET in
   x86_64-unknown-linux-gnu)
     # Host
     GC_STRESS=1 MIR_OPT=1 MANY_SEEDS=64 TEST_BENCH=1 CARGO_MIRI_ENV=1 run_tests
     # Extra tier 1
-    MIRI_TEST_TARGET=i686-unknown-linux-gnu run_tests
-    MIRI_TEST_TARGET=aarch64-unknown-linux-gnu run_tests
-    MIRI_TEST_TARGET=x86_64-apple-darwin run_tests
-    MIRI_TEST_TARGET=i686-pc-windows-gnu run_tests
-    MIRI_TEST_TARGET=x86_64-pc-windows-gnu run_tests
+    # With reduced many-seed count to avoid spending too much time on that.
+    # (All OSes are run with 64 seeds at least once though via the macOS runner.)
+    MANY_SEEDS=16 MIRI_TEST_TARGET=i686-unknown-linux-gnu run_tests
+    MANY_SEEDS=16 MIRI_TEST_TARGET=aarch64-unknown-linux-gnu run_tests
+    MANY_SEEDS=16 MIRI_TEST_TARGET=x86_64-apple-darwin run_tests
+    MANY_SEEDS=16 MIRI_TEST_TARGET=x86_64-pc-windows-gnu run_tests
     # Extra tier 2
     MIRI_TEST_TARGET=aarch64-apple-darwin run_tests
     MIRI_TEST_TARGET=arm-unknown-linux-gnueabi run_tests
@@ -155,13 +157,15 @@ case $HOST_TARGET in
     # Host (tier 2)
     GC_STRESS=1 MIR_OPT=1 MANY_SEEDS=64 TEST_BENCH=1 CARGO_MIRI_ENV=1 run_tests
     # Extra tier 1
-    MIRI_TEST_TARGET=x86_64-pc-windows-msvc CARGO_MIRI_ENV=1 run_tests
+    MANY_SEEDS=64 MIRI_TEST_TARGET=i686-pc-windows-gnu run_tests
+    MANY_SEEDS=64 MIRI_TEST_TARGET=x86_64-pc-windows-msvc CARGO_MIRI_ENV=1 run_tests
     # Extra tier 2
     MIRI_TEST_TARGET=s390x-unknown-linux-gnu run_tests # big-endian architecture
     ;;
   i686-pc-windows-msvc)
     # Host
-    # Only smoke-test `many-seeds`; 64 runs take 15min here!
+    # Only smoke-test `many-seeds`; 64 runs of just the scoped-thread-leak test take 15min here!
+    # See <https://github.com/rust-lang/miri/issues/3509>.
     GC_STRESS=1 MIR_OPT=1 MANY_SEEDS=1 TEST_BENCH=1 run_tests
     # Extra tier 1
     # We really want to ensure a Linux target works on a Windows host,
diff --git a/src/tools/miri/src/concurrency/weak_memory.rs b/src/tools/miri/src/concurrency/weak_memory.rs
index f544393cfe6..574962c48d4 100644
--- a/src/tools/miri/src/concurrency/weak_memory.rs
+++ b/src/tools/miri/src/concurrency/weak_memory.rs
@@ -520,7 +520,9 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
                     validate,
                 )?;
                 if global.track_outdated_loads && recency == LoadRecency::Outdated {
-                    this.emit_diagnostic(NonHaltingDiagnostic::WeakMemoryOutdatedLoad);
+                    this.emit_diagnostic(NonHaltingDiagnostic::WeakMemoryOutdatedLoad {
+                        ptr: place.ptr(),
+                    });
                 }
 
                 return Ok(loaded);
diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs
index 0c0ac4c6036..9fa786332e3 100644
--- a/src/tools/miri/src/diagnostics.rs
+++ b/src/tools/miri/src/diagnostics.rs
@@ -125,7 +125,9 @@ pub enum NonHaltingDiagnostic {
     Int2Ptr {
         details: bool,
     },
-    WeakMemoryOutdatedLoad,
+    WeakMemoryOutdatedLoad {
+        ptr: Pointer<Option<Provenance>>,
+    },
 }
 
 /// Level of Miri specific diagnostics
@@ -583,7 +585,8 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
             | AccessedAlloc(..)
             | FreedAlloc(..)
             | ProgressReport { .. }
-            | WeakMemoryOutdatedLoad => ("tracking was triggered".to_string(), DiagLevel::Note),
+            | WeakMemoryOutdatedLoad { .. } =>
+                ("tracking was triggered".to_string(), DiagLevel::Note),
         };
 
         let msg = match &e {
@@ -610,8 +613,8 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
             ProgressReport { .. } =>
                 format!("progress report: current operation being executed is here"),
             Int2Ptr { .. } => format!("integer-to-pointer cast"),
-            WeakMemoryOutdatedLoad =>
-                format!("weak memory emulation: outdated value returned from load"),
+            WeakMemoryOutdatedLoad { ptr } =>
+                format!("weak memory emulation: outdated value returned from load at {ptr}"),
         };
 
         let notes = match &e {
diff --git a/src/tools/miri/tests/many-seeds/tls-leak.rs b/src/tools/miri/tests/many-seeds/tls-leak.rs
new file mode 100644
index 00000000000..3b243633439
--- /dev/null
+++ b/src/tools/miri/tests/many-seeds/tls-leak.rs
@@ -0,0 +1,26 @@
+//! Regression test for <https://github.com/rust-lang/rust/issues/123583>.
+use std::thread;
+
+fn with_thread_local1() {
+    thread_local! { static X: Box<u8> = Box::new(0); }
+    X.with(|_x| {})
+}
+
+fn with_thread_local2() {
+    thread_local! { static Y: Box<u8> = Box::new(0); }
+    Y.with(|_y| {})
+}
+
+fn main() {
+    // Here we have two threads racing on initializing the thread-local and adding it to the global
+    // dtor list (on targets that have such a list, i.e., targets without target_thread_local).
+    let t = thread::spawn(with_thread_local1);
+    with_thread_local1();
+    t.join().unwrap();
+
+    // Here we have one thread running the destructors racing with another thread initializing a
+    // thread-local. The second thread adds a destructor that could be picked up by the first.
+    let t = thread::spawn(|| { /* immediately just run destructors */ });
+    with_thread_local2(); // initialize thread-local
+    t.join().unwrap();
+}