2010-09-28 3 views
20

plugin1.cpp का नाशक फोन नहीं करता है:dlclose() वैश्विक वस्तुओं

#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; 
} 

निर्माण और चलाएँ:

>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 

क्यों TestStatic :: ~ टेस्टस्टैटिक 'एक्जिट()' पर बुलाया जाता है लेकिन 'dlclose()' पर नहीं?

+0

अच्छा प्रश्न: +1। – Chubsdad

+2

क्या यह सहायक है? http://forum.soft32.com/linux2/dlclose-causing-segmentation-fault-exit-main-ftopict10002.html – Chubsdad

+0

विकल्प -fno-use-cxa-atexit compilation plugin.cpp समस्या हल करने के लिए – AndryBlack

उत्तर

15

सी ++ मानक की आवश्यकता है कि निर्माण के विपरीत क्रम में जब कोई प्रोग्राम बाहर निकलता है तो विनाशकों को वैश्विक वस्तुओं के लिए बुलाया जाता है। अधिकांश कार्यान्वयन ने इसे वितरकों को पंजीकृत करने के लिए सी लाइब्रेरी अनावश्यक दिनचर्या को कॉल करके इसे संभाला है। यह समस्याग्रस्त है क्योंकि 1 999 सी मानक के लिए केवल 32 पंजीकृत कार्यों का कार्यान्वयन करने की आवश्यकता है, हालांकि अधिकांश कार्यान्वयन कई और समर्थन करते हैं। अधिक महत्वपूर्ण बात यह है कि कार्यक्रम समाप्ति से पहले dlclose को कॉल करके चल रहे प्रोग्राम छवि से डीएसओ को हटाने के लिए अधिकांश कार्यान्वयन में क्षमता का सामना नहीं किया जाता है।

यह समस्या सीसीसी/सी ++ मानक पुस्तकालय और लिंकर सहित जीसीसी के बाद के संस्करणों में संबोधित की गई है। असल में, सी ++ विनाशकों को atexit (3) के बजाय __cxa_atexit फ़ंक्शन का उपयोग करके पंजीकृत किया जाना चाहिए।

__cxa_atexit पर पूर्ण तकनीकी विवरण के लिए, Itanium C++ ABI specification देखें।


यह आपके प्रश्न से स्पष्ट नहीं है कि आप जीसीसी, लिंकर और मानक सी लाइब्रेरी का किस संस्करण का उपयोग कर रहे हैं। इसके अलावा, आपके द्वारा प्रदान किया गया कोड POSIX मानक से मेल नहीं खाता है क्योंकि RTDL_NOW या RTDL_LOCAL मैक्रोज़ परिभाषित नहीं हैं। वे RTLD_NOW और RTLD_LOCAL हैं (देखें dlopen)।

अपने सी मानक पुस्तकालय __cxa_atexit का समर्थन नहीं करता, तो आप -fno-use-cxa-atexit जीसीसी ध्वज को निर्दिष्ट करके उसे निष्क्रिय करने की आवश्यकता हो सकती:

स्थिर भंडारण के साथ वस्तुओं के लिए -fuse-CXA-atexit

रजिस्टर विनाशकर्ता __cxa_ atexit फ़ंक्शन पर अयोग्य फ़ंक्शन के बजाय कार्यकाल। यह विकल्प स्थिर विनाशकों के पूर्ण मानकों-अनुरूप हैंडलिंग के लिए आवश्यक है, लेकिन यदि आपकी सी लाइब्रेरी __cxa_atexit का समर्थन करती है तो केवल काम करेगी।

लेकिन इसके परिणामस्वरूप एक समस्या हो सकती है जहां विनाशकों को अलग-अलग क्रम में बुलाया जाता है या बिल्कुल नहीं कहा जाता है। तो टूटा __cxa_atexit समर्थन या कोई समर्थन नहीं होने पर सबसे अच्छा समाधान आपके साझा पुस्तकालयों में विनाशकों के साथ स्थैतिक वस्तुओं का उपयोग नहीं करना है।

संबंधित मुद्दे