Bug 236344

Summary: [toolchain] gcc-built shared library crashes in static object constructors when dynamically loaded
Product: Base System Reporter: Yuri Victorovich <yuri>
Component: miscAssignee: freebsd-toolchain (Nobody) <toolchain>
Status: New ---    
Severity: Affects Only Me CC: dim, fernape, kib, marklmi26-fbsd, salvadore, theraven, val
Priority: ---    
Version: 11.2-STABLE   
Hardware: Any   
OS: Any   
Bug Depends on:    
Bug Blocks: 259070    

Description Yuri Victorovich freebsd_committer freebsd_triage 2019-03-07 04:04:12 UTC
Testcase: the port multimedia/webcamoid with added lines:
> WITH_DEBUG=yes
> USE_GCC=yes

When the executable runs, it crashes with this stack while the plugin is dynamically loaded:
> Thread 1 received signal SIGSEGV, Segmentation fault.
> 0x00000008056fed78 in vtable for __cxxabiv1::__si_class_type_info () from /lib/libcxxrt.so.1
> (gdb) bt
> #0  0x00000008056fed78 in vtable for __cxxabiv1::__si_class_type_info () at /lib/libcxxrt.so.1
> #1  0x00000008044ecf86 in __dynamic_cast () at /usr/local/lib/gcc8/libstdc++.so.6
> #2  0x000000080456bdb0 in bool std::has_facet<std::ctype<char> >(std::locale const&) () at /usr/local/lib/gcc8/libstdc++.so.6
> #3  0x000000080455f154 in std::basic_ios<char, std::char_traits<char> >::_M_cache_locale(std::locale const&) () at /usr/local/lib/gcc8/libstdc++.so.6
> #4  0x000000080455f5d0 in std::basic_ios<char, std::char_traits<char> >::init(std::basic_streambuf<char, std::char_traits<char> >*) ()
>     at /usr/local/lib/gcc8/libstdc++.so.6
> #5  0x0000000804500953 in std::ios_base::Init::Init() () at /usr/local/lib/gcc8/libstdc++.so.6
> #6  0x000000082aab4c56 in __static_initialization_and_destruction_0(int, int) (__initialize_p=1, __priority=65535) at /usr/local/lib/gcc8/include/c++/iostream:74
> #7  0x000000082aab4c89 in _GLOBAL__sub_I_ipcbridge.cpp(void) () at src/ipcbridge.cpp:3411
> #8  0x000000080073a7ab in objlist_call_init (list=<optimized out>, lockstate=<optimized out>) at /usr/src/libexec/rtld-elf/rtld.c:2657
> #9  0x000000080073f009 in dlopen_object
>     (name=0x80087cc00 "z\270", <incomplete sequence \325>, fd=<optimized out>, refobj=<optimized out>, lo_flags=10, mode=1, lockstate=0x800000002)
>     at /usr/src/libexec/rtld-elf/rtld.c:3356
> #10 0x000000080073b836 in rtld_dlopen (name=0x80b364e98 "/usr/local/lib/avkys/libVirtualCamera.so", fd=-1, mode=<optimized out>) at /usr/src/libexec/rtld-elf/rtld.c:3231
> #11 0x000000080386a7e5 in  () at /usr/local/lib/qt5/libQt5Core.so.5
> #12 0x00000008038654ea in  () at /usr/local/lib/qt5/libQt5Core.so.5
> #13 0x0000000803865913 in  () at /usr/local/lib/qt5/libQt5Core.so.5
> #14 0x00000008009923b2 in AkElement::createPtr(QString const&, QString const&) (pluginId=..., elementName=...) at src/akelement.cpp:260
> #15 0x0000000800992311 in AkElement::create(QString const&, QString const&) (pluginId=..., elementName=...) at src/akelement.cpp:243
> #16 0x0000000000416753 in MediaTools::MediaTools(QObject*) (this=0x7fffffffe780, parent=0x0) at src/mediatools.cpp:95
> #17 0x0000000000415c00 in main(int, char**) (argc=1, argv=0x7fffffffe808) at src/main.cpp:89
> (gdb) 

The crash occurs during the initialization of this static object:
> 74	  static ios_base::Init __ioinit;

It calls std::ios_base::Init::Init() which has likely been called during the main static constructors invocation, because it generally prints something from the executable.
It looks like the constructor is called twice.
The same code works fine when built with clang.
Comment 1 Fernando Apesteguía freebsd_committer freebsd_triage 2020-05-15 15:49:11 UTC
Any updates on this?

cad/openvsp doesn't build with clang anymore due to bug #230888.

It builds with gcc but it then segfaults with similar backtrace:

Program received signal SIGSEGV, Segmentation fault.
0x0000000802efba18 in vtable for __cxxabiv1::__si_class_type_info () from /lib/libcxxrt.so.1
(gdb) bt
#0  0x0000000802efba18 in vtable for __cxxabiv1::__si_class_type_info () from /lib/libcxxrt.so.1
#1  0x0000000801a273e6 in __dynamic_cast () from /usr/local/lib/gcc9/libstdc++.so.6
#2  0x0000000801aa9e8e in bool std::has_facet<std::ctype<char> >(std::locale const&) () from /usr/local/lib/gcc9/libstdc++.so.6
#3  0x0000000801a9bbd4 in std::basic_ios<char, std::char_traits<char> >::_M_cache_locale(std::locale const&) () from /usr/local/lib/gcc9/libstdc++.so.6
#4  0x0000000801a9c070 in std::basic_ios<char, std::char_traits<char> >::init(std::basic_streambuf<char, std::char_traits<char> >*) ()
   from /usr/local/lib/gcc9/libstdc++.so.6
