Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

std::thread::spawn: thread-local storage panics #138696

Open
yellowhatter opened this issue Mar 19, 2025 · 5 comments · May be fixed by #138702
Open

std::thread::spawn: thread-local storage panics #138696

yellowhatter opened this issue Mar 19, 2025 · 5 comments · May be fixed by #138702
Assignees
Labels
C-bug Category: This is a bug. needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. regression-untriaged Untriaged performance or correctness regression. T-libs Relevant to the library team, which will review and decide on the PR/issue.

Comments

@yellowhatter
Copy link

yellowhatter commented Mar 19, 2025

Hello, rust-team!

Code

I tried this code:

#[test]
fn spawn_in_atexit_main() {
    unsafe { libc::atexit(spawn_in_atexit) };
}

extern "C" fn spawn_in_atexit() {
    let _ = std::thread::spawn(|| {
        println!("Thread spawned in atexit");
    });
}

I expected to see this happen: thread spawned normally

Instead, this happened: panic at std::thread::spawnhook::run_spawn_hooks because it tries to talk to TLS which is not available inside of atexit context. Earlier versions of thread didn't have this hooks functionality and were OK spawning inside atexit and we tested it on Win, Mac and Linux.
Functionality to spawn thread inside atexit is very important as it is a silver bullet workaround to execute some TLS-using code from atexit context.

Version it worked on

It most recently worked on: at least 1.75

Version with regression

rustc --version --verbose:

rustc 1.85.1 (4eb161250 2025-03-15)
binary: rustc
commit-hash: 4eb161250e340c8f48f66e2b929ef4a5bed7c181
commit-date: 2025-03-15
host: x86_64-unknown-linux-gnu
release: 1.85.1
LLVM version: 19.1.7

Backtrace

Backtrace

thread 'main' panicked at library/std/src/thread/local.rs:272:26:
cannot access a Thread Local Storage value during or after destruction: AccessError
stack backtrace:
   0: rust_begin_unwind
             at /rustc/4d91de4e48198da2e33413efdcd9cd2cc0c46688/library/std/src/panicking.rs:692:5
   1: core::panicking::panic_fmt
             at /rustc/4d91de4e48198da2e33413efdcd9cd2cc0c46688/library/core/src/panicking.rs:75:14
   2: core::result::unwrap_failed
             at /rustc/4d91de4e48198da2e33413efdcd9cd2cc0c46688/library/core/src/result.rs:1704:5
   3: core::result::Result<T,E>::expect
             at /rustc/4d91de4e48198da2e33413efdcd9cd2cc0c46688/library/core/src/result.rs:1061:23
   4: std::thread::local::LocalKey<T>::with
             at /rustc/4d91de4e48198da2e33413efdcd9cd2cc0c46688/library/std/src/thread/local.rs:272:9
   5: std::thread::spawnhook::run_spawn_hooks
             at /rustc/4d91de4e48198da2e33413efdcd9cd2cc0c46688/library/std/src/thread/spawnhook.rs:116:29
   6: std::thread::Builder::spawn_unchecked_
             at /home/hatter/.rustup/toolchains/1.85.0-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/thread/mod.rs:512:13
   7: std::thread::Builder::spawn_unchecked
             at /home/hatter/.rustup/toolchains/1.85.0-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/thread/mod.rs:469:32
   8: std::thread::Builder::spawn
             at /home/hatter/.rustup/toolchains/1.85.0-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/thread/mod.rs:401:18
   9: std::thread::spawn
             at /home/hatter/.rustup/toolchains/1.85.0-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/thread/mod.rs:734:20
  10: atexit::spawn_in_atexit
             at ./tests/atexit.rs:88:13
  11: __run_exit_handlers
             at ./stdlib/exit.c:108:8
  12: __GI_exit
             at ./stdlib/exit.c:138:3
  13: __libc_start_call_main
             at ./csu/../sysdeps/nptl/libc_start_call_main.h:74:3
  14: __libc_start_main_impl
             at ./csu/../csu/libc-start.c:360:3
  15: _start
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

