2015-11-24 8 views
8

मुझे पता है कि पहले से ही कई समान प्रश्न हैं और उत्तर मौजूद हैं, लेकिन मैं अपनी समस्या का समाधान नहीं कर पा रहा हूं।पता लगाएं कि ढेर मेमोरी दूषित हो जाती है

मेरे बड़े एप्लिकेशन में ढेर कहीं दूषित हो रहा है और मैं इसे ढूंढने में सक्षम नहीं हूं। मैंने gflags जैसे टूल का उपयोग किया लेकिन कोई किस्मत नहीं।

मैं निम्न नमूना जो उद्देश्य से ढेर भ्रष्ट पर gflags की कोशिश की:

char* pBuffer = new char[256]; 
memset(pBuffer, 0, 256 + 1); 
delete[] pBuffer; 

लाइन # पर 2 ढेर ओवरराइट है, लेकिन कैसे gflags जैसे उपकरणों के माध्यम से इसे खोजने के लिए, windbg आदि हो सकता है मैं नहीं कर रहा हूँ gflags सही ढंग से उपयोग कर रहे हैं।

+3

'स्मृति' में '256 + 1' क्यों, जब आपने केवल' 256' बाइट आवंटित किए हैं? –

+3

आपके बड़े आवेदन में, आप कैसे जानते थे कि ढेर दूषित हो गया था? आपको किस टूल ने सूचित किया? – PaulMcKenzie

+3

@ टी.जेड। भ्रष्टाचार के प्रकार का प्रदर्शन करने के लिए ... – StoryTeller

उत्तर

1

यदि समान चर लगातार दूषित हो रहा है, तो डेटा ब्रेक पॉइंट परिवर्तन के लिए ज़िम्मेदार कोड ढूंढने का एक तेज़ और आसान तरीका है (यदि आपका आईडीई उनका समर्थन करता है)। (डीबग-> नया ब्रेक प्वाइंट-> एमएस विजुअल स्टूडियो 2008 में नया डेटा ब्रेकपॉइंट ...)। यदि आपकी ढेर भ्रष्टाचार अधिक यादृच्छिक है तो वे आपकी मदद नहीं करेंगे (लेकिन मुझे लगता है कि अगर यह मदद करता है तो मैं सरल जवाब साझा करूंगा)।

0

इलेक्ट्रिक बाड़ नामक एक उपकरण है जो मुझे लगता है कि विंडोज पर भी समर्थित है।

अनिवार्य रूप से, यह हाइजैक मॉलोक और सह क्या होता है, प्रत्येक आवंटन पृष्ठ सीमा पर समाप्त होता है और अगले पृष्ठ को पहुंच योग्य बनाता है।

प्रभाव यह है कि आपको बफर ओवररन पर सीजी गलती मिलती है।

शायद यह बफर अंडरन के लिए भी एक विकल्प है।

0

कृपया इस लिंक Visual Studio - how to find source of heap corruption errors

Is there a good Valgrind substitute for Windows?

यह खिड़कियों पर ढेर मुद्दों को खोजने के लिए तकनीक बताता है पढ़ें।

लेकिन दूसरी ओर आप हमेशा लिख ​​सकते हैं (यदि आप नया कोड लिख रहे हैं) मेमोरी मैनेजर्स। ऐसा करने का तरीका है: अपने रैपर एपिस का उपयोग करें जो मॉलोक/कॉलोक इत्यादि को कॉल करेगा

मान लीजिए कि आपके पास myialloc (size_t len) है; फिर अपने फ़ंक्शन के अंदर, आप हेडर + लेन + फ़ोटर आवंटन का प्रयास कर सकते हैं। अपने शीर्षलेख पर आवंटन के आकार की तरह जानकारी सहेजें या अधिक जानकारी हो सकती है। पाद लेख पर, मृतक की तरह कुछ जादू संख्या जोड़ें। और myMalloc से पीआरआर (malloc से) + हेडर वापस लौटें।

myfree (शून्य * पीआरटी) का उपयोग करके इसे मुक्त करते समय, तो केवल पीआरटी-हेडर करें, लेन की जांच करें, फिर FOOTER = ptr-HEADER + वास्तव में allcated लेन पर कूदें। इस ऑफसेट पर, आपको डेडबीफ मिलना चाहिए, और यदि आप नहीं पाते हैं, तो आप जानते हैं, यह दूषित हो गया है।

0

यदि स्वचालित उपकरण (जैसे इलेक्ट्रिक बाड़ या वालग्रिंड) चाल नहीं करते हैं, और अपने कोड पर ध्यान से देखकर यह पता लगाने के लिए कि यह गलत हो गया है, यह मदद नहीं करता है, और विभिन्न परिचालनों को अक्षम/सक्षम करने में सक्षम नहीं है (जब तक आप ढेर-भ्रष्टाचार की उपस्थिति और पहले से निष्पादित नहीं किए गए कार्यों के बीच एक सहसंबंध प्राप्त करते हैं) इसे संकीर्ण करने के लिए काम नहीं लगता है, आप हमेशा इस तकनीक को आजमा सकते हैं, जो बाद में भ्रष्टाचार को जल्द से जल्द खोजने का प्रयास करता है

अपने स्वयं के कस्टम बनाएं नया और ऑपरेटरों कि आबंटित स्मृति क्षेत्रों के आस-भ्रष्टाचार स्पष्ट गार्ड क्षेत्रों में कहें, कुछ इस तरह हटा दें::

, इतनी के रूप में यह आसान नीचे स्रोत ट्रैक करने के लिए बनाने के लिए 210
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <new> 

