Refactor signal handling code: prepare for demangling names, handle SIGINT w/o backtrace, remove our own signal handler frames from backtrace

This commit is contained in:
Alexander Mai 2014-03-16 18:37:28 +01:00
parent 4cad45e084
commit c2a602a6bd
1 changed files with 134 additions and 28 deletions

View File

@ -35,6 +35,7 @@
#if defined(__GNUC__) #if defined(__GNUC__)
#define USE_UNIX_SIGNAL_HANDLING #define USE_UNIX_SIGNAL_HANDLING
#include <execinfo.h> #include <execinfo.h>
#include <cxxabi.h>
#endif #endif
#ifdef USE_UNIX_SIGNAL_HANDLING #ifdef USE_UNIX_SIGNAL_HANDLING
@ -179,45 +180,146 @@ int CppCheckExecutor::check(int argc, const char* const argv[])
} }
#if defined(USE_UNIX_SIGNAL_HANDLING) #if defined(USE_UNIX_SIGNAL_HANDLING)
extern "C" void MySignalHandler(int signo, siginfo_t *info, void *context);
/* (declare this list here, so it may be used in signal handlers in addition to main()) /* (declare this list here, so it may be used in signal handlers in addition to main())
* A list of signals available in ISO C * A list of signals available in ISO C
* Check out http://pubs.opengroup.org/onlinepubs/009695399/basedefs/signal.h.html * Check out http://pubs.opengroup.org/onlinepubs/009695399/basedefs/signal.h.html
* For now we only want to detect abnormal behaviour for a few selected signals: * For now we only want to detect abnormal behaviour for a few selected signals:
*/ */
static const int listofsignals[] = { struct Signaltype {
/* don't care: SIGABRT, */ int signalnumber;
SIGFPE, const char *signalname;
SIGILL, };
SIGINT, #define DECLARE_SIGNAL(x) {x, #x}
SIGSEGV, static const Signaltype listofsignals[] = {
/* don't care: SIGTERM */ // don't care: SIGABRT,
DECLARE_SIGNAL(SIGFPE),
DECLARE_SIGNAL(SIGILL),
DECLARE_SIGNAL(SIGINT),
DECLARE_SIGNAL(SIGSEGV),
// don't care: SIGTERM
}; };
static void print_stacktrace(FILE* f) // Simple helper function
template<typename T, int size>
int GetArrayLength(T(&)[size])
{
return size;
}
/*
* Try to print the callstack.
* That is very sensitive to the operating system, hardware, compiler and runtime!
*/
static void print_stacktrace(FILE* f, bool demangling)
{ {
#if defined(__GNUC__) #if defined(__GNUC__)
void *array[50]= {0}; void *array[50]= {0};
size_t size = backtrace(array, int(sizeof(array)/sizeof(array[0]))); const int depth = backtrace(array, (int)GetArrayLength(array));
char **strings = backtrace_symbols(array, (int)size); char **symbolstrings = backtrace_symbols(array, depth);
fprintf(f, "Callstack:\n"); if (symbolstrings) {
for (std::size_t i = 0; i < size; i++) { fprintf(f, "Callstack:\n");
fprintf(f, "%s\n", strings[i]); const int offset=3; // the first two entries are simply within our own exception handling code, third is within libc
for (int i = offset; i < depth; ++i) {
const char * const symbol = symbolstrings[i];
char * realname = nullptr;
const char * const firstBracket = strchr(symbol, '(');
if (demangling && firstBracket) {
const char * const plus = strchr(firstBracket, '+');
if (plus) {
char input_buffer[512]= {0};
strncpy(input_buffer, firstBracket+1, plus-firstBracket-1);
char output_buffer[1024]= {0};
size_t length = GetArrayLength(output_buffer);
int status=0;
realname = abi::__cxa_demangle(input_buffer, output_buffer, &length, &status); // non-NULL on success
}
}
fprintf(f, "%d. %s\n",
i-offset, (realname) ? realname : symbolstrings[i]);
}
free(symbolstrings);
} else {
fprintf(f, "Callstack could not be obtained\n");
} }
free(strings);
#endif #endif
} }
void MySignalHandler(int signo, siginfo_t * /*info*/, void * /*context*/) /*
* Simple mapping
*/
static const char *signal_name(int signo)
{ {
fprintf(stderr, "Internal error (caught signal %d). Please report this to the cppcheck developers!\n", for (size_t s=0; s<GetArrayLength(listofsignals); ++s) {
signo); if (listofsignals[s].signalnumber==signo)
print_stacktrace(stderr); return listofsignals[s].signalname;
}
return "";
}
/*
* Entry pointer for signal handlers
*/
static void CppcheckSignalHandler(int signo, siginfo_t * info, void * /*context*/)
{
const char * const signame=signal_name(signo);
bool bPrintCallstack=true;
switch (signo) {
case SIGILL:
fprintf(stderr, "Internal error (caught signal %d=%s at 0x%p)\n",
signo, signame, info->si_addr);
break;
case SIGFPE:
fprintf(stderr, "Internal error (caught signal %d=%s at 0x%p)\n",
signo, signame, info->si_addr);
break;
case SIGSEGV:
fprintf(stderr, "Internal error (caught signal %d=%s at 0x%p)\n",
signo, signame, info->si_addr);
break;
/*
case SIGBUS:
fprintf(stderr, "Internal error (caught signal %d=%s at 0x%p)\n",
signo, signame, info->si_addr);
break;
case SIGTRAP:
fprintf(stderr, "Internal error (caught signal %d=%s at 0x%p)\n",
signo, signame, info->si_addr);
break;
*/
case SIGINT:
bPrintCallstack=false;
break;
default:
fprintf(stderr, "Internal error (caught signal %d)\n",
signo);
break;
}
if (bPrintCallstack) {
print_stacktrace(stderr, false);
fprintf(stderr, "Please report this to the cppcheck developers!\n");
}
abort(); abort();
} }
#endif #endif
#ifdef _MSC_VER
/*
* Any evaluation of the information about the exception needs to be done here!
*/
static int filterException(int code, PEXCEPTION_POINTERS ex)
{
// TODO we should try to extract some information here.
return EXCEPTION_EXECUTE_HANDLER;
}
#endif
/**
* Signal/SEH handling
* TODO Check for multi-threading issues!
*
*/
int CppCheckExecutor::check_wrapper(CppCheck& cppCheck, int argc, const char* const argv[]) int CppCheckExecutor::check_wrapper(CppCheck& cppCheck, int argc, const char* const argv[])
{ {
#ifdef _MSC_VER #ifdef _MSC_VER
@ -226,17 +328,21 @@ int CppCheckExecutor::check_wrapper(CppCheck& cppCheck, int argc, const char* co
*/ */
return check_internal(cppCheck, argc, argv); return check_internal(cppCheck, argc, argv);
/* /*
} }
except() { __except(filterException(GetExceptionCode(), GetExceptionInformation())) {
return -1; // reporting to stdout may not be helpful within a GUI application..
} fprintf(stderr, "Internal error\n");
fprintf(stderr, "Please report this to the cppcheck developers!\n");
return -1;
}
*/ */
#elif defined(USE_UNIX_SIGNAL_HANDLING) #elif defined(USE_UNIX_SIGNAL_HANDLING)
struct sigaction act = {0}; struct sigaction act;
memset(&act, 0, sizeof(act));
act.sa_flags=SA_SIGINFO; act.sa_flags=SA_SIGINFO;
act.sa_sigaction=MySignalHandler; act.sa_sigaction=CppcheckSignalHandler;
for (std::size_t s=0; s<sizeof(listofsignals)/sizeof(listofsignals[0]); ++s) { for (std::size_t s=0; s<GetArrayLength(listofsignals); ++s) {
sigaction(listofsignals[s], &act, NULL); sigaction(listofsignals[s].signalnumber, &act, NULL);
} }
return check_internal(cppCheck, argc, argv); return check_internal(cppCheck, argc, argv);
#else #else