Tôi đang xây dựng thư viện được chia sẻ với f-no-rtti
. Trong nội bộ, thư viện này ném std:invalid_argument
và bắt giữ std::exception
, nhưng không bao giờ nhập mệnh đề catch
.Đa hình bắt ngoại lệ trong thư viện được chia sẻ -fno-rtti trên Mac OS X
Các mã sau tái tạo vấn đề (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();
}
Output:
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
này chỉ xảy ra nếu mã ném nằm trong một thư viện được chia sẻ và chỉ khi loại bị bắt là loại cơ sở của ngoại lệ thực tế - catch(std::invalid_argument&)
hoạt động tốt, std::logic_error&
thì không.
Điều thú vị là điều này không xảy ra trên Linux, ngay cả khi chạy cùng một lệnh chính xác.
Câu hỏi:
- Tại sao điều này xảy ra? Đây có phải là lỗi, hành vi không xác định hoặc theo thiết kế không?
- Làm cách nào để làm cho nó hoạt động, thiếu liên kết với thư viện?
Cảm ơn rất nhiều.
Nếu theo "hành vi không xác định", nghĩa là theo tiêu chuẩn C++, thì tốt nhất là khi bạn sử dụng tùy chọn trình biên dịch, trình biên dịch ở chế độ không tuân thủ.Tôi nghi ngờ rằng sẽ giúp bạn nhiều, nhưng bạn không thể vô hiệu hóa bit của tiêu chuẩn và sau đó mong đợi các tiêu chuẩn để giúp bạn ;-) –