// make this however big you feel is "big enough" so that corrupted bytes will be seen in the guard bands 
static int GUARD_BAND_SIZE_BYTES = 64; 

static void * MyCustomAlloc(size_t userNumBytes) 
{ 
    // We'll allocate space for a guard-band, then space to store the user's allocation-size-value, 
    // then space for the user's actual data bytes, then finally space for a second guard-band at the end. 
    char * buf = (char *) malloc(GUARD_BAND_SIZE_BYTES+sizeof(userNumBytes)+userNumBytes+GUARD_BAND_SIZE_BYTES); 
    if (buf) 
    { 
     char * w = buf; 
     memset(w, 'B', GUARD_BAND_SIZE_BYTES);   w += GUARD_BAND_SIZE_BYTES; 
     memcpy(w, &userNumBytes, sizeof(userNumBytes)); w += sizeof(userNumBytes); 
     char * userRetVal = w;       w += userNumBytes; 
     memset(w, 'E', GUARD_BAND_SIZE_BYTES);   w += GUARD_BAND_SIZE_BYTES; 
     return userRetVal; 
    } 
    else throw std::bad_alloc(); 
} 

static void MyCustomDelete(void * p) 
{ 
    if (p == NULL) return; // since delete NULL is a safe no-op 

    // Convert the user's pointer back to a pointer to the top of our header bytes 
    char * internalCP = ((char *) p)-(GUARD_BAND_SIZE_BYTES+sizeof(size_t)); 

    char * cp = internalCP; 
    for (int i=0; i<GUARD_BAND_SIZE_BYTES; i++) 
    { 
     if (*cp++ != 'B') 
     { 
      printf("CORRUPTION DETECTED at BEGIN GUARD BAND POSITION %i of allocation %p\n", i, p); 
      abort(); 
     } 
    } 

    // At this point, (cp) should be pointing to the stored (userNumBytes) field 
    size_t userNumBytes = *((const size_t *)cp); 
    cp += sizeof(userNumBytes); // skip past the user's data 
    cp += userNumBytes; 

    // At this point, (cp) should be pointing to the second guard band 
    for (int i=0; i<GUARD_BAND_SIZE_BYTES; i++) 
    { 
     if (*cp++ != 'E') 
     { 
      printf("CORRUPTION DETECTED at END GUARD BAND POSITION %i of allocation %p\n", i, p); 
      abort(); 
     } 
    } 

    // If we got here, no corruption was detected, so free the memory and carry on 
    free(internalCP); 
} 

// override the global C++ new/delete operators to call our 
// instrumented functions rather than their normal behavior 
void * operator new(size_t s) throw(std::bad_alloc) {return MyCustomAlloc(s);} 
void * operator new[](size_t s) throw(std::bad_alloc) {return MyCustomAlloc(s);} 
void operator delete(void * p) throw()     {MyCustomDelete(p);} 
void operator delete[](void * p) throw()     {MyCustomDelete(p);} 

... उपरोक्त आप इलेक्ट्रिक-बाड़ शैली की कार्यक्षमता प्राप्त करने के लिए पर्याप्त होंगे, यदि कुछ भी किसी भी नई/हटाए गए स्मृति की शुरुआत या अंत में दो 64-बाइट "गार्ड बैंड" में से किसी एक में लिखता है - आवंटन, जब आवंटन हटा दिया जाता है, MyCustomDelete() भ्रष्टाचार को नोटिस करेगा और कार्यक्रम को दुर्घटनाग्रस्त करेगा।

यदि यह पर्याप्त नहीं है (उदाहरण के लिए जब तक विलोपन होता है, भ्रष्टाचार के बाद से इतना कुछ हुआ है कि भ्रष्टाचार के कारण क्या कहना मुश्किल है), आप आवंटित जोड़कर MyCustomAlloc() को और भी आगे बढ़ा सकते हैं आवंटन की एक सिंगलटन/वैश्विक दोगुनी-लिंक्ड सूची में बफर करें, और MyCustomDelete() को उसी सूची से हटा दें (यदि आपका प्रोग्राम बहुप्रचारित है तो इन परिचालनों को क्रमबद्ध करना सुनिश्चित करें!)। ऐसा करने का लाभ यह है कि आप फिर एक और फ़ंक्शन जोड़ सकते हैं उदा। CheckForHeapCorruption() जो उस लिंक की गई सूची पर फिर से शुरू होगा और लिंक की गई सूची में प्रत्येक आवंटन के गार्ड-बैंड की जांच करेगा, और रिपोर्ट करें कि उनमें से कोई भी दूषित हो गया है। फिर आप अपने पूरे कोड में CheckForHeapCorruption() पर कॉल छिड़का सकते हैं, ताकि जब भ्रष्टाचार ढेर हो जाए तो यह कुछ समय बाद चेकफोरहेप क्रॉन्शन() को अगली कॉल पर पता लगाया जाएगा। आखिरकार आप पाएंगे कि चेकफोरहेप कन्फ्रेश() को उड़ान रंगों से गुजरने के लिए एक कॉल, और उसके बाद चेकफोरहेपकॉर्प() के लिए अगली कॉल, कुछ ही पंक्तियों बाद भ्रष्टाचार का पता चला, जिस बिंदु पर आप जानते हैं कि भ्रष्टाचार के कारण जो भी कोड निष्पादित किया गया था CheckForHeapCorruption() पर दो कॉल, और फिर आप उस विशेष कोड का अध्ययन कर सकते हैं कि यह गलत तरीके से क्या कर रहा है, और/या उस कोड में चेकफोरहेप क्रॉन्शन() को और कॉल जोड़ना आवश्यक है।

बग स्पष्ट होने तक दोहराएं। सौभाग्य!

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