2014-09-18 3 views
5

क्लैंग 3.5.0 के साथ -फ्लो और साझा लाइब्रेरी से लिंक करते समय, ऐसा लगता है कि साझा लाइब्रेरी में operator delete पर कॉल नहीं है मुख्य वस्तुओं से operator new पर कॉल के रूप में एक ही प्रतीक संकल्प आदेश का पालन करें। उदाहरण:प्रतिस्थापित ऑपरेटर के साथ क्लैंग लिंक-टाइम ऑप्टिमाइज़ेशन नए कारणों से मेल नहीं खाता मुक्त()/valgrind

shared.cpp:

void deleteIt(int* ptr) { 
    delete ptr; 
} 

main.cpp:

$ clang++ -std=c++11 -g -O3 -flto -fuse-ld=gold -fPIC -shared shared.cpp -o libshared.so 
$ clang++ -std=c++11 -g -O3 -flto -fuse-ld=gold main.cpp -L. -lshared -o main 
$ LD_LIBRARY_PATH=. valgrind --quiet ./main 
==20557== Mismatched free()/delete/delete [] 
==20557== at 0x4C2B6D0: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==20557== by 0x4009F7: main (main.cpp:19) 
==20557== Address 0x5a03040 is 0 bytes inside a block of size 4 alloc'd 
==20557== at 0x4C29F90: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==20557== by 0x4009EA: operator new (main.cpp:5) 
==20557== by 0x4009EA: main (main.cpp:19) 
==20557== 
:

#include <cstdlib> 
#include <new> 

void* operator new(size_t size) { 
    void* result = std::malloc(size); 
    if (result == nullptr) { 
    throw std::bad_alloc(); 
    } 
    return result; 
} 

void operator delete(void* ptr) noexcept { 
    std::free(ptr); 
} 

void deleteIt(int* ptr); 

int main() { 
    deleteIt(new int); 
    return 0; 
} 

यहाँ जब मैं इसे बनाने और valgrind के माध्यम से इसे चलाने के क्या होता है

आप देख सकते हैं कि यह valgrind के operator delete ढूंढ रहा है, लेकिन main.cpp से उपयोग कर रहा है। इसके विपरीत, जीसीसी के साथ सटीक एक ही निर्माण (clang++ को g++ के साथ प्रतिस्थापित करें) ठीक काम करता है। कोई विचार क्यों, या इसके आसपास कैसे काम करना है?

संपादित करें: @Deduplicator द्वारा अनुरोध किए गए प्रतीक आयात और निर्यात।

$ objdump -T main | c++filt | grep operator 
0000000000400990 g DF .text 0000000000000033 Base  operator new(unsigned long) 
0000000000000000  DF *UND* 0000000000000000 Base  operator delete(void*) 
$ objdump -T libshared.so | c++filt | grep operator 
0000000000000000  DF *UND* 0000000000000000 GLIBCXX_3.4 operator delete(void*) 
+0

क्या आपने वास्तव में कोड के माध्यम से कदम रखा है (मुझे उम्मीद है कि साझा लाइब्रेरी की अपनी ढेर हो, इसलिए मैं पूरी तरह से आश्चर्यचकित नहीं हूं) –

+0

मुझे लगता है कि मुख्य के लिए ऑपरेटर-डिलीट-लाइन समस्या को इंगित करती है। किसी कारण से, मुख्य हटाई जा रही निर्यात नहीं कर रहा है ... वास्तव में, हटाया गया था हटा दिया गया था। – Deduplicator

+0

अच्छा पकड़ो। दिलचस्प बात यह है कि, यदि मैं 'ऑपरेटर डिलीट' के सी ++ 14 अधिभार को जोड़ता हूं और '-std = C++ 14' का उपयोग करता हूं, तो उसे निर्यात किया जाता है और सबकुछ काम करता है।लेकिन 'ऑपरेटर डिलीट (शून्य *) 'अभी भी निर्यात नहीं किया गया है। –

उत्तर

5

object-dump को देखते हुए, यह स्पष्ट operator delete(void*)main द्वारा निर्यात नहीं है।

$ objdump -T main | c++filt | grep operator 
0000000000400990 g DF .text 0000000000000033 Base  operator new(unsigned long) 
0000000000000000  DF *UND* 0000000000000000 Base  operator delete(void*) 

देखें कि अनुभाग जहां operator delete(void*) संग्रहीत किया जाता है *UND* है: यह वहाँ नहीं है!

अब, यह क्लैंग के हिस्से पर एक स्पष्ट विफलता है, एक अच्छी बग-रिपोर्ट कर सकता है, क्योंकि हमारे पास पहले से ही न्यूनतम परीक्षण-मामला है।

अब, बैंड-सहायता के रूप में operator delete(void*) को रखने और निर्यात करने के लिए क्लैंग को कैसे मजबूर किया जाए?
जवाब looking at the possible attributes है, वहाँ एक अच्छा एक है:

इस्तेमाल किया
यह लक्षण एक समारोह से जुड़ी, इसका मतलब है कि कोड भले ही ऐसा लगता है कि समारोह संदर्भित नहीं है समारोह के लिए उत्सर्जित किया जाना चाहिए । यह उपयोगी है, उदाहरण के लिए, जब फ़ंक्शन को केवल इनलाइन असेंबली में संदर्भित किया जाता है। जब एक सी ++ वर्ग टेम्पलेट के सदस्य फ़ंक्शन पर लागू होता है, तो विशेषता का भी अर्थ है कि यदि कक्षा को तुरंत चालू किया जाता है तो फ़ंक्शन तत्काल होता है।

कोड में लाना है कि:

void operator delete(void* ptr) noexcept __attribute__((used)) { 

और देखा, बजना नहीं रह गया है अनुचित तरीके से यह prunes।

+0

बग रिपोर्ट: http://llvm.org/bugs/show_bug.cgi?id=21001 –

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