Use alternative stack for signal handler to allow catching stack overflow induced SIGSEGV/SIGILL
This commit is contained in:
parent
0131bda065
commit
abde80f0d9
|
@ -254,16 +254,21 @@ static const char *signal_name(int signo)
|
||||||
* 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)
|
static void print_stacktrace(FILE* f, bool demangling, int maxdepth)
|
||||||
{
|
{
|
||||||
#if defined(USE_UNIX_BACKTRACE_SUPPORT)
|
#if defined(USE_UNIX_BACKTRACE_SUPPORT)
|
||||||
void *array[32]= {0}; // the less resources the better...
|
void *array[32]= {0}; // the less resources the better...
|
||||||
const int depth = backtrace(array, (int)GetArrayLength(array));
|
const int depth = backtrace(array, (int)GetArrayLength(array));
|
||||||
|
const int offset=3; // the first two entries are simply within our own exception handling code, third is within libc
|
||||||
|
if (maxdepth<0)
|
||||||
|
maxdepth=depth+offset;
|
||||||
|
else
|
||||||
|
maxdepth+=offset;
|
||||||
|
printf("maxdepth=%d\n", maxdepth);
|
||||||
char **symbolstrings = backtrace_symbols(array, depth);
|
char **symbolstrings = backtrace_symbols(array, depth);
|
||||||
if (symbolstrings) {
|
if (symbolstrings) {
|
||||||
fputs("Callstack:\n", f);
|
fputs("Callstack:\n", f);
|
||||||
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 < maxdepth; ++i) {
|
||||||
for (int i = offset; i < depth; ++i) {
|
|
||||||
const char * const symbol = symbolstrings[i];
|
const char * const symbol = symbolstrings[i];
|
||||||
char * realname = nullptr;
|
char * realname = nullptr;
|
||||||
const char * const firstBracketName = strchr(symbol, '(');
|
const char * const firstBracketName = strchr(symbol, '(');
|
||||||
|
@ -306,6 +311,22 @@ static void print_stacktrace(FILE* f, bool demangling)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Neither conclusive, nor portable
|
||||||
|
* Though one might to make it work beyond Linux x64
|
||||||
|
* \return true if address is supposed to be on stack (contrary to heap or elswhere).
|
||||||
|
* If unknown better retun false.
|
||||||
|
*/
|
||||||
|
static bool isAddressOnStack(const void* ptr)
|
||||||
|
{
|
||||||
|
#if defined(__linux) && defined(__amd64)
|
||||||
|
char a;
|
||||||
|
return ptr > &a;
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Entry pointer for signal handlers
|
* Entry pointer for signal handlers
|
||||||
* It uses functions which are not safe to be called from a signal handler,
|
* It uses functions which are not safe to be called from a signal handler,
|
||||||
|
@ -326,6 +347,7 @@ static void CppcheckSignalHandler(int signo, siginfo_t * info, void * context)
|
||||||
const char * const signame = signal_name(signo);
|
const char * const signame = signal_name(signo);
|
||||||
const char * const sigtext = strsignal(signo);
|
const char * const sigtext = strsignal(signo);
|
||||||
bool bPrintCallstack=true;
|
bool bPrintCallstack=true;
|
||||||
|
const bool isaddressonstack = isAddressOnStack(info->si_addr);
|
||||||
FILE* f=CppCheckExecutor::getExceptionOutput()=="stderr" ? stderr : stdout;
|
FILE* f=CppCheckExecutor::getExceptionOutput()=="stderr" ? stderr : stdout;
|
||||||
fputs("Internal error: cppcheck received signal ", f);
|
fputs("Internal error: cppcheck received signal ", f);
|
||||||
fputs(signame, f);
|
fputs(signame, f);
|
||||||
|
@ -420,8 +442,9 @@ static void CppcheckSignalHandler(int signo, siginfo_t * info, void * context)
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
fprintf(f, " (at 0x%p).\n",
|
fprintf(f, " (at 0x%p).%s\n",
|
||||||
info->si_addr);
|
info->si_addr,
|
||||||
|
(isaddressonstack)?" Stackoverflow?":"");
|
||||||
break;
|
break;
|
||||||
case SIGINT:
|
case SIGINT:
|
||||||
bPrintCallstack=false;
|
bPrintCallstack=false;
|
||||||
|
@ -438,17 +461,19 @@ static void CppcheckSignalHandler(int signo, siginfo_t * info, void * context)
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
fprintf(f, " (%sat 0x%p).\n",
|
fprintf(f, " (%sat 0x%p).%s\n",
|
||||||
(type==-1)? "" :
|
(type==-1)? "" :
|
||||||
(type==0) ? "reading " : "writing ",
|
(type==0) ? "reading " : "writing ",
|
||||||
info->si_addr);
|
info->si_addr,
|
||||||
|
(isaddressonstack)?" Stackoverflow?":""
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fputs(".\n", f);
|
fputs(".\n", f);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (bPrintCallstack) {
|
if (bPrintCallstack) {
|
||||||
print_stacktrace(f, true);
|
print_stacktrace(f, true, -1 /*(isaddressonstack)?8:-1*/);
|
||||||
fputs("\nPlease report this to the cppcheck developers!\n", f);
|
fputs("\nPlease report this to the cppcheck developers!\n", f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -681,6 +706,10 @@ static int filterException(int code, PEXCEPTION_POINTERS ex)
|
||||||
* TODO Check for multi-threading issues!
|
* TODO Check for multi-threading issues!
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
#if defined(USE_UNIX_SIGNAL_HANDLING)
|
||||||
|
const size_t MYSTACKSIZE = 64*1024+SIGSTKSZ;
|
||||||
|
char mytstack[MYSTACKSIZE];
|
||||||
|
#endif
|
||||||
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 USE_WINDOWS_SEH
|
#ifdef USE_WINDOWS_SEH
|
||||||
|
@ -693,9 +722,15 @@ int CppCheckExecutor::check_wrapper(CppCheck& cppcheck, int argc, const char* co
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#elif defined(USE_UNIX_SIGNAL_HANDLING)
|
#elif defined(USE_UNIX_SIGNAL_HANDLING)
|
||||||
|
stack_t segv_stack;
|
||||||
|
segv_stack.ss_sp = mytstack;
|
||||||
|
segv_stack.ss_flags = 0;
|
||||||
|
segv_stack.ss_size = MYSTACKSIZE;
|
||||||
|
sigaltstack(&segv_stack, NULL);
|
||||||
|
|
||||||
struct sigaction act;
|
struct sigaction act;
|
||||||
memset(&act, 0, sizeof(act));
|
memset(&act, 0, sizeof(act));
|
||||||
act.sa_flags=SA_SIGINFO;
|
act.sa_flags=SA_SIGINFO|SA_ONSTACK;
|
||||||
act.sa_sigaction=CppcheckSignalHandler;
|
act.sa_sigaction=CppcheckSignalHandler;
|
||||||
for (std::size_t s=0; s<GetArrayLength(listofsignals); ++s) {
|
for (std::size_t s=0; s<GetArrayLength(listofsignals); ++s) {
|
||||||
sigaction(listofsignals[s].signalnumber, &act, NULL);
|
sigaction(listofsignals[s].signalnumber, &act, NULL);
|
||||||
|
|
Loading…
Reference in New Issue