I forward it here for comments.

Basing on the behavior of both GCC and Clang, `__cxa_thread_atexit` is used to 
register the
destructor of thread_local objects directly, suggesting the first parameter 
should have `__thiscall`
convention.

libstdc++ used the default `__cdecl` convention and caused crashes on 
1686-w64-mingw32 (see
PR83562). But to my surprise, libcxxabi uses `__cdecl` too [1], but I haven't 
heard any of relevant
reports so far.

Original patch is attached in case you can't find it in gcc-patches.


[1]
https://github.com/llvm/llvm-project/blob/97b351a827677ebbedc10bfbce8ef8844c246553/libcxxabi/src/cxa_thread_atexit.cpp#L22





-------- 转发的消息 --------
主题: Re: libstdc++: Attempt to resolve PR83562
日期: Tue, 27 Oct 2020 22:38:29 +0800
发件人: Liu Hao <lh_mo...@126.com>
收件人: Jason Merrill <ja...@redhat.com>, GCC Patches <gcc-patches@gcc.gnu.org>

在 2020/10/8 22:56, Jason Merrill 写道:
> 
> Hmm, why isn't the mingw implementation used for all programs?  That would 
> avoid the bug.
> 

There was a little further discussion about this [1].

TL;DR: The mingw-w64 function is linked statically and subject to issues about 
order of destruction.

Recently mingw-w64 has got its own `__cxa_thread_atexit()` so libstdc++ no 
longer exposes it. This
patch for libstdc++ fixes
calling conventions for destructors on i686 so they match mingw-w64 ones.


[1] https://github.com/msys2/MINGW-packages/issues/7096

[2] Below is a direct quote from #mingw-w64 on OFTC:
    (lh_ideapad is me and wbs is Martin Storsjö.)

