भ्रष्टाचार त्रुटियों को ढेर कैसे करें?


165

मैं Visual Studio 2008 के तहत एक (मूल) बहु-थ्रेडेड C ++ एप्लिकेशन डिबगिंग कर रहा हूं। प्रतीत होता है कि यादृच्छिक अवसरों पर, मुझे एक "विंडोज ने एक ब्रेक प्वाइंट ट्रिगर किया है ..." ध्यान दें कि यह एक भ्रष्टाचार के कारण हो सकता है ढेर। ये त्रुटियां हमेशा एप्लिकेशन को तुरंत क्रैश नहीं करेंगी, हालांकि इसके थोड़ी देर बाद क्रैश होने की संभावना है।

इन त्रुटियों के साथ बड़ी समस्या यह है कि वे केवल भ्रष्टाचार होने के बाद ही पॉप अप होते हैं, जो उन्हें ट्रैक और डीबग करने के लिए बहुत कठिन बनाता है, खासकर एक बहु-थ्रेडेड एप्लिकेशन पर।

  • किस तरह की चीजें इन त्रुटियों का कारण बन सकती हैं?

  • मैं उन्हें कैसे डीबग करूं?

युक्तियाँ, उपकरण, विधियाँ, ज्ञान ... स्वागत है।

जवाबों:


128

विंडोज के लिए डिबगिंग टूल्स के साथ संयुक्त एप्लीकेशन वेरिफायर एक अद्भुत सेटअप है। आप विंडोज ड्राइवर किट या लाइटर विंडोज एसडीके के एक हिस्से के रूप में दोनों प्राप्त कर सकते हैं । ( ढेर भ्रष्टाचार के मुद्दे के बारे में पहले के प्रश्न पर शोध करते समय एप्लिकेशन वेरिफायर के बारे में पता चला ।) मैंने पिछले दिनों भी BoundsChecker और Insure ++ (अन्य उत्तरों में उल्लेखित) का उपयोग किया है, हालांकि मुझे आश्चर्य था कि Application Verifier में कितनी कार्यक्षमता थी।

इलेक्ट्रिक बाड़ (उर्फ "efence"), dmalloc , valgrind , और इसके आगे सब लायक उल्लेख कर रहे हैं, लेकिन इनमें से अधिकांश बहुत विंडोज की तुलना में * nix के तहत चलाने के लिए आसान होता है। Valgrind हास्यास्पद रूप से लचीला है: मैंने बड़े सर्वर सॉफ़्टवेयर को कई ढेर मुद्दों के साथ डीबग किया है जो इसका उपयोग कर रहा है।

जब अन्य सभी विफल हो जाते हैं, तो आप अपने स्वयं के वैश्विक ऑपरेटर को नए / डिलीट और मॉलोक / कॉलोक / रियललॉक ओवरलोड प्रदान कर सकते हैं - ऐसा करने के लिए कंपाइलर और प्लेटफॉर्म के आधार पर थोड़ा भिन्न होगा - और यह थोड़ा निवेश होगा - लेकिन यह लंबे समय से भुगतान कर सकता है। वांछनीय फीचर सूची को डलमॉक और इलेक्ट्रिकफेंस से परिचित होना चाहिए, और आश्चर्यजनक रूप से उत्कृष्ट पुस्तक राइटिंग सॉलिड कोड :

  • संतरी मान : प्रत्येक संरेखण से पहले और बाद में थोड़ा अधिक स्थान की अनुमति दें, अधिकतम संरेखण आवश्यकता का सम्मान करना; मैजिक नंबरों से भरें (बफर ओवरफ्लो और अंडरफ्लो को पकड़ने में मदद करता है, और सामयिक "वाइल्ड" पॉइंटर)
  • आबंटन भरण : एक जादू गैर-0 मान के साथ नए आबंटन भरें - विज़ुअल सी ++ डीबग बिल्ड में आपके लिए पहले से ही ऐसा करेगा (असिंचित संस्करण के उपयोग को पकड़ने में मदद करता है)
  • मुक्त भरण : एक गैर-मान के साथ मुक्त मेमोरी में भरें, एक सेगफॉल्ट को ट्रिगर करने के लिए डिज़ाइन किया गया है यदि यह ज्यादातर मामलों में संदर्भित है (झूलने वाले बिंदुओं को पकड़ने में मदद करता है)
  • देरी से मुक्त : ढेर के लिए मुक्त मेमोरी को कुछ समय के लिए वापस न करें , इसे मुफ्त भरा रखें लेकिन उपलब्ध नहीं है (अधिक झूलने वाले बिंदुओं को पकड़ने में मदद करता है, समीपवर्ती डबल-फ्रीज़ को पकड़ता है)
  • ट्रैकिंग : रिकॉर्ड करना जहां एक आवंटन किया गया था, कभी-कभी उपयोगी हो सकता है

