--exception-handling now prints callstack on SIGINT, allows to debug program hangs. Also add handler for some more signals.

This commit is contained in:
Alexander Mai 2015-11-14 19:59:22 +01:00
parent 5cc2b38767
commit bda9c8c2d5
3 changed files with 466 additions and 472 deletions

View File

@ -430,7 +430,7 @@ $(SRCDIR)/valueflow.o: lib/valueflow.cpp lib/cxx11emu.h lib/valueflow.h lib/conf
cli/cmdlineparser.o: cli/cmdlineparser.cpp lib/cxx11emu.h cli/cmdlineparser.h lib/cppcheck.h lib/config.h lib/settings.h lib/library.h lib/mathlib.h lib/token.h lib/valueflow.h lib/suppressions.h lib/standards.h lib/timer.h lib/errorlogger.h lib/check.h lib/tokenize.h lib/tokenlist.h cli/cppcheckexecutor.h cli/filelister.h lib/path.h
$(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o cli/cmdlineparser.o cli/cmdlineparser.cpp
cli/cppcheckexecutor.o: cli/cppcheckexecutor.cpp lib/cxx11emu.h cli/cppcheckexecutor.h lib/errorlogger.h lib/config.h lib/suppressions.h cli/cmdlineparser.h lib/cppcheck.h lib/settings.h lib/library.h lib/mathlib.h lib/token.h lib/valueflow.h lib/standards.h lib/timer.h lib/check.h lib/tokenize.h lib/tokenlist.h cli/filelister.h lib/path.h cli/pathmatch.h lib/preprocessor.h cli/threadexecutor.h
cli/cppcheckexecutor.o: cli/cppcheckexecutor.cpp lib/cxx11emu.h cli/cppcheckexecutor.h lib/errorlogger.h lib/config.h lib/suppressions.h cli/cmdlineparser.h lib/cppcheck.h lib/settings.h lib/library.h lib/mathlib.h lib/token.h lib/valueflow.h lib/standards.h lib/timer.h lib/check.h lib/tokenize.h lib/tokenlist.h cli/filelister.h lib/path.h cli/pathmatch.h lib/preprocessor.h cli/threadexecutor.h lib/utils.h
$(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o cli/cppcheckexecutor.o cli/cppcheckexecutor.cpp
cli/filelister.o: cli/filelister.cpp lib/cxx11emu.h cli/filelister.h lib/path.h lib/config.h cli/pathmatch.h

View File

@ -25,6 +25,7 @@
#include "pathmatch.h"
#include "preprocessor.h"
#include "threadexecutor.h"
#include "utils.h"
#include <climits>
#include <cstdlib> // EXIT_SUCCESS and EXIT_FAILURE
@ -167,7 +168,7 @@ int CppCheckExecutor::check(int argc, const char* const argv[])
CppCheck cppCheck(*this, true);
Settings& settings = cppCheck.settings();
const Settings& settings = cppCheck.settings();
_settings = &settings;
if (!parseFromArgs(&cppCheck, argc, argv)) {
@ -189,53 +190,21 @@ int CppCheckExecutor::check(int argc, const char* const argv[])
* \return size of array
* */
template<typename T, int size>
size_t GetArrayLength(const T(&)[size])
constexpr size_t GetArrayLength(const T(&)[size])
{
return size;
}
#if defined(USE_UNIX_SIGNAL_HANDLING)
/* (declare this list here, so it may be used in signal handlers in addition to main())
* A list of signals available in ISO C
* Check out http://pubs.opengroup.org/onlinepubs/009695399/basedefs/signal.h.html
* For now we only want to detect abnormal behaviour for a few selected signals:
*/
struct Signaltype {
int signalnumber;
const char *signalname;
};
#define DECLARE_SIGNAL(x) {x, #x}
static const Signaltype listofsignals[] = {
// don't care: SIGABRT,
DECLARE_SIGNAL(SIGBUS),
DECLARE_SIGNAL(SIGFPE),
DECLARE_SIGNAL(SIGILL),
DECLARE_SIGNAL(SIGINT),
DECLARE_SIGNAL(SIGSEGV),
// don't care: SIGTERM
DECLARE_SIGNAL(SIGUSR1)
};
/*
* Simple mapping
*/
static const char *signal_name(int signo)
{
for (size_t s=0; s<GetArrayLength(listofsignals); ++s) {
if (listofsignals[s].signalnumber==signo)
return listofsignals[s].signalname;
}
return "";
}
/*
namespace {
/*
* 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.
*/
static void print_stacktrace(FILE* f, bool demangling, int maxdepth)
{
static void print_stacktrace(FILE* f, bool demangling, int maxdepth)
{
#if defined(USE_UNIX_BACKTRACE_SUPPORT)
// 32 vs. 64bit
#define ADDRESSDISPLAYLENGTH ((sizeof(long)==8)?12:8)
@ -291,18 +260,18 @@ static void print_stacktrace(FILE* f, bool demangling, int maxdepth)
}
#undef ADDRESSDISPLAYLENGTH
#endif
}
}
static const size_t MYSTACKSIZE = 16*1024+SIGSTKSZ; // wild guess about a reasonable buffer
static char mytstack[MYSTACKSIZE]; // alternative stack for signal handler
static bool bStackBelowHeap=false; // lame attempt to locate heap vs. stack address space
const size_t MYSTACKSIZE = 16*1024+SIGSTKSZ; // wild guess about a reasonable buffer
char mytstack[MYSTACKSIZE]; // alternative stack for signal handler
bool bStackBelowHeap=false; // lame attempt to locate heap vs. stack address space
/*
/*
* \return true if address is supposed to be on stack (contrary to heap or elsewhere). If ptr is 0 false will be returned.
* If unknown better return false.
*/
static bool isAddressOnStack(const void* ptr)
{
bool isAddressOnStack(const void* ptr)
{
if (nullptr==ptr)
return false;
char a;
@ -310,16 +279,37 @@ static bool isAddressOnStack(const void* ptr)
return ptr < &a;
else
return ptr > &a;
}
}
/*
/* (declare this list here, so it may be used in signal handlers in addition to main())
* A list of signals available in ISO C
* Check out http://pubs.opengroup.org/onlinepubs/009695399/basedefs/signal.h.html
* For now we only want to detect abnormal behaviour for a few selected signals:
*/
#define DECLARE_SIGNAL(x) << std::make_pair(x, #x)
typedef std::map<int, std::string> Signalmap_t;
const Signalmap_t listofsignals = make_container< Signalmap_t > ()
DECLARE_SIGNAL(SIGABRT)
DECLARE_SIGNAL(SIGBUS)
DECLARE_SIGNAL(SIGFPE)
DECLARE_SIGNAL(SIGILL)
DECLARE_SIGNAL(SIGINT)
DECLARE_SIGNAL(SIGQUIT)
DECLARE_SIGNAL(SIGSEGV)
DECLARE_SIGNAL(SIGSYS)
// don't care: SIGTERM
DECLARE_SIGNAL(SIGUSR1)
DECLARE_SIGNAL(SIGUSR2)
;
/*
* Entry pointer for signal handlers
* It uses functions which are not safe to be called from a signal handler,
* but when ending up here something went terribly wrong anyway.
* And all which is left is just printing some information and terminate.
*/
static void CppcheckSignalHandler(int signo, siginfo_t * info, void * context)
{
void CppcheckSignalHandler(int signo, siginfo_t * info, void * context)
{
int type = -1;
pid_t killid = getpid();
const ucontext_t* const uc = reinterpret_cast<const ucontext_t*>(context);
@ -329,7 +319,8 @@ static void CppcheckSignalHandler(int signo, siginfo_t * info, void * context)
type = (int)uc->uc_mcontext.gregs[REG_ERR] & 2;
}
#endif
const char * const signame = signal_name(signo);
const Signalmap_t::const_iterator it=listofsignals.find(signo);
const char * const signame = (it==listofsignals.end()) ? "unknown" : it->second.c_str();
bool bPrintCallstack=true;
bool bUnexpectedSignal=true;
const bool isaddressonstack = isAddressOnStack(info->si_addr);
@ -437,7 +428,7 @@ static void CppcheckSignalHandler(int signo, siginfo_t * info, void * context)
bUnexpectedSignal=false;
fputs("cppcheck received signal ", f);
fputs(signame, f);
bPrintCallstack=false;
bPrintCallstack=true;
fputs(".\n", f);
break;
case SIGSEGV:
@ -483,33 +474,35 @@ static void CppcheckSignalHandler(int signo, siginfo_t * info, void * context)
// now let things proceed, shutdown and hopefully dump core for post-mortem analysis
signal(signo, SIG_DFL);
kill(killid, signo);
}
}
#endif
#ifdef USE_WINDOWS_SEH
static const ULONG maxnamelength = 512;
struct IMAGEHLP_SYMBOL64_EXT : public IMAGEHLP_SYMBOL64 {
namespace {
const ULONG maxnamelength = 512;
struct IMAGEHLP_SYMBOL64_EXT : public IMAGEHLP_SYMBOL64 {
TCHAR NameExt[maxnamelength]; // actually no need to worry about character encoding here
};
typedef BOOL (WINAPI *fpStackWalk64)(DWORD, HANDLE, HANDLE, LPSTACKFRAME64, PVOID, PREAD_PROCESS_MEMORY_ROUTINE64, PFUNCTION_TABLE_ACCESS_ROUTINE64, PGET_MODULE_BASE_ROUTINE64, PTRANSLATE_ADDRESS_ROUTINE64);
static fpStackWalk64 pStackWalk64;
typedef DWORD64(WINAPI *fpSymGetModuleBase64)(HANDLE, DWORD64);
static fpSymGetModuleBase64 pSymGetModuleBase64;
typedef BOOL (WINAPI *fpSymGetSymFromAddr64)(HANDLE, DWORD64, PDWORD64, PIMAGEHLP_SYMBOL64);
static fpSymGetSymFromAddr64 pSymGetSymFromAddr64;
typedef BOOL (WINAPI *fpSymGetLineFromAddr64)(HANDLE, DWORD64, PDWORD, PIMAGEHLP_LINE64);
static fpSymGetLineFromAddr64 pSymGetLineFromAddr64;
typedef DWORD (WINAPI *fpUnDecorateSymbolName)(const TCHAR*, PTSTR, DWORD, DWORD) ;
static fpUnDecorateSymbolName pUnDecorateSymbolName;
typedef PVOID(WINAPI *fpSymFunctionTableAccess64)(HANDLE, DWORD64);
static fpSymFunctionTableAccess64 pSymFunctionTableAccess64;
typedef BOOL (WINAPI *fpSymInitialize)(HANDLE, PCSTR, BOOL);
static fpSymInitialize pSymInitialize;
};
typedef BOOL (WINAPI *fpStackWalk64)(DWORD, HANDLE, HANDLE, LPSTACKFRAME64, PVOID, PREAD_PROCESS_MEMORY_ROUTINE64, PFUNCTION_TABLE_ACCESS_ROUTINE64, PGET_MODULE_BASE_ROUTINE64, PTRANSLATE_ADDRESS_ROUTINE64);
fpStackWalk64 pStackWalk64;
typedef DWORD64(WINAPI *fpSymGetModuleBase64)(HANDLE, DWORD64);
fpSymGetModuleBase64 pSymGetModuleBase64;
typedef BOOL (WINAPI *fpSymGetSymFromAddr64)(HANDLE, DWORD64, PDWORD64, PIMAGEHLP_SYMBOL64);
fpSymGetSymFromAddr64 pSymGetSymFromAddr64;
typedef BOOL (WINAPI *fpSymGetLineFromAddr64)(HANDLE, DWORD64, PDWORD, PIMAGEHLP_LINE64);
fpSymGetLineFromAddr64 pSymGetLineFromAddr64;
typedef DWORD (WINAPI *fpUnDecorateSymbolName)(const TCHAR*, PTSTR, DWORD, DWORD) ;
fpUnDecorateSymbolName pUnDecorateSymbolName;
typedef PVOID(WINAPI *fpSymFunctionTableAccess64)(HANDLE, DWORD64);
fpSymFunctionTableAccess64 pSymFunctionTableAccess64;
typedef BOOL (WINAPI *fpSymInitialize)(HANDLE, PCSTR, BOOL);
fpSymInitialize pSymInitialize;
static HMODULE hLibDbgHelp;
HMODULE hLibDbgHelp;
// avoid explicit dependency on Dbghelp.dll
static bool loadDbgHelp()
{
bool loadDbgHelp()
{
hLibDbgHelp = ::LoadLibraryW(L"Dbghelp.dll");
if (!hLibDbgHelp)
return false;
@ -521,11 +514,11 @@ static bool loadDbgHelp()
pSymInitialize = (fpSymInitialize) ::GetProcAddress(hLibDbgHelp, "SymInitialize");
pUnDecorateSymbolName = (fpUnDecorateSymbolName)::GetProcAddress(hLibDbgHelp, "UnDecorateSymbolName");
return true;
}
}
static void PrintCallstack(FILE* f, PEXCEPTION_POINTERS ex)
{
void PrintCallstack(FILE* f, PEXCEPTION_POINTERS ex)
{
if (!loadDbgHelp())
return;
const HANDLE hProcess = GetCurrentProcess();
@ -594,10 +587,10 @@ static void PrintCallstack(FILE* f, PEXCEPTION_POINTERS ex)
FreeLibrary(hLibDbgHelp);
hLibDbgHelp=0;
}
}
static void writeMemoryErrorDetails(FILE* f, PEXCEPTION_POINTERS ex, const char* description)
{
void writeMemoryErrorDetails(FILE* f, PEXCEPTION_POINTERS ex, const char* description)
{
fputs(description, f);
fprintf(f, " (instruction: 0x%p) ", ex->ExceptionRecord->ExceptionAddress);
// Using %p for ULONG_PTR later on, so it must have size identical to size of pointer
@ -619,13 +612,13 @@ static void writeMemoryErrorDetails(FILE* f, PEXCEPTION_POINTERS ex, const char*
default:
break;
}
}
}
/*
/*
* Any evaluation of the exception needs to be done here!
*/
static int filterException(int code, PEXCEPTION_POINTERS ex)
{
int filterException(int code, PEXCEPTION_POINTERS ex)
{
FILE *f = stdout;
fputs("Internal error: ", f);
switch (ex->ExceptionRecord->ExceptionCode) {
@ -704,6 +697,7 @@ static int filterException(int code, PEXCEPTION_POINTERS ex)
PrintCallstack(f, ex);
fflush(f);
return EXCEPTION_EXECUTE_HANDLER;
}
}
#endif
@ -743,8 +737,8 @@ int CppCheckExecutor::check_wrapper(CppCheck& cppcheck, int argc, const char* co
memset(&act, 0, sizeof(act));
act.sa_flags=SA_SIGINFO|SA_ONSTACK;
act.sa_sigaction=CppcheckSignalHandler;
for (std::size_t s=0; s<GetArrayLength(listofsignals); ++s) {
sigaction(listofsignals[s].signalnumber, &act, NULL);
for (std::map<int, std::string>::const_iterator sig=listofsignals.begin(); sig!=listofsignals.end(); ++sig) {
sigaction(sig->first, &act, NULL);
}
return check_internal(cppcheck, argc, argv);
#else