Improve exception handler: detect read or write on SIGSEGV (linux only), create more suitable core dump, reduce usage of fprintf()

This commit is contained in:
Alexander Mai 2014-11-14 23:40:53 +01:00
parent 149fe74d9d
commit 5786be99c5
1 changed files with 51 additions and 28 deletions

View File

@ -35,8 +35,14 @@
#if !defined(NO_UNIX_SIGNAL_HANDLING) && defined(__GNUC__) && !defined(__CYGWIN__) && !defined(__MINGW32__) && !defined(__OS2__) #if !defined(NO_UNIX_SIGNAL_HANDLING) && defined(__GNUC__) && !defined(__CYGWIN__) && !defined(__MINGW32__) && !defined(__OS2__)
#define USE_UNIX_SIGNAL_HANDLING #define USE_UNIX_SIGNAL_HANDLING
#include <signal.h>
#include <cstdio> #include <cstdio>
#include <signal.h>
#include <unistd.h>
#include <ucontext.h>
#ifdef __linux__
#include <sys/syscall.h>
#include <sys/types.h>
#endif
#endif #endif
#if !defined(NO_UNIX_BACKTRACE_SUPPORT) && defined(USE_UNIX_SIGNAL_HANDLING) && defined(__GNUC__) && !defined(__CYGWIN__) && !defined(__MINGW32__) && !defined(__NetBSD__) && !defined(__SVR4) #if !defined(NO_UNIX_BACKTRACE_SUPPORT) && defined(USE_UNIX_SIGNAL_HANDLING) && defined(__GNUC__) && !defined(__CYGWIN__) && !defined(__MINGW32__) && !defined(__NetBSD__) && !defined(__SVR4)
@ -296,9 +302,21 @@ static void print_stacktrace(FILE* f, bool demangling)
/* /*
* Entry pointer for signal handlers * Entry pointer for signal handlers
* It uses functions which are not safe to be called from a signal handler,
* but when ending up here something went terribly wrong anyway.
* And all which is left is just printing some information and terminate.
*/ */
static void CppcheckSignalHandler(int signo, siginfo_t * info, void * /*context*/) static void CppcheckSignalHandler(int signo, siginfo_t * info, void * context)
{ {
int type = -1;
pid_t killid = getpid();
const ucontext_t* uc = reinterpret_cast<const ucontext_t*>(context);
#ifdef __linux__
killid = (pid_t) syscall(SYS_gettid);
if (uc) {
type = (int)uc->uc_mcontext.gregs[REG_ERR] & 2;
}
#endif
const char * const signame = signal_name(signo); const char * const signame = signal_name(signo);
const char * const sigtext = strsignal(signo); const char * const sigtext = strsignal(signo);
bool bPrintCallstack=true; bool bPrintCallstack=true;
@ -311,22 +329,22 @@ static void CppcheckSignalHandler(int signo, siginfo_t * info, void * /*context*
case SIGBUS: case SIGBUS:
switch (info->si_code) { switch (info->si_code) {
case BUS_ADRALN: // invalid address alignment case BUS_ADRALN: // invalid address alignment
fprintf(f, " - BUS_ADRALN"); fputs(" - BUS_ADRALN", f);
break; break;
case BUS_ADRERR: // nonexistent physical address case BUS_ADRERR: // nonexistent physical address
fprintf(f, " - BUS_ADRERR"); fputs(" - BUS_ADRERR", f);
break; break;
case BUS_OBJERR: // object-specific hardware error case BUS_OBJERR: // object-specific hardware error
fprintf(f, " - BUS_OBJERR"); fputs(" - BUS_OBJERR", f);
break; break;
#ifdef BUS_MCEERR_AR #ifdef BUS_MCEERR_AR
case BUS_MCEERR_AR: // Hardware memory error consumed on a machine check; case BUS_MCEERR_AR: // Hardware memory error consumed on a machine check;
fprintf(f, " - BUS_MCEERR_AR"); fputs(" - BUS_MCEERR_AR", f);
break; break;
#endif #endif
#ifdef BUS_MCEERR_AO #ifdef BUS_MCEERR_AO
case BUS_MCEERR_AO: // Hardware memory error detected in process but not consumed case BUS_MCEERR_AO: // Hardware memory error detected in process but not consumed
fprintf(f, " - BUS_MCEERR_AO"); fputs(" - BUS_MCEERR_AO", f);
break; break;
#endif #endif
default: default:
@ -338,28 +356,28 @@ static void CppcheckSignalHandler(int signo, siginfo_t * info, void * /*context*
case SIGFPE: case SIGFPE:
switch (info->si_code) { switch (info->si_code) {
case FPE_INTDIV: // integer divide by zero case FPE_INTDIV: // integer divide by zero
fprintf(f, " - FPE_INTDIV"); fputs(" - FPE_INTDIV", f);
break; break;
case FPE_INTOVF: // integer overflow case FPE_INTOVF: // integer overflow
fprintf(f, " - FPE_INTOVF"); fputs(" - FPE_INTOVF", f);
break; break;
case FPE_FLTDIV: // floating-point divide by zero case FPE_FLTDIV: // floating-point divide by zero
fprintf(f, " - FPE_FLTDIV"); fputs(" - FPE_FLTDIV", f);
break; break;
case FPE_FLTOVF: // floating-point overflow case FPE_FLTOVF: // floating-point overflow
fprintf(f, " - FPE_FLTOVF"); fputs(" - FPE_FLTOVF", f);
break; break;
case FPE_FLTUND: // floating-point underflow case FPE_FLTUND: // floating-point underflow
fprintf(f, " - FPE_FLTUND"); fputs(" - FPE_FLTUND", f);
break; break;
case FPE_FLTRES: // floating-point inexact result case FPE_FLTRES: // floating-point inexact result
fprintf(f, " - FPE_FLTRES"); fputs(" - FPE_FLTRES", f);
break; break;
case FPE_FLTINV: // floating-point invalid operation case FPE_FLTINV: // floating-point invalid operation
fprintf(f, " - FPE_FLTINV"); fputs(" - FPE_FLTINV", f);
break; break;
case FPE_FLTSUB: // subscript out of range case FPE_FLTSUB: // subscript out of range
fprintf(f, " - FPE_FLTSUB"); fputs(" - FPE_FLTSUB", f);
break; break;
default: default:
break; break;
@ -370,28 +388,28 @@ static void CppcheckSignalHandler(int signo, siginfo_t * info, void * /*context*
case SIGILL: case SIGILL:
switch (info->si_code) { switch (info->si_code) {
case ILL_ILLOPC: // illegal opcode case ILL_ILLOPC: // illegal opcode
fprintf(f, " - ILL_ILLOPC"); fputs(" - ILL_ILLOPC", f);
break; break;
case ILL_ILLOPN: // illegal operand case ILL_ILLOPN: // illegal operand
fprintf(f, " - ILL_ILLOPN"); fputs(" - ILL_ILLOPN", f);
break; break;
case ILL_ILLADR: // illegal addressing mode case ILL_ILLADR: // illegal addressing mode
fprintf(f, " - ILL_ILLADR"); fputs(" - ILL_ILLADR", f);
break; break;
case ILL_ILLTRP: // illegal trap case ILL_ILLTRP: // illegal trap
fprintf(f, " - ILL_ILLTRP"); fputs(" - ILL_ILLTRP", f);
break; break;
case ILL_PRVOPC: // privileged opcode case ILL_PRVOPC: // privileged opcode
fprintf(f, " - ILL_PRVOPC"); fputs(" - ILL_PRVOPC", f);
break; break;
case ILL_PRVREG: // privileged register case ILL_PRVREG: // privileged register
fprintf(f, " - ILL_PRVREG"); fputs(" - ILL_PRVREG", f);
break; break;
case ILL_COPROC: // coprocessor error case ILL_COPROC: // coprocessor error
fprintf(f, " - ILL_COPROC"); fputs(" - ILL_COPROC", f);
break; break;
case ILL_BADSTK: // internal stack error case ILL_BADSTK: // internal stack error
fprintf(f, " - ILL_BADSTK"); fputs(" - ILL_BADSTK", f);
break; break;
default: default:
break; break;
@ -401,20 +419,22 @@ static void CppcheckSignalHandler(int signo, siginfo_t * info, void * /*context*
break; break;
case SIGINT: case SIGINT:
bPrintCallstack=false; bPrintCallstack=false;
fprintf(f, ".\n"); fputs(".\n", f);
break; break;
case SIGSEGV: case SIGSEGV:
switch (info->si_code) { switch (info->si_code) {
case SEGV_MAPERR: // address not mapped to object case SEGV_MAPERR: // address not mapped to object
fprintf(f, " - SEGV_MAPERR"); fputs(" - SEGV_MAPERR", f);
break; break;
case SEGV_ACCERR: // invalid permissions for mapped object case SEGV_ACCERR: // invalid permissions for mapped object
fprintf(f, " - SEGV_ACCERR"); fputs(" - SEGV_ACCERR", f);
break; break;
default: default:
break; break;
} }
fprintf(f, " (at 0x%p).\n", fprintf(f, " (%sat 0x%p).\n",
(type==-1)? "" :
(type==0) ? "reading " : "writing ",
info->si_addr); info->si_addr);
break; break;
default: default:
@ -425,7 +445,10 @@ static void CppcheckSignalHandler(int signo, siginfo_t * info, void * /*context*
print_stacktrace(f, true); print_stacktrace(f, true);
fputs("\nPlease report this to the cppcheck developers!\n", f); fputs("\nPlease report this to the cppcheck developers!\n", f);
} }
abort();
// now let the system proceed, shutdown and hopefully dump core for post-mortem analysis
signal(signo, SIG_DFL);
kill(killid, signo);
} }
#endif #endif