ध्यान दें कि हमारे स्थानीय होमब्रेव सिस्टम में (एक एम्बेडेड लक्ष्य के लिए) हम ट्रैकिंग को अन्य सामानों से अलग रखते हैं, क्योंकि रन-टाइम ओवरहेड बहुत अधिक है।


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


चूँकि मैं अपने जवाब को यहाँ खोजता रहता हूँ जब एमएस / एलोकेशन / फ़्री / वैल्यू वैल्यू के लिए खोज करता है, तो यहाँ एक और जवाब है जो माइक्रोसॉफ्ट के डीबगर्स को भरता है


3
अनुप्रयोग सत्यापनकर्ता के बारे में ध्यान देने योग्य एक छोटी सी बात: आपको अपने प्रतीक खोज पथ में Microsoft प्रतीक सर्वर प्रतीकों के आगे अनुप्रयोग सत्यापनकर्ता के प्रतीकों को पंजीकृत करना होगा, यदि आप इसका उपयोग करते हैं ... मुझे पता लगाने के लिए खोज करने का थोड़ा समझ लिया है! इसके लिए आवश्यक प्रतीकों को खोजना।
लींडर

आवेदन सत्यापनकर्ता मदद का एक बड़ा सौदा था, और कुछ अनुमान लगाने के साथ, मैं समस्या को हल करने में सक्षम था! बहुत बहुत धन्यवाद, और बाकी सभी के लिए भी, सहायक बिंदुओं को लाने के लिए।

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

@NathanReed: मेरा मानना ​​है कि यह वी.एस. के साथ भी काम करता है - देखें msdn.microsoft.com/en-us/library/ms220944(v=vs.90).aspx - हालांकि ध्यान दें कि यह लिंक VS2008 के लिए है, मैं नहीं हूँ बाद के संस्करणों के बारे में सुनिश्चित करें। मेमोरी थोड़ी फजी है, लेकिन मेरा मानना ​​है कि जब मेरे पास "पहले वाले सवाल" लिंक में मुद्दा था तो मैंने सिर्फ एप्लीकेशन वेरीफायर चलाया और विकल्पों को बचाया, प्रोग्राम चलाया, और जब यह क्रैश हुआ तो मैंने वीएस को डिबग करने के लिए चुना। एवी ने इसे पहले दुर्घटना / अभिकथन किया। Avrf कमांड WinDbg के लिए विशिष्ट है जहाँ तक मुझे पता है, हालाँकि। उम्मीद है कि अन्य लोग अधिक जानकारी प्रदान कर सकते हैं!
लिएंडर

धन्यवाद। मैंने वास्तव में अपने मूल मुद्दे को हल किया और यह निकला कि भ्रष्टाचार आखिरकार नहीं, बल्कि कुछ और है, इसलिए शायद यह बताता है कि ऐप वेरिफायर को कुछ नहीं मिला। :)
नाथन रीड

35

आप अपने आवेदन के लिए पेज हीप को सक्षम करके ढेर भ्रष्टाचार संबंधी समस्याओं का पता लगा सकते हैं। ऐसा करने के लिए आपको gflags.exe का उपयोग करना होगा जो विंडोज के लिए डिबगिंग टूल्स के एक भाग के रूप में आता है

अपने निष्पादन योग्य के लिए Gflags.exe और छवि फ़ाइल विकल्पों में चलाएं, "पृष्ठ हीप सक्षम करें" विकल्प जांचें।

अब अपने एक्स को पुनः आरंभ करें और डीबगर से संलग्न करें। जब भी कोई ढेर भ्रष्टाचार होता है, पेज हीप सक्षम होता है, एप्लिकेशन डिबगर में टूट जाएगा।


हाँ, लेकिन एक बार जब मैं अपने कॉलस्टैक डंप (स्मृति भ्रष्टाचार क्रैश के बाद) में यह फ़ंक्शन कॉल करता हूं: wow64! Wow64NotifyDebugger, मैं क्या कर सकता हूं? मैं अभी भी नहीं पता है कि अपने आवेदन में गलत हो रहा है
Guillaume07

