Bug 59788 - Mixing libc and libgcc_s unwinders on 64-bit Solaris 10+/x86 breaks EH
Summary: Mixing libc and libgcc_s unwinders on 64-bit Solaris 10+/x86 breaks EH
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: target (show other bugs)
Version: 4.9.0
: P3 normal
Target Milestone: 4.9.0
Assignee: Rainer Orth
URL: http://gcc.gnu.org/ml/gcc-patches/201...
Keywords:
Depends on:
Blocks:
 
Reported: 2014-01-13 14:15 UTC by Rainer Orth
Modified: 2014-02-04 09:33 UTC (History)
0 users

See Also:
Host: i386-pc-solaris2.1[01]
Target: i386-pc-solaris2.1[01]
Build: i386-pc-solaris2.1[01]
Known to work:
Known to fail:
Last reconfirmed: 2014-01-13 00:00:00


Attachments
initial patch (1.24 KB, patch)
2014-01-15 12:48 UTC, Rainer Orth
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Rainer Orth 2014-01-13 14:15:04 UTC
I've received a few reports in private mail that exception handling on 64-bit
Solaris 10+/x86 is broken when linking with -Bdirect.

The following testcase shows this:

$ cat unwind-direct.cc
#include <stdexcept>

int
main(void)
{
  try
    { throw std::runtime_error( "Catch me if you can!"); }
  catch(...)
    { return 0; }
  return 1;
}
$ g++ -Wl,-Bdirect -m64 -o unwind-direct unwind-direct.cc
$ ./unwind-direct
terminate called after throwing an instance of 'std::runtime_error'
Segmentation Fault (core dumped)

Investigating this with LD_DEBUG=bindings, one finds

$ LD_DEBUG=bindings ./unwind-direct 2>&1 | grep Unwind
03243: 1: binding file=../../../i386-pc-solaris2.11/amd64/libstdc++-v3/src/.libs/libstdc++.so.6 to file=/lib/64/libc.so.1: symbol '_Unwind_RaiseException'
03243: 1: binding file=../../../i386-pc-solaris2.11/amd64/libstdc++-v3/src/.libs/libstdc++.so.6 to file=/lib/64/libc.so.1: symbol '_Unwind_GetLanguageSpecificData'
03243: 1: binding file=../../../i386-pc-solaris2.11/amd64/libstdc++-v3/src/.libs/libstdc++.so.6 to file=/lib/64/libc.so.1: symbol '_Unwind_GetRegionStart'
03243: 1: binding file=../../../i386-pc-solaris2.11/amd64/libstdc++-v3/src/.libs/libstdc++.so.6 to file=../../amd64/libgcc_s.so.1: symbol '_Unwind_GetIPInfo'
03243: 1: binding file=../../../i386-pc-solaris2.11/amd64/libstdc++-v3/src/.libs/libstdc++.so.6 to file=../../amd64/libgcc_s.so.1: symbol '_Unwind_Resume_or_Rethrow'
03243: 1: binding file=../../amd64/libgcc_s.so.1 to file=/lib/64/libc.so.1: symbol '_Unwind_RaiseException'

The problem is that the amd64 Solaris 10+ libc contains an implementation of
the amd64 unwinder, as prescribed by the amd64 ABI, but only those functions
that are listed there.  libgcc_s contains some more, and both implementations
use different internal datastructures, so mixing them wreaks havoc.

This problem has been seen several times during gcc development when it affected
gcc runtime libraries.

I'm working on a patch to avoid this once and for all by forcing all gcc-built
executables to bind to the unwinder in libgcc_s.

  Rainer
Comment 1 Rainer Orth 2014-01-13 14:15:27 UTC
Mine, patch in progress.
Comment 2 Rainer Orth 2014-01-15 12:48:10 UTC
Created attachment 31843 [details]
initial patch

The attached initial patch works fine and fixes the testcase from the PR, but is
unacceptable as is.

Initially, I attempted to force direct binding to the libgcc_s unwinder by linking
with a special mapfile if linking with -lgcc_s.  This doesn't work since libtool
builds shared libraries with -shared -nostdlib, adding -lgcc_s itself.

The second attempt (attached) instead uses that mapfile when -shared is passed.
When libtool adds -lgcc_s -lc -lgcc_s itself, it usually `optimizes' this into
-lc -lgcc_s.  When direct binding is in effect due to the mapfile, we achieve 
exactly what this patch intends to avoid, namely binding to the partial unwinder
in amd64 libc.  This can be avoided by patching libtool to disable this optimization
on *solaris2*, which this patch does.

While this works fine for the gcc runtime libraries, as can be observed with 
elfdump -y, gcc 4.9 cannot be released with this patch included: even if the
libtool (ltmain.sh actually) patch were accepted upstream, every package built
with libtool will contain an old copy without that change, causing the breakage
this patch is designed to avoid.  While the optimization can be avoided by
invoking libtool with --preserve-dup-deps, this seem unacceptable, as would
requiring users to run libtoolize from a hypothetical new libtool release with
the ltmain.sh patch.
Comment 3 Rainer Orth 2014-01-17 14:22:25 UTC
Patch submitted.
Comment 4 Rainer Orth 2014-02-04 09:32:10 UTC
Author: ro
Date: Tue Feb  4 09:31:38 2014
New Revision: 207454

URL: http://gcc.gnu.org/viewcvs?rev=207454&root=gcc&view=rev
Log:
Ensure libgcc_s unwinder is always used on 64-bit Solaris 10+/x86 (PR target/59788)

	gcc:
	PR target/59788
	* config/sol2.h (LINK_LIBGCC_MAPFILE_SPEC): Define.
	(LINK_SPEC): Use it for -shared, -shared-libgcc.

	libgcc:
	PR target/59788
	* config/t-slibgcc-sld (libgcc-unwind.map): New target.
	(install-libgcc-unwind-map-forbuild): New target.
	(all): Depend on install-libgcc-unwind-map-forbuild.
	(install-libgcc-unwind-map): New target.
	(install): Depend on install-libgcc-unwind-map.

	gcc/testsuite:
	PR target/59788
	* g++.dg/eh/unwind-direct.C: New test.

	toplevel:
	PR target/59788
	* ltmain.sh (opt_duplicate_compiler_generated_deps): Enable on
	*solaris2*.

Added:
    trunk/gcc/testsuite/g++.dg/eh/unwind-direct.C
Modified:
    trunk/ChangeLog
    trunk/gcc/ChangeLog
    trunk/gcc/config/sol2.h
    trunk/gcc/testsuite/ChangeLog
    trunk/libgcc/ChangeLog
    trunk/libgcc/config/t-slibgcc-sld
    trunk/ltmain.sh
Comment 5 Rainer Orth 2014-02-04 09:33:00 UTC
Fixed for 4.9.0.