From 1e923170140007c10910376a3c69181e24a993de Mon Sep 17 00:00:00 2001 From: Tony Printezis Date: Thu, 6 Aug 2026 07:35:02 -0700 Subject: [PATCH] Fix thread-exit TSD cleanup on MinGW builds On MinGW, the legacy TlsAlloc TSD path has no thread-local variable, so the linker omitted the PE TLS directory and never invoked the .CRT$XLY callback (_tls_callback) on DLL_THREAD_DETACH. Per-thread TSD cleanup therefore never ran on thread exit, and test_tsd_sub_thread failed with data_cleanup_count == 0. Reference _tls_used from tsd.c under __GNUC__ to force the CRT's TLS support to be linked in, mirroring the existing MSVC /INCLUDE:_tls_used directive. --- src/tsd.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/tsd.c b/src/tsd.c index 849f2297..4511cdea 100644 --- a/src/tsd.c +++ b/src/tsd.c @@ -393,6 +393,18 @@ _tls_callback(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { linker, "/INCLUDE:" STRINGIFY(tls_callback)) # endif # pragma section(".CRT$XLY", long, read) +# elif defined(__GNUC__) +/* + * MinGW analog of the MSVC "/INCLUDE:_tls_used" directives above. Referencing + * _tls_used forces the linker to pull in the CRT's TLS support (tlssup), which + * emits the PE TLS directory so the loader actually invokes our .CRT$XLY + * callback (_tls_callback) on DLL_THREAD_DETACH. Without it, a statically + * linked MinGW binary (e.g. the unit tests) never runs per-thread TSD cleanup + * on thread exit. The compiler applies the correct symbol decoration, so this + * works for both 32- and 64-bit targets. + */ +extern char _tls_used; +JEMALLOC_ATTR(used) static char *const tls_used_ref = &_tls_used; # endif JEMALLOC_SECTION(".CRT$XLY") JEMALLOC_ATTR(used) BOOL(WINAPI *const tls_callback)(