बस ढेर भ्रष्टाचार की कोशिश की यहाँ ढेर भ्रष्टाचार, बहुत उपयोगी छोटे उपकरण, अत्यधिक की सिफारिश की। निकला मैं मुक्त स्मृति तक पहुँच रहा था, जो, जब gflags के साथ साधन तुरंत डीबगर में टूट जाएगा ... काम!
डेव एफ

महान उपकरण! बस एक बग पाया, कि मैं दिनों के लिए शिकार कर रहा था, क्योंकि विंडोज भ्रष्टाचार का पता नहीं कहता है, केवल यह कि "कुछ" गलत है, जो वास्तव में सहायक नहीं है।
Devolus

पार्टी के लिए थोड़ा देर हो गई, लेकिन मैंने एक महत्वपूर्ण वृद्धि मेमोरी उपयोग पर ध्यान दिया जब मैंने पेज हीप चालू किया तो मैं अपना डिबगिंग कर रहा हूं। दुर्भाग्य से बात करने के लिए (32 बिट) अनुप्रयोग ढेर भ्रष्टाचार का पता लगाने से पहले स्मृति से बाहर चलाता है। किसी भी विचार कैसे उस समस्या से निपटने के लिए?
१२:१०

13

वास्तव में चीजों को धीमा करने और बहुत सारे रनटाइम चेकिंग करने के लिए, main()Microsoft Visual Studio C ++ में अपने शीर्ष या समकक्ष के साथ निम्नलिखित को जोड़ने का प्रयास करें।

_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF | _CRTDBG_CHECK_ALWAYS_DF );


8

किस तरह की चीजें इन त्रुटियों का कारण बन सकती हैं?

स्मृति के साथ शरारती बातें करना, जैसे कि एक बफर के अंत के बाद लिखना, या एक बफर को लिखने के बाद इसे वापस ढेर में मुक्त कर दिया गया है।

मैं उन्हें कैसे डीबग करूं?

एक उपकरण का उपयोग करें जो आपके निष्पादन योग्य में स्वचालित सीमा-जाँच जोड़ता है: यानी यूनिक्स पर वैग्राइंड, या विंडोज पर BoundsChecker (विकिपीडिया भी शुद्ध और बीमा ++) का एक उपकरण।

सावधान रहें कि ये आपके आवेदन को धीमा कर देंगे, इसलिए यदि आपकी सॉफ्ट-रियल-टाइम एप्लिकेशन है तो वे अनुपयोगी हो सकते हैं।

एक अन्य संभावित डीबगिंग सहायता / उपकरण MicroQuill का HeapAgent हो सकता है।


1
डिबगिंग रनटाइम (/ MDd या / MTd ध्वज) के साथ एप्लिकेशन का पुनर्निर्माण मेरा पहला कदम होगा। ये मॉलॉक और मुफ्त में अतिरिक्त जांच करते हैं, और अक्सर बग (स्थान) के स्थान को कम करने में प्रभावी होते हैं।
रूसी

MicroQuill का HeapAgent: इसके बारे में बहुत कुछ लिखा या सुना नहीं गया है, लेकिन ढेर भ्रष्टाचार के लिए, यह आपकी सूची में होना चाहिए।
सम्राट पाटिल

1
BoundsChecker एक धूम्रपान परीक्षण के रूप में ठीक काम करता है, लेकिन उत्पादन में भी उस कार्यक्रम को चलाने की कोशिश करते समय इसके तहत एक कार्यक्रम चलाने के बारे में भी नहीं सोचते हैं। मंदी 60x से 300x तक कहीं भी हो सकती है, इस पर निर्भर करता है कि आप किन विकल्पों का उपयोग कर रहे हैं, और आप कंपाइलर इंस्ट्रूमेंटेशन फीचर का उपयोग कर रहे हैं या नहीं। अस्वीकरण: मैं उन लोगों में से एक हूं जो माइक्रो फोकस के लिए उत्पाद बनाए रखता है।
रिक पापो

8

एक त्वरित टिप, जो मुझे मुक्त मेमोरी में डिटेक्टिंग एक्सेस से मिली है:

यदि आप मेमोरी ब्लॉक को एक्सेस करने वाले हर स्टेटमेंट की जाँच किए बिना, त्रुटि का जल्द पता लगाना चाहते हैं, तो आप ब्लॉक को खाली करने के बाद मेमोरी पॉइंटर को अमान्य मान पर सेट कर सकते हैं:

