Clang / MacOS X exception type detection

I have a C ++ library that I am trying to run on Mac OS X with Clang. The library consists of a DLL and a Unit-Test executable. It compiles fine with GCC and MSVC, with GCC, I use the following settings:

  • Library compiled with -fvisibility=hidden
  • All public classes are explicitly marked as __attribute__(visibility("default"))
  • There are some exception classes in the library derived from std::runtime_error . All such classes are marked for visibility by default. There is a root class LibraryException from which more specific exceptions are thrown.
  • In GCC, I use -std=c++0x , with clang, and the library and unit test executable are built with -stdlib=libc++ -std=c++11

On Mac OS X, the unit test framework now fails because exceptions are of the wrong type. That is, such a test fails:

 // bla.foo () throws CustomException, which is derived from LibraryException TEST_THROWS (bla.foo (), CustomException) // This works however TEST_THROWS (bla.foo (), LibraryException) 

I checked that the typeinfo and vtable of my custom exception classes are exported using nm -g library.dylib | c++filt -p -i nm -g library.dylib | c++filt -p -i . It's like all exceptions ... what the hell is going on here? I tried to debug errors, and I see how the correct type is being created in the library, but the same type cannot be found in the unit test executable. Is there anything special for Clang to get this to work? I am using the latest googletest from SVN for testing.

A small test program shows the same problem:

 try { funcThatThrowsCustomExceptionFromLibraryDylib (); } catch (CustomException& e) { // doesn't get here } catch (LibraryException& e) { // does get here // after demangle, this prints CustomException // Can cast down to CustomException and access the fields as well std::cout << typeid (e).name () << "\n"; } 

It also fails, for example, when the boost::lexical_cast exception is boost::lexical_cast from the Library.

+6
source share
1 answer

Here is the correct solution:

When using the visibility attribute, it should be used both in the assembly of the library and in its consumption. Otherwise, the client will not see the classes. For boost :: lexical_cast, this means you should use

  #pragma GCC visibility push(default) #include <boost/lexical_cast.hpp> #pragma GCC visibility pop 

until they commit it to the library, adding __attribute((visibility("default"))) to the exception (with Boost 1.50 the attribute is present, but it seems Clang support doesn't exist yet). When using it in the header in the library, so it can be correctly caught in the client code. This #pragma also works with Clang.

The fact that specifying the throw () destructor helped was luck, but this is definitely not the correct fix.

+3
source

Source: https://habr.com/ru/post/922623/


All Articles