diff --git a/Makefile b/Makefile index 42b754733ec..a7f3feefba6 100644 --- a/Makefile +++ b/Makefile @@ -600,7 +600,7 @@ $(libcppdir)/cppcheck.o: lib/cppcheck.cpp externals/picojson/picojson.h external $(libcppdir)/ctu.o: lib/ctu.cpp externals/tinyxml2/tinyxml2.h lib/astutils.h lib/check.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h lib/xml.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/ctu.cpp -$(libcppdir)/errorlogger.o: lib/errorlogger.cpp externals/tinyxml2/tinyxml2.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/token.h lib/tokenlist.h lib/utils.h lib/vfvalue.h lib/xml.h +$(libcppdir)/errorlogger.o: lib/errorlogger.cpp externals/tinyxml2/tinyxml2.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenlist.h lib/utils.h lib/vfvalue.h lib/xml.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/errorlogger.cpp $(libcppdir)/errortypes.o: lib/errortypes.cpp lib/config.h lib/errortypes.h lib/utils.h diff --git a/lib/errorlogger.cpp b/lib/errorlogger.cpp index d58c5abcbba..f4580fa2dc4 100644 --- a/lib/errorlogger.cpp +++ b/lib/errorlogger.cpp @@ -23,6 +23,7 @@ #include "path.h" #include "settings.h" #include "suppressions.h" +#include "symboldatabase.h" #include "token.h" #include "tokenlist.h" #include "utils.h" @@ -35,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -106,6 +108,8 @@ ErrorMessage::ErrorMessage(const std::list& callstack, const Token file0 = list->getFiles()[0]; setmsg(msg); + + calculateWarningHash(callstack); } @@ -126,7 +130,7 @@ ErrorMessage::ErrorMessage(const std::list& callstack, const Token setmsg(msg); - // hash = calculateWarningHash(list, hashWarning.str()); + calculateWarningHash(callstack); } ErrorMessage::ErrorMessage(ErrorPath errorPath, const TokenList *tokenList, Severity severity, const char id[], const std::string &msg, const CWE &cwe, Certainty certainty) @@ -159,7 +163,11 @@ ErrorMessage::ErrorMessage(ErrorPath errorPath, const TokenList *tokenList, Seve setmsg(msg); - // hash = calculateWarningHash(tokenList, hashWarning.str()); + std::list callstack; + for (const ErrorPathItem& e: errorPath) { + callstack.push_back(e.first); + } + calculateWarningHash(callstack); } // TODO: improve errorhandling? @@ -244,6 +252,58 @@ void ErrorMessage::setmsg(const std::string &msg) } } +void ErrorMessage::calculateWarningHash(const std::list& callstack) +{ + if (callstack.empty()) + return; + // Calculate a hash for this warning message + std::string hashString; + for (const Token* tok: callstack) { + if (!tok) + continue; + if (!tok->scope()) + return; // might be a syntax error before scope info has been set + if (tok->scope()->isExecutable()) { + // Executable scope => include all tokens in the function => if the + // function is changed the hash is changed + for (const Token* t = tok; t; t = t->previous()) { + if (!t->scope()->isExecutable()) + break; + hashString += " " + t->str(); + } + for (const Token* t = tok->next(); t; t = t->next()) { + if (!t->scope()->isExecutable()) + break; + hashString += " " + t->str(); + } + } else { + // Non executable scope => include tokens in current statement => if the current statement is changed the hash is changed + for (const Token* t = tok; t; t = t->previous()) { + if (t->str() == ";") + break; + if (t->scope() != tok->scope()) // stop on {} unless its an initializer + break; + hashString += " " + t->str(); + } + for (const Token* t = tok->next(); t; t = t->next()) { + hashString += " " + t->str(); + if (t->str() == ";") + break; + if (t->scope() != tok->scope()) // stop on {} unless its an initializer + break; + } + } + } + + hashString = id + '\n' + mShortMessage + '\n' + hashString; + + // hash algorithm: sdbm + // any hash algorithm can be used but it has to be the same hash on different platforms and compilers + hash = std::accumulate(hashString.cbegin(), hashString.cend(), 0, [](std::size_t hash, char c) { + return static_cast(c) + (hash << 6) + (hash << 16) - hash; + }); +} + static void serializeString(std::string &oss, const std::string & str) { oss += std::to_string(str.length()); diff --git a/lib/errorlogger.h b/lib/errorlogger.h index 97cc3e7f82e..b28fdba244e 100644 --- a/lib/errorlogger.h +++ b/lib/errorlogger.h @@ -209,6 +209,8 @@ class CPPCHECKLIB ErrorMessage { private: static std::string fixInvalidChars(const std::string& raw); + void calculateWarningHash(const std::list& callstack); + /** Short message */ std::string mShortMessage; diff --git a/oss-fuzz/Makefile b/oss-fuzz/Makefile index eeb795bd35c..e6966747958 100644 --- a/oss-fuzz/Makefile +++ b/oss-fuzz/Makefile @@ -270,7 +270,7 @@ $(libcppdir)/cppcheck.o: ../lib/cppcheck.cpp ../externals/picojson/picojson.h .. $(libcppdir)/ctu.o: ../lib/ctu.cpp ../externals/tinyxml2/tinyxml2.h ../lib/astutils.h ../lib/check.h ../lib/config.h ../lib/ctu.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h ../lib/xml.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/ctu.cpp -$(libcppdir)/errorlogger.o: ../lib/errorlogger.cpp ../externals/tinyxml2/tinyxml2.h ../lib/check.h ../lib/checkers.h ../lib/color.h ../lib/config.h ../lib/cppcheck.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/standards.h ../lib/suppressions.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h ../lib/xml.h +$(libcppdir)/errorlogger.o: ../lib/errorlogger.cpp ../externals/tinyxml2/tinyxml2.h ../lib/check.h ../lib/checkers.h ../lib/color.h ../lib/config.h ../lib/cppcheck.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/suppressions.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h ../lib/xml.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/errorlogger.cpp $(libcppdir)/errortypes.o: ../lib/errortypes.cpp ../lib/config.h ../lib/errortypes.h ../lib/utils.h diff --git a/test/cli/other_test.py b/test/cli/other_test.py index c48a0b50354..e1553dcc904 100644 --- a/test/cli/other_test.py +++ b/test/cli/other_test.py @@ -2666,7 +2666,7 @@ def test_xml_output(tmp_path): # #13391 / #13485 - + p