#5  0x0000000801a3b463 in std::ios_base::Init::Init() () from /usr/local/lib/gcc9/libstdc++.so.6
#6  0x000000000049f60d in ?? ()
#7  0x000000080194846e in ?? () from /libexec/ld-elf.so.1
#8  0x00007fffffffc828 in ?? ()
#9  0x0000000801975800 in ?? ()
#10 0x0000000000000000 in ?? ()
Comment 2 Konstantin Belousov freebsd_committer freebsd_triage 2020-05-15 16:19:15 UTC
Can you extract the minimal test case ?
Comment 3 Fernando Apesteguía freebsd_committer freebsd_triage 2020-05-15 16:22:08 UTC
Yep, it involves a patch for cad/openvsp (to make it build with gcc). Should I open a different PR so I don't hijack this one?
Comment 4 Yuri Victorovich freebsd_committer freebsd_triage 2020-05-15 16:38:16 UTC
(In reply to Fernando Apesteguía from comment #3)

Yes, please open a different PR.
Comment 5 Fernando Apesteguía freebsd_committer freebsd_triage 2020-05-15 16:54:12 UTC
Done: bug #246488
Comment 6 Dimitry Andric freebsd_committer freebsd_triage 2020-05-16 12:51:10 UTC
I think that what Konstantin means with a minimal test case, is not a huge CAD port, but one or two .cpp files which can be independently compiled, to show the issue. That said, this seems like an issue with shared libraries initializing libstdc++'s iostream constructors twice. I guess the vtable pointer shows in the description and comment table is NULL? Did any of the original submitters check that?
Comment 7 Val Packett 2021-08-16 23:38:42 UTC
Encountered this in darktable (non-ports, just trying gcc to compare performance) as well. The only solution I've found is switching to libc++ via CXXFLAGS="-nostdinc++ -isystem /usr/include/c++/v1" and LDFLAGS="-L/tmp/somedir" where somedir is where you do ln -s /usr/lib/libc++.so libstdc++.so. The ports framework already supports this, see the gcc-c++11-lib section at the bottom of Mk/Uses/compiler.mk.
Comment 8 Mark Millard 2021-08-17 01:26:12 UTC
(In reply to Greg V from comment #7)

Just an FYI:

In use of FreeBSD's libc++ from g++ I use,
for example, from a specific context (not a port):

CXX=            g++11 -v -std=c++20 -Wpedantic -Wall -Wextra
CXX+=           -Wno-psabi -nostdinc -nostdinc++ \
                -I/usr/include/c++/v1 -I/usr/include
. . .
LDCXX=          -nodefaultlibs -lc++ -lcxxrt -lthr -lm -lc -lgcc_s

On aarch64 I've also use: -mno-outline-atomics
I also sometimes need -Wl,-rpath=/usr/local/lib/gcc11 for things
missing from the -lgcc_s .

The context does not load any other .so's, however.

For reference . . .

My FreeBSD goes back to 2021-Jul-05:

# uname -apKU
FreeBSD CA72_16Gp_ZFS 14.0-CURRENT FreeBSD 14.0-CURRENT #10 main-n247756-348c41d1815d-dirty: Mon Jul  5 10:23:55 PDT 2021     root@CA72_16Gp_ZFS:/usr/obj/BUILDs/main-CA72-nodbg-clang/usr/main-src/arm64.aarch64/sys/GENERIC-NODBG-CA72  arm64 aarch64 1400025 1400025

The ports go back to 2021-Jun-19:

# ~/fbsd-based-on-what-commit.sh 
branch: main
merge-base: 7e413d93a62bb844a193e568fd8a1ba4834e5ea5
merge-base: CommitDate: 2021-06-19 00:23:12 +0000
7e413d93a62b (HEAD -> main, freebsd/main, freebsd/HEAD) graphics/mesa-devel: update to 21.1.b.3189
n549134 (--first-parent --count for merge-base)
Comment 9 David Chisnall freebsd_committer freebsd_triage 2021-10-12 08:56:05 UTC
From the stack trace, it looks as if this is linking both from the base system libcxxrt.so and libstdc++.so from the gcc8 port.  The version of libstdc++.so from the base system was modified to link libcxxrt.so but I believe the versions from ports embed libsupc++.a.  Both libcxxrt and libsupc++ define the same symbols and so you end up with a mixture of them being called.  In particular, you're mixing part of the `dynamic_cast` implementation from libsupc++ (frame #1) with part from libcxxrt (frame #0).  This is very unlikely to work.

The correct fix for this would be to make the GCC ports link libstdc++.so against libcxxrt.so instead of building libsupc++.a, but that probably requires some invasive changes to the build system.

In general, mixing code linked against libc++ and libstdc++ is unlikely to work.  There are three ways of fixing this:

 - Teach the libstdc++ build to use libcxxrt
 - Teach gcc to support -stdlib=libc++
 - Use something like `-nostdinc++ -nodefaultlibs -isystem <install>/include/c++/v1    -lc++ -lcxxrt -lm -lc -lgcc_s -lgcc` when compiling / linking C++ things with gcc.
Comment 10 Lorenzo Salvadore freebsd_committer freebsd_triage 2023-02-26 09:17:27 UTC
*** Bug 269110 has been marked as a duplicate of this bug. ***
Comment 11 Mark Millard 2023-02-26 17:07:31 UTC
(In reply to David Chisnall from comment #9)

Some of the lang/gcc* ports were taught to support
-stdlib=libc++ back in late 2022-Aug.