Bug 68479 - Dynamic loading multiple shared libraries with identical static libstdc++ breaks streams
Summary: Dynamic loading multiple shared libraries with identical static libstdc++ bre...
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: libstdc++ (show other bugs)
Version: 5.2.1
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2015-11-22 01:10 UTC by Stefan H.
Modified: 2016-06-17 16:53 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2015-11-23 00:00:00


Attachments
Minimal reproducer (872 bytes, application/x-gzip)
2015-11-22 01:10 UTC, Stefan H.
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Stefan H. 2015-11-22 01:10:47 UTC
Created attachment 36802 [details]
Minimal reproducer

Loading two shared libraries compiled with identical flags and the same compiler into the same process using dlopen breaks the use of std::stringstream (and probably more) when they link libstdc++ statically using "-static-libstdc++".

This was reproducible for me using gcc 5.1.1 (old abi), gcc 5.2.1 (Ubuntu 15.10, new abi) and gcc-5-branch (r230629, new abi) with the attached minimal reproducer and did not occur in gcc 4.9.

The reproducer consists of a small C program (no C++ dependencies) which uses dlopen to load two practically identical .so's which perform a trivial stringstream operation. The reproducer .so's do this operation on-load but that's not relevant for the issue.

I'm unsure on whether this kind of breakage is expected or if this is an actual bug with libstdc++. I originally encountered it when loading multiple .so's using System.loadLibrary into a JVM.

Below is the README of the reproducer with some more information:

Requires:
- g++-5
- Some gcc (5 is fine)

How to reproduce:
- Run ./build.sh
- Run ./test

Expected:

$ ./test
dlopen x.so
X0
dlopen y.so
X1

What happens:

$ ./test
dlopen x.so
X0
dlopen y.so
terminate called after throwing an instance of 'std::bad_cast'
  what():  std::bad_cast
  Aborted (core dumped)

Does not occur when:
* Linking libstdc++ dynamically
* Not dynloading the .so's but instead using gcc to link them in
* LD_PRELOAD'ing libstdc++
* Building the .so's with gcc 4.9 instead of 5.1.1
Comment 1 Richard Biener 2015-11-23 09:17:48 UTC
Confirmed.  I don't think this is intended to work when you re-export the libstdc++ symbols.  Not sure if there is an easy way to make them hidden
with --begin-group/--end-group and a linker flag.  So you'd need to provide
a version script to the link of x.so and y.so.
Comment 2 Stefan H. 2015-11-23 21:49:48 UTC
Interesting. So this breakage is expected behavior? I wasn't sure as there were so many ways to load it differently that didn't seem to exhibit the problems. I assume the ones I listed (except linking libstdc++ dynamically everywhere to begin with) are equally forbidden?

Or in other words: Never use -static-libstdc++ in combination with -shared if you actually need C++ objects shared between the so's and hence cannot hide or version the symbols?

Would be very useful if libstdc++ could somehow make such conflicts more explicit when they occur (e.g. ideally making the dynamic linker fail or even terminating the program outright). I naively assumed I would be fine as long as I didn't start mixing libstdc++ versions and all I would incur was some duplicate code that simply wouldn't be used and did so until I starting seing very strange runtime breakages.
Comment 3 Drea Pinski 2015-11-23 23:25:00 UTC
I think there is another bug about this that was closed as invalid as you need to use the version script to hide all of libstdc++ symbols.