2010-09-03 23 views
6

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:

  1. 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?
  2. 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.

+0

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

Trả lời

3

Biến lỗi này thành gcc của Apple. Họ gần đây đã trả lời báo cáo lỗi của tôi nói rằng nó sẽ không được cố định, mặc dù.

-2

Từ trang thông tin cho gcc (highlighing của tôi).

-fno-rtti Disable thế hệ thông tin về tất cả các lớp học với chức năng ảo để sử dụng bằng C++ xác định kiểu thời gian chạy tính năng (dynamic_casttypeid). Nếu bạn không sử dụng các phần của ngôn ngữ, bạn có thể tiết kiệm một số không gian bằng cách sử dụng cờ này. Lưu ý xử lý ngoại lệ sử dụng cùng một thông tin, nhưng sẽ tạo nó khi cần. Toán tử dynamic_cast vẫn có thể là được sử dụng cho các phôi không yêu cầu thông tin loại thời gian chạy, tức là chuyển thành void * hoặc cho các lớp cơ sở không rõ ràng.

RTTI là một phần cốt lõi của ngôn ngữ. Nếu trình biên dịch cho phép bạn vô hiệu hóa nó, bạn đang làm việc bên ngoài các quy tắc của ngôn ngữ như vậy không nhất thiết phải có mọi thứ hoạt động như bạn mong đợi.

+1

Vâng, tôi muốn đọc điều đó, nhưng không phải là "nó sẽ tạo ra nó khi cần thiết" phần chủ chốt? Cảm ơn. –

+0

@Pedro d'Aquino: Thành thật mà nói, tôi không biết. Khó khăn là bạn hiện đang sử dụng một biến thể ngôn ngữ được xác định ngầm bởi hành vi thực sự của gcc. Tôi khuyên bạn không nên cố gắng vô hiệu hóa RTTI. –

+0

Tôi sắp sửa đăng bài tương tự. Nó gợi ý với tôi rằng việc xử lý ngoại lệ là * giả định * để tạo ra tất cả các thông tin kiểu cần thiết, bất kể là '-fno-rtti' được chỉ định, theo như GCC có liên quan. Nhưng tôi không chạy 'man' trên hệ điều hành OSX hay BSD, vì vậy nó có thể nói điều gì đó khác ở đó. Có thể là họ đã cố ý thay đổi hành vi (và ghi lại ở đâu đó), có thể họ đã âm thầm thay đổi nó (và không ghi lại nó ở bất cứ đâu - rất nghịch ngợm), hoặc nó có thể là một lỗi trong ngã ba gcc của họ và/hoặc hỗ trợ thời gian chạy C++ của họ. –

Các vấn đề liên quan