यहाँ कुछ जानकारी है जो आपकी समस्या को डीबग करने में काम आ सकती है
यदि अपवाद अपवाद नहीं है, तो विशेष लाइब्रेरी फ़ंक्शन std::terminate()
को स्वचालित रूप से कहा जाता है। समाप्त करना वास्तव में एक फ़ंक्शन का सूचक है और डिफ़ॉल्ट मान मानक सी लाइब्रेरी फ़ंक्शन है std::abort()
। कोई सफाई न आया हुआ अपवाद के लिए हो तो † , यह हो सकता है वास्तव में इस समस्या को दूर करने के रूप में कोई विनाशकर्ता कहा जाता है में सहायक हो।
† यह कार्यान्वयन-परिभाषित है कि क्या स्टैक को पहले std::terminate()
कहा गया है या नहीं ।
एक कॉल abort()
अक्सर एक कोर डंप पैदा करने में उपयोगी होता है जिसे अपवाद का कारण निर्धारित करने के लिए विश्लेषण किया जा सकता है। सुनिश्चित करें कि आप ulimit -c unlimited
(Linux) के माध्यम से कोर डंप सक्षम करें ।
आप अपने खुद के terminate()
फ़ंक्शन का उपयोग करके स्थापित कर सकते हैं std::set_terminate()
। आपको gdb में अपने समाप्ति कार्य पर एक ब्रेकपॉइंट सेट करने में सक्षम होना चाहिए। आप अपने फ़ंक्शन से एक स्टैक बैकट्रेस उत्पन्न करने में सक्षम हो सकते हैं terminate()
और यह बैकट्रेस अपवाद के स्थान की पहचान करने में मदद कर सकता है।
ब्रूस एकेल की थिंकिंग सी +, 2 डी एड में अनकैप्ड अपवादों पर एक संक्षिप्त चर्चा है जो सहायक भी हो सकती है।
चूंकि डिफ़ॉल्ट रूप से terminate()
कॉल abort()
(जो डिफ़ॉल्ट रूप से एक SIGABRT
सिग्नल का कारण होगा ), आप एक हैंडलर सेट करने में सक्षम हो सकते हैं SIGABRT
और फिर सिग्नल हैंडलर के भीतर से एक स्टैक बैकट्रेस प्रिंट कर सकते हैं । यह बैकट्रेस अपवाद के स्थान की पहचान करने में मदद कर सकता है।
नोट: मैं कह सकता हूं क्योंकि C ++ गैर-स्थानीय त्रुटि हैंडलिंग का समर्थन करता है, भाषा निर्माण के उपयोग के माध्यम से सामान्य कोड से त्रुटि हैंडलिंग और रिपोर्टिंग कोड को अलग करने के लिए। पकड़ ब्लॉक हो सकता है, और अक्सर, फेंकने के बिंदु से अलग फ़ंक्शन / विधि में स्थित होता है। यह भी मुझे टिप्पणियों में धन्यवाद दिया गया है (धन्यवाद डैन ) कि यह कार्यान्वयन-परिभाषित है कि क्या स्टैक अनबाउंड है या नहीं, terminate()
यह कहा जाता है।
अद्यतन: मैंने एक साथ एक लिनक्स टेस्ट प्रोग्राम को फेंक दिया जो कि एक terminate()
फ़ंक्शन के माध्यम से set_terminate()
और दूसरे के लिए सिग्नल हैंडलर में एक बैकट्रेस उत्पन्न करता है SIGABRT
। दोनों backtraces बिना किसी अपवाद के स्थान को सही ढंग से दिखाते हैं।
अद्यतन 2: समाप्ति के भीतर पकड़े गए अपवादों को पकड़ने पर एक ब्लॉग पोस्ट के लिए धन्यवाद , मैंने कुछ नई तरकीबें सीखीं; समाप्त हैंडलर के भीतर बिना किसी अपवाद के पुन: फेंकने सहित। यह ध्यान रखना महत्वपूर्ण है कि throw
कस्टम टर्मिनेट हैंडलर के भीतर खाली स्टेटमेंट GCC के साथ काम करता है और यह एक पोर्टेबल समाधान नहीं है।
कोड:
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#ifndef __USE_GNU
#define __USE_GNU
#endif
#include <execinfo.h>
#include <signal.h>
#include <string.h>
#include <iostream>
#include <cstdlib>
#include <stdexcept>
void my_terminate(void);
namespace {
// invoke set_terminate as part of global constant initialization
static const bool SET_TERMINATE = std::set_terminate(my_terminate);
}
// This structure mirrors the one found in /usr/include/asm/ucontext.h
typedef struct _sig_ucontext {
unsigned long uc_flags;
struct ucontext *uc_link;
stack_t uc_stack;
struct sigcontext uc_mcontext;
sigset_t uc_sigmask;
} sig_ucontext_t;
void crit_err_hdlr(int sig_num, siginfo_t * info, void * ucontext) {
sig_ucontext_t * uc = (sig_ucontext_t *)ucontext;
// Get the address at the time the signal was raised from the EIP (x86)
void * caller_address = (void *) uc->uc_mcontext.eip;
std::cerr << "signal " << sig_num
<< " (" << strsignal(sig_num) << "), address is "
<< info->si_addr << " from "
<< caller_address << std::endl;
void * array[50];
int size = backtrace(array, 50);
std::cerr << __FUNCTION__ << " backtrace returned "
<< size << " frames\n\n";
// overwrite sigaction with caller's address
array[1] = caller_address;
char ** messages = backtrace_symbols(array, size);
// skip first stack frame (points here)
for (int i = 1; i < size && messages != NULL; ++i) {
std::cerr << "[bt]: (" << i << ") " << messages[i] << std::endl;
}
std::cerr << std::endl;
free(messages);
exit(EXIT_FAILURE);
}
void my_terminate() {
static bool tried_throw = false;
try {
// try once to re-throw currently active exception
if (!tried_throw++) throw;
}
catch (const std::exception &e) {
std::cerr << __FUNCTION__ << " caught unhandled exception. what(): "
<< e.what() << std::endl;
}
catch (...) {
std::cerr << __FUNCTION__ << " caught unknown/unhandled exception."
<< std::endl;
}
void * array[50];
int size = backtrace(array, 50);
std::cerr << __FUNCTION__ << " backtrace returned "
<< size << " frames\n\n";
char ** messages = backtrace_symbols(array, size);
for (int i = 0; i < size && messages != NULL; ++i) {
std::cerr << "[bt]: (" << i << ") " << messages[i] << std::endl;
}
std::cerr << std::endl;
free(messages);
abort();
}
int throw_exception() {
// throw an unhandled runtime error
throw std::runtime_error("RUNTIME ERROR!");
return 0;
}
int foo2() {
throw_exception();
return 0;
}
int foo1() {
foo2();
return 0;
}
int main(int argc, char ** argv) {
struct sigaction sigact;
sigact.sa_sigaction = crit_err_hdlr;
sigact.sa_flags = SA_RESTART | SA_SIGINFO;
if (sigaction(SIGABRT, &sigact, (struct sigaction *)NULL) != 0) {
std::cerr << "error setting handler for signal " << SIGABRT
<< " (" << strsignal(SIGABRT) << ")\n";
exit(EXIT_FAILURE);
}
foo1();
exit(EXIT_SUCCESS);
}
आउटपुट:
my_terminate ने बिना किसी अपवाद के पकड़ा। क्या (): RUNTIME ERROR!
my_terminate backtrace में 10 फ़्रेम वापस आए
[bt]: (०) ।/estest(my_terminate__Fv+0x1a) [0x8048e52]
[bt]: (1) /usr/lib/libstdc++-libc6.2-2.so.3 [0x40045baa]
[bt]: (2) /usr/lib/libstdc++-libc6.2-2.so.3 [0x400468e5]
[bt]: (3) /usr/lib/libstdc++-libc6.2-2.so.3(__rethrow+0xaf) [0x40046bdf]
[bt]: (४) ./estest(throw_exception__Fv+0x68) [०x ]०४ ९ ४x]
[bt]: (५) ./estest(foo2__Fv+0xb) [0x8049043]
[bt]: (६) ./estest(foo1__Fv+0xb) [0x8049057]
[bt]: (।) ./test(main+0xc1) [0x8049121]
[bt]: (।) ./test(__libc_start_main+0x95) [0x42017589]
[bt]: (९) ./test(__eh_alloc+0x3d) [0x80bb21]
सिग्नल 6 (निरस्त), पता 0x2029331 से 0x1239 है
crit_err_hdlr बैकट्रेस ने 13 फ़्रेम वापस किए
[bt]: (१) ./test(kill+0x11) [0x42029331]
[bt]: (2)। /est(abort+0x16e) [0x4202a8c2]
[bt]: (3) ./est [0x8048f9f]
[bt]: (४) /rr/lib/libstdc++-libc6.2-2.so.3 [0x40045baa]
[bt]: (5) /usr/lib/libstdc++-libc6.2-2.so.3 [0x400468e5]
[bt]: (6) /usr/lib/libstdc++-libc6.2-2.so.3(__rethrow+0xaf) [0x40046bdf]
[bt]: (।) ./test(throw_exception__Fv+0x68) [०x ]०४ ९ ४x]
[bt]: (।) ./estest(foo2__Fv+0xb) [0x8049043]
[bt]: (9) ./estest(foo1__Fv+0xb) [0x8049057]
[bt]: (१०) ./test(main+0xc1) [0x8049121]
[bt]: (११) ./test(__libc_start_main+0x95) [0x42017589]
[bt]: (१२) ./estest(__eh_alloc+0x3d) [0x80bb21]