21

I know, this question has been asked quite some times, however I can't find a solution for my problem.

I have the following situation:

   A
  / \
 /   \
B <-- C
  • A is a shared library which contains the class EException
  • B and C link against A
  • C is a shared library as well
  • B dynamically loads C at runtime

At some point C throws an instance of EException:

void doSometing() {
    throw EException("test-message");
}

in B I would like to catch this exception:

try {
    doSomething();
} catch (const EException& ex) {
    // Not reached
} catch (...) {
    // Not reached
}

but as mentioned in the code, neither one of the catch clauses get called. Instead the thread, this code is executed in, gets aborted.

I tried the following things:

  • The visibility attribute of EException is set to "default" when compiling A
  • The EException header file contains declarations only
  • I am using the linker option -fvisibility=hidden in A, B and C
  • I am using the linker option -E in C

Using nm I get for A:

0000000000066260 T EException::EException(QString const&)
0000000000066306 T EException::EException(EException const&)
00000000000661d0 T EException::EException() 
0000000000066260 T EException::EException(QString const&) 
0000000000066306 T EException::EException(EException const&) 
00000000000661d0 T EException::EException() 
00000000000664de T EException::~EException()
000000000006641e T EException::~EException() 
000000000006641e T EException::~EException() 
00000000000663b6 T EException::operator=(EException const&)
<...>
000000000028de40 V typeinfo for EException
000000000028dd80 V typeinfo for EException*
000000000007342b V typeinfo name for EException
0000000000072ab7 V typeinfo name for EException*
000000000028de00 V vtable for EException

for B:

U EException::EException(QString const&)
U EException::~EException()
<...>
0000000000726f60 V typeinfo for EException

and for C:

U EException::EException(QString const&)
U EException::~EException()
<...>
U typeinfo for EException

Could the problem be, that B uses its own typeinfo of EException, while C uses the one provided by A? How would I fix this?

My environment:

  • gcc 4.6.3 on x86_64-linux-gnu
  • using Qt

Thank you for your help!

Sämy
  • 799
  • 2
  • 7
  • 17
  • 1
    That `catch(...)` doesn't seems to imply your error is no related to your exception class itself (or its an error in the ctor). Have you tried debugging it and seeing what happens on that throw line? – edA-qa mort-ora-y May 28 '12 at 17:13
  • On the throw line the copy-constructor of `EException` gets called. There is no error in the copy-constructor and after it finishes the thread aborts. – Sämy May 28 '12 at 17:46
  • Also see [dynamic_cast, throw, typeid don't work with shared libraries](https://gcc.gnu.org/faq.html#dso) from the GCC FAQ. It tells you to *avoid* the ***`-Bsymbolic`*** linker option, and to use the ***`-E`*** linker option. I'm also guessing ***`B`*** should be using ***`--exclude-libs ALL`***. – jww Jan 21 '16 at 00:20

5 Answers5

3

I had similar problems with gcc < 4.5 with RTTI symbols used across shared library boundaries, but not with gcc 4.6. However, you might still find the following information useful.

As already mentioned, the vtable (containing an entry to the typeinfo object) for EException seems to be duplicated in some translation units which was definitely a problem with gcc < 4.5 (well, it is an issue of libsupc++, as far as I know, not merging the type_info objects). Anchoring the vtable of EException by defining a virtual out-of-line destructor (it must be the first virtual function declaration in the header) in A did the trick for me.

Posting the complete header file for EException might also be helpful.

Sascha
  • 1,104
  • 8
  • 15
1

Check for

-fvisibility=hidden

option in your linker settings. If it set, change it to

-fvisibility=default

1

IMHO, this as nothing to do with the compiler flags whatsoever.

Declare your exception object as extern and don't provide any implementation anywhere except in your main binary.

This will force the linker (dynamic linker BTW) to use the only implementation that's possible.

No typeinfo is generated on extern definition only.

xryl669
  • 3,376
  • 24
  • 47
0

B is using it's own EException class definition V typeinfo for EException whereas C seems to use an Unresolved one ( the U means the type is undefined in the current translation unit and must be resolved by the loader and dynamic linker ).

Verify that B is still a shared library and it is not linked statically whith A but dynamicaly, preventing C from findind A's stuffs, cause as I cant see B won't link the same type as A. Take care of your header ^^.

Gold
  • 136
  • 6
  • I understand your first part. But `B` is my main application and no shared library. Both `B` and `C` link `A` at compile time. As far as I understand it, I should prevent `B` from using its own typeinfo of `EException` since both `B` and `C` are automatically loading `A` at runtime and should use `A`s typeinfo then. – Sämy May 29 '12 at 06:52
0

You may try to compile A, B and C with -rdynamic (at linkage stage)

The GCC man page tell about -rdynamic:

Pass the flag -export-dynamic to the ELF linker, on targets that support it. This instructs the linker to add all symbols, not only used ones, to the dynamic symbol table. This option is needed for some uses of "dlopen" or to allow obtaining backtraces from within a program.

neam
  • 894
  • 9
  • 19