2010-07-07 6 views
12

कोड का निम्न भागसी ++ पकड़ने झूलने संदर्भ

struct S { 
    S(int & value): value_(value) {} 
    int & value_; 
}; 

S function() { 
    int value = 0; 
    return S(value); // implicitly returning reference to local value 
} 

संकलक चेतावनी का उत्पादन नहीं करता (-Wall) मान लीजिए, इस त्रुटि को पकड़ने के लिए कठिन हो सकता है।

उपकरण क्या पकड़ इस तरह की समस्याओं

+0

यह संकलन भी नहीं करना चाहिए । आप एक पूर्णांक शाब्दिक के संदर्भ को बाध्य कर रहे हैं। आप किस कंपाइलर का उपयोग कर रहे हैं? – jalf

+0

@jalf क्षमा करें, जो एस (मान) – Anycorn

+1

होना चाहिए था इसका पता लगाने के लिए आपको टूल की आवश्यकता क्यों है? बस उस तरह स्पष्ट रूप से गलत कोड मत लिखो। यह बहुत ही असंभव है कि एक संदर्भ सदस्य के साथ एक वर्ग सही है। –

उत्तर

8

रनटाइम आधारित समाधान हैं जो अवैध पॉइंटर एक्सेस की जांच करने के लिए कोड का उपयोग करते हैं। मैंने अभी तक mudflap का उपयोग किया है (जिसे संस्करण 4.0 के बाद से जीसीसी में एकीकृत किया गया है)।mudflap कोड में प्रत्येक पॉइंटर (और संदर्भ) को ट्रैक करने का प्रयास करता है और पॉइंटर/संदर्भ वास्तव में इसके मूल प्रकार के जीवित वस्तु को इंगित करता है तो प्रत्येक पहुंच की जांच करता है।

#include <stdio.h> 
struct S { 
    S(int & value): value_(value) {} 
    int & value_; 
}; 

S function() { 
    int value = 0; 
    return S(value); // implicitly returning reference to local value 
} 
int main() 
{ 
    S x=function(); 
    printf("%s\n",x.value_); //<-oh noes! 
} 

mudflap के साथ इस संकलित सक्षम:

g++ -fmudflap s.cc -lmudflap 

और चल देता है:

$ ./a.out 
******* 
mudflap violation 1 (check/read): time=1279282951.939061 ptr=0x7fff141aeb8c size=4 
pc=0x7f53f4047391 location=`s.cc:14:24 (main)' 
     /opt/gcc-4.5.0/lib64/libmudflap.so.0(__mf_check+0x41) [0x7f53f4047391] 
     ./a.out(main+0x7f) [0x400c06] 
     /lib64/libc.so.6(__libc_start_main+0xfd) [0x7f53f358aa7d] 
Nearby object 1: checked region begins 332B before and ends 329B before 
mudflap object 0x703430: name=`argv[]' 
bounds=[0x7fff141aecd8,0x7fff141aece7] size=16 area=static check=0r/0w liveness=0 
alloc time=1279282951.939012 pc=0x7f53f4046791 
Nearby object 2: checked region begins 348B before and ends 345B before 
mudflap object 0x708530: name=`environ[]' 
bounds=[0x7fff141aece8,0x7fff141af03f] size=856 area=static check=0r/0w liveness=0 
alloc time=1279282951.939049 pc=0x7f53f4046791 
Nearby object 3: checked region begins 0B into and ends 3B into 
mudflap dead object 0x7089e0: name=`s.cc:8:9 (function) int value' 
bounds=[0x7fff141aeb8c,0x7fff141aeb8f] size=4 area=stack check=0r/0w liveness=0 
alloc time=1279282951.939053 pc=0x7f53f4046791 
dealloc time=1279282951.939059 pc=0x7f53f4046346 
number of nearby objects: 3 
Segmentation fault 

अंक के एक जोड़े को विचार करने के लिए:

  1. mudflap यहाँ एक उदाहरण है ठीक से देखा जा सकता है कि इसे वास्तव में क्या देखना चाहिए और करो विवरण के लिए http://gcc.gnu.org/wiki/Mudflap_Pointer_Debugging पढ़ें।
  2. डिफ़ॉल्ट व्यवहार उल्लंघन पर एक SIGSEGV बढ़ाने के लिए है, इसका मतलब है कि आप अपने डीबगर में उल्लंघन पा सकते हैं।
  3. mudflap एक कुतिया हो सकता है, विशेष रूप से जब आप पुस्तकालयों के साथ बातचीत कर रहे हैं जो mudflap समर्थन के साथ संकलित नहीं हैं।
  4. यह उस जगह पर छाल नहीं होगा जहां लटकने वाला संदर्भ बनाया गया है (वापसी एस (मान)), केवल संदर्भ जब संदर्भ दिया जाता है। यदि आपको इसकी आवश्यकता है, तो आपको एक स्थिर विश्लेषण उपकरण की आवश्यकता होगी।

