public inbox for gcc@gcc.gnu.org
 help / color / mirror / Atom feed
* Throwing exceptions from a .so linked with -static-lib* ?
@ 2017-01-12  5:06 Paul Smith
  2017-01-12 21:50 ` Yuri Gribov
  0 siblings, 1 reply; 3+ messages in thread
From: Paul Smith @ 2017-01-12  5:06 UTC (permalink / raw)
  To: gcc

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
#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

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: Throwing exceptions from a .so linked with -static-lib* ?
  2017-01-12  5:06 Throwing exceptions from a .so linked with -static-lib* ? Paul Smith
@ 2017-01-12 21:50 ` Yuri Gribov
  2017-01-16 15:08   ` Paul Smith
  0 siblings, 1 reply; 3+ messages in thread
From: Yuri Gribov @ 2017-01-12 21:50 UTC (permalink / raw)
  To: paul; +Cc: gcc

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

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: Throwing exceptions from a .so linked with -static-lib* ?
  2017-01-12 21:50 ` Yuri Gribov
@ 2017-01-16 15:08   ` Paul Smith
  0 siblings, 0 replies; 3+ messages in thread
From: Paul Smith @ 2017-01-16 15:08 UTC (permalink / raw)
  To: Yuri Gribov; +Cc: gcc

On Thu, 2017-01-12 at 21:49 +0000, Yuri Gribov wrote:
> 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.

I could have sworn I tried all different combinations of the different
static flags, but sure enough if I don't add -static-libgcc on either
the .so or the executable things work OK.

Thanks!

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2017-01-16 15:08 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-01-12  5:06 Throwing exceptions from a .so linked with -static-lib* ? Paul Smith
2017-01-12 21:50 ` Yuri Gribov
2017-01-16 15:08   ` Paul Smith

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).