C++ कोड की डिबगिंग: कैसे segmentation fault से डरना छोड़ें और GDB से प्यार करें
\n\nक्या आपने कभी किसी बग को खोजने में तीन घंटे बिताए हैं, जो अंततः switch में भूला हुआ break या if के बाद अतिरिक्त ; निकला? यदि हाँ — तो क्लब में आपका स्वागत है। C++ डिबगिंग एक कला है, जो मसोकिज़्म की सीमा पर है। लेकिन, किसी भी कला की तरह, इसे सीखा जा सकता है।
इस लेख में हम सिर्फ "GDB कैसे चलाएँ" नहीं, बल्कि वास्तविक तकनीकों पर चर्चा करेंगे जो डिबगिंग को कॉफी के आधार पर भविष्यवाणी करने से शर्लक होम्स के जासूसी काम में बदल देती हैं। हम आधुनिक सैनिटाइज़र, रिवर्स डिबगिंग और यहाँ तक कि उस बग को पकड़ने के बारे में भी बात करेंगे जो "केवल शुक्रवार दोपहर के बाद" दिखाई देता है।
\n\n1. क्लासिक शैली: GDB और LLDB
\n\nचलिए बुनियादी बातों से शुरू करते हैं। GNU Debugger (GDB) और इसका प्रतियोगी LLDB डिबगर के स्विस आर्मी चाकू हैं। लेकिन अधिकांश लोग इनका उपयोग केवल 10% क्षमता पर करते हैं। आइए इसे ठीक करें।
\n\nशर्तों के साथ ब्रेकपॉइंट
\n\nआप 10,000 पुनरावृत्तियों वाले लूप में एक ब्रेकपॉइंट लगाते हैं और 9999 बार continue दबाते हैं? रुक जाइए। सशर्त ब्रेकपॉइंट का उपयोग करें:
(gdb) break main.cpp:42 if i == 5000\n\nयह जीवन के घंटे बचाएगा। LLDB में सिंटैक्स समान है:
\n\n(lldb) breakpoint set --file main.cpp --line 42 --condition 'i == 5000'\n\nWatchpoints — वेरिएबल बदलने को पकड़ें
\n\nकल्पना करें: आपके पास एक वेरिएबल है जो अज्ञात स्थान पर बदलता है। एक watchpoint लगाएँ:
\n\n(gdb) watch my_variable\n(gdb) rwatch my_variable # पढ़ने पर ट्रिगर होगा\n(gdb) awatch my_variable # पढ़ने और लिखने दोनों पर ट्रिगर होगा\n\nअब प्रोग्राम ठीक उसी समय रुकेगा जब कोई आपके वेरिएबल को छूएगा। जादू, है ना?
\n\n2. Reverse Debugging: समय यात्रा
\n\nप्रोग्रामर का सबसे बुरा सपना: प्रोग्राम क्रैश हो गया, लेकिन आप नहीं जानते कि वह इस स्थिति तक कैसे पहुँचा। रिवर्स डिबगिंग (उल्टी डिबगिंग) आपको निष्पादन को "पीछे" करने की अनुमति देती है।
\n\nGDB में इसके लिए record समर्थन आवश्यक है:
(gdb) record\n(gdb) continue\n... प्रोग्राम क्रैश हुआ ...\n(gdb) reverse-step # एक कदम पीछे\n(gdb) reverse-continue # उल्टी दिशा में जारी रखें\n\nवाणिज्यिक उपकरणों (जैसे UndoDB या Mozilla का rr) में यह और भी अच्छा काम करता है। rr (Record and Replay) एक मुफ्त उपकरण है जो प्रोग्राम के निष्पादन को रिकॉर्ड करता है, और फिर इसे बार-बार चलाने की अनुमति देता है:
\n\n$ rr record ./my_program\n$ rr replay\n(gdb) continue\n... क्रैश स्थान मिला ...\n(gdb) reverse-step\n\nसुझाव: डेटा रेस (data races) खोजने के लिए rr का उपयोग करें — यह प्रत्येक निष्पादन को नियतात्मक रूप से पुन: उत्पन्न करता है।
3. सैनिटाइज़र: undefined behavior के खिलाफ टीका
\n\nआधुनिक C++ (Clang और GCC 4.8+ से शुरू) में अंतर्निहित उपकरण हैं जिनके बारे में हमारे पिताओं ने कभी सपना नहीं देखा था। AddressSanitizer (ASan), UndefinedBehaviorSanitizer (UBSan) और ThreadSanitizer (TSan) — ये must-have हैं।
\n\nउदाहरण: मेमोरी लीक पकड़ना
\n\n// compile with: g++ -fsanitize=address -g main.cpp -o main\n#include <iostream>\n\nvoid leak() {\n int* p = new int(42);\n // delete भूल गए\n}\n\nint main() {\n leak();\n return 0;\n}\n\nचलाएँ — और देखें:
\n\n==12345==ERROR: LeakSanitizer: detected memory leaks\n\nDirect leak of 4 byte(s) in 1 object(s) allocated from:\n #0 0x7f... in operator new(unsigned long)\n #1 0x400... in leak() main.cpp:5\n #2 0x400... in main main.cpp:10\n\nASan सटीक कॉल स्टैक दिखाएगा, जिसमें वह लाइन नंबर भी शामिल है जहाँ आवंटन हुआ था। अब और नहीं "कहीं मेमोरी लीक हो रही है"।
\n\nUBSan अपरिभाषित व्यवहार के खिलाफ
\n\n// compile with: g++ -fsanitize=undefined -g main.cpp\nint main() {\n int x = INT_M