Sorununuzun giderilmesinde faydalı olabilecek bazı bilgiler burada
Bir istisna yakalanırsa, özel kütüphane işlevi std::terminate()
otomatik olarak çağrılır. Terminate aslında bir işlevin göstericisidir ve varsayılan değer Standart C kitaplığı işlevidir std::abort()
. Yakalanmamış bir istisna için temizleme yapılmazsa † , hiçbir yıkıcı çağrılmadığından bu sorunun hatalarının ayıklanmasında yardımcı olabilir .
† Çağrılmadan önce yığının çözülüp çözülmeyeceği uygulama tanımlıdır std::terminate()
.
Çağrısı abort()
, istisnanın nedenini belirlemek için analiz edilebilecek bir çekirdek dökümü oluşturmada genellikle yararlıdır. ulimit -c unlimited
(Linux) aracılığıyla temel dökümleri etkinleştirdiğinizden emin olun .
terminate()
Kullanarak kendi fonksiyonunuzu kurabilirsiniz std::set_terminate()
. Sonlandırma işleviniz için gdb'de bir kesme noktası ayarlayabilmelisiniz. Sen olabilir senin bir yığın geri izlemesi oluşturmak mümkün terminate()
fonksiyonu ve bu Geriye dönük izleme edebilir istisna yerini belirlemede yardımcı olur.
Üzerine kısa bir tartışma vardır yakalanmamış istisnalar içinde C Bruce Eckel en Düşünce ++, 2. Baskı yanı yararlı olabilir.
Yana terminate()
aramalar abort()
varsayılan (a neden olacaktır tarafından SIGABRT
varsayılan olarak sinyal), sen olabilir bir ayarlayabilirsiniz SIGABRT
işleyicisi ve daha sonra sinyal işleyici içinden bir yığın geri izlemesi yazdırmak . Bu geri izleme , istisnanın yerini belirlemede yardımcı olabilir .
Not: Diyorum may C ++ destekler yerel olmayan hata ayrı hata işleme dili yapıları kullanımı yoluyla taşıma ve sıradan kodundan kodunu haber verdiği. Yakalama bloğu, fırlatma noktasından farklı bir işlev / yöntemde bulunabilir ve genellikle bulunur. Ayrıca yorumlarda bana ( Dan teşekkürler ) yığının terminate()
çağrılmadan önce çözülüp çözülmediğinin uygulama tanımlı olduğu belirtildi.
Güncelleme: Bir terminate()
işlev kümesinde set_terminate()
ve bir sinyal işleyicide başka bir işlev kümesinde bir geri izleme oluşturan adında bir Linux test programını bir araya getirdim SIGABRT
. Her iki geri izleme de işlenmemiş özel durumun konumunu doğru şekilde gösterir.
Güncelleme 2: Sonlandırma içinde yakalanmamış istisnaları yakalama üzerine bir blog yazısı sayesinde birkaç yeni numara öğrendim; sonlandırma işleyicisi içinde yakalanmamış istisnanın yeniden atılması dahil. throw
Özel sonlandırma işleyicisindeki boş ifadenin GCC ile çalıştığını ve taşınabilir bir çözüm olmadığını unutmamak önemlidir .
Kod:
#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 {
static const bool SET_TERMINATE = std::set_terminate(my_terminate);
}
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;
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";
array[1] = caller_address;
char ** messages = backtrace_symbols(array, size);
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 {
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 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);
}
Çıktı:
my_terminate işlenmeyen istisna yakaladı. ne (): ÇALIŞMA SÜRESİ HATASI!
my_terminate backtrace 10 kare döndürdü
[bt]: (0) ./test(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]: (4) ./test(throw_exception__Fv+0x68) [0x8049008]
[bt]: (5) ./test(foo2__Fv+0xb) [0x8049043]
[bt]: (6) ./test(foo1__Fv+0xb) [0x8049057]
[bt]: (7) ./test(main+0xc1) [0x8049121]
[bt]: (8) ./test(__libc_start_main+0x95) [0x42017589]
[bt]: (9) ./test(__eh_alloc+0x3d) [0x8048b21]
sinyal 6 (Durduruldu), adres 0x42029331'den 0x1239
crit_err_hdlr backtrace 13 kare döndürdü
[bt]: (1) ./test(kill+0x11) [0x42029331]
[bt]: (2) ./test(abort+0x16e) [0x4202a8c2]
[bt]: (3) ./test [0x8048f9f]
[bt]: (4) /usr/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]: (7) ./test(throw_exception__Fv+0x68) [0x8049008]
[bt]: (8) ./test(foo2__Fv+0xb) [0x8049043]
[bt]: (9) ./test(foo1__Fv+0xb) [0x8049057]
[bt]: (10) ./test(main+0xc1) [0x8049121]
[bt]: (11) ./test(__libc_start_main+0x95) [0x42017589]
[bt]: (12) ./test(__eh_alloc+0x3d) [0x8048b21]