diff --git a/Makefile b/Makefile
index de56620ae..6cae34dbb 100644
--- a/Makefile
+++ b/Makefile
@@ -209,10 +209,13 @@ EXTOBJ = externals/simplecpp/simplecpp.o \
CLIOBJ = cli/cmdlineparser.o \
cli/cppcheckexecutor.o \
+ cli/cppcheckexecutorseh.o \
+ cli/cppcheckexecutorsig.o \
cli/executor.o \
cli/filelister.o \
cli/main.o \
cli/processexecutor.o \
+ cli/stacktrace.o \
cli/threadexecutor.o
TESTOBJ = test/options.o \
@@ -291,7 +294,7 @@ cppcheck: $(LIBOBJ) $(CLIOBJ) $(EXTOBJ)
all: cppcheck testrunner
-testrunner: $(TESTOBJ) $(LIBOBJ) $(EXTOBJ) cli/executor.o cli/processexecutor.o cli/threadexecutor.o cli/cmdlineparser.o cli/cppcheckexecutor.o cli/filelister.o
+testrunner: $(TESTOBJ) $(LIBOBJ) $(EXTOBJ) cli/executor.o cli/processexecutor.o cli/threadexecutor.o cli/cmdlineparser.o cli/cppcheckexecutor.o cli/cppcheckexecutorseh.o cli/cppcheckexecutorsig.o cli/stacktrace.o cli/filelister.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -o $@ $^ $(LIBS) $(LDFLAGS) $(RDYNAMIC)
test: all
@@ -574,9 +577,15 @@ $(libcppdir)/valueflow.o: lib/valueflow.cpp lib/analyzer.h lib/astutils.h lib/ca
cli/cmdlineparser.o: cli/cmdlineparser.cpp cli/cmdlineparser.h cli/cppcheckexecutor.h cli/filelister.h externals/tinyxml2/tinyxml2.h lib/check.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/utils.h
$(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o cli/cmdlineparser.o cli/cmdlineparser.cpp
-cli/cppcheckexecutor.o: cli/cppcheckexecutor.cpp cli/cmdlineparser.h cli/cppcheckexecutor.h cli/executor.h cli/filelister.h cli/processexecutor.h cli/threadexecutor.h externals/simplecpp/simplecpp.h lib/analyzerinfo.h lib/check.h lib/checkunusedfunctions.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/path.h lib/pathmatch.h lib/platform.h lib/preprocessor.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/utils.h
+cli/cppcheckexecutor.o: cli/cppcheckexecutor.cpp cli/cmdlineparser.h cli/cppcheckexecutor.h cli/cppcheckexecutorseh.h cli/cppcheckexecutorsig.h cli/executor.h cli/filelister.h cli/processexecutor.h cli/threadexecutor.h externals/simplecpp/simplecpp.h lib/analyzerinfo.h lib/check.h lib/checkunusedfunctions.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/path.h lib/pathmatch.h lib/platform.h lib/preprocessor.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/utils.h
$(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o cli/cppcheckexecutor.o cli/cppcheckexecutor.cpp
+cli/cppcheckexecutorseh.o: cli/cppcheckexecutorseh.cpp cli/cppcheckexecutor.h cli/cppcheckexecutorseh.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/suppressions.h lib/utils.h
+ $(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o cli/cppcheckexecutorseh.o cli/cppcheckexecutorseh.cpp
+
+cli/cppcheckexecutorsig.o: cli/cppcheckexecutorsig.cpp cli/cppcheckexecutor.h cli/cppcheckexecutorsig.h cli/stacktrace.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/suppressions.h
+ $(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o cli/cppcheckexecutorsig.o cli/cppcheckexecutorsig.cpp
+
cli/executor.o: cli/executor.cpp cli/executor.h
$(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o cli/executor.o cli/executor.cpp
@@ -589,6 +598,9 @@ cli/main.o: cli/main.cpp cli/cppcheckexecutor.h lib/color.h lib/config.h lib/err
cli/processexecutor.o: cli/processexecutor.cpp cli/cppcheckexecutor.h cli/executor.h cli/processexecutor.h lib/analyzerinfo.h lib/check.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/utils.h
$(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o cli/processexecutor.o cli/processexecutor.cpp
+cli/stacktrace.o: cli/stacktrace.cpp cli/stacktrace.h lib/config.h lib/utils.h
+ $(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o cli/stacktrace.o cli/stacktrace.cpp
+
cli/threadexecutor.o: cli/threadexecutor.cpp cli/cppcheckexecutor.h cli/executor.h cli/threadexecutor.h lib/analyzerinfo.h lib/check.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/utils.h
$(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o cli/threadexecutor.o cli/threadexecutor.cpp
diff --git a/cli/cli.vcxproj b/cli/cli.vcxproj
index 9a2db8671..eb04e5dbf 100644
--- a/cli/cli.vcxproj
+++ b/cli/cli.vcxproj
@@ -407,10 +407,13 @@
+
+
+
@@ -420,11 +423,14 @@
+
+
+
diff --git a/cli/cli.vcxproj.filters b/cli/cli.vcxproj.filters
index f95e472bb..a378aeb51 100644
--- a/cli/cli.vcxproj.filters
+++ b/cli/cli.vcxproj.filters
@@ -26,9 +26,18 @@
Header Files
+
+ Header Files
+
+
+ Header Files
+
Header Files
+
+ Header Files
+
@@ -40,12 +49,21 @@
Source Files
+
+ Source Files
+
+
+ Source Files
+
Source Files
Source Files
+
+ Source Files
+
diff --git a/cli/cmdlineparser.cpp b/cli/cmdlineparser.cpp
index 446642a68..bc8e5ec77 100644
--- a/cli/cmdlineparser.cpp
+++ b/cli/cmdlineparser.cpp
@@ -341,6 +341,7 @@ bool CmdLineParser::parseFromArgs(int argc, const char* const argv[])
else if (std::strcmp(argv[i], "--exception-handling") == 0)
mSettings->exceptionHandling = true;
+ // TODO: only applied with Signal handling i.e. Linux
else if (std::strncmp(argv[i], "--exception-handling=", 21) == 0) {
mSettings->exceptionHandling = true;
const std::string exceptionOutfilename = &(argv[i][21]);
diff --git a/cli/cppcheckexecutor.cpp b/cli/cppcheckexecutor.cpp
index b622adeba..5e78cc7dc 100644
--- a/cli/cppcheckexecutor.cpp
+++ b/cli/cppcheckexecutor.cpp
@@ -41,56 +41,26 @@
#include "processexecutor.h"
#endif
-#include
#include
-#include
#include
#include // EXIT_SUCCESS and EXIT_FAILURE
-#include
#include
#include
#include
#include
-#include
#include
#include
-#if !defined(NO_UNIX_SIGNAL_HANDLING) && defined(__GNUC__) && !defined(__MINGW32__) && !defined(__OS2__)
-#define USE_UNIX_SIGNAL_HANDLING
-#include
-#if defined(__APPLE__)
-# define _XOPEN_SOURCE // ucontext.h APIs can only be used on Mac OSX >= 10.7 if _XOPEN_SOURCE is defined
-# include
-
-# undef _XOPEN_SOURCE
-#elif !defined(__OpenBSD__) && !defined(__HAIKU__)
-# include
-#endif
-#ifdef __linux__
-#include
-#endif
+#ifdef USE_UNIX_SIGNAL_HANDLING
+#include "cppcheckexecutorsig.h"
#endif
-#if !defined(NO_UNIX_BACKTRACE_SUPPORT) && defined(USE_UNIX_SIGNAL_HANDLING) && defined(__GNUC__) && defined(__GLIBC__) && !defined(__CYGWIN__) && !defined(__MINGW32__) && !defined(__NetBSD__) && !defined(__SVR4) && !defined(__QNX__)
-#define USE_UNIX_BACKTRACE_SUPPORT
-#include
-#include
+#ifdef USE_WINDOWS_SEH
+#include "cppcheckexecutorseh.h"
#endif
-#if defined(_WIN32)
-#if defined(_MSC_VER)
-#define USE_WINDOWS_SEH
-#endif
-#if defined (__MINGW32__)
-# include
-# include
-# include
-#else
-# include
-# include
-# include
-#endif
-#include
+#ifdef _WIN32
+#include
#endif
@@ -264,605 +234,12 @@ void CppCheckExecutor::setSettings(const Settings &settings)
mSettings = &settings;
}
-/**
- * Simple helper function:
- * \return size of array
- * */
-template
-std::size_t getArrayLength(const T (&)[size])
-{
- return 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!
- * 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)
-{
-#if defined(USE_UNIX_BACKTRACE_SUPPORT)
-// 32 vs. 64bit
-#define ADDRESSDISPLAYLENGTH ((sizeof(long)==8)?12:8)
- const int fd = fileno(output);
- void *callstackArray[32]= {nullptr}; // 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;
- else
- maxdepth = std::min(maxdepth, currentdepth);
- if (lowMem) {
- fputs("Callstack (symbols only):\n", output);
- backtrace_symbols_fd(callstackArray+offset, maxdepth, fd);
- } else {
- char **symbolStringList = backtrace_symbols(callstackArray, currentdepth);
- if (symbolStringList) {
- fputs("Callstack:\n", output);
- char demangle_buffer[2048]= {0};
- for (int i = offset; i < maxdepth; ++i) {
- 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);
- const int padLen = int(ADDRESSDISPLAYLENGTH-addressLen);
- if (demangling && firstBracketName) {
- const char * const plus = strchr(firstBracketName, '+');
- if (plus && (plus>(firstBracketName+1))) {
- char input_buffer[1024]= {0};
- strncpy(input_buffer, firstBracketName+1, plus-firstBracketName-1);
- size_t length = getArrayLength(demangle_buffer);
- int status=0;
- // 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, demangle_buffer, &length, &status); // non-NULL on success
- }
- }
- const int ordinal=i-offset;
- fprintf(output, "#%-2d 0x",
- ordinal);
- if (padLen>0)
- fprintf(output, "%0*d",
- padLen, 0);
- if (realnameString) {
- fprintf(output, "%.*s in %s\n",
- (int)(secondBracketAddress-firstBracketAddress-3), firstBracketAddress+3,
- realnameString);
- } else {
- fprintf(output, "%.*s in %.*s\n",
- (int)(secondBracketAddress-firstBracketAddress-3), firstBracketAddress+3,
- (int)(firstBracketAddress-symbolString), symbolString);
- }
- }
- free(symbolStringList);
- } else {
- fputs("Callstack could not be obtained\n", output);
- }
- }
-#undef ADDRESSDISPLAYLENGTH
-#else
- (void)output;
- (void)demangling;
- (void)maxdepth;
- (void)lowMem;
-#endif
-}
-
-#ifdef __USE_DYNAMIC_STACK_SIZE
-static const size_t MYSTACKSIZE = 16*1024+32768; // wild guess about a reasonable buffer
-#else
-static const size_t MYSTACKSIZE = 16*1024+SIGSTKSZ; // wild guess about a reasonable buffer
-#endif
-static char mytstack[MYSTACKSIZE]= {0}; // alternative stack for signal handler
-static bool bStackBelowHeap=false; // lame attempt to locate heap vs. stack address space. See CppCheckExecutor::check_wrapper()
-
-/**
- * \param[in] ptr address to be examined.
- * \return true if address is supposed to be on stack (contrary to heap). If ptr is 0 false will be returned.
- * If unknown better return false.
- */
-static bool IsAddressOnStack(const void* ptr)
-{
- if (nullptr==ptr)
- return false;
- char a;
- if (bStackBelowHeap)
- 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)
-using Signalmap_t = std::map;
-static const Signalmap_t listofsignals = {
- 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) no usage currently
-};
-#undef DECLARE_SIGNAL
-/*
- * Entry pointer for signal handlers
- * It uses functions which are not safe to be called from a signal handler,
- * (http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_04 has a whitelist)
- * 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)
-{
- int type = -1;
- pid_t killid;
-#if defined(__linux__) && defined(REG_ERR)
- const ucontext_t* const uc = reinterpret_cast(context);
- killid = (pid_t) syscall(SYS_gettid);
- if (uc) {
- type = (int)uc->uc_mcontext.gregs[REG_ERR] & 2;
- }
-#else
- (void)context;
- killid = getpid();
-#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; // try to print a callstack?
- bool lowMem=false; // was low-memory condition detected? Be careful then! Avoid allocating much more memory then.
- bool unexpectedSignal=true; // unexpected indicates program failure
- bool terminate=true; // exit process/thread
- const bool isAddressOnStack = IsAddressOnStack(info->si_addr);
- FILE* output = CppCheckExecutor::getExceptionOutput();
- switch (signo) {
- case SIGABRT:
- fputs("Internal error: cppcheck received signal ", output);
- fputs(signame, output);
- fputs(
-#ifdef NDEBUG
- " - out of memory?\n",
-#else
- " - out of memory or assertion?\n",
-#endif
- output);
- lowMem=true; // educated guess
- break;
- case SIGBUS:
- fputs("Internal error: cppcheck received signal ", output);
- fputs(signame, output);
- switch (info->si_code) {
- case BUS_ADRALN: // invalid address alignment
- fputs(" - BUS_ADRALN", output);
- break;
- case BUS_ADRERR: // nonexistent physical address
- fputs(" - BUS_ADRERR", output);
- break;
- case BUS_OBJERR: // object-specific hardware error
- fputs(" - BUS_OBJERR", output);
- break;
-#ifdef BUS_MCEERR_AR
- case BUS_MCEERR_AR: // Hardware memory error consumed on a machine check;
- fputs(" - BUS_MCEERR_AR", output);
- break;
-#endif
-#ifdef BUS_MCEERR_AO
- case BUS_MCEERR_AO: // Hardware memory error detected in process but not consumed
- fputs(" - BUS_MCEERR_AO", output);
- break;
-#endif
- default:
- break;
- }
- fprintf(output, " (at 0x%lx).\n",
- (unsigned long)info->si_addr);
- break;
- case SIGFPE:
- fputs("Internal error: cppcheck received signal ", output);
- fputs(signame, output);
- switch (info->si_code) {
- case FPE_INTDIV: // integer divide by zero
- fputs(" - FPE_INTDIV", output);
- break;
- case FPE_INTOVF: // integer overflow
- fputs(" - FPE_INTOVF", output);
- break;
- case FPE_FLTDIV: // floating-point divide by zero
- fputs(" - FPE_FLTDIV", output);
- break;
- case FPE_FLTOVF: // floating-point overflow
- fputs(" - FPE_FLTOVF", output);
- break;
- case FPE_FLTUND: // floating-point underflow
- fputs(" - FPE_FLTUND", output);
- break;
- case FPE_FLTRES: // floating-point inexact result
- fputs(" - FPE_FLTRES", output);
- break;
- case FPE_FLTINV: // floating-point invalid operation
- fputs(" - FPE_FLTINV", output);
- break;
- case FPE_FLTSUB: // subscript out of range
- fputs(" - FPE_FLTSUB", output);
- break;
- default:
- break;
- }
- fprintf(output, " (at 0x%lx).\n",
- (unsigned long)info->si_addr);
- break;
- case SIGILL:
- fputs("Internal error: cppcheck received signal ", output);
- fputs(signame, output);
- switch (info->si_code) {
- case ILL_ILLOPC: // illegal opcode
- fputs(" - ILL_ILLOPC", output);
- break;
- case ILL_ILLOPN: // illegal operand
- fputs(" - ILL_ILLOPN", output);
- break;
- case ILL_ILLADR: // illegal addressing mode
- fputs(" - ILL_ILLADR", output);
- break;
- case ILL_ILLTRP: // illegal trap
- fputs(" - ILL_ILLTRP", output);
- break;
- case ILL_PRVOPC: // privileged opcode
- fputs(" - ILL_PRVOPC", output);
- break;
- case ILL_PRVREG: // privileged register
- fputs(" - ILL_PRVREG", output);
- break;
- case ILL_COPROC: // coprocessor error
- fputs(" - ILL_COPROC", output);
- break;
- case ILL_BADSTK: // internal stack error
- fputs(" - ILL_BADSTK", output);
- break;
- default:
- break;
- }
- fprintf(output, " (at 0x%lx).%s\n",
- (unsigned long)info->si_addr,
- (isAddressOnStack)?" Stackoverflow?":"");
- break;
- case SIGINT:
- unexpectedSignal=false; // legal usage: interrupt application via CTRL-C
- fputs("cppcheck received signal ", output);
- fputs(signame, output);
- printCallstack=true;
- fputs(".\n", output);
- break;
- case SIGSEGV:
- fputs("Internal error: cppcheck received signal ", output);
- fputs(signame, output);
- switch (info->si_code) {
- case SEGV_MAPERR: // address not mapped to object
- fputs(" - SEGV_MAPERR", output);
- break;
- case SEGV_ACCERR: // invalid permissions for mapped object
- fputs(" - SEGV_ACCERR", output);
- break;
- default:
- break;
- }
- fprintf(output, " (%sat 0x%lx).%s\n",
- // cppcheck-suppress knownConditionTrueFalse ; FP
- (type==-1)? "" :
- (type==0) ? "reading " : "writing ",
- (unsigned long)info->si_addr,
- (isAddressOnStack)?" Stackoverflow?":""
- );
- break;
- case SIGUSR1:
- fputs("cppcheck received signal ", output);
- fputs(signame, output);
- fputs(".\n", output);
- terminate=false;
- break;
- default:
- fputs("Internal error: cppcheck received signal ", output);
- fputs(signame, output);
- fputs(".\n", output);
- break;
- }
- if (printCallstack) {
- print_stacktrace(output, true, -1, lowMem);
- }
- if (unexpectedSignal) {
- fputs("\nPlease report this to the cppcheck developers!\n", output);
- }
- fflush(output);
-
- 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
-
-#ifdef USE_WINDOWS_SEH
-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);
- 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;
-
- HMODULE hLibDbgHelp;
-// avoid explicit dependency on Dbghelp.dll
- bool loadDbgHelp()
- {
- hLibDbgHelp = ::LoadLibraryW(L"Dbghelp.dll");
- if (!hLibDbgHelp)
- return false;
- pStackWalk64 = (fpStackWalk64) ::GetProcAddress(hLibDbgHelp, "StackWalk64");
- pSymGetModuleBase64 = (fpSymGetModuleBase64) ::GetProcAddress(hLibDbgHelp, "SymGetModuleBase64");
- pSymGetSymFromAddr64 = (fpSymGetSymFromAddr64) ::GetProcAddress(hLibDbgHelp, "SymGetSymFromAddr64");
- pSymGetLineFromAddr64 = (fpSymGetLineFromAddr64)::GetProcAddress(hLibDbgHelp, "SymGetLineFromAddr64");
- pSymFunctionTableAccess64 = (fpSymFunctionTableAccess64)::GetProcAddress(hLibDbgHelp, "SymFunctionTableAccess64");
- pSymInitialize = (fpSymInitialize) ::GetProcAddress(hLibDbgHelp, "SymInitialize");
- pUnDecorateSymbolName = (fpUnDecorateSymbolName)::GetProcAddress(hLibDbgHelp, "UnDecorateSymbolName");
- return true;
- }
-
-
- void printCallstack(FILE* outputFile, PEXCEPTION_POINTERS ex)
- {
- if (!loadDbgHelp())
- return;
- const HANDLE hProcess = GetCurrentProcess();
- const HANDLE hThread = GetCurrentThread();
- pSymInitialize(
- hProcess,
- nullptr,
- TRUE
- );
- CONTEXT context = *(ex->ContextRecord);
- STACKFRAME64 stack= {0};
-#ifdef _M_IX86
- stack.AddrPC.Offset = context.Eip;
- stack.AddrPC.Mode = AddrModeFlat;
- stack.AddrStack.Offset = context.Esp;
- stack.AddrStack.Mode = AddrModeFlat;
- stack.AddrFrame.Offset = context.Ebp;
- stack.AddrFrame.Mode = AddrModeFlat;
-#else
- stack.AddrPC.Offset = context.Rip;
- stack.AddrPC.Mode = AddrModeFlat;
- stack.AddrStack.Offset = context.Rsp;
- stack.AddrStack.Mode = AddrModeFlat;
- stack.AddrFrame.Offset = context.Rsp;
- stack.AddrFrame.Mode = AddrModeFlat;
-#endif
- IMAGEHLP_SYMBOL64_EXT symbol;
- symbol.SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
- symbol.MaxNameLength = maxnamelength;
- DWORD64 displacement = 0;
- int beyond_main=-1; // emergency exit, see below
- for (ULONG frame = 0; ; frame++) {
- BOOL result = pStackWalk64
- (
-#ifdef _M_IX86
- IMAGE_FILE_MACHINE_I386,
-#else
- IMAGE_FILE_MACHINE_AMD64,
-#endif
- hProcess,
- hThread,
- &stack,
- &context,
- nullptr,
- pSymFunctionTableAccess64,
- pSymGetModuleBase64,
- nullptr
- );
- if (!result) // official end...
- break;
- pSymGetSymFromAddr64(hProcess, (ULONG64)stack.AddrPC.Offset, &displacement, &symbol);
- TCHAR undname[maxnamelength]= {0};
- pUnDecorateSymbolName((const TCHAR*)symbol.Name, (PTSTR)undname, (DWORD)getArrayLength(undname), UNDNAME_COMPLETE);
- if (beyond_main>=0)
- ++beyond_main;
- if (_tcscmp(undname, _T("main"))==0)
- beyond_main=0;
- fprintf(outputFile,
- "%lu. 0x%08I64X in ",
- frame, (ULONG64)stack.AddrPC.Offset);
- fputs((const char *)undname, outputFile);
- fputc('\n', outputFile);
- if (0==stack.AddrReturn.Offset || beyond_main>2) // StackWalk64() sometimes doesn't reach any end...
- break;
- }
-
- FreeLibrary(hLibDbgHelp);
- hLibDbgHelp=nullptr;
- }
-
- void writeMemoryErrorDetails(FILE* outputFile, PEXCEPTION_POINTERS ex, const char* description)
- {
- fputs(description, outputFile);
- fprintf(outputFile, " (instruction: 0x%p) ", ex->ExceptionRecord->ExceptionAddress);
- // Using %p for ULONG_PTR later on, so it must have size identical to size of pointer
- // This is not the universally portable solution but good enough for Win32/64
- C_ASSERT(sizeof(void*) == sizeof(ex->ExceptionRecord->ExceptionInformation[1]));
- switch (ex->ExceptionRecord->ExceptionInformation[0]) {
- case 0:
- fprintf(outputFile, "reading from 0x%p",
- reinterpret_cast(ex->ExceptionRecord->ExceptionInformation[1]));
- break;
- case 1:
- fprintf(outputFile, "writing to 0x%p",
- reinterpret_cast(ex->ExceptionRecord->ExceptionInformation[1]));
- break;
- case 8:
- fprintf(outputFile, "data execution prevention at 0x%p",
- reinterpret_cast(ex->ExceptionRecord->ExceptionInformation[1]));
- break;
- default:
- break;
- }
- }
-
- /*
- * Any evaluation of the exception needs to be done here!
- */
- int filterException(int code, PEXCEPTION_POINTERS ex)
- {
- FILE *outputFile = stdout;
- fputs("Internal error: ", outputFile);
- switch (ex->ExceptionRecord->ExceptionCode) {
- case EXCEPTION_ACCESS_VIOLATION:
- writeMemoryErrorDetails(outputFile, ex, "Access violation");
- break;
- case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
- fputs("Out of array bounds", outputFile);
- break;
- case EXCEPTION_BREAKPOINT:
- fputs("Breakpoint", outputFile);
- break;
- case EXCEPTION_DATATYPE_MISALIGNMENT:
- fputs("Misaligned data", outputFile);
- break;
- case EXCEPTION_FLT_DENORMAL_OPERAND:
- fputs("Denormalized floating-point value", outputFile);
- break;
- case EXCEPTION_FLT_DIVIDE_BY_ZERO:
- fputs("Floating-point divide-by-zero", outputFile);
- break;
- case EXCEPTION_FLT_INEXACT_RESULT:
- fputs("Inexact floating-point value", outputFile);
- break;
- case EXCEPTION_FLT_INVALID_OPERATION:
- fputs("Invalid floating-point operation", outputFile);
- break;
- case EXCEPTION_FLT_OVERFLOW:
- fputs("Floating-point overflow", outputFile);
- break;
- case EXCEPTION_FLT_STACK_CHECK:
- fputs("Floating-point stack overflow", outputFile);
- break;
- case EXCEPTION_FLT_UNDERFLOW:
- fputs("Floating-point underflow", outputFile);
- break;
- case EXCEPTION_GUARD_PAGE:
- fputs("Page-guard access", outputFile);
- break;
- case EXCEPTION_ILLEGAL_INSTRUCTION:
- fputs("Illegal instruction", outputFile);
- break;
- case EXCEPTION_IN_PAGE_ERROR:
- writeMemoryErrorDetails(outputFile, ex, "Invalid page access");
- break;
- case EXCEPTION_INT_DIVIDE_BY_ZERO:
- fputs("Integer divide-by-zero", outputFile);
- break;
- case EXCEPTION_INT_OVERFLOW:
- fputs("Integer overflow", outputFile);
- break;
- case EXCEPTION_INVALID_DISPOSITION:
- fputs("Invalid exception dispatcher", outputFile);
- break;
- case EXCEPTION_INVALID_HANDLE:
- fputs("Invalid handle", outputFile);
- break;
- case EXCEPTION_NONCONTINUABLE_EXCEPTION:
- fputs("Non-continuable exception", outputFile);
- break;
- case EXCEPTION_PRIV_INSTRUCTION:
- fputs("Invalid instruction", outputFile);
- break;
- case EXCEPTION_SINGLE_STEP:
- fputs("Single instruction step", outputFile);
- break;
- case EXCEPTION_STACK_OVERFLOW:
- fputs("Stack overflow", outputFile);
- break;
- default:
- fprintf(outputFile, "Unknown exception (%d)\n",
- code);
- break;
- }
- fputc('\n', outputFile);
- printCallstack(outputFile, ex);
- fflush(outputFile);
- return EXCEPTION_EXECUTE_HANDLER;
- }
-}
-#endif
-
-/**
- * Signal/SEH handling
- * Has to be clean for using with SEH on windows, i.e. no construction of C++ object instances is allowed!
- * TODO Check for multi-threading issues!
- *
- */
int CppCheckExecutor::check_wrapper(CppCheck& cppcheck)
{
#ifdef USE_WINDOWS_SEH
- FILE *outputFile = stdout;
- __try {
- return check_internal(cppcheck);
- } __except (filterException(GetExceptionCode(), GetExceptionInformation())) {
- // reporting to stdout may not be helpful within a GUI application...
- fputs("Please report this to the cppcheck developers!\n", outputFile);
- return -1;
- }
+ return check_wrapper_seh(*this, &CppCheckExecutor::check_internal, cppcheck);
#elif defined(USE_UNIX_SIGNAL_HANDLING)
- // determine stack vs. heap
- char stackVariable;
- char *heapVariable=(char*)malloc(1);
- bStackBelowHeap = &stackVariable < heapVariable;
- free(heapVariable);
-
- // set up alternative stack for signal handler
- stack_t segv_stack;
- segv_stack.ss_sp = mytstack;
- segv_stack.ss_flags = 0;
- segv_stack.ss_size = MYSTACKSIZE;
- sigaltstack(&segv_stack, nullptr);
-
- // install signal handler
- struct sigaction act;
- memset(&act, 0, sizeof(act));
- act.sa_flags=SA_SIGINFO|SA_ONSTACK;
- act.sa_sigaction=CppcheckSignalHandler;
- for (std::map::const_iterator sig=listofsignals.begin(); sig!=listofsignals.end(); ++sig) {
- sigaction(sig->first, &act, nullptr);
- }
- return check_internal(cppcheck);
+ return check_wrapper_sig(*this, &CppCheckExecutor::check_internal, cppcheck);
#else
return check_internal(cppcheck);
#endif
diff --git a/cli/cppcheckexecutorseh.cpp b/cli/cppcheckexecutorseh.cpp
new file mode 100644
index 000000000..b0d3a1425
--- /dev/null
+++ b/cli/cppcheckexecutorseh.cpp
@@ -0,0 +1,269 @@
+/*
+ * Cppcheck - A tool for static C/C++ code analysis
+ * Copyright (C) 2007-2022 Cppcheck team.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "cppcheckexecutorseh.h"
+
+#ifdef USE_WINDOWS_SEH
+
+#include "cppcheckexecutor.h"
+#include "utils.h"
+
+#include
+#include
+#include
+
+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);
+ 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;
+
+ HMODULE hLibDbgHelp;
+// avoid explicit dependency on Dbghelp.dll
+ bool loadDbgHelp()
+ {
+ hLibDbgHelp = ::LoadLibraryW(L"Dbghelp.dll");
+ if (!hLibDbgHelp)
+ return false;
+ pStackWalk64 = (fpStackWalk64) ::GetProcAddress(hLibDbgHelp, "StackWalk64");
+ pSymGetModuleBase64 = (fpSymGetModuleBase64) ::GetProcAddress(hLibDbgHelp, "SymGetModuleBase64");
+ pSymGetSymFromAddr64 = (fpSymGetSymFromAddr64) ::GetProcAddress(hLibDbgHelp, "SymGetSymFromAddr64");
+ pSymGetLineFromAddr64 = (fpSymGetLineFromAddr64)::GetProcAddress(hLibDbgHelp, "SymGetLineFromAddr64");
+ pSymFunctionTableAccess64 = (fpSymFunctionTableAccess64)::GetProcAddress(hLibDbgHelp, "SymFunctionTableAccess64");
+ pSymInitialize = (fpSymInitialize) ::GetProcAddress(hLibDbgHelp, "SymInitialize");
+ pUnDecorateSymbolName = (fpUnDecorateSymbolName)::GetProcAddress(hLibDbgHelp, "UnDecorateSymbolName");
+ return true;
+ }
+
+
+ void printCallstack(FILE* outputFile, PEXCEPTION_POINTERS ex)
+ {
+ if (!loadDbgHelp())
+ return;
+ const HANDLE hProcess = GetCurrentProcess();
+ const HANDLE hThread = GetCurrentThread();
+ pSymInitialize(
+ hProcess,
+ nullptr,
+ TRUE
+ );
+ CONTEXT context = *(ex->ContextRecord);
+ STACKFRAME64 stack= {0};
+#ifdef _M_IX86
+ stack.AddrPC.Offset = context.Eip;
+ stack.AddrPC.Mode = AddrModeFlat;
+ stack.AddrStack.Offset = context.Esp;
+ stack.AddrStack.Mode = AddrModeFlat;
+ stack.AddrFrame.Offset = context.Ebp;
+ stack.AddrFrame.Mode = AddrModeFlat;
+#else
+ stack.AddrPC.Offset = context.Rip;
+ stack.AddrPC.Mode = AddrModeFlat;
+ stack.AddrStack.Offset = context.Rsp;
+ stack.AddrStack.Mode = AddrModeFlat;
+ stack.AddrFrame.Offset = context.Rsp;
+ stack.AddrFrame.Mode = AddrModeFlat;
+#endif
+ IMAGEHLP_SYMBOL64_EXT symbol;
+ symbol.SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
+ symbol.MaxNameLength = maxnamelength;
+ DWORD64 displacement = 0;
+ int beyond_main=-1; // emergency exit, see below
+ for (ULONG frame = 0; ; frame++) {
+ BOOL result = pStackWalk64
+ (
+#ifdef _M_IX86
+ IMAGE_FILE_MACHINE_I386,
+#else
+ IMAGE_FILE_MACHINE_AMD64,
+#endif
+ hProcess,
+ hThread,
+ &stack,
+ &context,
+ nullptr,
+ pSymFunctionTableAccess64,
+ pSymGetModuleBase64,
+ nullptr
+ );
+ if (!result) // official end...
+ break;
+ pSymGetSymFromAddr64(hProcess, (ULONG64)stack.AddrPC.Offset, &displacement, &symbol);
+ TCHAR undname[maxnamelength]= {0};
+ pUnDecorateSymbolName((const TCHAR*)symbol.Name, (PTSTR)undname, (DWORD)getArrayLength(undname), UNDNAME_COMPLETE);
+ if (beyond_main>=0)
+ ++beyond_main;
+ if (_tcscmp(undname, _T("main"))==0)
+ beyond_main=0;
+ fprintf(outputFile,
+ "%lu. 0x%08I64X in ",
+ frame, (ULONG64)stack.AddrPC.Offset);
+ fputs((const char *)undname, outputFile);
+ fputc('\n', outputFile);
+ if (0==stack.AddrReturn.Offset || beyond_main>2) // StackWalk64() sometimes doesn't reach any end...
+ break;
+ }
+
+ FreeLibrary(hLibDbgHelp);
+ hLibDbgHelp=nullptr;
+ }
+
+ void writeMemoryErrorDetails(FILE* outputFile, PEXCEPTION_POINTERS ex, const char* description)
+ {
+ fputs(description, outputFile);
+ fprintf(outputFile, " (instruction: 0x%p) ", ex->ExceptionRecord->ExceptionAddress);
+ // Using %p for ULONG_PTR later on, so it must have size identical to size of pointer
+ // This is not the universally portable solution but good enough for Win32/64
+ C_ASSERT(sizeof(void*) == sizeof(ex->ExceptionRecord->ExceptionInformation[1]));
+ switch (ex->ExceptionRecord->ExceptionInformation[0]) {
+ case 0:
+ fprintf(outputFile, "reading from 0x%p",
+ reinterpret_cast(ex->ExceptionRecord->ExceptionInformation[1]));
+ break;
+ case 1:
+ fprintf(outputFile, "writing to 0x%p",
+ reinterpret_cast(ex->ExceptionRecord->ExceptionInformation[1]));
+ break;
+ case 8:
+ fprintf(outputFile, "data execution prevention at 0x%p",
+ reinterpret_cast(ex->ExceptionRecord->ExceptionInformation[1]));
+ break;
+ default:
+ break;
+ }
+ }
+
+ /*
+ * Any evaluation of the exception needs to be done here!
+ */
+ int filterException(int code, PEXCEPTION_POINTERS ex)
+ {
+ FILE *outputFile = stdout;
+ fputs("Internal error: ", outputFile);
+ switch (ex->ExceptionRecord->ExceptionCode) {
+ case EXCEPTION_ACCESS_VIOLATION:
+ writeMemoryErrorDetails(outputFile, ex, "Access violation");
+ break;
+ case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
+ fputs("Out of array bounds", outputFile);
+ break;
+ case EXCEPTION_BREAKPOINT:
+ fputs("Breakpoint", outputFile);
+ break;
+ case EXCEPTION_DATATYPE_MISALIGNMENT:
+ fputs("Misaligned data", outputFile);
+ break;
+ case EXCEPTION_FLT_DENORMAL_OPERAND:
+ fputs("Denormalized floating-point value", outputFile);
+ break;
+ case EXCEPTION_FLT_DIVIDE_BY_ZERO:
+ fputs("Floating-point divide-by-zero", outputFile);
+ break;
+ case EXCEPTION_FLT_INEXACT_RESULT:
+ fputs("Inexact floating-point value", outputFile);
+ break;
+ case EXCEPTION_FLT_INVALID_OPERATION:
+ fputs("Invalid floating-point operation", outputFile);
+ break;
+ case EXCEPTION_FLT_OVERFLOW:
+ fputs("Floating-point overflow", outputFile);
+ break;
+ case EXCEPTION_FLT_STACK_CHECK:
+ fputs("Floating-point stack overflow", outputFile);
+ break;
+ case EXCEPTION_FLT_UNDERFLOW:
+ fputs("Floating-point underflow", outputFile);
+ break;
+ case EXCEPTION_GUARD_PAGE:
+ fputs("Page-guard access", outputFile);
+ break;
+ case EXCEPTION_ILLEGAL_INSTRUCTION:
+ fputs("Illegal instruction", outputFile);
+ break;
+ case EXCEPTION_IN_PAGE_ERROR:
+ writeMemoryErrorDetails(outputFile, ex, "Invalid page access");
+ break;
+ case EXCEPTION_INT_DIVIDE_BY_ZERO:
+ fputs("Integer divide-by-zero", outputFile);
+ break;
+ case EXCEPTION_INT_OVERFLOW:
+ fputs("Integer overflow", outputFile);
+ break;
+ case EXCEPTION_INVALID_DISPOSITION:
+ fputs("Invalid exception dispatcher", outputFile);
+ break;
+ case EXCEPTION_INVALID_HANDLE:
+ fputs("Invalid handle", outputFile);
+ break;
+ case EXCEPTION_NONCONTINUABLE_EXCEPTION:
+ fputs("Non-continuable exception", outputFile);
+ break;
+ case EXCEPTION_PRIV_INSTRUCTION:
+ fputs("Invalid instruction", outputFile);
+ break;
+ case EXCEPTION_SINGLE_STEP:
+ fputs("Single instruction step", outputFile);
+ break;
+ case EXCEPTION_STACK_OVERFLOW:
+ fputs("Stack overflow", outputFile);
+ break;
+ default:
+ fprintf(outputFile, "Unknown exception (%d)\n",
+ code);
+ break;
+ }
+ fputc('\n', outputFile);
+ printCallstack(outputFile, ex);
+ fflush(outputFile);
+ return EXCEPTION_EXECUTE_HANDLER;
+ }
+}
+
+/**
+ * Signal/SEH handling
+ * Has to be clean for using with SEH on windows, i.e. no construction of C++ object instances is allowed!
+ * TODO Check for multi-threading issues!
+ *
+ */
+int check_wrapper_seh(CppCheckExecutor& executor, int (CppCheckExecutor::*f)(CppCheck&), CppCheck& cppcheck)
+{
+ FILE *outputFile = stdout;
+ __try {
+ return (&executor->*f)(cppcheck);
+ } __except (filterException(GetExceptionCode(), GetExceptionInformation())) {
+ // reporting to stdout may not be helpful within a GUI application...
+ fputs("Please report this to the cppcheck developers!\n", outputFile);
+ return -1;
+ }
+}
+
+#endif
diff --git a/cli/cppcheckexecutorseh.h b/cli/cppcheckexecutorseh.h
new file mode 100644
index 000000000..487cc9221
--- /dev/null
+++ b/cli/cppcheckexecutorseh.h
@@ -0,0 +1,33 @@
+/*
+ * Cppcheck - A tool for static C/C++ code analysis
+ * Copyright (C) 2007-2022 Cppcheck team.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#ifndef CPPCHECKEXECUTORSEH_H
+#define CPPCHECKEXECUTORSEH_H
+
+#include "config.h"
+
+#ifdef USE_WINDOWS_SEH
+
+class CppCheckExecutor;
+class CppCheck;
+
+int check_wrapper_seh(CppCheckExecutor& executor, int (CppCheckExecutor::*f)(CppCheck&), CppCheck& cppcheck);
+
+#endif
+
+#endif // CPPCHECKEXECUTORSEH_H
diff --git a/cli/cppcheckexecutorsig.cpp b/cli/cppcheckexecutorsig.cpp
new file mode 100644
index 000000000..5f8943da2
--- /dev/null
+++ b/cli/cppcheckexecutorsig.cpp
@@ -0,0 +1,326 @@
+/*
+ * Cppcheck - A tool for static C/C++ code analysis
+ * Copyright (C) 2007-2022 Cppcheck team.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "cppcheckexecutorsig.h"
+
+#if defined(USE_UNIX_SIGNAL_HANDLING)
+
+#include "cppcheckexecutor.h"
+
+#ifdef USE_UNIX_BACKTRACE_SUPPORT
+#include "stacktrace.h"
+#endif
+
+#include
+#include
+#include
+#include
+#include