```
[14:29:32] <lh_ideapad> wbs, what was the rationale for the `__thiscall` 
convention for
`__cxa_thread_atexit()` and
`__cxa_atexit()` in our CRT? I suspect it is correct, but it is not specified 
anywhere in Itanium ABI.
[14:30:41] <lh_ideapad> In case of evidence for that, the GCC prototype (with 
default __cdecl)
should be wrong.
[14:31:10] <lh_ideapad> See this:  
https://github.com/msys2/MINGW-packages/issues/7096
[14:52:05] <wbs> lh_ideapad: itanium ABI doesn't really talk about windows 
things, but, the function
that is passed to
__cxa_thread_atexit is the object's destructor function, and when calling the 
destructor, which is
technically a member
function, it's done with the thiscall calling convention
[14:52:31] <wbs> lh_ideapad: example: https://godbolt.org/z/qbfWT1 (only clang 
as there's no
gcc-mingw there, but if you try
the same there you'll see the same thing)
[14:52:35] <minifox> Title: Compiler Explorer (at godbolt.org)
[14:52:58] <wbs> lh_ideapad: the destruct function shows that when calling 
__ZN7MyClassD1Ev, the
destructor, it passes the
object pointer in ecx, i.e. thiscall
[14:53:42] <wbs> lh_ideapad: and when adding the object to the cleanup list, 
the __ZN7MyClassD1Ev
function is passed
directly to ___cxa_thread_atexit, which then will need to call the function 
using the thiscall
convention
[14:59:54] <wbs> lh_ideapad: so yes, I would agree with your patch changing 
libsupc++ to use thiscall
[15:13:01] <lh_ideapad> gcc is doing the same thing with a wrong calling 
convention , leaving a
garbage value on
i686-w64-mingw32.
[15:13:38] <wbs> yup, so definite +1 on your libsupc++ patch for that
[15:14:00] <lh_ideapad> then how about `__cxa_atexit`?
[15:14:26] <wbs> I would say it should work the same, but gcc doesn't normally 
use that one, right?
[15:14:29] <lh_ideapad> it's not used by GCC (the standard `atexit()` is used).
[15:15:26] <wbs> clang has a flag -fuse-cxa-atexit, which makes it use 
cxa_atexit instead of atexit
[15:15:40] <lh_ideapad> I was a bit dubious on it.
[15:18:59] <lh_ideapad> GCC has `-fuse-cxa-atexit` too .  Let me check.
[15:18:59] <wbs> (I tested it), clang does use __cxa_atexit if the 
-fuse-cxa-atexit flag is used,
and then the dtor
(thiscall) is passed directly to __cxa_atexit, so that's +1 datapoint to that 
it should have
thiscall. gcc doesn't use
__cxa_atexit for i686 windows despite -fuse-cxa-atexit, so that's no points in 
either direction
[15:19:28] <wbs> both clang and gcc use a wrapper function that fixes the 
calling convention, when
using atexit at least
[15:20:22] <lh_ideapad> `-fuse-cxa-atexit` seems to have no effect on 
`i686-w64-mingw32-g++`.
[15:20:46] <wbs> exactly. so in practice it doesn't matter for gcc, but I think 
libsupc++ should
handle it the same
[15:23:11] <lh_ideapad> ok I will compose a new patch for both functions later 
today.
[15:23:13] <lh_ideapad> :)
[15:23:25] <wbs> \o/
[15:24:40] <wbs> then for the other issue that the user was posting about; I 
remember testing and
noticing that the
mingw-w64-crt implementation of __cxa_thread_atexit doesn't work with emutls, 
but in all of my
tests, it has been a
non-issue as it has ended up using the libsupc++ code instead
[15:50:50] <lh_ideapad> probably static linking is broken, so one must link 
against shared libstdc++.
[15:52:20] <lh_ideapad> it doesn't matter whether it is the CRT or libsupc++ 
implementation that is
linked statically.
[15:53:13] <wbs> it seems like current msys builds of libstdc++ doesn't include 
__cxa_thread_atexit
in libstdc++ at all. I'm
pretty sure I tested this back when I made the mingw version, but I'll 
investigate and try to
pinpoint what changed (did gcc
at some point start noticing that mingw-w64-crt contains it and stop providing 
their own?) or
whether I just missed
something when I tested it back when I wrote it...
[15:59:47] <wbs> I'll follow up on that other issue and mingw bugtracker issue, 
but I'll do a couple
hours of comple
testing/studying things first to be able to give an informed comment
[16:15:34] * pamaury (~pama...@ip-41.net-89-3-53.rev.numericable.fr) has joined
[16:27:34] <lh_ideapad> wbs, there is a check in `libstdc++-v3/configure.ac` 
around line 275.
[16:29:22] <wbs> lh_ideapad: yeah, but in my tests it doesn't pick up on it. I 
test by
cross-bootstrapping a toolchain, so
maybe this check runs before the mingw-w64-crt actually is built
[16:29:50] <wbs> so it doesn't detect if just bootstrapping once, but if 
building a new gcc in an
already complete
environment, it behaves differently
[16:33:21] * Pali (~p...@0001caa5.user.oftc.net) has joined
[16:34:52] <wbs> ah, here it is:
[16:34:52] <wbs> # Only do link tests if native. Else, hardcode.
[16:34:52] <wbs> if $GLIBCXX_IS_NATIVE; then
```





-- 
Best regards,
LH_Mouse


From ac325bdcd6e3fa522f8b59d436cd4b3ab663de5c Mon Sep 17 00:00:00 2001
From: Liu Hao <lh_mo...@126.com>
Date: Thu, 8 Oct 2020 10:26:13 +0800
Subject: [PATCH] libsupc++: Make the destructor parameter to
 `__cxa_thread_atexit()` use the `__thiscall` calling convention for
 i686-w64-mingw32

The mingw-w64 implementations of `__cxa_thread_atexit()` and `__cxa_atexit()` have been
using `__thiscall` since two years ago. Using the default calling convention (which is
`__cdecl`) causes crashes as explained in PR83562.

Calling conventions have no effect on x86_64-w64-mingw32.

Reference: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83562
Reference: https://sourceforge.net/p/mingw-w64/mingw-w64/ci/master/tree/mingw-w64-crt/crt/cxa_thread_atexit.c
Reference: https://sourceforge.net/p/mingw-w64/mingw-w64/ci/f3e0fbb40cbc9f8821db8bd8a0c4dae8ff671e9f/
Reference: https://github.com/msys2/MINGW-packages/issues/7071
Signed-off-by: Liu Hao <lh_mo...@126.com>
---
 libstdc++-v3/libsupc++/atexit_thread.cc | 14 ++++++++++----
 libstdc++-v3/libsupc++/cxxabi.h         |  8 ++++++++
 2 files changed, 18 insertions(+), 4 deletions(-)

diff --git a/libstdc++-v3/libsupc++/atexit_thread.cc b/libstdc++-v3/libsupc++/atexit_thread.cc
index e97644f8cd4..4f7f982ac6b 100644
--- a/libstdc++-v3/libsupc++/atexit_thread.cc
+++ b/libstdc++-v3/libsupc++/atexit_thread.cc
@@ -30,16 +30,21 @@
 #include <windows.h>
 #endif
 
+// Simplify it a little for this file.
+#ifndef _GLIBCXX_CDTOR_CALLABI
+#  define _GLIBCXX_CDTOR_CALLABI
+#endif
+
 #if _GLIBCXX_HAVE___CXA_THREAD_ATEXIT
 
 // Libc provides __cxa_thread_atexit definition.
 
 #elif _GLIBCXX_HAVE___CXA_THREAD_ATEXIT_IMPL
 
-extern "C" int __cxa_thread_atexit_impl (void (*func) (void *),
+extern "C" int __cxa_thread_atexit_impl (void (_GLIBCXX_CDTOR_CALLABI *func) (void *),
 					 void *arg, void *d);
 extern "C" int
-__cxxabiv1::__cxa_thread_atexit (void (*dtor)(void *),
+__cxxabiv1::__cxa_thread_atexit (void (_GLIBCXX_CDTOR_CALLABI *dtor)(void *),
 				 void *obj, void *dso_handle)
   _GLIBCXX_NOTHROW
 {
@@ -52,7 +57,7 @@ namespace {
   // One element in a singly-linked stack of cleanups.
   struct elt
   {
-    void (*destructor)(void *);
+    void (_GLIBCXX_CDTOR_CALLABI *destructor)(void *);
     void *object;
     elt *next;
 #ifdef _GLIBCXX_THREAD_ATEXIT_WIN32
@@ -116,7 +121,8 @@ namespace {
 }
 
 extern "C" int
-__cxxabiv1::__cxa_thread_atexit (void (*dtor)(void *), void *obj, void */*dso_handle*/)
+__cxxabiv1::__cxa_thread_atexit (void (_GLIBCXX_CDTOR_CALLABI *dtor)(void *),
+				 void *obj, void */*dso_handle*/)
   _GLIBCXX_NOTHROW
 {
   // Do this initialization once.
diff --git a/libstdc++-v3/libsupc++/cxxabi.h b/libstdc++-v3/libsupc++/cxxabi.h
index 000713ecdf8..3d6217a6fac 100644
--- a/libstdc++-v3/libsupc++/cxxabi.h
+++ b/libstdc++-v3/libsupc++/cxxabi.h
@@ -125,14 +125,22 @@ namespace __cxxabiv1
 
   // DSO destruction.
   int
+#ifdef _GLIBCXX_CDTOR_CALLABI
+  __cxa_atexit(void (_GLIBCXX_CDTOR_CALLABI *)(void*), void*, void*) _GLIBCXX_NOTHROW;
+#else
   __cxa_atexit(void (*)(void*), void*, void*) _GLIBCXX_NOTHROW;
+#endif
 
   void
   __cxa_finalize(void*);
 
   // TLS destruction.
   int
+#ifdef _GLIBCXX_CDTOR_CALLABI
+  __cxa_thread_atexit(void (_GLIBCXX_CDTOR_CALLABI *)(void*), void*, void *) _GLIBCXX_NOTHROW;
+#else
   __cxa_thread_atexit(void (*)(void*), void*, void *) _GLIBCXX_NOTHROW;
+#endif
 
   // Pure virtual functions.
   void
-- 
2.20.1

Attachment: signature.asc
Description: OpenPGP digital signature

Reply via email to