Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Polymorphically catching an exception in a -fno-rtti shared library on Mac OS X

I'm building a shared library with f-no-rtti. Internally, this library throws std:invalid_argument and catches std::exception, but the catch clause is never entered.

The following code reproduces the problem (g++ 4.2, Mac OS X 10.6):

// library.cpp: exports f(), compiled with -fno-rtti
#include <stdexcept>
#include <iostream>
extern "C" {
    void f() {
        try {
            throw std::invalid_argument("std::exception handler");
        } catch( std::exception& e) {
            std::cout << e.what() << "\n";
        } catch(...) {
            std::cout << "... handler\n";
        }
    }
}

// main.cpp: the main executable, dynamically loads the library
#include <dlfcn.h>
typedef void(*fPtr)();

int main() {
    void* handle = dlopen( "./libexception_problem.dylib", RTLD_LAZY );
    fPtr p_f = reinterpret_cast<fPtr>( dlsym( handle, "f" ) );
    p_f();
}

Output:

MacBook-Pro:teste pfranco$ # works fine with rtti
MacBook-Pro:teste pfranco$ g++ -c library.cpp && g++ -shared -o libexception_problem.dylib library.o && g++ main.cpp -o main && ./main
std::exception handler
MacBook-Pro:teste pfranco$ # breaks with -fno-rtti
MacBook-Pro:teste pfranco$ g++ -c -fno-rtti library.cpp && g++ -shared -o libexception_problem.dylib library.o && g++ -fno-rtti main.cpp -o main && ./main
... handler
MacBook-Pro:teste pfranco$ #-no_dead_strip_inits_and_terms doesn't change anything
MacBook-Pro:teste pfranco$ g++ -c -no_dead_strip_inits_and_terms -fno-rtti library.cpp && g++ -no_dead_strip_inits_and_terms -shared -o libexception_problem.dylib library.o && g++ -fno-rtti -no_dead_strip_inits_and_terms main.cpp -o main && ./main
... handler
MacBook-Pro:teste pfranco$ # linking against the shared library works, but this isn't always an option
MacBook-Pro:teste pfranco$ g++ -c -fno-rtti library.cpp && g++ -shared -o libexception_problem.dylib library.o && g++ -fno-rtti main.cpp -o main -L. -lexception_problem && ./main
std::exception handler

This only happens if the code that throws is in a shared library, and only if the caught type is a base class of the actual exception - catch(std::invalid_argument&) works fine, std::logic_error& doesn't.

Interestingly, this doesn't happen on Linux, even when running the exact same commands.

Questions:

  1. Why does this happen? Is this a bug, undefined behavior or by design?
  2. How could I make it work, short of linking against the library?

Thanks a lot.

like image 317
Pedro d'Aquino Avatar asked Sep 03 '10 17:09

Pedro d'Aquino


1 Answers

Turns out this a bug on Apple's gcc. They've recently replied to my bug report saying it won't be fixed, though.

like image 126
Pedro d'Aquino Avatar answered Nov 03 '22 21:11

Pedro d'Aquino