This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Throwing exceptions from a .so linked with -static-lib* ?


On Thu, Jan 12, 2017 at 5:06 AM, Paul Smith <paul@mad-scientist.net> wrote:
> TL;DR:
> I have an issue where if I have a .so linked with -static-lib* making
> all STL symbols private, and if I throw an exception out of that .so to
> be caught by the caller, then I get a SIGABRT from a gcc_assert() down
> in the guts of the signal handling:
>
> #0  0x00007ffff773a428 in raise () from /lib/x86_64-linux-gnu/libc.so.6
> #1  0x00007ffff773c02a in abort () from /lib/x86_64-linux-gnu/libc.so.6
> #2  0x000000000040e938 in _Unwind_SetGR (context=<optimized out>, index=<optimized out>, val=<optimized out>) at /usr/src/cc/gcc-6.2.0/libgcc/unwind-dw2.c:271
> 271       gcc_assert (index < (int) sizeof(dwarf_reg_size_table));
>
> Should it be possible to do this successfully or am I doomed to failure?
> More details and a test case below.
>
>
> More detail:
>
> I'm trying to distribute a shared library built with the latest version
> of C++ (well, GCC 6.2 with C++14) on GNU/Linux.  I compile it with an
> older sysroot, taken from RHEL 6.3 (glibc 2.12) so it will run on older
> systems.
>
> My .so is written in C++ and programs that link it will also be written
> in C++ although they may be compiled and linked with potentially much
> older versions of GCC (like, 4.9 etc.)  I'm not worried about programs
> compiled with clang or whatever at this point.
>
> Because I want to use new C++ but want users to be able to use my .so on
> older systems, I link with -static-libgcc -static-libstdc++.  Because I
> don't want to worry about security issues etc. in system libraries, I
> don't link anything else statically.
>
> I also use a linker script to force all symbols (even libstdc++ symbols)
> to be private to my shared library except the ones I want to publish.
>
> Using "nm | grep ' [A-TV-Z] '" I can see that no other symbols besides
> mine are public.
>
> However, if my library throws an exception which I expect to be handled
> by the program linking my library, then I get a SIGABRT, as above; the
> full backtrace is:
>
> #0  0x00007ffff773a428 in raise () from /lib/x86_64-linux-gnu/libc.so.6
> #1  0x00007ffff773c02a in abort () from /lib/x86_64-linux-gnu/libc.so.6
> #2  0x000000000040e938 in _Unwind_SetGR (context=<optimized out>, index=<optimized out>, val=<optimized out>) at /usr/src/cc/gcc-6.2.0/libgcc/unwind-dw2.c:271

That seems to be
  gcc_assert (index < (int) sizeof(dwarf_reg_size_table));
which _probably_ means that unwinder is using broken unwind table.

Note that documentation for -static-libgcc explicitly mentions that
           There are several situations in which an application should
use the shared libgcc instead of the static version.  The most
           common of these is when the application wishes to throw and
catch exceptions across different shared libraries.  In that case,
           each of the libraries as well as the application itself
should use the shared libgcc.
Removing -static-libgcc fixes problem with your reprocase.

My (most probably wrong) guess is that unwind tables for main
executable and library get registered in two different instances of
libgcc (one in libgcc_s.so loaded by myprog and one statically linked
into mylib.so) which prevents normal exception propagation.

Also this thead may be relevant:
https://gcc.gnu.org/ml/gcc-help/2009-12/msg00186.html

> #3  0x00000000004012a2 in __gxx_personality_v0 ()
> #4  0x00007ffff7feb903 in _Unwind_RaiseException_Phase2 (exc=exc@entry=0x43b890, context=context@entry=0x7fffffffe330) at /usr/src/cc/gcc-6.2.0/libgcc/unwind.inc:62
> #5  0x00007ffff7febf8a in _Unwind_RaiseException (exc=0x43b890) at /usr/src/cc/gcc-6.2.0/libgcc/unwind.inc:131
> #6  0x00007ffff7fde84b in __cxa_throw () from /home/psmith/src/static-eh/libmylib.so
> #7  0x00007ffff7fddecb in MyLib::create () at mylib.cpp:2
> #8  0x0000000000400da4 in main () at myprog.cpp:2
>
> I should note that if I use the GCC 5.4 that comes standard on my OS
> rather than my locally-built version I get identical behavior and
> backtrace (except not as much debuggability of course).  So I don't
> think it's an incorrect build.
>
> If I don't use -static-libstdc++ with my .so then it doesn't fail.  Also
> if I don't use a linker script to hide all the C++ symbols it doesn't
> fail (but of course anyone who links with my shared library will use my
> copy of the STL).
>
>
> Here's a repro case (this shows the problem on my Ubuntu GNOME 16.04
> GNU/Linux system with GCC 5.4 and binutils 2.26.1):
>
> ~$ cat mylib.h
> class MyLib { public: static void create(); };
>
> ~$ cat mylib.cpp
> #include "mylib.h"
> void MyLib::create() { throw 42; }
>
> ~$ cat myprog.cpp
> #include "mylib.h"
> int main() { try { MyLib::create(); } catch (...) { return 0; } return 1; }
>
> ~$ cat ver.map
> { global: _ZN5MyLib6createEv; local: *; };
>
> ~$ g++ -I. -g -fPIC -static-libgcc -static-libstdc++ \
>     -Wl,--version-script=ver.map -Wl,-soname=libmylib.so \
>     -shared -o libmylib.so mylib.cpp
>
> ~$ g++ -I. -g -fPIC  -L. -Wl,-rpath="\$ORIGIN" -o myprog myprog.cpp \
>     -lmylib
>
> ~$ ./myprog
> Aborted (core dumped)
>
> Now if I rebuild without the --version-script argument or without
> -static-libstdc++, I get success as expected:
>
> ~$ ./myprog
>
> ~$ echo $?
> 0


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]