पीएस विचार करने के लिए एक बात थी, गैर-पोर्टेबल एस() की प्रतिलिपि बनाने के लिए जांच करें, जो दावा करता है कि value_ एक छोटे से जीवन काल के साथ एक पूर्णांक के लिए बाध्य नहीं है (उदाहरण के लिए, यदि यह एक पर स्थित है ढेर के "पुराने" स्लॉट कि पूर्णांक यह बाध्य है)। यह निश्चित रूप से सही होने के लिए higly-machine विशिष्ट और संभवतः मुश्किल है, लेकिन यह तब तक ठीक होना चाहिए जब तक यह केवल डीबगिंग के लिए न हो।

+0

का उपयोग करके असेंबली डंप उत्पन्न कर सकते हैं। मैं इसे आज़मा दूंगा। मुझे – Anycorn

1

मदद करने के लिए मुझे नहीं लगता कि किसी भी स्थिर उपकरण है जो पकड़ कर सकते हैं कि कोई बाहर हैं, लेकिन अगर आप कुछ इकाई परीक्षण के साथ Valgrind का उपयोग करें या जो कुछ भी कोड क्रैश हो रहा है (SEG दोष), आप आसानी से पता लगा सकते हैं कि स्मृति कहां संदर्भित की जाती है और जहां इसे मूल रूप से आवंटित किया गया था।

+1

जबकि valgrind _awesome_ है, क्योंकि इस मामले में स्टैक पर सब कुछ आवंटित किया गया है, वाल्ग्रिंड समस्या को पकड़ नहीं पाएगा। –

1

आपका कोड भी संकलित नहीं करना चाहिए। जिन कंपाइलरों को मैं जानता हूं वे कोड को संकलित करने में विफल होंगे, या कम से कम एक चेतावनी फेंक देंगे।

यदि आप return S(value) बजाय मतलब है, तो आकाश खातिर कॉपी कोड आप यहाँ पोस्ट पेस्ट करें।

फिर से लिखने और लिखने की त्रुटियों को शुरू सिर्फ यह असंभव है हमें वास्तव में अनुमान लगाने के लिए जो त्रुटियों आप रहे के बारे में पूछ लगे और कौन से दुर्घटनाओं हम उपेक्षा करने वाले रहे थे मतलब है।

जब आप इंटरनेट पर कहीं भी कोई प्रश्न पोस्ट करते हैं, तो उस प्रश्न में कोड शामिल है, सटीक कोड पोस्ट करें।

अब, यह मानते हुए कि यह वास्तव में एक टाइपो था, कोड पूरी तरह से कानूनी है, और किसी भी उपकरण को चेतावनी देने का कोई कारण नहीं है।

जब तक आप खतरनाक संदर्भ को कम करने की कोशिश नहीं करते हैं, तो कोड पूरी तरह से सुरक्षित है।

यह संभव है कि कुछ स्थैतिक विश्लेषण उपकरण (उदाहरण के लिए वालग्रिंड, या एमएसवीसी/विश्लेषण, उदाहरण के लिए) आपको इस बारे में चेतावनी दे सकते हैं, लेकिन ऐसा लगता है कि आप कुछ भी गलत नहीं कर रहे हैं। आप एक ऑब्जेक्ट लौट रहे हैं जिसमें एक लटकती संदर्भ शामिल है। आप सीधे स्थानीय ऑब्जेक्ट का संदर्भ नहीं दे रहे हैं (जो आमतौर पर के बारे में चेतावनी देते हैं), लेकिन व्यवहार के साथ एक उच्च स्तरीय वस्तु जो इसे उपयोग करने के लिए पूरी तरह से सुरक्षित बना सकती है, भले ही इसमें किसी स्थानीय ऑब्जेक्ट का संदर्भ हो गुंजाइश से बाहर चला गया।

4

मुझे लगता है कि इन सभी को पकड़ना संभव नहीं है, हालांकि कुछ कंपाइलर कुछ मामलों में चेतावनियां दे सकते हैं।

यह रूप में अच्छी तरह याद रखना होगा कि संदर्भ वास्तव में हुड के नीचे संकेत दिए गए हैं, और संकेत के साथ संभव शूट स्वयं में फुट परिदृश्यों से कई अभी भी संभव हो रहे हैं .. है

स्पष्ट करने के लिए मैं "संकेत के बारे में क्या मतलब है हुड के तहत ", निम्नलिखित दो कक्षाएं लें। एक संदर्भ, अन्य पॉइंटर्स का उपयोग करता है।

class Ref 
{ 
    int &ref; 
public: 
    Ref(int &r) : ref(r) {}; 
    int get() { return ref; }; 
}; 

class Ptr 
{ 
    int *ptr; 
public: 
    Ptr(int *p) : ptr(p) {}; 
    int get() { return *ptr; }; 
}; 

अब, दोनों के लिए जेनरेट कोड पर तुलना करें।

