Skip to content

Commit f6fff71

Browse files
authored
Fix #15013 (warning hash: calculate hash for CTU warnings) (#8829)
1 parent bb630c2 commit f6fff71

3 files changed

Lines changed: 115 additions & 3 deletions

File tree

lib/errorlogger.cpp

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,21 @@ const std::set<std::string> ErrorLogger::mCriticalErrorIds{
6161
"unknownMacro"
6262
};
6363

64+
static std::size_t sdbm(const std::string& hashString) {
65+
return std::accumulate(hashString.cbegin(), hashString.cend(), std::size_t{0}, [](std::size_t h, unsigned char c) {
66+
return static_cast<std::size_t>(c) + (h << 6) + (h << 16) - h;
67+
});
68+
}
69+
6470
ErrorMessage::ErrorMessage()
6571
: severity(Severity::none), cwe(0U), certainty(Certainty::normal)
6672
{}
6773

74+
static bool needsFallbackHash(const std::string &id)
75+
{
76+
return startsWith(id, "ctu") || id == "unusedFunction" || id == "staticFunction";
77+
}
78+
6879
// TODO: id and msg are swapped compared to other calls
6980
ErrorMessage::ErrorMessage(std::list<FileLocation> callStack, std::string file1, Severity severity, const std::string &msg, std::string id, Certainty certainty) :
7081
callStack(std::move(callStack)), // locations for this error message
@@ -76,6 +87,9 @@ ErrorMessage::ErrorMessage(std::list<FileLocation> callStack, std::string file1,
7687
{
7788
// set the summary and verbose messages
7889
setmsg(msg);
90+
91+
if (hash == 0 && needsFallbackHash(this->id))
92+
calculateWarningHashFromLocations();
7993
}
8094

8195

@@ -90,6 +104,9 @@ ErrorMessage::ErrorMessage(std::list<FileLocation> callStack, std::string file1,
90104
{
91105
// set the summary and verbose messages
92106
setmsg(msg);
107+
108+
if (hash == 0 && needsFallbackHash(this->id))
109+
calculateWarningHashFromLocations();
93110
}
94111

95112
ErrorMessage::ErrorMessage(const std::list<const Token*>& callstack, const TokenList* list, Severity severity, std::string id, const std::string& msg, Certainty certainty)
@@ -300,9 +317,25 @@ void ErrorMessage::calculateWarningHash(const std::list<const Token*>& callstack
300317

301318
// hash algorithm: sdbm
302319
// any hash algorithm can be used but it has to be the same hash on different platforms and compilers
303-
hash = std::accumulate(hashString.cbegin(), hashString.cend(), std::size_t{0}, [](std::size_t h, unsigned char c) {
304-
return static_cast<std::size_t>(c) + (h << 6) + (h << 16) - h;
305-
});
320+
hash = sdbm(hashString);
321+
}
322+
323+
void ErrorMessage::calculateWarningHashFromLocations()
324+
{
325+
// No token information is available for this warning (e.g. whole-program/CTU
326+
// checks, unusedFunction, staticFunction) so calculateWarningHash() can't be
327+
// used. Instead hash the id, message and all filenames/notes in the callstack.
328+
std::string hashString = id + '\n' + mShortMessage;
329+
for (const FileLocation &loc : callStack) {
330+
std::string fileName = loc.getfile(false);
331+
if (Path::isAbsolute(fileName))
332+
fileName = fileName.substr(fileName.rfind('/') + 1);
333+
hashString += '\n' + fileName + '\n' + loc.getinfo();
334+
}
335+
336+
// hash algorithm: sdbm
337+
// any hash algorithm can be used but it has to be the same hash on different platforms and compilers
338+
hash = sdbm(hashString);
306339
}
307340

308341
static void serializeString(std::string &oss, const std::string & str)

lib/errorlogger.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,13 @@ class CPPCHECKLIB ErrorMessage {
211211

212212
void calculateWarningHash(const std::list<const Token*>& callstack);
213213

214+
/**
215+
* Fallback hash calculation for warnings that have no token information
216+
* (e.g. whole-program/CTU checks, unusedFunction, staticFunction). Hashes
217+
* the id, message and all filenames/notes in the callstack instead.
218+
*/
219+
void calculateWarningHashFromLocations();
220+
214221
/** Short message */
215222
std::string mShortMessage;
216223

test/testerrorlogger.cpp

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ class TestErrorLogger : public TestFixture {
4949
TEST_CASE(FileLocationSetFile2);
5050
TEST_CASE(ErrorMessageConstruct);
5151
TEST_CASE(ErrorMessageConstructLocations);
52+
TEST_CASE(ErrorMessageHashFallback);
5253
TEST_CASE(ErrorMessageVerbose);
5354
TEST_CASE(ErrorMessageVerboseLocations);
5455
TEST_CASE(ErrorMessageVerboseSymbol);
@@ -267,6 +268,77 @@ class TestErrorLogger : public TestFixture {
267268
ASSERT_EQUALS("[foo.cpp:5] -> [bar.cpp:8]: (error) Programming error.", msg.toString(true, templateFormat, ""));
268269
}
269270

271+
// unusedFunction/staticFunction/ctu* warnings carry no token information, so
272+
// ErrorMessage::calculateWarningHash() (which needs tokens) can't compute a
273+
// hash for them. calculateWarningHashFromLocations() is the fallback used
274+
// instead - it hashes the id, message and all location filenames/notes.
275+
void ErrorMessageHashFallback() const {
276+
// ids that don't need a fallback hash still get none
277+
{
278+
std::list<ErrorMessage::FileLocation> locs(1, fooCpp5);
279+
ErrorMessage msg(std::move(locs), "", Severity::style, "Some warning.", "someOtherId", Certainty::normal);
280+
ASSERT_EQUALS(0, msg.hash);
281+
}
282+
283+
// unusedFunction, staticFunction and any ctu* id get a non-zero fallback hash
284+
for (const std::string& id : { std::string("unusedFunction"), std::string("staticFunction"), std::string("ctuOneDefinitionRuleViolation") }) {
285+
std::list<ErrorMessage::FileLocation> locs(1, fooCpp5);
286+
ErrorMessage msg(std::move(locs), "", Severity::style, "Some warning.", id, Certainty::normal);
287+
ASSERT(msg.hash != 0);
288+
}
289+
290+
// same id/message/locations => same hash
291+
{
292+
std::list<ErrorMessage::FileLocation> locs1(1, fooCpp5);
293+
ErrorMessage msg1(std::move(locs1), "", Severity::style, "Some warning.", "unusedFunction", Certainty::normal);
294+
295+
std::list<ErrorMessage::FileLocation> locs2(1, fooCpp5);
296+
ErrorMessage msg2(std::move(locs2), "", Severity::style, "Some warning.", "unusedFunction", Certainty::normal);
297+
298+
ASSERT_EQUALS(msg1.hash, msg2.hash);
299+
}
300+
301+
// different message => different hash
302+
{
303+
std::list<ErrorMessage::FileLocation> locs1(1, fooCpp5);
304+
ErrorMessage msg1(std::move(locs1), "", Severity::style, "Some warning.", "unusedFunction", Certainty::normal);
305+
306+
std::list<ErrorMessage::FileLocation> locs2(1, fooCpp5);
307+
ErrorMessage msg2(std::move(locs2), "", Severity::style, "Some other warning.", "unusedFunction", Certainty::normal);
308+
309+
ASSERT(msg1.hash != msg2.hash);
310+
}
311+
312+
// different location filename => different hash
313+
{
314+
std::list<ErrorMessage::FileLocation> locs1(1, fooCpp5);
315+
ErrorMessage msg1(std::move(locs1), "", Severity::style, "Some warning.", "unusedFunction", Certainty::normal);
316+
317+
std::list<ErrorMessage::FileLocation> locs2(1, barCpp8);
318+
ErrorMessage msg2(std::move(locs2), "", Severity::style, "Some warning.", "unusedFunction", Certainty::normal);
319+
320+
ASSERT(msg1.hash != msg2.hash);
321+
}
322+
323+
// different location note (info) => different hash
324+
{
325+
std::list<ErrorMessage::FileLocation> locs1(1, barCpp8);
326+
ErrorMessage msg1(std::move(locs1), "", Severity::error, "Some warning.", "ctuOneDefinitionRuleViolation", Certainty::normal);
327+
328+
std::list<ErrorMessage::FileLocation> locs2(1, barCpp8_i);
329+
ErrorMessage msg2(std::move(locs2), "", Severity::error, "Some warning.", "ctuOneDefinitionRuleViolation", Certainty::normal);
330+
331+
ASSERT(msg1.hash != msg2.hash);
332+
}
333+
334+
// hash shows up in the XML output
335+
{
336+
std::list<ErrorMessage::FileLocation> locs(1, fooCpp5);
337+
ErrorMessage msg(std::move(locs), "", Severity::style, "Some warning.", "unusedFunction", Certainty::normal);
338+
ASSERT(msg.toXML().find(" hash=\"") != std::string::npos);
339+
}
340+
}
341+
270342
void ErrorMessageVerbose() const {
271343
std::list<ErrorMessage::FileLocation> locs(1, fooCpp5);
272344
ErrorMessage msg(std::move(locs), "", Severity::error, "Programming error.\nVerbose error", "errorId", Certainty::normal);

0 commit comments

Comments
 (0)