2010-09-03 3 views
6

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:

  1. Perché accade questo? Si tratta di un bug, comportamento indefinito o di progettazione?
  2. Come posso farlo funzionare, a corto di collegamento alla libreria?

Grazie mille.

+0

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

risposta

3

Risulta un bug su gcc di Apple. Di recente hanno risposto al mio bug report dicendo che non verrà risolto, però.

-2

Dalla pagina info di gcc (my highlighing).

-fno-rtti Disable generazione di dati su ogni classe con virtuali funzioni per l'uso da parte ++ C identificazione del tipo di runtime dispone (dynamic_cast e typeid). Se non si utilizzano le parti della lingua , è possibile risparmiare spazio utilizzando questo flag. Nota che la gestione delle eccezioni utilizza le stesse informazioni, ma verrà generata da come necessario. L'operatore dynamic_cast può essere ancora utilizzato per i cast che non richiedono informazioni sul tipo di runtime, ovvero convertiti in void * o in classi di base non ambigue.

RTTI è una parte fondamentale del linguaggio. Se il compilatore ti permette di disabilitarlo, stai lavorando al di fuori delle regole del linguaggio, quindi non avrai necessariamente tutto per funzionare come ti aspetti.

+1

Sì, l'avrei letto, ma non è "lo genererà se necessario" il parte fondamentale? Grazie. –

+0

@Pedro d'Aquino: Ad essere sincero, non lo so. La difficoltà è che ora stai utilizzando una variante linguistica definita implicitamente dal comportamento di gcc. Vi consiglio di non provare a disabilitare RTTI. –

+0

Stavo per pubblicare la stessa cosa. Mi suggerisce che * la gestione delle eccezioni * sia * supposta * per generare tutte le informazioni di tipo necessarie, indipendentemente dal fatto che '-fno-rtti' sia specificato, per quanto riguarda GCC. Ma non ho eseguito 'man' su un sistema OSX o BSD, quindi potrebbe dire qualcosa di diverso lì. Potrebbe essere che hanno deliberatamente cambiato il comportamento (e documentato da qualche parte), potrebbe essere che lo hanno cambiato in modo silenzioso (e non documentato ovunque - molto cattivo), o potrebbe essere un bug nella loro forcella di gcc e/o il loro supporto di runtime C++. –