@@[email protected]$bctr$qri proc near // Ref::Ref(int &ref) 
    push  ebp 
    mov  ebp,esp 
    mov  eax,dword ptr [ebp+8] 
    mov  edx,dword ptr [ebp+12] 
    mov  dword ptr [eax],edx 
    pop  ebp 
    ret 

@@[email protected]$bctr$qpi proc near // Ptr::Ptr(int *ptr) 
    push  ebp 
    mov  ebp,esp 
    mov  eax,dword ptr [ebp+8] 
    mov  edx,dword ptr [ebp+12] 
    mov  dword ptr [eax],edx 
    pop  ebp 
    ret 

@@[email protected]$qv proc near // int Ref:get() 
    push  ebp 
    mov  ebp,esp 
    mov  eax,dword ptr [ebp+8] 
    mov  eax,dword ptr [eax] 
    mov  eax,dword ptr [eax] 
    pop  ebp 
    ret 

@@[email protected]$qv proc near // int Ptr::get() 
    push  ebp 
    mov  ebp,esp 
    mov  eax,dword ptr [ebp+8] 
    mov  eax,dword ptr [eax] 
    mov  eax,dword ptr [eax] 
    pop  ebp 
    ret 

अंतर स्पॉट? कोई नहीं है।

+0

वे पूरी तरह से हुड के नीचे पॉइंटर्स नहीं हैं, उनके पास कोई स्थान नहीं है (वे अप्रत्यक्ष नहीं हैं), वे एक उपनाम हैं। – oscode

+4

@ स्टेवन - यह समय है कि आप हुड के नीचे देख रहे थे! मैंने जवाब अपडेट कर लिया है। – Roddy

+0

आप सही हैं और मैंने कुछ सीखा है इसलिए मैं आपको धन्यवाद देता हूं, लेकिन प्रभावी सी ++ थर्ड एडिशन के पेज 89 को उद्धृत करता हूं, "यदि आप सी ++ कंपाइलर के हुड के नीचे देखते हैं, तो आप पाएंगे कि संदर्भ आमतौर पर पॉइंटर्स के रूप में लागू होते हैं।" क्या कोई विस्तार कर सकता है? – oscode

1

है एक दिशानिर्देश के इस सटीक बात से पीटा किए जाने के बाद मैं का पालन करें:

एक वर्ग के लिए एक संदर्भ के सदस्य (या कुछ और करने के लिए एक सूचक एक जीवन भर आप नियंत्रित नहीं करते हो सकता है) होता है, ऑब्जेक्ट को गैर-कॉपी करने योग्य बनाएं।

इस तरह, आप एक खतरनाक संदर्भ के साथ दायरे से बचने की संभावनाओं को कम करते हैं।

+0

धन्यवाद से पहले इस टूल के बारे में पता नहीं था। दुर्भाग्यवश, उस पुस्तकालय में कक्षाओं पर मेरा कोई नियंत्रण नहीं है। मैं स्थिर विश्लेषण उपकरण – Anycorn

2

आपको संकलन-समय वाद्ययंत्र के आधार पर एक तकनीक का उपयोग करना होगा। जबकि वालग्रिंड रन-टाइम (मॉलोक, फ्री) पर सभी फ़ंक्शन कॉल देख सकता है, लेकिन यह कोड पर जांच नहीं कर सका।

अपनी वास्तुकला के आधार पर, आईबीएम PurifyPlus इनमें से कुछ समस्याएं पाएं। इसलिए, आपको इसका उपयोग करने के लिए वैध लाइसेंस (या अपनी कंपनी का उपयोग करें) ढूंढना चाहिए, या परीक्षण संस्करण के साथ इसे आज़माएं।

0

यह पूरी तरह से मान्य कोड है।

यदि आप अपना कार्य कहते हैं और अस्थायी को एक कॉन्स्ट संदर्भ में बांधते हैं तो दायरा लंबा हो जाता है।

const S& s1 = function(); // valid 

S& s2 = function(); // invalid 

यह स्पष्ट रूप से C++ standard में अनुमत है।

12.2 देखें।4:

दो संदर्भ हैं जिनमें पूर्ण अभिव्यक्ति के अंत की तुलना में एक अलग बिंदु पर अस्थायी नष्ट हो जाते हैं।

और 12.2.5:

दूसरा संदर्भ जब एक संदर्भ के लिए एक अस्थायी करने के लिए बाध्य किया जाता है। अस्थायी जिस पर संदर्भ बाध्य है या अस्थायी है जो उपरोक्त का पूर्ण उद्देश्य है, जिसके संदर्भ में संदर्भ बाध्य संदर्भ के जीवनकाल के लिए बनी हुई है: [...]

+1

एस प्राप्त करने की उम्मीद कर रहा था एस एस गुंजाइश में रह सकता है, लेकिन एस द्वारा संदर्भित वस्तु (इस मामले में एक int) दायरे से बाहर हो जाएगी। – MSN

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