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:
parent
4cad45e084
commit
c2a602a6bd
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue