Improve exception handling on un*x: try to print a callstack in out-of-memory situations as well
This commit is contained in:
parent
c62b23c4fc
commit
9757f5b5f4
|
@ -66,6 +66,9 @@
|
||||||
#include <TCHAR.H>
|
#include <TCHAR.H>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*static*/ std::string CppCheckExecutor::exceptionOutput = "stdout";
|
||||||
|
|
||||||
CppCheckExecutor::CppCheckExecutor()
|
CppCheckExecutor::CppCheckExecutor()
|
||||||
: _settings(0), time1(0), errorlist(false)
|
: _settings(0), time1(0), errorlist(false)
|
||||||
{
|
{
|
||||||
|
@ -203,11 +206,13 @@ namespace {
|
||||||
* 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, it's using functions not whitelisted for usage in a signal handler function.
|
||||||
*/
|
*/
|
||||||
static void print_stacktrace(FILE* f, bool demangling, int maxdepth)
|
void print_stacktrace(bool useStdout, bool demangling, int maxdepth, bool bLowMem)
|
||||||
{
|
{
|
||||||
#if defined(USE_UNIX_BACKTRACE_SUPPORT)
|
#if defined(USE_UNIX_BACKTRACE_SUPPORT)
|
||||||
// 32 vs. 64bit
|
// 32 vs. 64bit
|
||||||
#define ADDRESSDISPLAYLENGTH ((sizeof(long)==8)?12:8)
|
#define ADDRESSDISPLAYLENGTH ((sizeof(long)==8)?12:8)
|
||||||
|
FILE* f = (useStdout) ? stdout : stderr;
|
||||||
|
const int fd = (useStdout) ? 1 : 2;
|
||||||
void *array[32]= {0}; // the less resources the better...
|
void *array[32]= {0}; // the less resources the better...
|
||||||
const int currentdepth = backtrace(array, (int)GetArrayLength(array));
|
const int currentdepth = backtrace(array, (int)GetArrayLength(array));
|
||||||
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
|
||||||
|
@ -215,56 +220,61 @@ namespace {
|
||||||
maxdepth=currentdepth-offset;
|
maxdepth=currentdepth-offset;
|
||||||
else
|
else
|
||||||
maxdepth = std::min(maxdepth, currentdepth);
|
maxdepth = std::min(maxdepth, currentdepth);
|
||||||
char **symbolstrings = backtrace_symbols(array, currentdepth);
|
if (bLowMem) {
|
||||||
if (symbolstrings) {
|
|
||||||
fputs("Callstack:\n", f);
|
fputs("Callstack:\n", f);
|
||||||
for (int i = offset; i < maxdepth; ++i) {
|
backtrace_symbols_fd(array+offset, maxdepth, fd);
|
||||||
const char * const symbol = symbolstrings[i];
|
} else {
|
||||||
char * realname = nullptr;
|
char **symbolstrings = backtrace_symbols(array, currentdepth);
|
||||||
const char * const firstBracketName = strchr(symbol, '(');
|
if (symbolstrings) {
|
||||||
const char * const firstBracketAddress = strchr(symbol, '[');
|
fputs("Callstack:\n", f);
|
||||||
const char * const secondBracketAddress = strchr(firstBracketAddress, ']');
|
for (int i = offset; i < maxdepth; ++i) {
|
||||||
const char * const beginAddress = firstBracketAddress+3;
|
const char * const symbol = symbolstrings[i];
|
||||||
const int addressLen = int(secondBracketAddress-beginAddress);
|
char * realname = nullptr;
|
||||||
const int padLen = int(ADDRESSDISPLAYLENGTH-addressLen);
|
const char * const firstBracketName = strchr(symbol, '(');
|
||||||
if (demangling && firstBracketName) {
|
const char * const firstBracketAddress = strchr(symbol, '[');
|
||||||
const char * const plus = strchr(firstBracketName, '+');
|
const char * const secondBracketAddress = strchr(firstBracketAddress, ']');
|
||||||
if (plus && (plus>(firstBracketName+1))) {
|
const char * const beginAddress = firstBracketAddress+3;
|
||||||
char input_buffer[512]= {0};
|
const int addressLen = int(secondBracketAddress-beginAddress);
|
||||||
strncpy(input_buffer, firstBracketName+1, plus-firstBracketName-1);
|
const int padLen = int(ADDRESSDISPLAYLENGTH-addressLen);
|
||||||
char output_buffer[1024]= {0};
|
if (demangling && firstBracketName) {
|
||||||
size_t length = GetArrayLength(output_buffer);
|
const char * const plus = strchr(firstBracketName, '+');
|
||||||
int status=0;
|
if (plus && (plus>(firstBracketName+1))) {
|
||||||
realname = abi::__cxa_demangle(input_buffer, output_buffer, &length, &status); // non-NULL on success
|
char input_buffer[512]= {0};
|
||||||
|
strncpy(input_buffer, firstBracketName+1, plus-firstBracketName-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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const int ordinal=i-offset;
|
||||||
|
fprintf(f, "#%-2d 0x",
|
||||||
|
ordinal);
|
||||||
|
if (padLen>0)
|
||||||
|
fprintf(f, "%0*d",
|
||||||
|
padLen, 0);
|
||||||
|
if (realname) {
|
||||||
|
fprintf(f, "%.*s in %s\n",
|
||||||
|
(int)(secondBracketAddress-firstBracketAddress-3), firstBracketAddress+3,
|
||||||
|
realname);
|
||||||
|
} else {
|
||||||
|
fprintf(f, "%.*s in %.*s\n",
|
||||||
|
(int)(secondBracketAddress-firstBracketAddress-3), firstBracketAddress+3,
|
||||||
|
(int)(firstBracketAddress-symbol), symbol);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const int ordinal=i-offset;
|
free(symbolstrings);
|
||||||
fprintf(f, "#%-2d 0x",
|
} else {
|
||||||
ordinal);
|
fputs("Callstack could not be obtained\n", f);
|
||||||
if (padLen>0)
|
|
||||||
fprintf(f, "%0*d",
|
|
||||||
padLen, 0);
|
|
||||||
if (realname) {
|
|
||||||
fprintf(f, "%.*s in %s\n",
|
|
||||||
(int)(secondBracketAddress-firstBracketAddress-3), firstBracketAddress+3,
|
|
||||||
realname);
|
|
||||||
} else {
|
|
||||||
fprintf(f, "%.*s in %.*s\n",
|
|
||||||
(int)(secondBracketAddress-firstBracketAddress-3), firstBracketAddress+3,
|
|
||||||
(int)(firstBracketAddress-symbol), symbol);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
free(symbolstrings);
|
|
||||||
} else {
|
|
||||||
fputs("Callstack could not be obtained\n", f);
|
|
||||||
}
|
}
|
||||||
#undef ADDRESSDISPLAYLENGTH
|
#undef ADDRESSDISPLAYLENGTH
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
const size_t MYSTACKSIZE = 16*1024+SIGSTKSZ; // wild guess about a reasonable buffer
|
const size_t MYSTACKSIZE = 16*1024+SIGSTKSZ; // wild guess about a reasonable buffer
|
||||||
char mytstack[MYSTACKSIZE]; // alternative stack for signal handler
|
char mytstack[MYSTACKSIZE]= {0}; // alternative stack for signal handler
|
||||||
bool bStackBelowHeap=false; // lame attempt to locate heap vs. stack address space
|
bool bStackBelowHeap=false; // lame attempt to locate heap vs. stack address space. See CppCheckExecutor::check_wrapper()
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* \return true if address is supposed to be on stack (contrary to heap or elsewhere). If ptr is 0 false will be returned.
|
* \return true if address is supposed to be on stack (contrary to heap or elsewhere). If ptr is 0 false will be returned.
|
||||||
|
@ -322,10 +332,18 @@ namespace {
|
||||||
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 bPrintCallstack=true;
|
bool bPrintCallstack=true;
|
||||||
|
bool bLowMem=false;
|
||||||
bool bUnexpectedSignal=true;
|
bool bUnexpectedSignal=true;
|
||||||
const bool isaddressonstack = isAddressOnStack(info->si_addr);
|
const bool isaddressonstack = isAddressOnStack(info->si_addr);
|
||||||
FILE* f = (CppCheckExecutor::getExceptionOutput()=="stderr") ? stderr : stdout;
|
const bool useStdout = CppCheckExecutor::getExceptionOutput()=="stdout";
|
||||||
|
FILE* f = (useStdout) ? stdout : stderr;
|
||||||
switch (signo) {
|
switch (signo) {
|
||||||
|
case SIGABRT:
|
||||||
|
fputs("Internal error: cppcheck received signal ", f);
|
||||||
|
fputs(signame, f);
|
||||||
|
fputs(" - out of memory?\n", f);
|
||||||
|
bLowMem=true;
|
||||||
|
break;
|
||||||
case SIGBUS:
|
case SIGBUS:
|
||||||
fputs("Internal error: cppcheck received signal ", f);
|
fputs("Internal error: cppcheck received signal ", f);
|
||||||
fputs(signame, f);
|
fputs(signame, f);
|
||||||
|
@ -464,7 +482,7 @@ namespace {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (bPrintCallstack) {
|
if (bPrintCallstack) {
|
||||||
print_stacktrace(f, true, -1);
|
print_stacktrace(f, true, -1, bLowMem);
|
||||||
}
|
}
|
||||||
if (bUnexpectedSignal) {
|
if (bUnexpectedSignal) {
|
||||||
fputs("\nPlease report this to the cppcheck developers!\n", f);
|
fputs("\nPlease report this to the cppcheck developers!\n", f);
|
||||||
|
@ -990,5 +1008,3 @@ bool CppCheckExecutor::tryLoadLibrary(Library& destination, const char* basepath
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string CppCheckExecutor::exceptionOutput;
|
|
||||||
|
|
|
@ -89,11 +89,12 @@ public:
|
||||||
static void reportStatus(std::size_t fileindex, std::size_t filecount, std::size_t sizedone, std::size_t sizetotal);
|
static void reportStatus(std::size_t fileindex, std::size_t filecount, std::size_t sizedone, std::size_t sizetotal);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param fn file name to be used from exception handler
|
* @param fn file name to be used from exception handler: Has to be either "stdout" or "stderr".
|
||||||
|
* Invalid arguments will be silently ignored. Default is "stdout".
|
||||||
*/
|
*/
|
||||||
static void setExceptionOutput(const std::string& fn);
|
static void setExceptionOutput(const std::string& fn);
|
||||||
/**
|
/**
|
||||||
* @return file name to be used for output from exception handler
|
* @return file name to be used for output from exception handler. Has to be either "stdout" or "stderr".
|
||||||
*/
|
*/
|
||||||
static const std::string& getExceptionOutput();
|
static const std::string& getExceptionOutput();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue