Repository navigation
Calling std::thread::current() in global allocator results in non-obvious error #115209
Description
Activity
- addedneeds-triageThis issue may need triage. Remove when done. See docs forge.rust-lang.org/release/issue-triagingThis issue may need triage. Remove when done. See docs forge.rust-lang.org/release/issue-triaging
on Aug 25, 2023 - 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 - 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 - 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 In macos result is always
[1] 99360 illegal hardware instruction cargo runMeta
rustc --version --verboserustc 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.0Pre-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.
Reacted by lolbinarycatI’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.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]orthread::spawn, it works normallyrustc --version --verboserustc 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.0Reacted by Sergey Ivanov- addedT-libs-api[DEPRECATED; DO NOT USE][DEPRECATED; DO NOT USE]T-libsRelevant to the library team, which will review and decide on the PR/issue.Relevant to the library team, which will review and decide on the PR/issue.and removedneeds-triageThis issue may need triage. Remove when done. See docs forge.rust-lang.org/release/issue-triagingThis issue may need triage. Remove when done. See docs forge.rust-lang.org/release/issue-triaging
on Aug 25, 2023 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::currentitself allocating.it seems that it allocates because it uses
thread_local!, it's the same underlying issue as #116390Reacted by lolbinarycatWith #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.- added a commit that references this issue
on Aug 23, 2025 - added a commit that references this issue
on Oct 21, 2025 - added a commit that references this issue
on Dec 21, 2025 - added a commit that references this issue
on Aug 7, 2026
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 ofGlobalAlloc, 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
GlobalAllocand#[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):
I expected to see this happen: nothing at all, it should just work.
Instead, this happened:
I’ve also seen:
but I can’t reliably reproduce it.
Meta
rustc --version --verbose: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:
std::thread::current().id()without crashing the program,GlobalAlloc,#[global_allocator], orstd::thread::current(), preferably all of them.