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)
/*
* Try to print the callstack.
* 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.
* That is very sensitive to the operating system, hardware, compiler and runtime.
* 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)
{
@ -220,8 +221,8 @@ static void print_stacktrace(FILE* output, bool demangling, int maxdepth, bool l
// 32 vs. 64bit
#define ADDRESSDISPLAYLENGTH ((sizeof(long)==8)?12:8)
const int fd = fileno(output);
void *array[32]= {0}; // the less resources the better...
const int currentdepth = backtrace(array, (int)GetArrayLength(array));
void *callstackArray[32]= {0}; // the less resources the better...
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
if (maxdepth<0)
maxdepth=currentdepth-offset;
@ -229,17 +230,16 @@ static void print_stacktrace(FILE* output, bool demangling, int maxdepth, bool l
maxdepth = std::min(maxdepth, currentdepth);
if (lowMem) {
fputs("Callstack (symbols only):\n", output);
backtrace_symbols_fd(array+offset, maxdepth, fd);
fflush(output);
backtrace_symbols_fd(callstackArray+offset, maxdepth, fd);
} else {
char **symbolstrings = backtrace_symbols(array, currentdepth);
if (symbolstrings) {
char **symbolStringList = backtrace_symbols(callstackArray, currentdepth);
if (symbolStringList) {
fputs("Callstack:\n", output);
for (int i = offset; i < maxdepth; ++i) {
const char * const symbol = symbolstrings[i];
char * realname = nullptr;
const char * const firstBracketName = strchr(symbol, '(');
const char * const firstBracketAddress = strchr(symbol, '[');
const char * const symbolString = symbolStringList[i];
char * realnameString = nullptr;
const char * const firstBracketName = strchr(symbolString, '(');
const char * const firstBracketAddress = strchr(symbolString, '[');
const char * const secondBracketAddress = strchr(firstBracketAddress, ']');
const char * const beginAddress = firstBracketAddress+3;
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) {
const char * const plus = strchr(firstBracketName, '+');
if (plus && (plus>(firstBracketName+1))) {
char input_buffer[512]= {0};
char input_buffer[1024]= {0};
strncpy(input_buffer, firstBracketName+1, plus-firstBracketName-1);
char output_buffer[1024]= {0};
char output_buffer[2048]= {0};
size_t length = GetArrayLength(output_buffer);
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;
@ -261,17 +263,17 @@ static void print_stacktrace(FILE* output, bool demangling, int maxdepth, bool l
if (padLen>0)
fprintf(output, "%0*d",
padLen, 0);
if (realname) {
if (realnameString) {
fprintf(output, "%.*s in %s\n",
(int)(secondBracketAddress-firstBracketAddress-3), firstBracketAddress+3,
realname);
realnameString);
} else {
fprintf(output, "%.*s in %.*s\n",
(int)(secondBracketAddress-firstBracketAddress-3), firstBracketAddress+3,
(int)(firstBracketAddress-symbol), symbol);
(int)(firstBracketAddress-symbolString), symbolString);
}
}
free(symbolstrings);
free(symbolStringList);
} else {
fputs("Callstack could not be obtained\n", output);
}
@ -319,7 +321,7 @@ static const Signalmap_t listofsignals = make_container< Signalmap_t > ()
DECLARE_SIGNAL(SIGSYS)
// don't care: SIGTERM
DECLARE_SIGNAL(SIGUSR1)
DECLARE_SIGNAL(SIGUSR2)
//DECLARE_SIGNAL(SIGUSR2) no usage currently
;
#undef DECLARE_SIGNAL
/*
@ -342,10 +344,11 @@ static void CppcheckSignalHandler(int signo, siginfo_t * info, void * context)
#endif
const Signalmap_t::const_iterator it=listofsignals.find(signo);
const char * const signame = (it==listofsignals.end()) ? "unknown" : it->second.c_str();
bool printCallstack=true;
bool lowMem=false;
bool unexpectedSignal=true;
const bool isaddressonstack = IsAddressOnStack(info->si_addr);
bool printCallstack=true; // try to print a callstack?
bool lowMem=false; // was low-memory condition detected?
bool unexpectedSignal=true; // unexpected indicates things didn't go as they should...
bool terminate=true; // exit process/thread
const bool isAddressOnStack = IsAddressOnStack(info->si_addr);
FILE* output = CppCheckExecutor::getExceptionOutput();
switch (signo) {
case SIGABRT:
@ -450,7 +453,7 @@ static void CppcheckSignalHandler(int signo, siginfo_t * info, void * context)
}
fprintf(output, " (at 0x%lx).%s\n",
(unsigned long)info->si_addr,
(isaddressonstack)?" Stackoverflow?":"");
(isAddressOnStack)?" Stackoverflow?":"");
break;
case SIGINT:
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==0) ? "reading " : "writing ",
(unsigned long)info->si_addr,
(isaddressonstack)?" Stackoverflow?":""
(isAddressOnStack)?" Stackoverflow?":""
);
break;
case SIGUSR1:
case SIGUSR2:
fputs("cppcheck received signal ", output);
fputs(signame, output);
fputs(".\n", output);
terminate=false;
break;
default:
fputs("Internal error: cppcheck received signal ", output);
@ -499,9 +502,14 @@ static void CppcheckSignalHandler(int signo, siginfo_t * info, void * context)
}
fflush(output);
// now let things proceed, shutdown and hopefully dump core for post-mortem analysis
signal(signo, SIG_DFL);
kill(killid, signo);
if (terminate) {
// now let things proceed, shutdown and hopefully dump core for post-mortem analysis
struct sigaction act;
memset(&act, 0, sizeof(act));
act.sa_handler=SIG_DFL;
sigaction(signo, &act, nullptr);
kill(killid, signo);
}
}
#endif