2010-09-28 36 views
20

plugin1.cpp:dlclose() không gọi destructor của các đối tượng toàn cầu

#include <iostream> 

static class TestStatic { 
public: 
    TestStatic() { 
    std::cout << "TestStatic create" << std::endl; 
    } 
    ~TestStatic() { 
    std::cout << "TestStatic destroy" << std::endl; 
    } 
} test_static; 

host.cpp

#include <dlfcn.h> 
#include <iostream> 
int main(int argc,char *argv[]) { 
    void* handle = dlopen("./plugin1.so",RTLD_NOW | RTLD_LOCAL); 
    dlclose(handle); 
    return 0; 
} 

xây dựng và chạy:

>g++ -c plugin1.cpp -o plugin1.o -fPIC 
>g++ -shared plugin.o -o plugin1.so 
>g++ host.cpp -o host -ldl 
>./host 
>TestStatic create 
>Segmentation fault 

tại sao TestStatic :: ~ TestStatic được gọi là 'exit()' nhưng không phải tại 'dlclose()'?

+0

Câu hỏi hay: +1. – Chubsdad

+2

Điều này có hữu ích không? http://forum.soft32.com/linux2/dlclose-causing-segmentation-fault-exit-main-ftopict10002.html – Chubsdad

+0

tùy chọn -fno-use-cxa-atexit cho trình biên dịch plugin.cpp giải quyết vấn đề – AndryBlack

Trả lời

15

Tiêu chuẩn C++ yêu cầu các trình phá hủy được gọi cho các đối tượng chung khi chương trình thoát theo thứ tự xây dựng ngược lại. Hầu hết các triển khai đã xử lý điều này bằng cách gọi thư viện C thường xuyên để đăng ký các destructors. Đây là vấn đề vì tiêu chuẩn C năm 1999 chỉ yêu cầu hỗ trợ thực hiện 32 chức năng đã đăng ký, mặc dù hầu hết các triển khai hỗ trợ nhiều hơn nữa. Quan trọng hơn, nó không giải quyết chút nào với khả năng trong hầu hết các triển khai để loại bỏ DSO khỏi một hình ảnh chương trình đang chạy bằng cách gọi dlclose trước khi chấm dứt chương trình.

Vấn đề này được đề cập trong các phiên bản sau của GCC bao gồm thư viện chuẩn và liên kết C/C++. Về cơ bản, C++ destructors phải được đăng ký sử dụng hàm __cxa_atexit thay vì atexit (3).

Để biết chi tiết kỹ thuật đầy đủ trên __cxa_atexit, hãy xem Itanium C++ ABI specification.


Không rõ câu hỏi của bạn về phiên bản gcc, liên kết và thư viện C chuẩn mà bạn đang sử dụng. Ngoài ra, mã bạn đã cung cấp không đáp ứng được tiêu chuẩn POSIX vì không có các macro RTDL_NOW hoặc RTDL_LOCAL được xác định. Chúng là RTLD_NOWRTLD_LOCAL (xem dlopen).

Nếu thư viện chuẩn C của bạn không hỗ trợ __cxa_atexit, bạn có thể cần phải vô hiệu hóa nó bằng cách xác định -fno-use-cxa-atexit gcc cờ:

-fuse-CXA-atexit

Đăng ký destructors cho các đối tượng với dung lượng tĩnh thời gian với hàm __cxa_ atexit thay vì hàm atexit . Tùy chọn này là bắt buộc đối với việc xử lý tuân thủ tiêu chuẩn đầy đủ của các trình phá hủy tĩnh, nhưng sẽ chỉ hoạt động nếu thư viện C của bạn hỗ trợ __cxa_atexit.

Nhưng điều đó có thể dẫn đến sự cố trong đó trình tự hủy được gọi theo thứ tự khác hoặc không được gọi. Vì vậy, giải pháp tốt nhất trong trường hợp bị hỏng __cxa_atexit hỗ trợ hoặc không có hỗ trợ nào cả là không sử dụng các đối tượng tĩnh với các destructors trong các thư viện được chia sẻ của bạn.

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