Signal handling: Don't mix sigaction and signal. SIGUSR1 can be used to print current callstack, SIGUSR2 is being ignored. Minor refactoring

This commit is contained in:
Alexander Mai 2017-06-06 20:56:59 +02:00
parent 0967700f4b
commit 9da28d5f4c
1 changed files with 38 additions and 30 deletions

View File

@ -211,8 +211,9 @@ std::size_t GetArrayLength(const T(&)[size])
#if defined(USE_UNIX_SIGNAL_HANDLING) #if defined(USE_UNIX_SIGNAL_HANDLING)
/* /*
* Try to print the callstack. * Try to print the callstack.
* That is very sensitive to the operating system, hardware, compiler and runtime! * That is very sensitive to the operating system, hardware, compiler and runtime.
* The code is not meant for production environment, it's using functions not whitelisted for usage in a signal handler function. * The code is not meant for production environment!
* One reason is named first: it's using functions not whitelisted for usage in a signal handler function.
*/ */
static void print_stacktrace(FILE* output, bool demangling, int maxdepth, bool lowMem) static void print_stacktrace(FILE* output, bool demangling, int maxdepth, bool lowMem)
{ {
@ -220,8 +221,8 @@ static void print_stacktrace(FILE* output, bool demangling, int maxdepth, bool l
// 32 vs. 64bit // 32 vs. 64bit
#define ADDRESSDISPLAYLENGTH ((sizeof(long)==8)?12:8) #define ADDRESSDISPLAYLENGTH ((sizeof(long)==8)?12:8)
const int fd = fileno(output); const int fd = fileno(output);
void *array[32]= {0}; // the less resources the better... void *callstackArray[32]= {0}; // the less resources the better...
const int currentdepth = backtrace(array, (int)GetArrayLength(array)); const int currentdepth = backtrace(callstackArray, (int)GetArrayLength(callstackArray));
const int offset=2; // some entries on top are within our own exception handling code or libc const int offset=2; // some entries on top are within our own exception handling code or libc
if (maxdepth<0) if (maxdepth<0)
maxdepth=currentdepth-offset; maxdepth=currentdepth-offset;
@ -229,17 +230,16 @@ static void print_stacktrace(FILE* output, bool demangling, int maxdepth, bool l
maxdepth = std::min(maxdepth, currentdepth); maxdepth = std::min(maxdepth, currentdepth);
if (lowMem) { if (lowMem) {
fputs("Callstack (symbols only):\n", output); fputs("Callstack (symbols only):\n", output);
backtrace_symbols_fd(array+offset, maxdepth, fd); backtrace_symbols_fd(callstackArray+offset, maxdepth, fd);
fflush(output);
} else { } else {
char **symbolstrings = backtrace_symbols(array, currentdepth); char **symbolStringList = backtrace_symbols(callstackArray, currentdepth);
if (symbolstrings) { if (symbolStringList) {
fputs("Callstack:\n", output); fputs("Callstack:\n", output);
for (int i = offset; i < maxdepth; ++i) { for (int i = offset; i < maxdepth; ++i) {
const char * const symbol = symbolstrings[i]; const char * const symbolString = symbolStringList[i];
char * realname = nullptr; char * realnameString = nullptr;
const char * const firstBracketName = strchr(symbol, '('); const char * const firstBracketName = strchr(symbolString, '(');
const char * const firstBracketAddress = strchr(symbol, '['); const char * const firstBracketAddress = strchr(symbolString, '[');
const char * const secondBracketAddress = strchr(firstBracketAddress, ']'); const char * const secondBracketAddress = strchr(firstBracketAddress, ']');
const char * const beginAddress = firstBracketAddress+3; const char * const beginAddress = firstBracketAddress+3;
const int addressLen = int(secondBracketAddress-beginAddress); const int addressLen = int(secondBracketAddress-beginAddress);
@ -247,12 +247,14 @@ static void print_stacktrace(FILE* output, bool demangling, int maxdepth, bool l
if (demangling && firstBracketName) { if (demangling && firstBracketName) {
const char * const plus = strchr(firstBracketName, '+'); const char * const plus = strchr(firstBracketName, '+');
if (plus && (plus>(firstBracketName+1))) { if (plus && (plus>(firstBracketName+1))) {
char input_buffer[512]= {0}; char input_buffer[1024]= {0};
strncpy(input_buffer, firstBracketName+1, plus-firstBracketName-1); strncpy(input_buffer, firstBracketName+1, plus-firstBracketName-1);
char output_buffer[1024]= {0}; char output_buffer[2048]= {0};
size_t length = GetArrayLength(output_buffer); size_t length = GetArrayLength(output_buffer);
int status=0; int status=0;
realname = abi::__cxa_demangle(input_buffer, output_buffer, &length, &status); // non-NULL on success // We're violating the specification - passing stack address instead of malloc'ed heap.
// Benefit is that no further heap is required, while there is sufficient stack...
realnameString = abi::__cxa_demangle(input_buffer, output_buffer, &length, &status); // non-NULL on success
} }
} }
const int ordinal=i-offset; const int ordinal=i-offset;
@ -261,17 +263,17 @@ static void print_stacktrace(FILE* output, bool demangling, int maxdepth, bool l
if (padLen>0) if (padLen>0)
fprintf(output, "%0*d", fprintf(output, "%0*d",
padLen, 0); padLen, 0);
if (realname) { if (realnameString) {
fprintf(output, "%.*s in %s\n", fprintf(output, "%.*s in %s\n",
(int)(secondBracketAddress-firstBracketAddress-3), firstBracketAddress+3, (int)(secondBracketAddress-firstBracketAddress-3), firstBracketAddress+3,
realname); realnameString);
} else { } else {
fprintf(output, "%.*s in %.*s\n", fprintf(output, "%.*s in %.*s\n",
(int)(secondBracketAddress-firstBracketAddress-3), firstBracketAddress+3, (int)(secondBracketAddress-firstBracketAddress-3), firstBracketAddress+3,
(int)(firstBracketAddress-symbol), symbol); (int)(firstBracketAddress-symbolString), symbolString);
} }
} }
free(symbolstrings); free(symbolStringList);
} else { } else {
fputs("Callstack could not be obtained\n", output); fputs("Callstack could not be obtained\n", output);
} }
@ -319,7 +321,7 @@ static const Signalmap_t listofsignals = make_container< Signalmap_t > ()
DECLARE_SIGNAL(SIGSYS) DECLARE_SIGNAL(SIGSYS)
// don't care: SIGTERM // don't care: SIGTERM
DECLARE_SIGNAL(SIGUSR1) DECLARE_SIGNAL(SIGUSR1)
DECLARE_SIGNAL(SIGUSR2) //DECLARE_SIGNAL(SIGUSR2) no usage currently
; ;
#undef DECLARE_SIGNAL #undef DECLARE_SIGNAL
/* /*
@ -342,10 +344,11 @@ static void CppcheckSignalHandler(int signo, siginfo_t * info, void * context)
#endif #endif
const Signalmap_t::const_iterator it=listofsignals.find(signo); const Signalmap_t::const_iterator it=listofsignals.find(signo);
const char * const signame = (it==listofsignals.end()) ? "unknown" : it->second.c_str(); const char * const signame = (it==listofsignals.end()) ? "unknown" : it->second.c_str();
bool printCallstack=true; bool printCallstack=true; // try to print a callstack?
bool lowMem=false; bool lowMem=false; // was low-memory condition detected?
bool unexpectedSignal=true; bool unexpectedSignal=true; // unexpected indicates things didn't go as they should...
const bool isaddressonstack = IsAddressOnStack(info->si_addr); bool terminate=true; // exit process/thread
const bool isAddressOnStack = IsAddressOnStack(info->si_addr);
FILE* output = CppCheckExecutor::getExceptionOutput(); FILE* output = CppCheckExecutor::getExceptionOutput();
switch (signo) { switch (signo) {
case SIGABRT: case SIGABRT:
@ -450,7 +453,7 @@ static void CppcheckSignalHandler(int signo, siginfo_t * info, void * context)
} }
fprintf(output, " (at 0x%lx).%s\n", fprintf(output, " (at 0x%lx).%s\n",
(unsigned long)info->si_addr, (unsigned long)info->si_addr,
(isaddressonstack)?" Stackoverflow?":""); (isAddressOnStack)?" Stackoverflow?":"");
break; break;
case SIGINT: case SIGINT:
unexpectedSignal=false; // legal usage: interrupt application via CTRL-C unexpectedSignal=false; // legal usage: interrupt application via CTRL-C
@ -476,14 +479,14 @@ static void CppcheckSignalHandler(int signo, siginfo_t * info, void * context)
(type==-1)? "" : (type==-1)? "" :
(type==0) ? "reading " : "writing ", (type==0) ? "reading " : "writing ",
(unsigned long)info->si_addr, (unsigned long)info->si_addr,
(isaddressonstack)?" Stackoverflow?":"" (isAddressOnStack)?" Stackoverflow?":""
); );
break; break;
case SIGUSR1: case SIGUSR1:
case SIGUSR2:
fputs("cppcheck received signal ", output); fputs("cppcheck received signal ", output);
fputs(signame, output); fputs(signame, output);
fputs(".\n", output); fputs(".\n", output);
terminate=false;
break; break;
default: default:
fputs("Internal error: cppcheck received signal ", output); fputs("Internal error: cppcheck received signal ", output);
@ -499,9 +502,14 @@ static void CppcheckSignalHandler(int signo, siginfo_t * info, void * context)
} }
fflush(output); fflush(output);
// now let things proceed, shutdown and hopefully dump core for post-mortem analysis if (terminate) {
signal(signo, SIG_DFL); // now let things proceed, shutdown and hopefully dump core for post-mortem analysis
kill(killid, signo); struct sigaction act;
memset(&act, 0, sizeof(act));
act.sa_handler=SIG_DFL;
sigaction(signo, &act, nullptr);
kill(killid, signo);
}
} }
#endif #endif