https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80883
Bug ID: 80883 Summary: Hardcoded null DSO handle parameter to __cxa_thread_atexit() on MinGW-w64 targets Product: gcc Version: 7.1.1 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: lh_mouse at 126 dot com Target Milestone: --- It looks like that GCC for MinGW-w64 targets always passes a null DSO handle to `__cxa_thread_atexit()` when registering destructors for objects with thread storage duration. This violates Itanium ABI apparently, doesn't it? The `__cxa_thread_atexit()` function calls `GetModuleHandleExW()` to obtain a DLL handle from the function that will be called, which isn't reliable at all, because when we have `thread_local std::string s; s = "hello";` the first parameter actually points to `std::string::~basic_string` which is in libstdc++. The destructor is then called only when libstdc++ is unloaded, but it should have been called when the DLL that contains that thread_local definition is unloaded. Testcase: (This can be found http://paste.ubuntu.com/24657853/ at the moment.) --------------------------------------------- E:\Desktop>cat test.cc #include <string> extern "C" int __stdcall DllMain(void *hInstance, void *, unsigned long dwReason, void *pReserved){ thread_local std::string s; s = "hello"; return 1; } E:\Desktop>g++ test.cc -std=c++11 -O3 -shared -S E:\Desktop>cat test.s .file "test.cc" .section .rdata,"dr" .LC0: .ascii "hello\0" .text .globl DllMain .def DllMain; .scl 2; .type 32; .endef .seh_proc DllMain DllMain: .LFB1041: pushq %rsi .seh_pushreg %rsi pushq %rbx .seh_pushreg %rbx subq $56, %rsp .seh_stackalloc 56 .seh_endprologue leaq __emutls_v._ZGVZ7DllMainE1s(%rip), %rcx call __emutls_get_address movq %rax, %rsi leaq __emutls_v._ZZ7DllMainE1s(%rip), %rcx call __emutls_get_address movq %rax, %rbx cmpb $0, (%rsi) jne .L2 leaq 16(%rax), %rax movq %rax, (%rbx) movq $0, 8(%rbx) movb $0, 16(%rbx) movb $1, (%rsi) xorl %r8d, %r8d movq %rbx, %rdx leaq _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEED1Ev(%rip), %rcx call __cxa_thread_atexit .L2: movq 8(%rbx), %r8 movq $5, 32(%rsp) leaq .LC0(%rip), %r9 xorl %edx, %edx movq %rbx, %rcx call _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE10_M_replaceEyyPKcy movl $1, %eax addq $56, %rsp popq %rbx popq %rsi ret .seh_endproc .data .align 32 __emutls_v._ZZ7DllMainE1s: .quad 32 .quad 8 .quad 0 .quad 0 .align 32 __emutls_v._ZGVZ7DllMainE1s: .quad 8 .quad 8 .quad 0 .quad 0 .ident "GCC: (gcc-7-branch HEAD with MCF thread model, built by LH_Mouse.) 7.1.1 20170518" .def __emutls_get_address; .scl 2; .type 32; .endef .def _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEED1Ev; .scl 2; .type 32; .endef .def __cxa_thread_atexit; .scl 2; .type 32; .endef .def _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE10_M_replaceEyyPKcy; .scl 2; .type 32; .endef .section .rdata$.refptr._ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEED1Ev, "dr" .globl .refptr._ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEED1Ev .linkonce discard .refptr._ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEED1Ev: .quad _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEED1Ev E:\Desktop>gcc --version gcc (gcc-7-branch HEAD with MCF thread model, built by LH_Mouse.) 7.1.1 20170518 Copyright (C) 2017 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. E:\Desktop> --------------------------------------------- In the case of Windows x64 ABI the first four parameters are passed in RCX/XMM0, RDX/XMM1, R8/XMM2 and R9/XMM3, respectively. The third parameter (DSO handle) is R8 and here it is apparently set to zero on line #43.