Sto costruendo una libreria condivisa con f-no-rtti
. Internamente, questa libreria genera std:invalid_argument
e raggiunge std::exception
, ma la clausola catch
non viene mai inserita.Cattura in modo polimorfico un'eccezione in una libreria condivisa -fno-rtti su Mac OS X
Il seguente codice riproduce il problema (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();
}
uscita:
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
Questo accade solo se il codice che gira è in una libreria condivisa , e solo se il tipo rilevato è una classe di base dell'effettiva eccezione - non funziona.
È interessante notare che non si verifica su Linux, anche quando si eseguono esattamente gli stessi comandi.
Domande:
- Perché accade questo? Si tratta di un bug, comportamento indefinito o di progettazione?
- Come posso farlo funzionare, a corto di collegamento alla libreria?
Grazie mille.
Se per "comportamento non definito" si intende in base allo standard C++, quindi è (nella migliore delle ipotesi) definito dall'implementazione cosa succede quando si utilizza un'opzione del compilatore che pone il compilatore in una modalità non conforme.Dubito che ti aiuti molto, ma non puoi disabilitare i bit dello standard e poi aspettarti che lo standard ti aiuti ;-) –