Skip to content

Commit abde80f

Browse files
committed
Use alternative stack for signal handler to allow catching stack overflow induced SIGSEGV/SIGILL
1 parent 0131bda commit abde80f

1 file changed

Lines changed: 44 additions & 9 deletions

File tree

cli/cppcheckexecutor.cpp

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -254,16 +254,21 @@ static const char *signal_name(int signo)
254254
* That is very sensitive to the operating system, hardware, compiler and runtime!
255255
* The code is not meant for production environment, it's using functions not whitelisted for usage in a signal handler function.
256256
*/
257-
static void print_stacktrace(FILE* f, bool demangling)
257+
static void print_stacktrace(FILE* f, bool demangling, int maxdepth)
258258
{
259259
#if defined(USE_UNIX_BACKTRACE_SUPPORT)
260260
void *array[32]= {0}; // the less resources the better...
261261
const int depth = backtrace(array, (int)GetArrayLength(array));
262+
const int offset=3; // the first two entries are simply within our own exception handling code, third is within libc
263+
if (maxdepth<0)
264+
maxdepth=depth+offset;
265+
else
266+
maxdepth+=offset;
267+
printf("maxdepth=%d\n", maxdepth);
262268
char **symbolstrings = backtrace_symbols(array, depth);
263269
if (symbolstrings) {
264270
fputs("Callstack:\n", f);
265-
const int offset=3; // the first two entries are simply within our own exception handling code, third is within libc
266-
for (int i = offset; i < depth; ++i) {
271+
for (int i = offset; i < maxdepth; ++i) {
267272
const char * const symbol = symbolstrings[i];
268273
char * realname = nullptr;
269274
const char * const firstBracketName = strchr(symbol, '(');
@@ -306,6 +311,22 @@ static void print_stacktrace(FILE* f, bool demangling)
306311
#endif
307312
}
308313

314+
/*
315+
* Neither conclusive, nor portable
316+
* Though one might to make it work beyond Linux x64
317+
* \return true if address is supposed to be on stack (contrary to heap or elswhere).
318+
* If unknown better retun false.
319+
*/
320+
static bool isAddressOnStack(const void* ptr)
321+
{
322+
#if defined(__linux) && defined(__amd64)
323+
char a;
324+
return ptr > &a;
325+
#else
326+
return false;
327+
#endif
328+
}
329+
309330
/*
310331
* Entry pointer for signal handlers
311332
* 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)
326347
const char * const signame = signal_name(signo);
327348
const char * const sigtext = strsignal(signo);
328349
bool bPrintCallstack=true;
350+
const bool isaddressonstack = isAddressOnStack(info->si_addr);
329351
FILE* f=CppCheckExecutor::getExceptionOutput()=="stderr" ? stderr : stdout;
330352
fputs("Internal error: cppcheck received signal ", f);
331353
fputs(signame, f);
@@ -420,8 +442,9 @@ static void CppcheckSignalHandler(int signo, siginfo_t * info, void * context)
420442
default:
421443
break;
422444
}
423-
fprintf(f, " (at 0x%p).\n",
424-
info->si_addr);
445+
fprintf(f, " (at 0x%p).%s\n",
446+
info->si_addr,
447+
(isaddressonstack)?" Stackoverflow?":"");
425448
break;
426449
case SIGINT:
427450
bPrintCallstack=false;
@@ -438,17 +461,19 @@ static void CppcheckSignalHandler(int signo, siginfo_t * info, void * context)
438461
default:
439462
break;
440463
}
441-
fprintf(f, " (%sat 0x%p).\n",
464+
fprintf(f, " (%sat 0x%p).%s\n",
442465
(type==-1)? "" :
443466
(type==0) ? "reading " : "writing ",
444-
info->si_addr);
467+
info->si_addr,
468+
(isaddressonstack)?" Stackoverflow?":""
469+
);
445470
break;
446471
default:
447472
fputs(".\n", f);
448473
break;
449474
}
450475
if (bPrintCallstack) {
451-
print_stacktrace(f, true);
476+
print_stacktrace(f, true, -1 /*(isaddressonstack)?8:-1*/);
452477
fputs("\nPlease report this to the cppcheck developers!\n", f);
453478
}
454479

@@ -681,6 +706,10 @@ static int filterException(int code, PEXCEPTION_POINTERS ex)
681706
* TODO Check for multi-threading issues!
682707
*
683708
*/
709+
#if defined(USE_UNIX_SIGNAL_HANDLING)
710+
const size_t MYSTACKSIZE = 64*1024+SIGSTKSZ;
711+
char mytstack[MYSTACKSIZE];
712+
#endif
684713
int CppCheckExecutor::check_wrapper(CppCheck& cppcheck, int argc, const char* const argv[])
685714
{
686715
#ifdef USE_WINDOWS_SEH
@@ -693,9 +722,15 @@ int CppCheckExecutor::check_wrapper(CppCheck& cppcheck, int argc, const char* co
693722
return -1;
694723
}
695724
#elif defined(USE_UNIX_SIGNAL_HANDLING)
725+
stack_t segv_stack;
726+
segv_stack.ss_sp = mytstack;
727+
segv_stack.ss_flags = 0;
728+
segv_stack.ss_size = MYSTACKSIZE;
729+
sigaltstack(&segv_stack, NULL);
730+
696731
struct sigaction act;
697732
memset(&act, 0, sizeof(act));
698-
act.sa_flags=SA_SIGINFO;
733+
act.sa_flags=SA_SIGINFO|SA_ONSTACK;
699734
act.sa_sigaction=CppcheckSignalHandler;
700735
for (std::size_t s=0; s<GetArrayLength(listofsignals); ++s) {
701736
sigaction(listofsignals[s].signalnumber, &act, NULL);

0 commit comments

Comments
 (0)