views:

718

answers:

4

The situation is that I have a dynamic library written in C++ that is wrapped for Python by another dynamic library, also written in C++ (generated by SIP to be specific). The first dynamic library defines a function do_raise, which throws an exception RaiserError, a subclass of std::exception. The second dynamic library, in wrapping do_raise, tries to catch RaiserError in order to translate it to a Python exception.

Building with Visual C++, everything works as expected and RaiserError is caught correctly. Using g++ on Linux however, RaiserError is not caught. If I try to catch std::exception instead (RaiserError's baseclass), it works. What goes wrong here? Do the two libraries have different notions of the RaiserError type, since it does not get recognized by the catch block?

For testing I also write a small executable which calls do_raise in the C++ library, and here I am able to catch RaiserError even with g++.

+3  A: 

You can't reliably pass C++ exceptions across module boundaries. On Windows (at least for 32-bit processes) there is a standard ABI for that, but with gcc, you're out of luck.

avakar
+2  A: 

I believe that GCC uses some kind of pointer to the type information and if it does not match the pointer, then the types are not the same.

This sounds like one of the cases where Microsoft C++ falls back to string comparisons of type information (slow but works). That will not help you with GCC.

You might try making sure that the exception class is not hidden and that the typeinfo is visible in the ELF .so file. Try to make sure that the type is defined in only one .so.

Edit: I just thought of this: I believe ELF dynamic linkers are just fine with multiple copies of the typeinfo symbols and will choose a single copy to use. I think you can get multiple copies though if you linked some static code or did -Bsymbolic in one of the .so or executable files.

Zan Lynx
Do you know how the relevant symbols should look in the ELF libraries? As an example I have in my real project an exception "LoadImageError". In the defining/throwing library I have these typeinfo symbols:000b9634 V typeinfo for igmUtil::LoadImageError000a3d5c V typeinfo name for igmUtil::LoadImageErrorAnd in the Python wrapper library (trying to catch the exception):000174b8 d DW.ref._ZTIN7igmUtil14LoadImageErrorE00016540 V typeinfo for igmUtil::LoadImageError00011e85 V typeinfo name for igmUtil::LoadImageError
Hm .. apparently it wasn't such a good idea to paste symbol table excerpts :) My noobness shows I guess. I've made a pastebin page instead: http://pastebin.com/f52cf15b1
A: 

As per other answers the problem is (more then likely) missing RTTI information in the .so's.

Try appending -Wl,-E to your compiler flags, this will cause the linker to export the needed type information.

VC++ uses string compares (as opposed to pointer compares) to match types (whilst dynamic casting, catching etc), this is slower at runtime but results in smaller dll's (because of less RTTI being exported in the dll's).

This will be reliable as long as your using the same compiler to compile your shared objects (or you use the vendor-neutral ABI, as available with g++ >= 4.3).

Hayman
Thanks for the tip regarding -Wl,-E, it didn't do me much good though :/
+1  A: 

I haven't previously had problems catching exceptions thrown by a .so, so can't speak to the other responses I've seen here.

Something unrelated to look for is whether any of your destructors might be throwing an exception: if you throw a new exception in a destructor while unwinding the stack throwing a first exception, your program will abort, independent of any wrapping try/catches. With g++, the error message looks the same as if you didn't catch the first exception. Carefully step through the unwinding of the stack to see if this might be happening to you.

Randy