यह कैसे निर्धारित किया जाता है कि गलती उस कोड में कहां है जो एक विभाजन गलती का कारण बनता है ?
क्या मेरा कंपाइलर ( gcc
) प्रोग्राम में गलती का स्थान दिखा सकता है ?
यह कैसे निर्धारित किया जाता है कि गलती उस कोड में कहां है जो एक विभाजन गलती का कारण बनता है ?
क्या मेरा कंपाइलर ( gcc
) प्रोग्राम में गलती का स्थान दिखा सकता है ?
जवाबों:
GCC ऐसा नहीं कर सकता है लेकिन GDB ( डिबगर ) निश्चित रूप से कर सकता है। आप -g
इस तरह से स्विच का उपयोग कर प्रोग्राम संकलित करें:
gcc program.c -g
फिर gdb का उपयोग करें:
$ gdb ./a.out
(gdb) run
<segfault happens here>
(gdb) backtrace
<offending code is shown here>
GDB के साथ आरंभ करने के लिए यहां एक अच्छा ट्यूटोरियल है।
जहां सेगफॉल्ट होता है, आमतौर पर यह केवल एक सुराग होता है कि "गलती का कारण क्या होता है" यह कोड में है। दी गई जगह जरूरी नहीं है कि जहां समस्या रहती है।
bt
लिए एक आशुलिपि के रूप में उपयोग करें backtrace
।
इसके अलावा, आप valgrind
एक कोशिश दे सकते हैं : यदि आप इंस्टॉल करते हैं valgrind
और चलाते हैं
valgrind --leak-check=full <program>
तब यह आपके प्रोग्राम को चलाएगा और किसी भी सेगफॉल्ट के लिए स्टैक के निशान को प्रदर्शित करेगा, साथ ही किसी भी अवैध मेमोरी को पढ़ता है या लिखता है और मेमोरी लीक करता है। यह वास्तव में काफी उपयोगी है।
--leak-check=full
segfaults को डीबग करने में मदद नहीं करेगा। यह केवल मेमोरी लीक डिबगिंग के लिए उपयोगी है।
आप कोर डंप का उपयोग भी कर सकते हैं और फिर इसे gdb के साथ जांच सकते हैं। उपयोगी जानकारी प्राप्त करने के लिए आपको -g
ध्वज के साथ संकलन करने की भी आवश्यकता है ।
जब भी आपको संदेश मिले:
Segmentation fault (core dumped)
एक कोर फ़ाइल को आपकी वर्तमान निर्देशिका में लिखा जाता है। और आप इसे कमांड से जांच सकते हैं
gdb your_program core_file
जब प्रोग्राम क्रैश हो जाता है तो फ़ाइल में मेमोरी की स्थिति होती है। एक कोर डंप आपके सॉफ्टवेयर की तैनाती के दौरान उपयोगी हो सकता है।
सुनिश्चित करें कि आपका सिस्टम कोर डंप फ़ाइल आकार को शून्य पर सेट नहीं करता है। आप इसे असीमित के साथ सेट कर सकते हैं:
ulimit -c unlimited
हालांकि सावधान! कि कोर डंप विशाल हो सकते हैं।
ऐसे कई उपकरण उपलब्ध हैं जो विभाजन दोषों को डीबग करने में मदद करते हैं और मैं अपने पसंदीदा टूल को सूची में जोड़ना चाहूंगा: एड्रेस सैनिटाइज़र (अक्सर संक्षिप्त एएसएएन) ।
आधुनिक कंपाइलर काम के -fsanitize=address
झंडे के साथ आते हैं , कुछ संकलन समय जोड़ते हैं और ओवरहेड रन करते हैं जो अधिक त्रुटि जाँच करता है।
प्रलेखन के अनुसार इन चेक में डिफ़ॉल्ट रूप से विभाजन दोषों को पकड़ना शामिल है। यहां लाभ यह है कि आपको जीडीबी के आउटपुट के समान स्टैक ट्रेस मिलता है, लेकिन डिबगर के अंदर प्रोग्राम को चलाने के बिना। एक उदाहरण:
int main() {
volatile int *ptr = (int*)0;
*ptr = 0;
}
$ gcc -g -fsanitize=address main.c
$ ./a.out
AddressSanitizer:DEADLYSIGNAL
=================================================================
==4848==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x5654348db1a0 bp 0x7ffc05e39240 sp 0x7ffc05e39230 T0)
==4848==The signal is caused by a WRITE memory access.
==4848==Hint: address points to the zero page.
#0 0x5654348db19f in main /tmp/tmp.s3gwjqb8zT/main.c:3
#1 0x7f0e5a052b6a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x26b6a)
#2 0x5654348db099 in _start (/tmp/tmp.s3gwjqb8zT/a.out+0x1099)
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV /tmp/tmp.s3gwjqb8zT/main.c:3 in main
==4848==ABORTING
आउटपुट gdb के उत्पादन की तुलना में थोड़ा अधिक जटिल है, लेकिन अपसाइड होते हैं:
स्टैक ट्रेस प्राप्त करने के लिए समस्या को पुन: उत्पन्न करने की कोई आवश्यकता नहीं है। बस विकास के दौरान ध्वज को सक्षम करना पर्याप्त है।
ASANs केवल विभाजन दोषों की तुलना में बहुत अधिक पकड़ते हैं। भले ही वह स्मृति क्षेत्र इस प्रक्रिया के लिए सुलभ था, भले ही सीमा से बाहर कई को पकड़ा जाएगा।
Ang यही क्लैंग 3.1+ और GCC 4.8+ है ।
कोर डंप के बारे में लुकास का जवाब अच्छा है। मेरे .cshrc में मेरे पास है:
alias core 'ls -lt core; echo where | gdb -core=core -silent; echo "\n"'
'कोर' दर्ज करके बैकट्रेस प्रदर्शित करने के लिए। और तारीख की मोहर, यह सुनिश्चित करने के लिए कि मैं सही फ़ाइल देख रहा हूँ :(।
जोड़ा गया : यदि कोई स्टैक करप्ट बग है, तो कोर डंप पर लागू बैकट्रेस अक्सर कचरा होता है। इस मामले में, जीडीबी के भीतर कार्यक्रम को चलाने से बेहतर परिणाम मिल सकते हैं, जैसा कि स्वीकृत उत्तर के अनुसार (दोष आसानी से प्रतिलिपि प्रस्तुत करने योग्य है)। और कई प्रक्रियाओं को एक साथ कोर डंपिंग से भी सावधान रहें; कुछ OS कोर फाइल के नाम में PID जोड़ते हैं।
ulimit -c unlimited
पहली जगह में कोर डंप को सक्षम करने के लिए मत भूलना ।
उपरोक्त सभी उत्तर सही और अनुशंसित हैं; यह उत्तर केवल एक अंतिम उपाय के रूप में अभिप्रेत है यदि उपरोक्त किसी भी दृष्टिकोण का उपयोग नहीं किया जा सकता है।
यदि बाकी सभी विफल हो जाते हैं, तो आप हमेशा अपने अस्थायी डिबग-प्रिंट स्टेटमेंट (जैसे fprintf(stderr, "CHECKPOINT REACHED @ %s:%i\n", __FILE__, __LINE__);
) के साथ अपने कार्यक्रम को फिर से जोड़ सकते हैं, जिसे आप अपने कोड के प्रासंगिक भागों के रूप में मानते हैं। फिर प्रोग्राम को चलाएं, और देखें कि क्रैश होने से ठीक पहले आखिरी डिबग-प्रिंट क्या छपा था - आपको पता है कि आपका प्रोग्राम अभी तक मिला है, इसलिए क्रैश उस बिंदु के बाद हुआ होगा। डिबग-प्रिंट जोड़ें, हटाएं, पुन: परीक्षण करें, और फिर से परीक्षण चलाएं, जब तक कि आपने इसे कोड की एकल पंक्ति तक सीमित न कर दिया हो। उस बिंदु पर आप बग को ठीक कर सकते हैं और सभी अस्थायी डिबग-प्रिंट निकाल सकते हैं।
यह काफी थकाऊ है, लेकिन इसके बारे में कहीं भी काम करने का फायदा है - केवल एक बार ऐसा नहीं हो सकता है यदि आपके पास किसी कारण से स्टडआउट या स्टेडर तक पहुंच नहीं है, या यदि आप जिस बग को ठीक करने की कोशिश कर रहे हैं वह एक दौड़ है -कंडिशन जिसका व्यवहार कार्यक्रम के समय में परिवर्तन होता है (चूंकि डिबग-प्रिंट प्रोग्राम को धीमा कर देगा और इसके समय को बदल देगा)