Skip to content

LocalKey dropped after calling std::process::exit() #127637

Open
@SteveBeeblebrox

Description

@SteveBeeblebrox

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);
}

Link to playground

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-docsArea: Documentation for any part of the project, including the compiler, standard library, and toolsA-processArea: `std::process` and `std::env`C-enhancementCategory: An issue proposing an enhancement or a PR with one.T-libs-apiRelevant to the library API team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions