Skip to content

Calling std::thread::current() in global allocator results in non-obvious error #115209

Description

@GoldsteinE

Global allocator is a special piece of code because it runs before main(). Parts of standard library are not available at this time and it’s (as far as I know) not documented in safety contract of GlobalAlloc, or, for that matter, anywhere else.

It seems like some sort of a doc specifying which functions are “before-main-safe” (so can be used in GlobalAlloc and #[ctor]) would be really useful. On top of that, I think that identifying the current thread should be allowed in the global allocator.

I tried this code (playground):

use std::alloc::{GlobalAlloc, Layout, System};

struct MyGlobalAlloc;

unsafe impl GlobalAlloc for MyGlobalAlloc {
    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
        std::panic::catch_unwind(|| std::thread::current()).ok();
        System.alloc(layout)
    }
    unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
        System.dealloc(ptr, layout)
    }
}

#[global_allocator]
static _ALLOCATOR: MyGlobalAlloc = MyGlobalAlloc;

fn main() {}

I expected to see this happen: nothing at all, it should just work.

Instead, this happened:

thread panicked while processing panic. aborting.

I’ve also seen:

fatal runtime error: assertion failed: thread_info.is_none()

but I can’t reliably reproduce it.

Meta

rustc --version --verbose:

rustc 1.73.0-nightly (08d00b40a 2023-08-09)
binary: rustc
commit-hash: 08d00b40aef2017fe6dba3ff7d6476efa0c10888
commit-date: 2023-08-09
host: x86_64-unknown-linux-gnu
release: 1.73.0-nightly
LLVM version: 17.0.0

but it reproduces on stable, beta and nightly.

I’m not actually sure if this is a bug, but I think one of the following must be true:

  1. Either global allocator should be able to call std::thread::current().id() without crashing the program,
  2. or its inability to do so should be documented in docs for GlobalAlloc, #[global_allocator], or std::thread::current(), preferably all of them.

Activity

  1. added
    needs-triageThis issue may need triage. Remove when done. See docs forge.rust-lang.org/release/issue-triaging
    on Aug 25, 2023
  2. changed the title [-]Calling std::thread::current() in global allocator results in non-obvious error[/-] [+]Calling `std::thread::current()` in global allocator results in non-obvious error[/+] on Aug 25, 2023
  3. changed the title [-]Calling `std::thread::current()` in global allocator results in non-obvious error[/-] [+]Calling `std::thread::current() in global allocator results in non-obvious error[/+] on Aug 25, 2023
  4. changed the title [-]Calling `std::thread::current() in global allocator results in non-obvious error[/-] [+]Calling `std::thread::current()` in global allocator results in non-obvious error[/+] on Aug 25, 2023
  5. asokol123 commented on Aug 25, 2023

    @asokol123

    In macos result is always [1] 99360 illegal hardware instruction cargo run

    Meta

    rustc --version --verbose

    rustc 1.74.0-nightly (58eefc33a 2023-08-24)
    binary: rustc
    commit-hash: 58eefc33adf769a1abe12ad94b3e6811185b4ce5
    commit-date: 2023-08-24
    host: aarch64-apple-darwin
    release: 1.74.0-nightly
    LLVM version: 17.0.0
    
  6. ChrisDenton commented on Aug 25, 2023

    @ChrisDenton
    Member

    Pre-main behaviour was also discussed in #110708. The feeling was that in general we should endeavour to make as much of the std work as possible and document where it doesn't. The complicating factor is that this is highly platform specific and there are likely to always be caveats and shifting behaviour as implementations evolve.

    But yes, documenting it is definitely worth doing if someone wants to help with that.

  7. GoldsteinE commented on Aug 25, 2023

    @GoldsteinE
    ContributorAuthor

    I’d help with documenting, but I’m not sure where this should be documented. I’m also not sure whether it should be documented as “you can use these APIs pre-main” or “you can’t use these other APIs pre-main”.

    A separate question is why std::thread::current() is not pre-main-safe. Linked issue only talks about it being non-post-main-safe.

  8. asokol123 commented on Aug 25, 2023

    @asokol123

    Also, this code hangs in macos, so maybe not related to pre-main:

    use std::alloc::{GlobalAlloc, Layout, System};
    use std::sync::atomic::AtomicBool;
    use std::thread;
    
    static IS_MAIN_STARED: AtomicBool = AtomicBool::new(false);
    
    struct MyGlobalAlloc;
    
    unsafe impl GlobalAlloc for MyGlobalAlloc {
        unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
            if IS_MAIN_STARED.load(std::sync::atomic::Ordering::SeqCst) {
                std::panic::catch_unwind(std::thread::current).ok();
            }
            System.alloc(layout)
        }
        unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
            System.dealloc(ptr, layout)
        }
    }
    
    #[global_allocator]
    static _ALLOCATOR: MyGlobalAlloc = MyGlobalAlloc;
    
    fn main() {
        IS_MAIN_STARED.store(true, std::sync::atomic::Ordering::SeqCst);
        let e = thread::spawn(|| {});
        e.join().unwrap();
    }

    If you remove #[global_allocator] or thread::spawn, it works normally

    rustc --version --verbose

    rustc 1.74.0-nightly (58eefc33a 2023-08-24)
    binary: rustc
    commit-hash: 58eefc33adf769a1abe12ad94b3e6811185b4ce5
    commit-date: 2023-08-24
    host: aarch64-apple-darwin
    release: 1.74.0-nightly
    LLVM version: 17.0.0
    
  9. added
    T-libs-api[DEPRECATED; DO NOT USE]
    T-libsRelevant to the library team, which will review and decide on the PR/issue.
    and removed
    needs-triageThis issue may need triage. Remove when done. See docs forge.rust-lang.org/release/issue-triaging
    on Aug 25, 2023
  10. ChrisDenton commented on Aug 25, 2023

    @ChrisDenton
    Member

    Also, this code hangs in macos, so maybe not related to pre-main:

    Oh hm, yeah it seems more likely that the issue is std::thread::current itself allocating.

  11. lolbinarycat commented on Jul 15, 2024

    @lolbinarycat
    Contributor

    it seems that it allocates because it uses thread_local!, it's the same underlying issue as #116390

  12. joboet commented on Oct 9, 2024

    @joboet
    Member

    With #127912 merged, this now triggers an abort with a hopefully clearer message:

    fatal runtime error: 
    
                Attempted to access thread-local data while allocating said data.
    
                Do not access functions that allocate in the global allocator!
    
                This is a bug in the global allocator.
    
  13. added a commit that references this issue on Aug 23, 2025
  14. added a commit that references this issue on Oct 21, 2025
  15. added 2 commits that reference this issue on Nov 28, 2025
  16. added a commit that references this issue on Jan 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-bugCategory: This is a bug.T-libsRelevant to the library team, which will review and decide on the PR/issue.T-libs-api[DEPRECATED; DO NOT USE]

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions