Bug 78968 - conflict between gnu's __cxa_thread_atexit and LLVM's/FreeBSD's implementation
Summary: conflict between gnu's __cxa_thread_atexit and LLVM's/FreeBSD's implementation
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: libstdc++ (show other bugs)
Version: unknown
: P3 normal
Target Milestone: 7.0
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2017-01-02 16:36 UTC by Hannes Hauswedell
Modified: 2019-02-04 09:32 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2017-01-03 00:00:00


Attachments
Check for __cxa_thread_atexit in libc (822 bytes, patch)
2017-01-03 12:53 UTC, Jonathan Wakely
Details | Diff
intermediate for O3 (526.36 KB, application/gzip)
2017-01-04 13:19 UTC, Hannes Hauswedell
Details
intermediate for O3 -fno-printf-return-value (526.36 KB, application/gzip)
2017-01-04 13:20 UTC, Hannes Hauswedell
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Hannes Hauswedell 2017-01-02 16:36:43 UTC
I originally reported this here:
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=215709

libc++ / FreeBSD has recently acquired it's own implementation of __cxa_thread_atexit so that thread_local storage now works. This is great, except that it breaks static linkage with GCC which now complains about double definition:

cd /home/mi/h4nn3s/devel/lambda-build/pkg/src && /usr/local/bin/cmake -E cmake_link_script CMakeFiles/lambda.dir/link.txt --verbose=1
/usr/local/libexec/ccache/g++6     -fopenmp -Wno-vla -O3 -DNDEBUG -flto=8 -s   -static CMakeFiles/lambda.dir/lambda.cpp.o  -o ../bin/lambda  -lpthread -lexecinfo -lelf -lz -lbz2 
//usr/lib/libc.a(cxa_thread_atexit.o): In function `__cxa_thread_atexit':
/usr/src/lib/libc/stdlib/cxa_thread_atexit.c:(.text+0x0): multiple definition of `__cxa_thread_atexit'
/usr/local/lib/gcc6/gcc/x86_64-portbld-freebsd11.0/6.3.0/../../../libstdc++.a(atexit_thread.o):/wrkdirs/usr/ports/lang/gcc6/work/gcc-6.3.0/libstdc++-v3/libsupc++/atexit_thread.cc:117: first defined here
collect2: error: ld returned 1 exit status

The FreeBSD maintainer responded with:
This is a bug in gcc.  The libsupc++ configuration assumes that there are exactly two possibilities: either libc is glibc and implements __cxa_thread_atexit() using __cxa_thread_atexit_impl(), or libsupc++ must provide an implementation on its own.  Right solution is to add detection of __cxa_thread_atexit() in libc, to libstdc++ configure.ac and libsupc++/atexit_thread.cc.

What is your opinion on the matter?

Thanks!
Comment 1 Jonathan Wakely 2017-01-03 12:52:23 UTC
I agree.
Comment 2 Jonathan Wakely 2017-01-03 12:53:02 UTC
Created attachment 40448 [details]
Check for __cxa_thread_atexit in libc

Does this fix it?
Comment 3 Jonathan Wakely 2017-01-03 13:00:32 UTC
(In reply to h2+bugs from comment #0)
> This is a bug in gcc.  The libsupc++ configuration assumes that there are
> exactly two possibilities: either libc is glibc and implements
> __cxa_thread_atexit() using __cxa_thread_atexit_impl(), or libsupc++ must
> provide an implementation on its own.

Although this isn't quite right, there's no assumption of glibc.

The two possibilities are that only __cxa_thread_atexit_impl exists, or that neither __cxa_thread_atexit_impl nor __cxa_thread_atexit exists.

There's no assumption about the provenance of __cxa_thread_atexit_impl.
Comment 4 Jonathan Wakely 2017-01-03 13:04:58 UTC
I wonder why FreeBSD chose to do it that way, instead of providing the _impl function, which would also work with LLVM's libcxxabi.
Comment 5 Jonathan Wakely 2017-01-03 13:18:45 UTC
It seems entirely wrong for libc to be providing any __cxa entry point called by the compiler, such as __cxa_thread_atexit. It should come from the C++ runtime, such as libsupc++, or libcxxabi, or FreeBSD's libcxxrt. We can work around it, but it's still wrong.
Comment 6 Hannes Hauswedell 2017-01-03 14:06:45 UTC
Thanks for your quick response!

To be honest, I only have a very basic understanding of the matter. The original discussion of the implementation in FreeBSD can found here:
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=192320
https://reviews.freebsd.org/rS303795

If you feel that this should be solved differently on FreeBSD's end, I will re-open discussion there. If that doesn't lead anywhere a workaround in GCC would be great, but since this actually affects all currently released GCCs on FreeBSD11, I would prefer an OS solution as gcc patches would likely only land in the most recent GCC-branch(es), right?
Comment 7 Jonathan Wakely 2017-01-03 14:09:25 UTC
Right. This can be worked around for any GCC releases except 5.5, 6.4 and 7.1, but anything older can't be fixed.
Comment 8 Jonathan Wakely 2017-01-03 14:10:19 UTC
(In reply to Jonathan Wakely from comment #7)
> Right. This can be worked around for any GCC releases except 5.5, 6.4 and
> 7.1, but anything older can't be fixed.

Sorry, I edited that sentence half way through writing it. I meant:

Right. This can be worked around for the future GCC releases 5.5, 6.4 and
7.1, but anything older can't be fixed.
Comment 9 Konstantin Belousov 2017-01-03 14:42:05 UTC
Would older gcc releases fine if FreeBSD exports __cxa_thread_atexit_impl as an alias for __cxa_thread_atexit ?  Note that there were no FreeBSD release which provided __cxa_thread_atexit, although the symbol is already present on the stable/11 branch and cannot be removed due ABI compat guarantees.  It is used by libc++ already, I believe.

Request for __cxa_thread_atexit came directly from one of the LLVM developers, at least this is how I see the history.
Comment 10 Jonathan Wakely 2017-01-03 15:19:25 UTC
(In reply to Kostik Belousov from comment #9)
> Would older gcc releases fine if FreeBSD exports __cxa_thread_atexit_impl as
> an alias for __cxa_thread_atexit ?

I think there would still be a duplicate definition of __cxa_thread_atexit in that case.

> Note that there were no FreeBSD release
> which provided __cxa_thread_atexit, although the symbol is already present
> on the stable/11 branch and cannot be removed due ABI compat guarantees.  It
> is used by libc++ already, I believe.

Is that a local change in FreeBSD's copy of libc++? Because there's no reference to it in the upstream libc++ repo.
 
> Request for __cxa_thread_atexit came directly from one of the LLVM
> developers, at least this is how I see the history.

I understand the desire to have __cxa_thread_atexit available. The point is that it belongs in the C++ runtime, and that at least two implementations of the C++ runtime (libsupc++ and libcxxabi) already do the same thing, defining __cxa_thread_atexit unconditionally, but making use of __cxa_thread_atexit_impl if libc provides that.
Comment 11 Konstantin Belousov 2017-01-03 15:55:39 UTC
(In reply to Jonathan Wakely from comment #10)
> (In reply to Kostik Belousov from comment #9)
> > Would older gcc releases fine if FreeBSD exports __cxa_thread_atexit_impl as
> > an alias for __cxa_thread_atexit ?
> 
> I think there would still be a duplicate definition of __cxa_thread_atexit
> in that case.
Yes, but the definitions will be runtime-identical.

I mean that the benefit would be that not patched gcc configure will detect presence of __cxa_thread_atexit_impl and libsupc++ only provide trivial wrapper.  This means that both implementations use compatible runtime.

I am still somewhat puzzled by the 'duplicate definitions' linker diagnostic.  It should be satisfied by whatever implementation it finds first.  In the op case, somehow a whole static library is linked in, and we do not even know is it libc or libstdc++.

> 
> > Note that there were no FreeBSD release
> > which provided __cxa_thread_atexit, although the symbol is already present
> > on the stable/11 branch and cannot be removed due ABI compat guarantees.  It
> > is used by libc++ already, I believe.
> 
> Is that a local change in FreeBSD's copy of libc++? Because there's no
> reference to it in the upstream libc++ repo.
No, there is no change in libc++.  Compiler generated references to __cxa_thread_atexit() are satisfied by libc directly.  This was what asked for by the LLVM dev.

>  
> > Request for __cxa_thread_atexit came directly from one of the LLVM
> > developers, at least this is how I see the history.
> 
> I understand the desire to have __cxa_thread_atexit available. The point is
> that it belongs in the C++ runtime, and that at least two implementations of
> the C++ runtime (libsupc++ and libcxxabi) already do the same thing,
> defining __cxa_thread_atexit unconditionally, but making use of
> __cxa_thread_atexit_impl if libc provides that.

BTW, it was not unnatural to provide __cxa_thread_atexit() from libc, given the precedent of __cxa_atexit(3).
Comment 12 Hannes Hauswedell 2017-01-04 13:19:56 UTC
Created attachment 40451 [details]
intermediate for O3
Comment 13 Hannes Hauswedell 2017-01-04 13:20:30 UTC
Created attachment 40452 [details]
intermediate for O3 -fno-printf-return-value
Comment 14 Hannes Hauswedell 2017-01-04 13:23:07 UTC
sorry, please ignore the attachments, bugzilla dropped me in a different issue than planned.
Comment 15 Jonathan Wakely 2017-01-04 15:41:51 UTC
Author: redi
Date: Wed Jan  4 15:41:19 2017
New Revision: 244057

URL: https://gcc.gnu.org/viewcvs?rev=244057&root=gcc&view=rev
Log:
PR78968 add configure check for __cxa_thread_atexit in libc

	PR libstdc++/78968
	* config.h.in: Regenerate.
	* configure: Likewise.
	* configure.ac: Check for __cxa_thread_atexit.
	* libsupc++/atexit_thread.cc [_GLIBCXX_HAVE___CXA_THREAD_ATEXIT]:
	Don't define __cxa_thread_atexit if libc provides it.

Modified:
    trunk/libstdc++-v3/ChangeLog
    trunk/libstdc++-v3/config.h.in
    trunk/libstdc++-v3/configure
    trunk/libstdc++-v3/configure.ac
    trunk/libstdc++-v3/libsupc++/atexit_thread.cc
Comment 16 Jonathan Wakely 2017-01-04 15:45:00 UTC
Trunk no longer defines __cxa_thread_atexit if it's found in libc. We might want to backport this to the gcc-5-branch and gcc-6-branch.

I will try to test this in a FreeBSD 11 VM some time soon.
Comment 17 Jonathan Wakely 2017-01-06 17:06:56 UTC
Author: redi
Date: Fri Jan  6 17:06:24 2017
New Revision: 244169

URL: https://gcc.gnu.org/viewcvs?rev=244169&root=gcc&view=rev
Log:
Check for __cxa_thread_atexit for freebsd crosses

	PR libstdc++/78968
	* crossconfig.m4: Check for __cxa_thread_atexit on *-*-freebsd*.
	* configure: Regenerate.

Modified:
    trunk/libstdc++-v3/ChangeLog
    trunk/libstdc++-v3/configure
    trunk/libstdc++-v3/crossconfig.m4
Comment 18 Konstantin Belousov 2017-01-07 16:06:50 UTC
(In reply to Jonathan Wakely from comment #16)
> Trunk no longer defines __cxa_thread_atexit if it's found in libc. We might
> want to backport this to the gcc-5-branch and gcc-6-branch.
> 
> I will try to test this in a FreeBSD 11 VM some time soon.

I just built trunk gcc on FreeBSD HEAD.  Indeed, the newest gcc
does not export __cxa_thread_atexit from libstdc++.so.6 when configured
on a FreeBSD system which provides the symbol from libc.

I also added __cxa_thread_atexit_impl, which does help with older gcc versions.
I verified that libstdc++.so.6 provides __cxa_thread_atexit and expectedly
forwards the calls to libc:__cxa_thread_atexit_impl.

https://svnweb.freebsd.org/changeset/base/311651
Comment 19 Martin Liška 2018-11-19 14:42:07 UTC
Jonathan: Can the bug be marked as resolved?
Comment 20 Hannes Hauswedell 2018-11-19 19:28:59 UTC
Yes, this was fixed, thanks!