在Mac OS X上的-fno-rtti共享库中多态捕获异常

Ped*_*ino 6 c++ macos gcc shared-libraries rtti

我正在建立一个共享库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";
        }
    }
}
Run Code Online (Sandbox Code Playgroud)
// 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();
}
Run Code Online (Sandbox Code Playgroud)

输出:

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
Run Code Online (Sandbox Code Playgroud)

只有当抛出的代码在共享库中时才会发生这种情况,并且只有当捕获的类型是实际异常的基类时才会发生- catch(std::invalid_argument&)工作正常,std::logic_error&不会.

有趣的是,即使在运行完全相同的命令时,这也不会发生在Linux上.

问题:

  1. 为什么会这样?这是一个错误,未定义的行为还是设计?
  2. 如果没有链接到图书馆,我怎么能让它工作?

非常感谢.

Ped*_*ino 5

事实证明这是苹果 gcc 上的一个错误。他们最近回复了我的错误报告,表示不会修复该问题。