From aa6fa0e67d677e31a13869f399144c42ff9b40c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sun, 26 Oct 2025 14:17:05 +0100 Subject: [PATCH 1/2] Fix #14225 (addons; add optional "hash" attribute for warning messages) --- lib/cppcheck.cpp | 3 +++ lib/errorlogger.cpp | 14 ++++++-------- lib/errorlogger.h | 2 +- lib/sarifreport.cpp | 6 ++++++ test/cli/premium_test.py | 19 ++++++++++++++++++- 5 files changed, 34 insertions(+), 10 deletions(-) diff --git a/lib/cppcheck.cpp b/lib/cppcheck.cpp index 9c411a8b0af..81c7a28e2e0 100644 --- a/lib/cppcheck.cpp +++ b/lib/cppcheck.cpp @@ -1624,6 +1624,9 @@ void CppCheck::executeAddons(const std::vector& files, const std::s } errmsg.file0 = file0; + if (obj.count("hash")>0) + errmsg.hash = obj["hash"].get(); + mErrorLogger.reportErr(errmsg); } } diff --git a/lib/errorlogger.cpp b/lib/errorlogger.cpp index 17b87cc2c93..c8d7b02dd34 100644 --- a/lib/errorlogger.cpp +++ b/lib/errorlogger.cpp @@ -57,7 +57,7 @@ const std::set ErrorLogger::mCriticalErrorIds{ }; ErrorMessage::ErrorMessage() - : severity(Severity::none), cwe(0U), certainty(Certainty::normal), hash(0) + : severity(Severity::none), cwe(0U), certainty(Certainty::normal) {} // TODO: id and msg are swapped compared to other calls @@ -67,8 +67,7 @@ ErrorMessage::ErrorMessage(std::list callStack, std::string file1, file0(std::move(file1)), severity(severity), // severity for this error message cwe(0U), - certainty(certainty), - hash(0) + certainty(certainty) { // set the summary and verbose messages setmsg(msg); @@ -82,15 +81,14 @@ ErrorMessage::ErrorMessage(std::list callStack, std::string file1, file0(std::move(file1)), severity(severity), // severity for this error message cwe(cwe.id), - certainty(certainty), - hash(0) + certainty(certainty) { // set the summary and verbose messages setmsg(msg); } ErrorMessage::ErrorMessage(const std::list& callstack, const TokenList* list, Severity severity, std::string id, const std::string& msg, Certainty certainty) - : id(std::move(id)), severity(severity), cwe(0U), certainty(certainty), hash(0) + : id(std::move(id)), severity(severity), cwe(0U), certainty(certainty) { // Format callstack for (auto it = callstack.cbegin(); it != callstack.cend(); ++it) { @@ -125,7 +123,7 @@ ErrorMessage::ErrorMessage(const std::list& callstack, const Token setmsg(msg); - hash = 0; // calculateWarningHash(list, hashWarning.str()); + // hash = calculateWarningHash(list, hashWarning.str()); } ErrorMessage::ErrorMessage(ErrorPath errorPath, const TokenList *tokenList, Severity severity, const char id[], const std::string &msg, const CWE &cwe, Certainty certainty) @@ -158,7 +156,7 @@ ErrorMessage::ErrorMessage(ErrorPath errorPath, const TokenList *tokenList, Seve setmsg(msg); - hash = 0; // calculateWarningHash(tokenList, hashWarning.str()); + // hash = calculateWarningHash(tokenList, hashWarning.str()); } ErrorMessage::ErrorMessage(const tinyxml2::XMLElement * const errmsg) diff --git a/lib/errorlogger.h b/lib/errorlogger.h index 5101f765fad..8c88cfbbc9e 100644 --- a/lib/errorlogger.h +++ b/lib/errorlogger.h @@ -179,7 +179,7 @@ class CPPCHECKLIB ErrorMessage { std::string guideline; /** Warning hash */ - std::size_t hash; + std::size_t hash{}; /** set short and verbose messages */ void setmsg(const std::string &msg); diff --git a/lib/sarifreport.cpp b/lib/sarifreport.cpp index 08eddbf8198..9d4d0b82145 100644 --- a/lib/sarifreport.cpp +++ b/lib/sarifreport.cpp @@ -145,6 +145,12 @@ picojson::array SarifReport::serializeResults() const message["text"] = picojson::value(finding.shortMessage()); res["message"] = picojson::value(message); res["ruleId"] = picojson::value(finding.id); + if (finding.hash != 0) { + picojson::object partialFingerprints; + partialFingerprints["hash"] = picojson::value(std::to_string(finding.hash)); + partialFingerprints["id"] = picojson::value(finding.id); + res["partialFingerprints"] = picojson::value(partialFingerprints); + } results.emplace_back(res); } return results; diff --git a/test/cli/premium_test.py b/test/cli/premium_test.py index b93636880b3..45121819e87 100644 --- a/test/cli/premium_test.py +++ b/test/cli/premium_test.py @@ -163,4 +163,21 @@ def test_help(tmpdir): assert exitcode == 0 assert stdout.startswith('Cppcheck ') # check for product name - TODO: should be "Cppcheck Premium" assert '--premium=' in stdout, stdout # check for premium option - assert 'cppchecksolutions.com' in stdout, stdout # check for premium help link \ No newline at end of file + assert 'cppchecksolutions.com' in stdout, stdout # check for premium help link + + +def test_hash(tmpdir): + # Trac 14225 - warnings with hash + test_file = os.path.join(tmpdir, 'test.c') + addon_file = os.path.join(tmpdir, 'premiumaddon.py') + + with open(test_file, 'wt') as f: + f.write('void foo();\n') + + args = [f"--addon={addon_file}", '--xml', test_file] + + with open(addon_file, 'wt') as f: + f.write('print(\'{"addon":"a","column":1,"errorId":"id","extra":"","file":"test.c","hash":123,"linenr":1,"message":"bug","severity":"error"}\')') + + _, _, stderr = cppcheck(args) + assert ' Date: Mon, 27 Oct 2025 21:25:23 +0100 Subject: [PATCH 2/2] review comments --- lib/sarifreport.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/sarifreport.cpp b/lib/sarifreport.cpp index 9d4d0b82145..4dadc3d5d71 100644 --- a/lib/sarifreport.cpp +++ b/lib/sarifreport.cpp @@ -147,8 +147,7 @@ picojson::array SarifReport::serializeResults() const res["ruleId"] = picojson::value(finding.id); if (finding.hash != 0) { picojson::object partialFingerprints; - partialFingerprints["hash"] = picojson::value(std::to_string(finding.hash)); - partialFingerprints["id"] = picojson::value(finding.id); + partialFingerprints["hash/v1"] = picojson::value(std::to_string(finding.hash)); res["partialFingerprints"] = picojson::value(partialFingerprints); } results.emplace_back(res);