From f23e76e0d273b2c7612421b2d8505f84c9ea480f Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 19 Mar 2025 12:49:18 +0100 Subject: [PATCH 1/4] Allow spawning threads after TLS destruction. --- library/std/src/thread/spawnhook.rs | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/library/std/src/thread/spawnhook.rs b/library/std/src/thread/spawnhook.rs index 99b5ad9cb9fe5..98f471ad54b2e 100644 --- a/library/std/src/thread/spawnhook.rs +++ b/library/std/src/thread/spawnhook.rs @@ -113,18 +113,23 @@ where pub(super) fn run_spawn_hooks(thread: &Thread) -> ChildSpawnHooks { // Get a snapshot of the spawn hooks. // (Increments the refcount to the first node.) - let hooks = SPAWN_HOOKS.with(|hooks| { + if let Ok(hooks) = SPAWN_HOOKS.try_with(|hooks| { let snapshot = hooks.take(); hooks.set(snapshot.clone()); snapshot - }); - // Iterate over the hooks, run them, and collect the results in a vector. - let to_run: Vec<_> = iter::successors(hooks.first.as_deref(), |hook| hook.next.as_deref()) - .map(|hook| (hook.hook)(thread)) - .collect(); - // Pass on the snapshot of the hooks and the results to the new thread, - // which will then run SpawnHookResults::run(). - ChildSpawnHooks { hooks, to_run } + }) { + // Iterate over the hooks, run them, and collect the results in a vector. + let to_run: Vec<_> = iter::successors(hooks.first.as_deref(), |hook| hook.next.as_deref()) + .map(|hook| (hook.hook)(thread)) + .collect(); + // Pass on the snapshot of the hooks and the results to the new thread, + // which will then run SpawnHookResults::run(). + ChildSpawnHooks { hooks, to_run } + } else { + // TLS has been destroyed. Skip running the hooks. + // See https://github.com/rust-lang/rust/issues/138696 + ChildSpawnHooks::default() + } } /// The results of running the spawn hooks. From 5912dadf08fa2b29f723ec2c2b2315399a75c06e Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 19 Mar 2025 12:49:41 +0100 Subject: [PATCH 2/4] Add test. --- tests/ui/thread-local/spawn-hook-atexit.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 tests/ui/thread-local/spawn-hook-atexit.rs diff --git a/tests/ui/thread-local/spawn-hook-atexit.rs b/tests/ui/thread-local/spawn-hook-atexit.rs new file mode 100644 index 0000000000000..cc517e8fa4c66 --- /dev/null +++ b/tests/ui/thread-local/spawn-hook-atexit.rs @@ -0,0 +1,22 @@ +// Regression test for https://github.com/rust-lang/rust/issues/138696 +//@ run-pass + +#![feature(rustc_private)] + +extern crate libc; + +fn main() { + std::thread::spawn(|| { + unsafe { libc::atexit(spawn_in_atexit) }; + }) + .join() + .unwrap(); +} + +extern "C" fn spawn_in_atexit() { + std::thread::spawn(|| { + println!("Thread spawned in atexit"); + }) + .join() + .unwrap(); +} From 3237b5092bb2dd6bc72ccf38fd42a226eed09e77 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 27 Mar 2025 08:46:35 +0100 Subject: [PATCH 3/4] Add needs-threads to test. --- tests/ui/thread-local/spawn-hook-atexit.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/ui/thread-local/spawn-hook-atexit.rs b/tests/ui/thread-local/spawn-hook-atexit.rs index cc517e8fa4c66..41fcbab1a8124 100644 --- a/tests/ui/thread-local/spawn-hook-atexit.rs +++ b/tests/ui/thread-local/spawn-hook-atexit.rs @@ -1,4 +1,5 @@ // Regression test for https://github.com/rust-lang/rust/issues/138696 +//@ needs-threads //@ run-pass #![feature(rustc_private)] From 6c2161a07c8f54e5b2838087a9a7406a789c98e8 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 27 Mar 2025 14:11:11 +0100 Subject: [PATCH 4/4] Mark test as only-unix. --- tests/ui/thread-local/spawn-hook-atexit.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/ui/thread-local/spawn-hook-atexit.rs b/tests/ui/thread-local/spawn-hook-atexit.rs index 41fcbab1a8124..b084e0bb38785 100644 --- a/tests/ui/thread-local/spawn-hook-atexit.rs +++ b/tests/ui/thread-local/spawn-hook-atexit.rs @@ -1,4 +1,5 @@ // Regression test for https://github.com/rust-lang/rust/issues/138696 +//@ only-unix //@ needs-threads //@ run-pass