Description
Unlike normal static variables (or the differently implemented unstable #[thread_local]
statics), thread_local!
/LocalKey
statics are still dropped after calling std::process::exit()
.
I tried this code:
#![feature(thread_local)]
use std::sync::LazyLock;
#[derive(Debug)]
struct Droppable {
name: &'static str
}
impl Drop for Droppable {
fn drop(&mut self) {
println!("Dropping {}", self.name);
println!("{}", std::backtrace::Backtrace::force_capture());
}
}
impl Droppable {
fn new(name: &'static str) -> Self {
return Self {
name
};
}
}
static SHARED_STATIC: LazyLock<Droppable> = LazyLock::new(|| Droppable::new("SHARED_STATIC"));
thread_local! {
static TLS_STATIC: Droppable = Droppable::new("TLS_STATIC");
}
#[thread_local]
static UNSTABLE_THREAD_LOCAL: LazyLock<Droppable> = LazyLock::new(|| Droppable::new("UNSTABLE_THREAD_LOCAL"));
fn main() {
// Force initialize
LazyLock::force(&SHARED_STATIC);
LazyLock::force(&UNSTABLE_THREAD_LOCAL);
TLS_STATIC.with(|_| {});
println!("std::process::exit(1)");
std::process::exit(1);
}
I expected to see this happen: No output from drop()
since the documentation for std::process::exit()
makes a point of saying no destructors will be called and the program will exit immediately. When calling exit, I assumed that almost nothing happens after that.
Instead, this happened: The static variable wrapped with thread_local!
had its drop implementation called after calling std::process::exit()
meanwhile a normal static variable and one with the unstable #[thread_local]
attribute did not.
Other notes: The same behavior occurs where only the thread_local!
value is dropped when normally exiting from main()
.
LocalKey's documentation sort of makes it sound like this is intentional behavior that the destructors are run even when exiting the main thread (See "Platform-specific behavior" 1.). If this is working as intended, it would be nice if the documentation were slightly clearer.
Meta
rustc --version --verbose
:
rustc 1.81.0-nightly (20ae37c18 2024-07-07)
binary: rustc
commit-hash: 20ae37c18df95f9246c019b04957d23b4164bf7a
commit-date: 2024-07-07
host: x86_64-unknown-linux-gnu
release: 1.81.0-nightly
LLVM version: 18.1.7
Backtrace
0: <playground::Droppable as core::ops::drop::Drop>::drop
at ./src/main.rs:12:24
1: core::ptr::drop_in_place<playground::Droppable>
at /rustc/5315cbe15b79533f380bbb6685aa5480d5ff4ef5/library/core/src/ptr/mod.rs:542:1
2: core::ptr::drop_in_place<std::sys::thread_local::native::lazy::State<playground::Droppable,()>>
at /rustc/5315cbe15b79533f380bbb6685aa5480d5ff4ef5/library/core/src/ptr/mod.rs:542:1
3: core::mem::drop
at /rustc/5315cbe15b79533f380bbb6685aa5480d5ff4ef5/library/core/src/mem/mod.rs:938:24
4: std::sys::thread_local::native::lazy::destroy::{{closure}}
at /rustc/5315cbe15b79533f380bbb6685aa5480d5ff4ef5/library/std/src/sys/thread_local/native/lazy.rs:99:9
5: std::sys::thread_local::abort_on_dtor_unwind
at /rustc/5315cbe15b79533f380bbb6685aa5480d5ff4ef5/library/std/src/sys/thread_local/mod.rs:168:5
6: std::sys::thread_local::native::lazy::destroy
at /rustc/5315cbe15b79533f380bbb6685aa5480d5ff4ef5/library/std/src/sys/thread_local/native/lazy.rs:94:5
7: __call_tls_dtors
8: <unknown>
9: exit
10: std::sys::pal::unix::os::exit
at /rustc/5315cbe15b79533f380bbb6685aa5480d5ff4ef5/library/std/src/sys/pal/unix/os.rs:761:14
11: std::process::exit
at /rustc/5315cbe15b79533f380bbb6685aa5480d5ff4ef5/library/std/src/process.rs:2320:5
12: playground::main
at ./src/main.rs:40:5
13: core::ops::function::FnOnce::call_once
at /rustc/5315cbe15b79533f380bbb6685aa5480d5ff4ef5/library/core/src/ops/function.rs:250:5
14: std::sys::backtrace::__rust_begin_short_backtrace
at /rustc/5315cbe15b79533f380bbb6685aa5480d5ff4ef5/library/std/src/sys/backtrace.rs:155:18
15: std::rt::lang_start::{{closure}}
at /rustc/5315cbe15b79533f380bbb6685aa5480d5ff4ef5/library/std/src/rt.rs:159:18
16: core::ops::function::impls::<impl core::ops::function::FnOnce<A> for &F>::call_once
at /rustc/5315cbe15b79533f380bbb6685aa5480d5ff4ef5/library/core/src/ops/function.rs:284:13
17: std::panicking::try::do_call
at /rustc/5315cbe15b79533f380bbb6685aa5480d5ff4ef5/library/std/src/panicking.rs:553:40
18: std::panicking::try
at /rustc/5315cbe15b79533f380bbb6685aa5480d5ff4ef5/library/std/src/panicking.rs:517:19
19: std::panic::catch_unwind
at /rustc/5315cbe15b79533f380bbb6685aa5480d5ff4ef5/library/std/src/panic.rs:350:14
20: std::rt::lang_start_internal::{{closure}}
at /rustc/5315cbe15b79533f380bbb6685aa5480d5ff4ef5/library/std/src/rt.rs:141:48
21: std::panicking::try::do_call
at /rustc/5315cbe15b79533f380bbb6685aa5480d5ff4ef5/library/std/src/panicking.rs:553:40
22: std::panicking::try
at /rustc/5315cbe15b79533f380bbb6685aa5480d5ff4ef5/library/std/src/panicking.rs:517:19
23: std::panic::catch_unwind
at /rustc/5315cbe15b79533f380bbb6685aa5480d5ff4ef5/library/std/src/panic.rs:350:14
24: std::rt::lang_start_internal
at /rustc/5315cbe15b79533f380bbb6685aa5480d5ff4ef5/library/std/src/rt.rs:141:20
25: std::rt::lang_start
at /rustc/5315cbe15b79533f380bbb6685aa5480d5ff4ef5/library/std/src/rt.rs:158:17
26: main
27: __libc_start_main
28: _start