#ifdef _DEBUG // detect the access to freed memory
#undef free
#define free(p) _free_dbg(p, _NORMAL_BLOCK); *(int*)&p = 0x666;
#endif

5

सबसे अच्छा उपकरण जो मैंने उपयोगी पाया और हर बार काम किया वह है कोड समीक्षा (अच्छे कोड समीक्षकों के साथ)।

कोड की समीक्षा के अलावा, मैं पहले पेज हीप की कोशिश करूंगा । पेज हीप को सेट होने में कुछ सेकंड लगते हैं और भाग्य के साथ यह आपकी समस्या को दूर कर सकता है।

यदि पेज हीप के साथ कोई भाग्य नहीं है, तो Microsoft से विंडोज के लिए डिबगिंग टूल डाउनलोड करें और WinDbg का उपयोग करना सीखें। क्षमा करना आपको अधिक विशिष्ट सहायता नहीं दे सकता है, लेकिन बहु-थ्रेडेड हीप दूषण को डीबग करना विज्ञान से अधिक एक कला है। "WinDbg हीप करप्शन" के लिए Google और आपको इस विषय पर कई लेख खोजने चाहिए।


4

आप यह देखने के लिए भी जांच कर सकते हैं कि आप डायनामिक या स्टैटिक सी रनटाइम लाइब्रेरी के खिलाफ लिंक कर रहे हैं या नहीं। यदि आपकी DLL फाइलें स्टेटिक C रनटाइम लाइब्रेरी के खिलाफ लिंक कर रही हैं, तो DLL फाइल का अलग ढेर है।

इसलिए, यदि आप एक DLL में कोई ऑब्जेक्ट बनाते हैं और इसे किसी अन्य DLL में खाली करने का प्रयास करते हैं, तो आपको वही संदेश मिलेगा जो आप ऊपर देख रहे हैं। इस समस्या को एक अन्य स्टैक ओवरफ्लो प्रश्न में संदर्भित किया जाता है, एक अलग DLL में आवंटित की गई Freeing मेमोरी


3

आप किस प्रकार के आवंटन कार्यों का उपयोग कर रहे हैं? मैंने हाल ही में हीप * शैली आवंटन कार्यों का उपयोग करके एक समान त्रुटि की।

यह पता चला कि मैं गलती से HEAP_NO_SERIALIZEविकल्प के साथ ढेर बना रहा था । यह अनिवार्य रूप से हीप कार्यों को थ्रेड सुरक्षा के बिना चलाता है। यदि यह ठीक से उपयोग किया जाता है तो यह एक प्रदर्शन में सुधार है, लेकिन कभी भी इसका उपयोग नहीं किया जाना चाहिए यदि आप मल्टी-थ्रेडेड प्रोग्राम [1] में HeapAlloc का उपयोग कर रहे हैं। मैं केवल इस बात का उल्लेख करता हूं क्योंकि आपके पोस्ट में उल्लेख है कि आपके पास एक बहु-थ्रेडेड ऐप है। यदि आप कहीं भी HEAP_NO_SERIALIZE का उपयोग कर रहे हैं, तो उसे हटा दें और यह आपकी समस्या को ठीक कर देगा।

[१] कुछ ऐसी स्थितियाँ हैं जहाँ यह कानूनी है, लेकिन इसके लिए आपको H * * पर कॉल को अनुक्रमित करना होगा और आमतौर पर बहु-थ्रेडेड प्रोग्राम के लिए ऐसा नहीं है।


हां: एप्लिकेशन के कंपाइलर / बिल्ड विकल्पों को देखें, और यह सुनिश्चित करें कि इसे C रन-टाइम लाइब्रेरी के "मल्टी-थ्रेडेड" संस्करण के साथ लिंक करने के लिए बनाया जा रहा है।
क्रिस जू

HeapAlloc स्टाइल API के लिए @ChrisW यह अलग है। यह वास्तव में एक पैरामीटर है जिसे हीप निर्माण के समय में बदला जा सकता है, लिंक समय पर नहीं।
जारेदपार

ओह। मेरे साथ ऐसा नहीं हुआ कि ओपी उस ढेर के बारे में बात कर रहे हों, न कि सीआरटी के ढेर के बारे में।
क्रिस डब्ल्यूडब्ल्यू

