From d30dfaaf27af5891899b52ef9aa2e64c48b1152c Mon Sep 17 00:00:00 2001 From: rnd Date: Tue, 24 May 2016 13:40:18 +0300 Subject: [PATCH 1/3] Add feature: Cache check results for subsequent checks: - Add command line flag: --cache=path/to/cache.xml - Each check is cached along side the check file's size, preprocessed code hash (SHA-512), configuration, check results - In subsequent runs, if a file with the same path, size, hash is found in cache- report the cached results rather than running the full check again. - File hash and size are calculated on preprocessed code. This ensures that the file hasn't changed as well as the included files. - Results are cached disregarding uniquity. This allows subsequent runs with different configuration-sets to have all the results available. Report output is still unique- just the cache isn't. - File path must be exact across runs. (either use same relative paths or same full path) --- .gitmodules | 3 + CMakeLists.txt | 1 + cli/CMakeLists.txt | 11 +- cli/cmdlineparser.cpp | 16 ++ cli/cppcheckexecutor.cpp | 495 ++++++++++++++++++----------------- externals/cryptopp | 1 + lib/CMakeLists.txt | 1 + lib/cache.cpp | 296 +++++++++++++++++++++ lib/cache.h | 122 +++++++++ lib/cppcheck.cpp | 27 +- lib/cppcheck.h | 5 +- lib/cppcheck.vcxproj | 3 + lib/cppcheck.vcxproj.filters | 9 + lib/settings.h | 8 +- lib/tempcache.h | 61 +++++ 15 files changed, 806 insertions(+), 253 deletions(-) create mode 100644 .gitmodules create mode 160000 externals/cryptopp create mode 100644 lib/cache.cpp create mode 100644 lib/cache.h create mode 100644 lib/tempcache.h diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000000..94f9912cd19 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "externals/cryptopp"] + path = externals/cryptopp + url = git@github.com:nirbar/cryptopp.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 4de3c06e588..bae8f6e8875 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,6 +17,7 @@ if (BUILD_TESTS) endif() add_subdirectory(externals/tinyxml) +add_subdirectory(externals/cryptopp) add_subdirectory(lib) # CppCheck Library add_subdirectory(cli) # Client application add_subdirectory(test) # Tests diff --git a/cli/CMakeLists.txt b/cli/CMakeLists.txt index a7fc54fcca5..d877907fe2a 100644 --- a/cli/CMakeLists.txt +++ b/cli/CMakeLists.txt @@ -1,16 +1,25 @@ include_directories(${PROJECT_SOURCE_DIR}/lib/) include_directories(SYSTEM ${PROJECT_SOURCE_DIR}/externals/tinyxml/) +include_directories(SYSTEM ${PROJECT_SOURCE_DIR}/externals/) file(GLOB hdrs "*.h") file(GLOB srcs "*.cpp") file(GLOB mainfile "main.cpp") list(REMOVE_ITEM srcs ${mainfile}) +set(libs + cryptopp-static + ) +if(WIN32) + set(libs ${libs} Shlwapi.lib) +endif() + add_library(cli_objs OBJECT ${hdrs} ${srcs}) add_executable(cppcheck ${hdrs} ${mainfile} $ $ $) if (HAVE_RULES) - target_link_libraries(cppcheck pcre) + set(libs ${libs} pcre) endif() +target_link_libraries(cppcheck ${libs}) install(TARGETS cppcheck RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_BINDIR} diff --git a/cli/cmdlineparser.cpp b/cli/cmdlineparser.cpp index e3c5b3f8018..7625d21e201 100644 --- a/cli/cmdlineparser.cpp +++ b/cli/cmdlineparser.cpp @@ -173,6 +173,22 @@ bool CmdLineParser::ParseFromArgs(int argc, const char* const argv[]) } } + // Cache file (--cache=) + else if (std::strncmp(argv[i], "--cache=", strlen("--cache=")) == 0) { + std::string str(argv[i]); + str=str.substr(strlen("--cache=")); + if( str.empty()){ + PrintMessage("cppcheck: No cache file given to '--cache=' option."); + return false; + } + + _settings->cacheFile = str; + if (0 != _settings->cache.Load(str)) + { + PrintMessage("cppcheck: Failed loading cache file " + str); + } + } + // Filter errors else if (std::strncmp(argv[i], "--exitcode-suppressions=", 24) == 0) { // exitcode-suppressions=filename.txt diff --git a/cli/cppcheckexecutor.cpp b/cli/cppcheckexecutor.cpp index fa5e880e165..74331cc4456 100644 --- a/cli/cppcheckexecutor.cpp +++ b/cli/cppcheckexecutor.cpp @@ -198,76 +198,76 @@ std::size_t GetArrayLength(const T(&)[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, it's using functions not whitelisted for usage in a signal handler function. - */ + /* + * 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* 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 *array[32]= {0}; // the less resources the better... - 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 - if (maxdepth<0) - maxdepth=currentdepth-offset; - else - maxdepth = std::min(maxdepth, currentdepth); - if (lowMem) { - fputs("Callstack (symbols only):\n", output); - backtrace_symbols_fd(array+offset, maxdepth, fd); - fflush(output); - } else { - char **symbolstrings = backtrace_symbols(array, currentdepth); - if (symbolstrings) { - fputs("Callstack:\n", output); - for (int i = offset; i < maxdepth; ++i) { - const char * const symbol = symbolstrings[i]; - char * realname = nullptr; - const char * const firstBracketName = strchr(symbol, '('); - const char * const firstBracketAddress = strchr(symbol, '['); - 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[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 fd = fileno(output); + void *array[32]= {0}; // the less resources the better... + 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 + if (maxdepth<0) + maxdepth=currentdepth-offset; + else + maxdepth = std::min(maxdepth, currentdepth); + if (lowMem) { + fputs("Callstack (symbols only):\n", output); + backtrace_symbols_fd(array+offset, maxdepth, fd); + fflush(output); + } else { + char **symbolstrings = backtrace_symbols(array, currentdepth); + if (symbolstrings) { + fputs("Callstack:\n", output); + for (int i = offset; i < maxdepth; ++i) { + const char * const symbol = symbolstrings[i]; + char * realname = nullptr; + const char * const firstBracketName = strchr(symbol, '('); + const char * const firstBracketAddress = strchr(symbol, '['); + 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[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(output, "#%-2d 0x", + ordinal); + if (padLen>0) + fprintf(output, "%0*d", + padLen, 0); + if (realname) { + fprintf(output, "%.*s in %s\n", + (int)(secondBracketAddress-firstBracketAddress-3), firstBracketAddress+3, + realname); + } else { + fprintf(output, "%.*s in %.*s\n", + (int)(secondBracketAddress-firstBracketAddress-3), firstBracketAddress+3, + (int)(firstBracketAddress-symbol), symbol); } } - const int ordinal=i-offset; - fprintf(output, "#%-2d 0x", - ordinal); - if (padLen>0) - fprintf(output, "%0*d", - padLen, 0); - if (realname) { - fprintf(output, "%.*s in %s\n", - (int)(secondBracketAddress-firstBracketAddress-3), firstBracketAddress+3, - realname); - } else { - fprintf(output, "%.*s in %.*s\n", - (int)(secondBracketAddress-firstBracketAddress-3), firstBracketAddress+3, - (int)(firstBracketAddress-symbol), symbol); - } + free(symbolstrings); + } else { + fputs("Callstack could not be obtained\n", output); } - free(symbolstrings); - } else { - fputs("Callstack could not be obtained\n", output); } - } #undef ADDRESSDISPLAYLENGTH #endif -} + } static const size_t MYSTACKSIZE = 16*1024+SIGSTKSZ; // wild guess about a reasonable buffer static char mytstack[MYSTACKSIZE]= {0}; // alternative stack for signal handler @@ -279,37 +279,37 @@ static bool bStackBelowHeap=false; // lame attempt to locate heap vs. stack addr * 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; -} + { + 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: - */ + /* (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 Signalmap_t; + typedef std::map Signalmap_t; static 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) - ; + 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) + ; #undef DECLARE_SIGNAL /* * Entry pointer for signal handlers @@ -320,178 +320,178 @@ static const Signalmap_t listofsignals = make_container< Signalmap_t > () */ static void CppcheckSignalHandler(int signo, siginfo_t * info, void * context) { - int type = -1; - pid_t killid = getpid(); + int type = -1; + pid_t killid = getpid(); #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; - } + 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; + } #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; - bool lowMem=false; - bool unexpectedSignal=true; - 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(" - out of memory?\n", 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; + const Signalmap_t::const_iterator it=listofsignals.find(signo); + const char * const signame = (it==listofsignals.end()) ? "unknown" : it->second.c_str(); + bool printCallstack=true; + bool lowMem=false; + bool unexpectedSignal=true; + 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(" - out of memory?\n", 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; + 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; + 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); + 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 FPE_FLTSUB: // subscript out of range - fputs(" - FPE_FLTSUB", output); + 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", + (type==-1)? "" : + (type==0) ? "reading " : "writing ", + (unsigned long)info->si_addr, + (isaddressonstack)?" Stackoverflow?":"" + ); + break; + case SIGUSR1: + case SIGUSR2: + fputs("cppcheck received signal ", output); + fputs(signame, output); + fputs(".\n", output); break; default: + fputs("Internal error: cppcheck received signal ", output); + fputs(signame, output); + fputs(".\n", output); 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; + if (printCallstack) { + print_stacktrace(output, true, -1, lowMem); } - 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; + if (unexpectedSignal) { + fputs("\nPlease report this to the cppcheck developers!\n", output); } - fprintf(output, " (%sat 0x%lx).%s\n", - (type==-1)? "" : - (type==0) ? "reading " : "writing ", - (unsigned long)info->si_addr, - (isaddressonstack)?" Stackoverflow?":"" - ); - break; - case SIGUSR1: - case SIGUSR2: - fputs("cppcheck received signal ", output); - fputs(signame, output); - fputs(".\n", output); - 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); + fflush(output); - // now let things proceed, shutdown and hopefully dump core for post-mortem analysis - signal(signo, SIG_DFL); - kill(killid, signo); -} + // 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 @@ -880,6 +880,11 @@ int CppCheckExecutor::check_internal(CppCheck& cppcheck, int /*argc*/, const cha reportErr(ErrorLogger::ErrorMessage::getXMLFooter(settings.xml_version)); } + if (!settings.cacheFile.empty()) + { + settings.cache.Save(); + } + _settings = 0; if (returnValue) return settings.exitCode; diff --git a/externals/cryptopp b/externals/cryptopp new file mode 160000 index 00000000000..55f34935781 --- /dev/null +++ b/externals/cryptopp @@ -0,0 +1 @@ +Subproject commit 55f349357819719a7f439d7f6c68b6ec9720a868 diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 3d5949baa53..3eaaf5e958c 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -1,4 +1,5 @@ include_directories(SYSTEM ${PROJECT_SOURCE_DIR}/externals/tinyxml/) +include_directories(SYSTEM ${PROJECT_SOURCE_DIR}/externals/) file(GLOB_RECURSE hdrs "*.h") file(GLOB_RECURSE srcs "*.cpp") diff --git a/lib/cache.cpp b/lib/cache.cpp new file mode 100644 index 00000000000..ddd7fdc8241 --- /dev/null +++ b/lib/cache.cpp @@ -0,0 +1,296 @@ +#include "cache.h" +#include "errorlogger.h" +#include +#include +#include +#include +using namespace std; +using namespace tinyxml2; +using namespace CryptoPP; + +Cache::Cache() +{ +} + +Cache::Cache(const Cache & other) +{ + *this = other; +} + +Cache & Cache::operator=(const Cache & other) +{ + Clear(); + if (!_cacheFile.empty()) + { + Load(other._cacheFile); + } + return *this; +} + +int Cache::Load(const string& file) +{ + XMLError er = XML_SUCCESS; + + if (!_cacheFile.empty()) + { + return -1; + } + + _cacheFile = file; + er = _cache.LoadFile(file.c_str()); + + return((er == XML_SUCCESS) || (er == XML_NO_ERROR)) ? 0 : (er | XML_SUCCESS); +} + +int Cache::LoadFromCache(const char* filePath, const char* configuration, size_t* pCachedSize, std::string* pHash, const tinyxml2::XMLElement** ppElem) const +{ + const XMLElement *elem = NULL; + const char* sizeStr = NULL; + const char* hashStr = NULL; + size_t tmpSize = 0; + string path; + (*pCachedSize) = 0; + (*ppElem) = NULL; + pHash->clear(); + + path = Normalize(filePath); + + if ((Find(path.c_str(), configuration, &elem) != 0) || (elem == NULL)) + { + return -1; + } + + // Parse size + if ((sizeStr = elem->Attribute("Size")) == NULL) + { + return -1; + } + + if ((tmpSize = ::stoull(sizeStr, NULL)) == 0) + { + return -1; + } + + // Hash + if ((hashStr = elem->Attribute("Hash")) == NULL) + { + return -1; + } + + (*pCachedSize) = tmpSize; + (*pHash) = hashStr; + (*ppElem) = elem; + return 0; +} + +int Cache::Find(const char* filePath, const char* configuration, XMLElement** ppElem) +{ + return Find(filePath, configuration, (const XMLElement**)ppElem); +} + +int Cache::Find(const char* filePath, const char* configuration, const XMLElement** ppElem) const +{ + (*ppElem) = NULL; + + string path = Normalize(filePath); + if (path.empty() || _cacheFile.empty()) + { + return -1; + } + + const XMLElement* root = _cache.RootElement(); + if (root == NULL) + { + return -1; + } + + for (const XMLElement* currElem = root->FirstChildElement("File"); currElem != NULL; currElem = currElem->NextSiblingElement("File")) + { + if (currElem->Attribute("Path", path.c_str()) && currElem->Attribute("Configuration", configuration)) + { + (*ppElem) = currElem; + break; + } + } + + return ((*ppElem) == NULL); +} + +string Cache::CalcHash(const char* code) const +{ + SHA3_512 sha; + string out; + Base64Encoder* enc = new Base64Encoder(new StringSink(out), false); + + StringSource(code, true, new HashFilter(sha, enc)); + + return out; +} + +string Cache::Normalize(const char* filePath) const +{ + size_t i; + string path(filePath); + + while ((i = path.find('\\')) != string::npos) + { + path = path.replace(i, 1, "/"); + } + while ((i = path.find("//")) != string::npos) + { + path = path.replace(i, 2, "/"); + } + return path; +} + +bool Cache::ReportCachedResults(const char* filePath, const char* configuration, const char* code, ErrorLogger* pLogger) const +{ + string cachedHash; + size_t cachedSize = 0; + const XMLElement* pElem = NULL; + + // Cached? + if ((LoadFromCache(filePath, configuration, &cachedSize, &cachedHash, &pElem) != 0) || (cachedSize == 0) || cachedHash.empty() || (pElem == NULL)) + { + return false; + } + + // Compare size + size_t actualSize = strlen(code); + if (actualSize != cachedSize) + { + return false; + } + + // Compare hash + string actualHash = CalcHash(code); + if (actualHash.compare(cachedHash) != 0) + { + return false; + } + + for (const XMLElement* currChild = pElem->FirstChildElement("Report"); currChild != NULL; currChild = currChild->NextSiblingElement("Report")) + { + ErrorLogger::ErrorMessage msg; + string t = currChild->GetText(); + if (msg.deserialize(t)) + { + pLogger->reportErr(msg); + } + } + + return true; +} + +int Cache::CacheFile(const char* filePath, const char* configuration, const char* code, const std::list& reports) +{ + // Cache disabled + if (_cacheFile.empty()) + { + return 0; + } + + string path = Normalize(filePath); + if (path.empty()) + { + return -1; + } + + size_t actualSize = strlen(code); + if (actualSize == 0) + { + return -1; + } + + string actualHash = CalcHash(code); + if (actualHash.empty()) + { + return -1; + } + + XMLElement* pElem = NULL; + if ((Find(path.c_str(), configuration, &pElem) != 0) || (pElem == NULL)) + { + // Create element + XMLElement* root = _cache.RootElement(); + if (root == NULL) + { + root = _cache.NewElement("CppCheckCache"); + if (root == NULL) + { + return -1; + } + + if (_cache.InsertFirstChild(root) == NULL) + { + return -1; + } + } + + pElem = _cache.NewElement("File"); + if (pElem == NULL) + { + return -1; + } + + if (root->InsertEndChild(pElem) == NULL) + { + return -1; + } + } + + pElem->DeleteChildren(); + pElem->SetAttribute("Configuration", configuration); + pElem->SetAttribute("Size", actualSize); + pElem->SetAttribute("Hash", actualHash.c_str()); + pElem->SetAttribute("Path", path.c_str()); + + // Insert reports + std::list::const_iterator currIt, endIt; + for (currIt = reports.begin(), endIt = reports.end(); currIt != endIt; ++currIt) + { + XMLElement *report = _cache.NewElement("Report"); + if (report == NULL) + { + return -1; + } + + report->SetText(currIt->c_str()); + pElem->InsertEndChild(report); + } + + return 0; +} + +int Cache::Remove(const char* filePath, const char* configuration) +{ + XMLElement* pElem = NULL; + if ((Find(filePath, configuration, &pElem) != 0) || (pElem == NULL)) + { + return 0; + } + + XMLElement* root = _cache.RootElement(); + if (root == NULL) + { + return -1; + } + + root->DeleteChild(pElem); + return 0; +} + +void Cache::Clear() +{ + _cache.Clear(); + _cacheFile.clear(); +} + +int Cache::Save() +{ + XMLError er = XML_SUCCESS; + + er = _cache.SaveFile(_cacheFile.c_str()); + + return((er == XML_SUCCESS) || (er == XML_NO_ERROR)) ? 0 : (er | XML_SUCCESS); +} \ No newline at end of file diff --git a/lib/cache.h b/lib/cache.h new file mode 100644 index 00000000000..b82079a9874 --- /dev/null +++ b/lib/cache.h @@ -0,0 +1,122 @@ + +//--------------------------------------------------------------------------- +#ifndef cacheH +#define cacheH +//--------------------------------------------------------------------------- + +#include "config.h" +#include +#include "tinyxml2.h" +#include +#include +class ErrorLogger; +/// @addtogroup Core +/// @{ + +/** + * @brief Class maintains a cache of checked files + * + * Cache is enabled by command line switch --cache=_CacheFile_ + */ +class CPPCHECKLIB Cache { +public: + + /*! @brief Constructor + */ + Cache(); + + /*! @brief Copy Constructor + */ + Cache(const Cache& other); + + /*! @brief Copy another Cache instance + @param other- Cache to copy + @return Reference to this instance. + */ + Cache& operator=(const Cache& other); + + /*! @brief Loads cache from file + @param cacheFile- File used to load and save cached files data + @return Zero if file was successfully loaded to cache + */ + int Load(const std::string& cacheFile); + + /*! @brief Load cached results and report them + @details If a file has not changed since cached, load cached results and report them + @param filePath- Path to the file in question + @param configuration- Preprocessor configuration + @param code- Preprocessor code, as returned from Preprocessor::getcode() + @param pLogger- Logger to report errors to + @return true if and only if the file is in cache and has not changed since cached. + */ + bool ReportCachedResults(const char* filePath, const char* configuration, const char* code, ErrorLogger* pLogger) const; + + /*! @brief Place a file in cache + @details Caches the requested file in cache along with its hash value and size. + If a file is present in cache it is replaced with the new hash and size. + @param filePath- Path to the file to store in cache + @param configuration- Preprocessor configuration + @param code- Preprocessor code, as returned from Preprocessor::getcode() + @return Zero if file was successfully cached + */ + int CacheFile(const char* filePath, const char* configuration, const char* code, const std::list& reports); + + /*! @brief Removes a file from cache + @details Removes the requested file from cache. + @param filePath- Path to the file to store in cache + @param configuration- Preprocessor configuration + @return Zero if file was successfully removed from cache + */ + int Remove(const char* filePath, const char* configuration); + + /*! @brief Clears the cache + @details Clear the cache entirely, without saving to file + */ + void Clear(); + + /*! @brief Saves the cache to file + @details All operations since constructing the cache are performed in memory. Only when Save() is explicitly called will the cache be persisted to file. + @return Zero if cache was successfully saved + */ + int Save(); + +protected: + + /*! @brief Calaculate a file hash + @details For a given file path, calculate the file hash. Currently we use MD5 hash + @param code- Preprocessor code, as returned from Preprocessor::getcode() + @return Hash, or empty string if an error occured + */ + virtual std::string CalcHash(const char* code) const; + + /*! @brief Loads a file data from cache + @details Checks if the requested file is present in cache. If yes, output its cached size and hash + @param filePath- Path to the file in question + @param configuration- Preprocessor configuration + @param[out] pCachedSize- Pointer to a size_t variable to receive the file's cached size, if available + @param[out] pHash- Pointer to a string variable to receive the file's cached hash value, if available + @param[out] ppElem- Pointer to a XML element to receive the cached element, if available + @return Zero if file was successfully retreived from cache + */ + virtual int LoadFromCache(const char* filePath, const char* configuration, size_t* pCachedSize, std::string* pHash, const tinyxml2::XMLElement** ppElem) const; + + /*! @brief Returns a normalized representation of the file path + @details As file path separators are file system dependant, this function ensures a distinct represenatation accross file systems. + In this implementation, '\' is replaced with '/', and '//' is replaced with '/' + @param filePath- Path to normalize + @return A normalized form of path + */ + virtual std::string Normalize(const char* filePath) const; + +private: + + int Find(const char* filePath, const char* configuration, const tinyxml2::XMLElement** ppElem) const; + int Find(const char* filePath, const char* configuration, tinyxml2::XMLElement** ppElem); + + tinyxml2::XMLDocument _cache; + std::string _cacheFile; +}; + +/// @} +//--------------------------------------------------------------------------- +#endif // cacheH diff --git a/lib/cppcheck.cpp b/lib/cppcheck.cpp index 238073dd026..59758e0a6cd 100644 --- a/lib/cppcheck.cpp +++ b/lib/cppcheck.cpp @@ -160,7 +160,10 @@ unsigned int CppCheck::processFile(const std::string& filename, std::istream& fi std::set checksums; unsigned int checkCount = 0; for (std::list::const_iterator it = configurations.begin(); it != configurations.end(); ++it) { - // bail out if terminated + + _tempCache.reset(); // dump previous iteration results. + + // bail out if terminated if (_settings.terminated()) break; @@ -188,6 +191,13 @@ unsigned int CppCheck::processFile(const std::string& filename, std::istream& fi std::string codeWithoutCfg = preprocessor.getcode(filedata, cfg, filename); t.Stop(); + if (_settings.cache.ReportCachedResults(filename.c_str(), cfg.c_str(), codeWithoutCfg.c_str(), this)) + { + reportOut("File is cached: " + filename); + continue; + } + _tempCache.reset(new TempCache(this, &_settings, filename, cfg, codeWithoutCfg)); + codeWithoutCfg += _settings.append(); if (_settings.preprocessOnly) { @@ -263,9 +273,9 @@ unsigned int CppCheck::processFile(const std::string& filename, std::istream& fi // Check simplified tokens checkSimplifiedTokens(_tokenizer); - } - - } catch (const InternalError &e) { + } + + } catch (const InternalError &e) { if (_settings.isEnabled("information") && (_settings.debug || _settings.verbose)) purgedConfigurationMessage(filename, cfg); internalErrorFound=true; @@ -302,6 +312,7 @@ unsigned int CppCheck::processFile(const std::string& filename, std::istream& fi internalError(filename, e.errorMessage); exitcode=1; // e.g. reflect a syntax error } + _tempCache.reset(); // In jointSuppressionReport mode, unmatched suppressions are // collected after all files are processed @@ -567,7 +578,13 @@ void CppCheck::reportErr(const ErrorLogger::ErrorMessage &msg) if (errmsg.empty()) return; - // Alert only about unique errors + // Cache- even non-unique errors, as next test may be we different configurations and we don't want to mask an error just because in this scan it had different configurations. + if (!!_tempCache && !_settings.cacheFile.empty()) + { + _tempCache->Report(msg.serialize()); + } + + // Alert only about unique errors if (std::find(_errorList.begin(), _errorList.end(), errmsg) != _errorList.end()) return; diff --git a/lib/cppcheck.h b/lib/cppcheck.h index 380ba713db0..9fd09db7553 100644 --- a/lib/cppcheck.h +++ b/lib/cppcheck.h @@ -25,10 +25,12 @@ #include "settings.h" #include "errorlogger.h" #include "check.h" +#include "tempcache.h" #include #include #include +#include class Tokenizer; @@ -185,7 +187,8 @@ class CPPCHECKLIB CppCheck : ErrorLogger { */ virtual void reportOut(const std::string &outmsg); - std::list _errorList; + std::list _errorList; + std::shared_ptr _tempCache; Settings _settings; void reportProgress(const std::string &filename, const char stage[], const std::size_t value); diff --git a/lib/cppcheck.vcxproj b/lib/cppcheck.vcxproj index d0980e94878..5335f3420a8 100644 --- a/lib/cppcheck.vcxproj +++ b/lib/cppcheck.vcxproj @@ -37,6 +37,7 @@ + Create Create @@ -91,6 +92,8 @@ + + diff --git a/lib/cppcheck.vcxproj.filters b/lib/cppcheck.vcxproj.filters index c647ce9004f..338565d86b9 100644 --- a/lib/cppcheck.vcxproj.filters +++ b/lib/cppcheck.vcxproj.filters @@ -140,6 +140,9 @@ Source Files + + Source Files + @@ -280,6 +283,12 @@ Header Files + + Header Files + + + Header Files + diff --git a/lib/settings.h b/lib/settings.h index 13532e351dd..01115363fd9 100644 --- a/lib/settings.h +++ b/lib/settings.h @@ -31,7 +31,7 @@ #include "standards.h" #include "errorlogger.h" #include "timer.h" - +#include "cache.h" /// @addtogroup Core /// @{ @@ -114,6 +114,12 @@ class CPPCHECKLIB Settings { /** @brief Paths used as base for conversion to relative paths. */ std::vector basePaths; + /** @brief Path to cache file. */ + std::string cacheFile; + + /** @brief Cache */ + Cache cache; + /** @brief write XML results (--xml) */ bool xml; diff --git a/lib/tempcache.h b/lib/tempcache.h new file mode 100644 index 00000000000..702b7e8527a --- /dev/null +++ b/lib/tempcache.h @@ -0,0 +1,61 @@ + +//--------------------------------------------------------------------------- +#ifndef tempcacheH +#define tempcacheH +//--------------------------------------------------------------------------- + +#include "config.h" +#include +#include "tinyxml2.h" +#include +#include +class ErrorLogger; +/// @addtogroup Core +/// @{ + +/** + * @brief Class maintains a temporary cache for a single file and single configuration + * + * @details A scope-based temporay cache to accumulate check results before dumping them all to global cache. + */ +class CPPCHECKLIB TempCache { +public: + + /*! @brief Constructor + */ + TempCache(ErrorLogger* logger, Settings *settings, const std::string& filename, const std::string& cfg, const std::string& codeWithoutCfg) + : _settings(settings) + , _logger(logger) + , _filename(filename) + , _cfg(cfg) + , _codeWithoutCfg(codeWithoutCfg) + {} + + /*! @brief Dump errors to global cache + */ + ~TempCache() + { + if (0 > _settings->cache.CacheFile(_filename.c_str(), _cfg.c_str(), _codeWithoutCfg.c_str(), _reportCache)) + { + _logger->reportOut("Failed caching file: " + _filename); + } + } + + /*! @brief Report an error + */ + void Report(const std::string& msg) + { + _reportCache.push_back(msg); + } + +private: + + Settings *_settings; + ErrorLogger* _logger; + std::string _filename, _cfg, _codeWithoutCfg; + std::list _reportCache; +}; + +/// @} +//--------------------------------------------------------------------------- +#endif // tempcacheH From 93cf2396f880226e7fbe1d5e27da6d0bd75c9401 Mon Sep 17 00:00:00 2001 From: rnd Date: Tue, 24 May 2016 13:49:35 +0300 Subject: [PATCH 2/3] - Add command line flag: --cache=path/to/cache.xml - Each check is cached along side the file's pre-processed size, code hash (SHA-512), configuration, check results - In subsequent runs, if a file with the same path, size, hash is found in cache- report the cached results rather than running the full check again. - File hash and size are calculated on preprocessed code. This ensures that the file hasn't changed as well as the included files. - Results are cached disregarding uniquity. This allows subsequent runs with different configuration-sets to have all the results available. Report output is still unique- just the cache isn't. - File path must be exact across runs. (either use same relative paths or same full path) --- cli/cppcheckexecutor.cpp | 490 +++++++++++++++++++-------------------- 1 file changed, 245 insertions(+), 245 deletions(-) diff --git a/cli/cppcheckexecutor.cpp b/cli/cppcheckexecutor.cpp index 74331cc4456..c97edd627e9 100644 --- a/cli/cppcheckexecutor.cpp +++ b/cli/cppcheckexecutor.cpp @@ -198,76 +198,76 @@ std::size_t GetArrayLength(const T(&)[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, it's using functions not whitelisted for usage in a signal handler function. - */ +/* + * 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* 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 *array[32]= {0}; // the less resources the better... - 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 - if (maxdepth<0) - maxdepth=currentdepth-offset; - else - maxdepth = std::min(maxdepth, currentdepth); - if (lowMem) { - fputs("Callstack (symbols only):\n", output); - backtrace_symbols_fd(array+offset, maxdepth, fd); - fflush(output); - } else { - char **symbolstrings = backtrace_symbols(array, currentdepth); - if (symbolstrings) { - fputs("Callstack:\n", output); - for (int i = offset; i < maxdepth; ++i) { - const char * const symbol = symbolstrings[i]; - char * realname = nullptr; - const char * const firstBracketName = strchr(symbol, '('); - const char * const firstBracketAddress = strchr(symbol, '['); - 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[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(output, "#%-2d 0x", - ordinal); - if (padLen>0) - fprintf(output, "%0*d", - padLen, 0); - if (realname) { - fprintf(output, "%.*s in %s\n", - (int)(secondBracketAddress-firstBracketAddress-3), firstBracketAddress+3, - realname); - } else { - fprintf(output, "%.*s in %.*s\n", - (int)(secondBracketAddress-firstBracketAddress-3), firstBracketAddress+3, - (int)(firstBracketAddress-symbol), symbol); + const int fd = fileno(output); + void *array[32]= {0}; // the less resources the better... + 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 + if (maxdepth<0) + maxdepth=currentdepth-offset; + else + maxdepth = std::min(maxdepth, currentdepth); + if (lowMem) { + fputs("Callstack (symbols only):\n", output); + backtrace_symbols_fd(array+offset, maxdepth, fd); + fflush(output); + } else { + char **symbolstrings = backtrace_symbols(array, currentdepth); + if (symbolstrings) { + fputs("Callstack:\n", output); + for (int i = offset; i < maxdepth; ++i) { + const char * const symbol = symbolstrings[i]; + char * realname = nullptr; + const char * const firstBracketName = strchr(symbol, '('); + const char * const firstBracketAddress = strchr(symbol, '['); + 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[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 } } - free(symbolstrings); - } else { - fputs("Callstack could not be obtained\n", output); + const int ordinal=i-offset; + fprintf(output, "#%-2d 0x", + ordinal); + if (padLen>0) + fprintf(output, "%0*d", + padLen, 0); + if (realname) { + fprintf(output, "%.*s in %s\n", + (int)(secondBracketAddress-firstBracketAddress-3), firstBracketAddress+3, + realname); + } else { + fprintf(output, "%.*s in %.*s\n", + (int)(secondBracketAddress-firstBracketAddress-3), firstBracketAddress+3, + (int)(firstBracketAddress-symbol), symbol); + } } + free(symbolstrings); + } else { + fputs("Callstack could not be obtained\n", output); } + } #undef ADDRESSDISPLAYLENGTH #endif - } +} static const size_t MYSTACKSIZE = 16*1024+SIGSTKSZ; // wild guess about a reasonable buffer static char mytstack[MYSTACKSIZE]= {0}; // alternative stack for signal handler @@ -279,37 +279,37 @@ static bool bStackBelowHeap=false; // lame attempt to locate heap vs. stack addr * 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; - } +{ + 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: - */ +/* (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 Signalmap_t; +typedef std::map Signalmap_t; static 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) - ; + 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) + ; #undef DECLARE_SIGNAL /* * Entry pointer for signal handlers @@ -320,178 +320,178 @@ static const Signalmap_t listofsignals = make_container< Signalmap_t > () */ static void CppcheckSignalHandler(int signo, siginfo_t * info, void * context) { - int type = -1; - pid_t killid = getpid(); + int type = -1; + pid_t killid = getpid(); #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; - } + 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; + } #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; - bool lowMem=false; - bool unexpectedSignal=true; - 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(" - out of memory?\n", 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; + const Signalmap_t::const_iterator it=listofsignals.find(signo); + const char * const signame = (it==listofsignals.end()) ? "unknown" : it->second.c_str(); + bool printCallstack=true; + bool lowMem=false; + bool unexpectedSignal=true; + 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(" - out of memory?\n", 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; + 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; + 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?":""); + default: 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", - (type==-1)? "" : - (type==0) ? "reading " : "writing ", - (unsigned long)info->si_addr, - (isaddressonstack)?" Stackoverflow?":"" - ); - break; - case SIGUSR1: - case SIGUSR2: - fputs("cppcheck received signal ", output); - fputs(signame, output); - fputs(".\n", output); + } + 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: - fputs("Internal error: cppcheck received signal ", output); - fputs(signame, output); - fputs(".\n", output); break; } - if (printCallstack) { - print_stacktrace(output, true, -1, lowMem); + 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; } - if (unexpectedSignal) { - fputs("\nPlease report this to the cppcheck developers!\n", output); + 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; } - fflush(output); - - // now let things proceed, shutdown and hopefully dump core for post-mortem analysis - signal(signo, SIG_DFL); - kill(killid, signo); + fprintf(output, " (%sat 0x%lx).%s\n", + (type==-1)? "" : + (type==0) ? "reading " : "writing ", + (unsigned long)info->si_addr, + (isaddressonstack)?" Stackoverflow?":"" + ); + break; + case SIGUSR1: + case SIGUSR2: + fputs("cppcheck received signal ", output); + fputs(signame, output); + fputs(".\n", output); + 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); + + // 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 From f172bc1a24ec02e3f0a3ebfa85b68993c7f39e6e Mon Sep 17 00:00:00 2001 From: rnd Date: Tue, 31 May 2016 16:22:42 +0300 Subject: [PATCH 3/3] Report cached errors in headers multiple times when included in multiple source files. This somewhat reduces unique repoting, but follows full-scan convention. --- lib/cache.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/cache.cpp b/lib/cache.cpp index ddd7fdc8241..da0143c421d 100644 --- a/lib/cache.cpp +++ b/lib/cache.cpp @@ -173,10 +173,15 @@ bool Cache::ReportCachedResults(const char* filePath, const char* configuration, { ErrorLogger::ErrorMessage msg; string t = currChild->GetText(); - if (msg.deserialize(t)) + if (!msg.deserialize(t)) { - pLogger->reportErr(msg); + return false; } + if (msg._id.compare("syntaxError") != 0) + { + msg.file0 = filePath; + } + pLogger->reportErr(msg); } return true;