0

Is it that the absence or damage of the .eh_frame ELF section is the cause of exceptions in my C++ code stopped working? Any exception that previously was caught successfully is now calling std::terminate().

My situation:

  1. My zzz.so shared library has try-catch blocks:

    try {
        throw Exc();
    } catch (const Exc &e) {
        LOG("ok " << e.what());
    } catch (...) {
        LOG("all");
    }
    
  2. An executable which loads the zzz.so (using ldopen). It call a function in the zzz.so

  3. All the exceptions thrown in the zzz.so are successfully caught inside zzz.so and dumped into my log file
  4. There is another aaa.so that is loaded into another binary. That another aaa.so is loading my zzz.so.
  5. All the same exceptions thrown in the zzz.so lead to call std::terminate().

How is that possible?

update

I don't know HOW is that possible still, but Clang 3.3 (FreeBSD clang version 3.3 (tags/RELEASE_33/final 183502) 20130610) solved the problem.

pavelkolodin
  • 2,859
  • 3
  • 31
  • 74

1 Answers1

2

How is that possible?

When an exception is thrown, control passes to __cxa_throw routine (usually in libstdc++.so), which is then responsible for finding the catch clause and calling destructors along the way, or calling std::terminate if no catch is found.

The answer then is most likely that the first executable (the one where exceptions work) uses libstdc++.so that is capable of decoding .eh_frame in your library, while the second application (the one where exceptions do not work), either uses an older (incompatible) version of libstdc++.so, or links against libstdc++.a, or something along these lines.

Note: the actual work of raising the exception is done by _Unwind_RaiseException in libgcc_s.so.1, so even if both applications use the same libstdc++.so, they may still use different libgcc.

Update:

Will I benefit from static linking libstdc++ and libgcc into my .so library?

Maybe. TL;DR: it's complicated.

There are a few things to consider:

  1. On any platform other than i386, you would have to build your own copy of libstdc++.a and libgcc.a with -fPIC before you can link them into your zzz.so. Normally these libraries are built without -fPIC, and can't be statically linked into any .so.

  2. Static linking of libstdc++.a into your zzz.so may make it a derived work, and subject to GPL (consult your lawyer).

  3. Even when there is a _Unwind_RaiseException exported from zzz.so, normally there will already be another instance of _Unwind_RaiseException defined in (loaded earlier) libgcc_s.so, and that earlier instance is the one that will be called, rendering your workaround ineffective. To make sure that your copy of _Unwind_RaiseException is called, you would need to link zzz.so with -Bsymbolic, or with a special linker script to make all calls to _Unwind_RaiseException (and everything else from libgcc.a) internal.

  4. Your workaround may fix the problem for zzz.so, but may cause a problem for unrelated yyy.so that is loaded even later, and that wants the system-provided _Unwind_RaiseException, not the one from zzz.so. This is another argument for hiding all libgcc.a symbols and making them internal to zzz.so.

So the short answer is: such workaround is somewhat likely to cause you a lot of pain.

Employed Russian
  • 199,314
  • 34
  • 295
  • 362
  • Will I benefit from static linking libstdc++ and libgcc into my .so library? – pavelkolodin Oct 10 '15 at 14:47
  • Is "__cxa_throw" just a wrapper for "_Unwind_RaiseException" ? – pavelkolodin Oct 10 '15 at 17:12
  • 1
    @pavelkolodin Yes, for some definition of "just a wrapper". It doesn't merely call `_Unwind_RaiseException` if that's what you mean. It's source is here: https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/eh_throw.cc#L60 – Employed Russian Oct 10 '15 at 17:34
  • My .so exceptions stop working if I add -std=c++11 to compiler g++47. But ldd's output for both versions of the final .so is THE SAME. Without -std=c++11 everything works fine. – pavelkolodin Oct 10 '15 at 18:12
  • I also noticed that -std=c++11 .so binary has no section ".tdata" which appears if I remove -std=c++11 compiler option. – pavelkolodin Oct 10 '15 at 21:37