@ क्रिस, सवाल बल्कि अस्पष्ट है, लेकिन मैंने अभी ~ 1 सप्ताह पहले जो समस्या बताई है, उसे मैंने मारा है, इसलिए यह मेरे दिमाग में ताजा है।
जारेदपार

3

यदि ये त्रुटियां बेतरतीब ढंग से होती हैं, तो उच्च संभावना है कि आपने डेटा-दौड़ का सामना किया। कृपया, जांचें: क्या आप विभिन्न थ्रेड्स से साझा किए गए मेमोरी पॉइंटर्स को संशोधित करते हैं? इंटेल थ्रेड चेकर मल्टीथ्रेडेड प्रोग्राम में ऐसे मुद्दों का पता लगाने में मदद कर सकता है।


1

साधनों की तलाश के अलावा, एक संभावित अपराधी की तलाश पर विचार करें। क्या कोई ऐसा घटक है जिसका आप उपयोग कर रहे हैं, शायद आपके द्वारा नहीं लिखा गया है, जिसे एक बहुस्तरीय वातावरण में चलाने के लिए डिज़ाइन और परीक्षण नहीं किया गया हो सकता है? या बस एक जिसे आप नहीं जानते हैं वह ऐसे वातावरण में चला है।

पिछली बार जब यह मेरे साथ हुआ था, यह एक देशी पैकेज था जो वर्षों से बैच की नौकरियों से सफलतापूर्वक उपयोग किया गया था। लेकिन इस कंपनी में यह पहली बार था कि इसका उपयोग .NET वेब सेवा (जिसे मल्टीथ्रेड्रेड किया गया है) से किया गया था। यह वही था - उन्होंने कोड को सुरक्षित रखने के बारे में झूठ बोला था।


1

आप _CrtSetDbgFlag : _CRTDBG_CHECK_ALWAYS_DF या _CRTDBG_CHECK_EVERY -16_DF .. _CRTDBG_CHECK_EVERY_1024_DF के लिए VC CRT हीप-चेक मैक्रोज़ का उपयोग कर सकते हैं ।


0

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

  • इस पर पुनरावृत्ति करते समय एक एसटीएल संग्रह से तत्वों को हटाना (मेरा मानना ​​है कि इन चीज़ों को पकड़ने के लिए विजुअल स्टूडियो में डीबग फ़्लैग हैं; मैंने इसे कोड समीक्षा के दौरान पकड़ा)
  • यह एक और अधिक जटिल है, मैं इसे चरणों में विभाजित करूंगा:
    • मूल C ++ थ्रेड से, प्रबंधित कोड में वापस कॉल करें
    • प्रबंधित भूमि में, Control.Invokeएक प्रबंधित ऑब्जेक्ट को कॉल करें और डिस्पोज़ करें जो उस मूल ऑब्जेक्ट को लपेटता है जिससे कॉलबैक संबंधित है।
    • चूंकि ऑब्जेक्ट अभी भी देशी धागे के अंदर जीवित है (यह कॉलबैक कॉल में तब तक अवरुद्ध रहेगा जब तक कि Control.Invokeसमाप्त न हो जाए)। मुझे स्पष्ट करना चाहिए कि मैं उपयोग करता हूं boost::thread, इसलिए मैं थ्रेड फ़ंक्शन के रूप में एक सदस्य फ़ंक्शन का उपयोग करता हूं।
    • समाधान : Control.BeginInvokeइसके बजाय (मेरा GUI Winforms के साथ बनाया गया है) ताकि ऑब्जेक्ट नष्ट होने से पहले देशी धागा समाप्त हो सके (कॉलबैक का उद्देश्य ठीक से सूचित कर रहा है कि धागा समाप्त हो गया है और ऑब्जेक्ट नष्ट हो सकता है)।

0

मुझे एक समान समस्या थी - और यह काफी अनियमित रूप से पॉप अप हुआ। शायद बिल्ड फ़ाइलों में कुछ भ्रष्ट था, लेकिन मैंने पहले प्रोजेक्ट को फिर से पुनर्निर्माण करके इसे ठीक करना समाप्त कर दिया।

तो दी गई अन्य प्रतिक्रियाओं के अलावा:

किस तरह की चीजें इन त्रुटियों का कारण बन सकती हैं? बिल्ड फ़ाइल में कुछ दूषित है।

मैं उन्हें कैसे डीबग करूं? परियोजना की सफाई और पुनर्निर्माण। यदि यह ठीक है, तो यह समस्या थी।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.