https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83562
Bug ID: 83562 Summary: broken destructors of thread_local objects on i686 mingw targets Product: gcc Version: 7.2.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: lh_mouse at 126 dot com Target Milestone: --- Test program: ```c++ struct cat { cat(){ __builtin_printf("cat(): %p\n", (void *)this); } ~cat(){ __builtin_printf("~cat(): %p\n", (void *)this); } void meow(){ __builtin_printf("meow(): %p\n", (void *)this); } }; thread_local cat c; int main(){ c.meow(); } ``` Compiling and running this program outputs a garbage pointer inside the dtor: ```plaintext E:\Desktop>i686-w64-mingw32-g++ test.cpp && a.exe cat(): 0084177C meow(): 0084177C ~cat(): 76EC2FED ``` Recompile the original program with `-S -O2` and notice the following assembly code: ```s C1: .ascii "cat(): %p\12\0" .text .def ___tls_init.part.0; .scl 3; .type 32; .endef __tls_init.part.0: pushl %ebx subl $24, %esp movl $___emutls_v.__tls_guard, (%esp) call ___emutls_get_address movb $1, (%eax) movl $___emutls_v.c, (%esp) call ___emutls_get_address movl %eax, %ebx movl %eax, 4(%esp) movl $LC1, (%esp) call _printf movl $0, 8(%esp) movl %ebx, 4(%esp) movl $__ZN3catD1Ev, (%esp) call ___cxa_thread_atexit addl $24, %esp popl %ebx ret ``` GCC emits a call to the destructor of `cat` using `__cxa_thread_atexit()`. This causes the crash, because `__cxa_thread_atexit()` requires the callback to use the `__cdecl` calling convention, where its argument is to be pushed onto stack, while the destructor expects the `__thiscall` calling convention, where its argument, the implicit `this` pointer, is to be passed via the ECX register. Hence inside the callback ECX merely gets whatever garbage value that happens to reside in it. Reference: https://sourceforge.net/p/mingw-w64/bugs/527/