Estoy compilando una biblioteca compartida con f-no-rtti
. Internamente, esta biblioteca arroja std:invalid_argument
y captura std::exception
, pero la cláusula catch
nunca se ingresa.Captura polimórfica de una excepción en una biblioteca compartida -fno-rtti en Mac OS X
El código siguiente reproduce el 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();
}
de salida:
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
Este solo sucede si el código que arroja está en una biblioteca compartida , y solo si el tipo capturado es clase base de la excepción real - catch(std::invalid_argument&)
funciona bien, std::logic_error&
no.
Curiosamente, esto no ocurre en Linux, incluso cuando se ejecutan exactamente los mismos comandos.
Preguntas:
- ¿Por qué sucede esto? ¿Es esto un error, un comportamiento indefinido o por diseño?
- ¿Cómo podría hacer que funcione, salvo enlaces contra la biblioteca?
Muchas gracias.
Si se refiere al "comportamiento indefinido" de acuerdo con el estándar de C++, entonces (en el mejor de los casos) se define la implementación de lo que ocurre cuando se utiliza una opción de compilación que no permite el compilador.Dudo que eso te ayude mucho, pero no puedes desactivar partes del estándar y luego esperar que el estándar te ayude ;-) –