From 1937ce7efd2f3ca53793a2d4ce0de3be7031badd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Wed, 5 Aug 2026 14:43:50 +0200 Subject: [PATCH 1/4] Fix #14959 (Warning hash for token-based warnings) --- lib/errorlogger.cpp | 61 +++++++++++++++++++++++++++++++++++++++++++-- lib/errorlogger.h | 2 ++ 2 files changed, 61 insertions(+), 2 deletions(-) diff --git a/lib/errorlogger.cpp b/lib/errorlogger.cpp index d58c5abcbba..f61e9607b9c 100644 --- a/lib/errorlogger.cpp +++ b/lib/errorlogger.cpp @@ -106,6 +106,8 @@ ErrorMessage::ErrorMessage(const std::list& callstack, const Token file0 = list->getFiles()[0]; setmsg(msg); + + calculateWarningHash(callstack); } @@ -126,7 +128,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 +161,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 +250,57 @@ 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()->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 = 0; + for (auto c: hashString) { + hash = 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; From 7e349835b47705ac72acbbdd651ae6ca095f014e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Wed, 5 Aug 2026 16:35:34 +0200 Subject: [PATCH 2/4] fix --- Makefile | 2 +- lib/errorlogger.cpp | 22 +++++++++++++--------- oss-fuzz/Makefile | 2 +- test/cli/other_test.py | 2 +- 4 files changed, 16 insertions(+), 12 deletions(-) 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 f61e9607b9c..7c592a32225 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 @@ -161,11 +163,12 @@ ErrorMessage::ErrorMessage(ErrorPath errorPath, const TokenList *tokenList, Seve setmsg(msg); - std::list callstack; - for (const ErrorPathItem& e: errorPath) { - callstack.push_back(e.first); - } - calculateWarningHash(callstack); + std::list tokens; + std::transform(errorPath.cbegin(), errorPath.cend(), std::back_inserter(tokens), + [](const ErrorPathItem& e) { + return e.first; + }); + calculateWarningHash(tokens); } // TODO: improve errorhandling? @@ -259,6 +262,8 @@ void ErrorMessage::calculateWarningHash(const std::list& callstack 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 @@ -295,10 +300,9 @@ void ErrorMessage::calculateWarningHash(const std::list& callstack // hash algorithm: sdbm // any hash algorithm can be used but it has to be the same hash on different platforms and compilers - hash = 0; - for (auto c: hashString) { - hash = c + (hash << 6) + (hash << 16) - hash; - } + 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) 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 From 7635fa2f208f27332deb60682ebeadb670e2c51b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Thu, 6 Aug 2026 16:06:57 +0200 Subject: [PATCH 3/4] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- lib/errorlogger.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/errorlogger.cpp b/lib/errorlogger.cpp index 7c592a32225..d57ad999734 100644 --- a/lib/errorlogger.cpp +++ b/lib/errorlogger.cpp @@ -300,8 +300,8 @@ void ErrorMessage::calculateWarningHash(const std::list& callstack // 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; + hash = std::accumulate(hashString.cbegin(), hashString.cend(), std::size_t{0}, [](std::size_t h, unsigned char c) { + return static_cast(c) + (h << 6) + (h << 16) - h; }); } From eef690af150f4a4f89fdfb91b1e7c9386b1a1b9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Thu, 6 Aug 2026 18:07:14 +0200 Subject: [PATCH 4/4] hash --- test/cli/other_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/cli/other_test.py b/test/cli/other_test.py index e1553dcc904..f5928c07de5 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