2010-09-03 4 views
6

Buduję wspólną bibliotekę z f-no-rtti. Wewnętrznie ta biblioteka wyrzuca std:invalid_argument i przechwytuje std::exception, ale klauzula catch nigdy nie jest wprowadzana.Polimorficzne wychwytywanie wyjątku w bibliotece współdzielonej -fno-rtti na Mac OS X

Poniższy kod reprodukuje problemu (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(); 
} 

wyjściowa:

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 

ten dzieje się tak tylko wtedy, gdy kod, który wyrzuca, znajduje się w udostępnionej bibliotece , i tylko wtedy, gdy złapany typ jest podstawową klasą rzeczywistego wyjątku - catch(std::invalid_argument&) działa dobrze, std::logic_error& nie działa.

Co ciekawe, nie dzieje się to w Linuksie, nawet podczas wykonywania dokładnie tych samych poleceń.

Pytania:

  1. Dlaczego tak się dzieje? Czy jest to błąd, niezdefiniowane zachowanie lub projekt?
  2. Jak mogę sprawić, by działało, bez łączenia z biblioteką?

Wielkie dzięki.

+0

Jeśli przez "niezdefiniowane zachowanie" rozumie się zgodnie ze standardem C++, to jest to (w najlepszym przypadku) zdefiniowane przez implementację, co się dzieje, gdy używa się opcji kompilatora, która umieszcza kompilator w trybie niezgodnym.Wątpię, że to ci bardzo pomaga, ale nie możesz wyłączyć bitów standardu, a potem oczekiwać, że standard ci pomoże ;-) –

Odpowiedz

3

Włącza to błąd w gcc firmy Apple. Niedawno odpowiedzieli na mój raport o błędzie, twierdząc, że nie zostanie to naprawione.

-2

Ze strony z informacjami o gcc (mój highlighing).

-fno-rtti Wyłącz generowanie informacji na temat każdej klasie z wirtualnymi funkcji do wykorzystania przez C++ Runtime identyfikacji typu wyposażony (dynamic_cast i typeid). Jeśli nie używasz tych części języka, możesz zaoszczędzić trochę miejsca, używając tej flagi. Uwaga obsługa wyjątków używa tych samych informacji, ale wygeneruje je w razie potrzeby. Operator dynamic_cast może nadal być stosowany w rzutach, które nie wymagają informacji o typie czasu działania, tj. rzutów na void * lub na jednoznaczne klasy bazowe.

RTTI jest rdzeniem języka. Jeśli kompilator pozwala na wyłączenie go, pracujesz poza regułami języka, więc niekoniecznie wszystko będzie działać zgodnie z oczekiwaniami.

+1

Tak, przeczytałem to, ale nie "wygeneruje to w razie potrzeby". kluczowa część? Dzięki. –

+0

@Pedro d'Aquino: Szczerze mówiąc, nie wiem. Trudność polega na tym, że używasz wariantu języka, który jest zdefiniowany domyślnie przez rzeczywiste zachowanie gcc. Polecam przed próbą wyłączenia RTTI. –

+0

Już miałem opublikować to samo. Sugeruje mi, że obsługa wyjątków * ma * generować wszystkie niezbędne informacje o typach, niezależnie od tego, czy podano '-fno-rtti', jeśli chodzi o GCC. Ale nie uruchomiłem 'man' na systemie OSX lub BSD, więc może powiedzieć coś innego. Możliwe, że celowo zmienili zachowanie (i gdzieś je udokumentowali), mogło to być po cichu zmienione (i nie udokumentowane gdziekolwiek - bardzo niegrzeczne), lub może to być błąd w ich gcc widelcu i/lub ich obsługa środowiska wykonawczego C++. –