2010-09-03 16 views
6

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:

  1. ¿Por qué sucede esto? ¿Es esto un error, un comportamiento indefinido o por diseño?
  2. ¿Cómo podría hacer que funcione, salvo enlaces contra la biblioteca?

Muchas gracias.

+0

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 ;-) –

Respuesta

3

Resulta que esto es un error en el gcc de Apple. Sin embargo, recientemente respondieron a mi informe de error diciendo que no será reparado.

-2

Desde la página de información de gcc (my highlighing).

-fno-rtti generación Disable de información acerca de cada clase con virtuales funciones para su uso por el C++ de identificación de tipo de tiempo de ejecución presenta (dynamic_cast y typeid). Si no usa esas partes del lenguaje , puede ahorrar algo de espacio usando esta bandera. Nota que el manejo de excepciones utiliza la misma información, pero se generar según sea necesario. El operador dynamic_cast aún puede ser utilizado para moldes que no requieren información del tipo de tiempo de ejecución, es decir, moldes para void * o clases base no ambiguas.

RTTI es una parte central de la lengua. Si el compilador le permite desactivarlo, está trabajando fuera de las reglas del lenguaje, por lo que no necesariamente va a hacer que todo funcione como espera.

+1

Sí, lo leí, pero no es "lo generará según sea necesario" el ¿parte clave? Gracias. –

+0

@Pedro d'Aquino: para ser sincero, no sé. La dificultad es que ahora estás usando una variante del lenguaje que se define implícitamente por el comportamiento real de gcc. Recomiendo no intentar deshabilitar RTTI. –

+0

Estaba a punto de publicar lo mismo. Me sugiere que el manejo de excepciones es * supuesto * para generar toda la información de tipo necesaria, independientemente de si se especifica '-fno-rtti', en lo que concierne a GCC. Pero no ejecuté 'man' en un sistema OSX o BSD, por lo que podría decir algo diferente allí. Podría ser que hayan cambiado deliberadamente el comportamiento (y documentado en alguna parte), podría ser que lo hayan cambiado silenciosamente (y no lo hayan documentado en ningún lado, muy travieso), o podría ser un error en su horquilla gcc y/o su soporte en tiempo de ejecución C++. –