thread 'main' panicked at library/core/src/panicking.rs:218:5:
panic in a function that cannot unwind
stack backtrace:
   0:     0x65482003492a - std::backtrace_rs::backtrace::libunwind::trace::h88deb10bd0145eb8
                               at /rustc/4d91de4e48198da2e33413efdcd9cd2cc0c46688/library/std/src/../../backtrace/src/backtrace/libunwind.rs:116:5
   1:     0x65482003492a - std::backtrace_rs::backtrace::trace_unsynchronized::he1036f5481c14dff
                               at /rustc/4d91de4e48198da2e33413efdcd9cd2cc0c46688/library/std/src/../../backtrace/src/backtrace/mod.rs:66:5
   2:     0x65482003492a - std::sys::backtrace::_print_fmt::hecc345b6e70c4b20
                               at /rustc/4d91de4e48198da2e33413efdcd9cd2cc0c46688/library/std/src/sys/backtrace.rs:66:9
   3:     0x65482003492a - <std::sys::backtrace::BacktraceLock::print::DisplayBacktrace as core::fmt::Display>::fmt::he089f96442833f67
                               at /rustc/4d91de4e48198da2e33413efdcd9cd2cc0c46688/library/std/src/sys/backtrace.rs:39:26
   4:     0x654820060683 - core::fmt::rt::Argument::fmt::h1f77cded99c71a14
                               at /rustc/4d91de4e48198da2e33413efdcd9cd2cc0c46688/library/core/src/fmt/rt.rs:177:76
   5:     0x654820060683 - core::fmt::write::h2f210ed4c94745cb
                               at /rustc/4d91de4e48198da2e33413efdcd9cd2cc0c46688/library/core/src/fmt/mod.rs:1440:21
   6:     0x654820030423 - std::io::Write::write_fmt::h7de08171ab770fb2
                               at /rustc/4d91de4e48198da2e33413efdcd9cd2cc0c46688/library/std/src/io/mod.rs:1887:15
   7:     0x654820034772 - std::sys::backtrace::BacktraceLock::print::h810fbd31421329e6
                               at /rustc/4d91de4e48198da2e33413efdcd9cd2cc0c46688/library/std/src/sys/backtrace.rs:42:9
   8:     0x654820035e60 - std::panicking::default_hook::{{closure}}::hbaad47ed9dc6356d
                               at /rustc/4d91de4e48198da2e33413efdcd9cd2cc0c46688/library/std/src/panicking.rs:295:22
   9:     0x654820035c40 - std::panicking::default_hook::h24e207139139d40a
                               at /rustc/4d91de4e48198da2e33413efdcd9cd2cc0c46688/library/std/src/panicking.rs:322:9
  10:     0x6548200365c2 - std::panicking::rust_panic_with_hook::ha9131beeb2ddc506
                               at /rustc/4d91de4e48198da2e33413efdcd9cd2cc0c46688/library/std/src/panicking.rs:828:13
  11:     0x654820036336 - std::panicking::begin_panic_handler::{{closure}}::h1bba0eaeb6da506f
                               at /rustc/4d91de4e48198da2e33413efdcd9cd2cc0c46688/library/std/src/panicking.rs:694:13
  12:     0x654820034e29 - std::sys::backtrace::__rust_end_short_backtrace::h1d1ca3eade483f4c
                               at /rustc/4d91de4e48198da2e33413efdcd9cd2cc0c46688/library/std/src/sys/backtrace.rs:168:18
  13:     0x654820035ffd - rust_begin_unwind
                               at /rustc/4d91de4e48198da2e33413efdcd9cd2cc0c46688/library/std/src/panicking.rs:692:5
  14:     0x65481ebd45ed - core::panicking::panic_nounwind_fmt::runtime::hdd2d1a56a8b6cee7
                               at /rustc/4d91de4e48198da2e33413efdcd9cd2cc0c46688/library/core/src/panicking.rs:117:22
  15:     0x65481ebd45ed - core::panicking::panic_nounwind_fmt::h0d5ff668f956fac4
                               at /rustc/4d91de4e48198da2e33413efdcd9cd2cc0c46688/library/core/src/intrinsics/mod.rs:3869:9
  16:     0x65481ebd4682 - core::panicking::panic_nounwind::h385b7d9bda51382d
                               at /rustc/4d91de4e48198da2e33413efdcd9cd2cc0c46688/library/core/src/panicking.rs:218:5
  17:     0x65481ebd4846 - core::panicking::panic_cannot_unwind::h757b6ea37bf9b60a
                               at /rustc/4d91de4e48198da2e33413efdcd9cd2cc0c46688/library/core/src/panicking.rs:307:5
  18:     0x65481ec436e9 - atexit::spawn_in_atexit::h8fbdd131c26eac2f
                               at /home/hatter/work/repos/zenoh/zenoh/tests/atexit.rs:87:1
  19:     0x7982d2a47a76 - __run_exit_handlers
                               at ./stdlib/exit.c:108:8
  20:     0x7982d2a47bbe - __GI_exit
                               at ./stdlib/exit.c:138:3
  21:     0x7982d2a2a1d1 - __libc_start_call_main
                               at ./csu/../sysdeps/nptl/libc_start_call_main.h:74:3
  22:     0x7982d2a2a28b - __libc_start_main_impl
                               at ./csu/../csu/libc-start.c:360:3
  23:     0x65481ebd4f15 - _start
  24:                0x0 - <unknown>
