Полиморфно перехватывать исключение в общей библиотеке -fno-rtti в Mac OS X - PullRequest
6 голосов
/ 03 сентября 2010

Я создаю общую библиотеку с f-no-rtti. Внутренне эта библиотека генерирует std:invalid_argument и перехватывает std::exception, но предложение catch никогда не вводится.

Следующий код воспроизводит проблему (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();
}

Выход:

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

Это происходит только в том случае, если генерируемый код находится в общей библиотеке , и только если перехваченный тип представляет собой базовый класс фактического исключения - catch(std::invalid_argument&) работает нормально, std::logic_error& нет.

Интересно, что этого не происходит в Linux , даже при выполнении точно таких же команд.

Вопросы:

  1. Почему это происходит? Это ошибка, неопределенное поведение или дизайн?
  2. Как я могу заставить его работать, если не ссылаться на библиотеку?

Большое спасибо.

Ответы [ 2 ]

3 голосов
/ 23 марта 2011

Оказывается, это ошибка на gcc от Apple.Недавно они ответили на мое сообщение об ошибке, сказав, что оно не будет исправлено.

0 голосов
/ 03 сентября 2010

со страницы информации о gcc (мое выделение).

-fno-rtti Отключить генерацию информации о каждом классе с виртуальным функции для использования функциями идентификации типа среды выполнения C ++ (dynamic_cast и typeid). Если вы не используете эти части язык, вы можете сэкономить место с помощью этого флага. Примечание эта обработка исключений использует ту же информацию , но она будет генерировать его по мере необходимости. Оператор dynamic_cast все еще может быть используется для приведений, которые не требуют информации о типе среды выполнения, т.е. приведение к void * или к однозначным базовым классам.

RTTI является основной частью языка. Если компилятор позволяет вам отключить его, вы работаете вне правил языка, поэтому не обязательно все будет работать так, как вы ожидаете.

...