thread caused non-unwinding panic. aborting.
error: test failed, to rerun pass `-p zenoh --test atexit`

Caused by:
  process didn't exit successfully: `/home/hatter/work/repos/zenoh/target/debug/deps/atexit-f97afb099485217a spawn_in_atexit_main --exact --show-output` (signal: 6, SIGABRT: process abort signal)

 *  The terminal process "cargo 'test', '--package', 'zenoh', '--test', 'atexit', '--', 'spawn_in_atexit_main', '--exact', '--show-output'" terminated with exit code: 101. 
 *  Terminal will be reused by tasks, press any key to close it. 

@yellowhatter yellowhatter added C-bug Category: This is a bug. regression-untriaged Untriaged performance or correctness regression. labels Mar 19, 2025
@rustbot rustbot added I-prioritize Issue: Indicates that prioritization has been requested for this issue. needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. labels Mar 19, 2025
@yellowhatter
Copy link
Author

yellowhatter commented Mar 19, 2025

To restore previous behavior we need to have the way to spawn without going into hooks code. However, thread Builder's no_hooks setter method is unstable, so execution always goes to std::thread::spawnhook::run_spawn_hooks and touches TLS.

@yellowhatter
Copy link
Author

@jieyouxu jieyouxu added the T-libs Relevant to the library team, which will review and decide on the PR/issue. label Mar 19, 2025
@tgross35
Copy link
Contributor

Cc @m-ou-se, this likely relates to #125405.

@m-ou-se m-ou-se self-assigned this Mar 19, 2025
@m-ou-se m-ou-se linked a pull request Mar 19, 2025 that will close this issue
@m-ou-se
Copy link
Member

m-ou-se commented Mar 19, 2025

Fixed by #138702

@apiraino apiraino removed the I-prioritize Issue: Indicates that prioritization has been requested for this issue. label Mar 19, 2025
@yellowhatter
Copy link
Author

Thanks!

YuanYuYuan added a commit to eclipse-zenoh/zenoh that referenced this issue Mar 24, 2025
* Make background close builder nolocal

* make close builders internally-public

* Update lib.rs

* do not use flume channel s it is not nolocal

* fix exports

* switch runtime to Net

* Make close more atexit-safe

* add tests for wait() in close

* Add important note

* Update Cargo.toml and atexit.rs

* Code format

* fix clippy

* Update Cargo.lock

* - review fixes
- get rid of async-channel (use tokio channel instead until it is nolocal)
- improve testing coverage (test background close to be nolocal)

* code format

* fix feature set

* disable session_close_in_atexit test on 1.85 as std has regression rust-lang/rust#138696

* fix tokio executor blockage

* Paic with message describing nolocal thread spawning error

* spelling

* Handle nolocal errors more properly

* refactor: replace `mpsc::channel` with `oneshot::channel` and address the `block_in_place` issue (#26)

---------

Co-authored-by: Yuyuan Yuan <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-bug Category: This is a bug. needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. regression-untriaged Untriaged performance or correctness regression. T-libs Relevant to the library team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants