Skip to content

Fix first instance rule being used as rule description for all violations of that rule and other SARIF improvements #7640

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 83 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
83 commits
Select commit Hold shift + click to select a range
793e0a6
add description for sarif based on id so github doesnt show same text…
Nettozx Jul 1, 2025
152f804
better description handling and add rule.name to serialize
Nettozx Jul 1, 2025
f68a78e
only set severity level for security related sarif findings
Nettozx Jul 1, 2025
348abc7
set problem severity for non security findings
Nettozx Jul 1, 2025
11d537a
Merge branch 'danmar:main' into main
Nettozx Jul 1, 2025
ad9703a
no prefix string, and always set problem severity
Nettozx Jul 1, 2025
6c231a6
Merge branch 'main' of github.com:Nettozx/cppcheck
Nettozx Jul 1, 2025
49f64df
set defaultConfiguration to the same severity level
Nettozx Jul 1, 2025
86846fc
oops it was already there
Nettozx Jul 2, 2025
af080f2
guess recommendation is not valid even though the github documentatio…
Nettozx Jul 2, 2025
ed9b0ae
security-severity needs to be a string
Nettozx Jul 2, 2025
ce9c164
try short message for name
Nettozx Jul 2, 2025
069b0dd
update description functions to fallback to values from finding. add …
Nettozx Jul 2, 2025
1ddf844
change name back to short desc, change short desc to shortMessage, up…
Nettozx Jul 2, 2025
428f2ef
revert the shortDescription value, that causes the original issue to …
Nettozx Jul 2, 2025
50575b0
update comment
Nettozx Jul 2, 2025
c19bca9
more comment updates
Nettozx Jul 2, 2025
c1c4e90
add to authors
Nettozx Jul 2, 2025
a0da1e0
braces
Nettozx Jul 2, 2025
de9a4bc
unit tests
Nettozx Jul 2, 2025
e46a4fb
remove duplicate code
Nettozx Jul 2, 2025
c1d8f9b
match sarifSeverity for security-severity levels
Nettozx Jul 2, 2025
b43ac8f
fix misconception about isCriticalErrorId()
Nettozx Jul 2, 2025
8c9e3a9
update unit test
Nettozx Jul 2, 2025
ef874d3
test generic message builder
Nettozx Jul 2, 2025
cc301a5
Merge branch 'danmar:main' into generic
Nettozx Jul 2, 2025
346587a
add more regex to handle empty qutoes and extra spaces
Nettozx Jul 2, 2025
692c237
formatting
Nettozx Jul 2, 2025
5461bf1
add more pattern recognition for generification output. update messag…
Nettozx Jul 2, 2025
e676f87
uncrustify downloaded from link has _f suffix, update DETECTED_VERSIO…
Nettozx Jul 2, 2025
9a402a8
added unit tests for sarif and ran uncrustify
Nettozx Jul 2, 2025
2d15a78
add cwe tags
Nettozx Jul 2, 2025
f941ec9
add tests for cwe tags
Nettozx Jul 2, 2025
eb23dbe
fix regex issues for repeated varnames and empty brackets. fix issue …
Nettozx Jul 2, 2025
af98d3b
add more sarif test cases
Nettozx Jul 2, 2025
6b29143
fix issue for invalidScanfArgType_int output not being generic
Nettozx Jul 2, 2025
dff042a
fix scanf regex and add unit test for it
Nettozx Jul 2, 2025
47cec25
remove ruleID specific pattern matching and define generic regex that…
Nettozx Jul 2, 2025
235f950
fix column number being 0 issue
Nettozx Jul 3, 2025
35c575a
allow cwe tags for all rules and not just security related
Nettozx Jul 3, 2025
58df85f
more regex patterns to cover more instance specific data coming throu…
Nettozx Jul 3, 2025
2b64d7a
make description getters static
Nettozx Jul 3, 2025
5f2195e
Merge branch 'main' into main
Nettozx Jul 15, 2025
93c3a8f
move logic to errorlogger and make generic member
Nettozx Jul 15, 2025
dba842a
more regex and cleanup duplicate logic
Nettozx Jul 15, 2025
6c2829d
make it more simpler, remove generic for xml, update tests
Nettozx Jul 15, 2025
c978499
run uncrustify
Nettozx Jul 15, 2025
ee36017
Merge pull request #1 from Nettozx/generic
Nettozx Jul 15, 2025
aaea761
just make everything empty strings because github will then default t…
Nettozx Jul 16, 2025
754e509
dont need generic message anymore
Nettozx Jul 17, 2025
bab310b
revert error logger tests
Nettozx Jul 17, 2025
2e721e9
remove irrelevant tests
Nettozx Jul 17, 2025
cc9702c
add test case to check instance specific error messages
Nettozx Jul 17, 2025
cf78418
run uncrustify
Nettozx Jul 17, 2025
f52bce4
add description
Nettozx Jul 17, 2025
928d988
cross platform approach to running tests copied from cppcheckexecutor
Nettozx Jul 17, 2025
c973c26
run uncrustify
Nettozx Jul 17, 2025
e789c06
Merge branch 'generic'
Nettozx Jul 17, 2025
717d459
remove any unneccessary changes
Nettozx Jul 17, 2025
6e8bf04
revert formatting changes made by uncrustify. use ss instead of to_st…
Nettozx Jul 17, 2025
a1562fa
fix selfcheck issues
Nettozx Jul 17, 2025
143e2c8
add attempts at other executable paths
Nettozx Jul 17, 2025
47749d2
fix clang-tidy issues
Nettozx Jul 17, 2025
50b7c22
few more braces
Nettozx Jul 17, 2025
88854d4
revert a few more spacing
Nettozx Jul 17, 2025
ac402ff
cmake executable path in test, and clang-tidy fixes
Nettozx Jul 18, 2025
c1be953
empty spaces
Nettozx Jul 18, 2025
f2ab096
fix selfcheck issues
Nettozx Jul 18, 2025
74999d5
fix clang-tidy issues
Nettozx Jul 18, 2025
deb707f
Merge branch 'main' into main
Nettozx Jul 19, 2025
1df55f0
add helper since selfcheck complains both ways
Nettozx Jul 19, 2025
0a5fa05
Merge remote-tracking branch 'refs/remotes/origin/main'
Nettozx Jul 19, 2025
6486e9c
fix formatter complaint
Nettozx Jul 19, 2025
6baeeaf
fix dmake issue
Nettozx Jul 20, 2025
ca1b522
windows executable path changed since last merge
Nettozx Jul 21, 2025
f6f4d25
move sarif reporter to its own class so it can be used for tests, cha…
Nettozx Jul 31, 2025
726650b
selfcheck and clangtidy fixes
Nettozx Aug 1, 2025
859d909
Move SarifReport class to lib directory to fix Windows DLL export issues
Nettozx Aug 1, 2025
45fe918
Fix Linux Makefile dependencies for moved sarifreport files
Nettozx Aug 1, 2025
d71fa5a
dmake
Nettozx Aug 1, 2025
e0d764f
Fix picojson type conflicts in sarifreport - Remove incorrect forward…
Nettozx Aug 1, 2025
7ccea9c
dmake
Nettozx Aug 1, 2025
8eb89e3
formatting
Nettozx Aug 1, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,7 @@ Tomo Dote
Toralf Förster
Troshin V.S.
Tyson Nottingham
Usman Majid
Valentin Batz
Valerii Lashmanov
Vasily Maslyukov
Expand Down
12 changes: 10 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ ifndef INCLUDE_FOR_CLI
endif

ifndef INCLUDE_FOR_TEST
INCLUDE_FOR_TEST=-Ilib -Ifrontend -Icli -isystem externals/simplecpp -isystem externals/tinyxml2
INCLUDE_FOR_TEST=-Ilib -Ifrontend -Icli -isystem externals/picojson -isystem externals/simplecpp -isystem externals/tinyxml2
endif

BIN=$(DESTDIR)$(PREFIX)/bin
Expand Down Expand Up @@ -239,6 +239,7 @@ LIBOBJ = $(libcppdir)/valueflow.o \
$(libcppdir)/preprocessor.o \
$(libcppdir)/programmemory.o \
$(libcppdir)/reverseanalyzer.o \
$(libcppdir)/sarifreport.o \
$(libcppdir)/settings.o \
$(libcppdir)/standards.o \
$(libcppdir)/summaries.o \
Expand Down Expand Up @@ -316,6 +317,7 @@ TESTOBJ = test/fixture.o \
test/testpreprocessor.o \
test/testprocessexecutor.o \
test/testprogrammemory.o \
test/testsarif.o \
test/testsettings.o \
test/testsimplifytemplate.o \
test/testsimplifytokens.o \
Expand Down Expand Up @@ -621,6 +623,9 @@ $(libcppdir)/programmemory.o: lib/programmemory.cpp lib/addoninfo.h lib/astutils
$(libcppdir)/reverseanalyzer.o: lib/reverseanalyzer.cpp lib/addoninfo.h lib/analyzer.h lib/astutils.h lib/checkers.h lib/config.h lib/errortypes.h lib/forwardanalyzer.h lib/library.h lib/mathlib.h lib/platform.h lib/reverseanalyzer.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/utils.h lib/valueptr.h lib/vfvalue.h
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/reverseanalyzer.cpp

$(libcppdir)/sarifreport.o: lib/sarifreport.cpp externals/picojson/picojson.h lib/addoninfo.h lib/check.h lib/checkers.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/json.h lib/library.h lib/mathlib.h lib/platform.h lib/sarifreport.h lib/settings.h lib/standards.h lib/utils.h
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/sarifreport.cpp

$(libcppdir)/settings.o: lib/settings.cpp externals/picojson/picojson.h lib/addoninfo.h lib/checkers.h lib/config.h lib/errortypes.h lib/json.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/summaries.h lib/suppressions.h lib/utils.h lib/vfvalue.h
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/settings.cpp

Expand Down Expand Up @@ -666,7 +671,7 @@ frontend/frontend.o: frontend/frontend.cpp frontend/frontend.h lib/addoninfo.h l
cli/cmdlineparser.o: cli/cmdlineparser.cpp cli/cmdlinelogger.h cli/cmdlineparser.h cli/filelister.h externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/importproject.h lib/library.h lib/mathlib.h lib/path.h lib/pathmatch.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/utils.h lib/xml.h
$(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ cli/cmdlineparser.cpp

cli/cppcheckexecutor.o: cli/cppcheckexecutor.cpp cli/cmdlinelogger.h cli/cmdlineparser.h cli/cppcheckexecutor.h cli/executor.h cli/processexecutor.h cli/sehwrapper.h cli/signalhandler.h cli/singleexecutor.h cli/threadexecutor.h externals/picojson/picojson.h lib/addoninfo.h lib/analyzerinfo.h lib/check.h lib/checkers.h lib/checkersreport.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/json.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/utils.h
cli/cppcheckexecutor.o: cli/cppcheckexecutor.cpp cli/cmdlinelogger.h cli/cmdlineparser.h cli/cppcheckexecutor.h cli/executor.h cli/processexecutor.h cli/sehwrapper.h cli/signalhandler.h cli/singleexecutor.h cli/threadexecutor.h externals/picojson/picojson.h lib/addoninfo.h lib/analyzerinfo.h lib/check.h lib/checkers.h lib/checkersreport.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/json.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/sarifreport.h lib/settings.h lib/standards.h lib/suppressions.h lib/utils.h
$(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ cli/cppcheckexecutor.cpp

cli/executor.o: cli/executor.cpp cli/executor.h lib/addoninfo.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/utils.h
Expand Down Expand Up @@ -834,6 +839,9 @@ test/testprocessexecutor.o: test/testprocessexecutor.cpp cli/executor.h cli/proc
test/testprogrammemory.o: test/testprogrammemory.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/programmemory.h lib/settings.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testprogrammemory.cpp

test/testsarif.o: test/testsarif.cpp externals/picojson/picojson.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/json.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/sarifreport.h lib/settings.h lib/standards.h lib/suppressions.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testsarif.cpp

test/testsettings.o: test/testsettings.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testsettings.cpp

Expand Down
175 changes: 14 additions & 161 deletions cli/cppcheckexecutor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include "errortypes.h"
#include "filesettings.h"
#include "json.h"
#include "sarifreport.h"
#include "settings.h"
#include "singleexecutor.h"
#include "suppressions.h"
Expand Down Expand Up @@ -78,156 +79,6 @@
#endif

namespace {
class SarifReport {
public:
void addFinding(ErrorMessage msg) {
mFindings.push_back(std::move(msg));
}

picojson::array serializeRules() const {
picojson::array ret;
std::set<std::string> ruleIds;
for (const auto& finding : mFindings) {
// github only supports findings with locations
if (finding.callStack.empty())
continue;
if (ruleIds.insert(finding.id).second) {
picojson::object rule;
rule["id"] = picojson::value(finding.id);
// rule.shortDescription.text
picojson::object shortDescription;
shortDescription["text"] = picojson::value(finding.shortMessage());
rule["shortDescription"] = picojson::value(shortDescription);
// rule.fullDescription.text
picojson::object fullDescription;
fullDescription["text"] = picojson::value(finding.verboseMessage());
rule["fullDescription"] = picojson::value(fullDescription);
// rule.help.text
picojson::object help;
help["text"] = picojson::value(finding.verboseMessage()); // FIXME provide proper help text
rule["help"] = picojson::value(help);
// rule.properties.precision, rule.properties.problem.severity
picojson::object properties;
properties["precision"] = picojson::value(sarifPrecision(finding));
const char* securitySeverity = nullptr;
if (finding.severity == Severity::error && !ErrorLogger::isCriticalErrorId(finding.id))
securitySeverity = "9.9"; // We see undefined behavior
//else if (finding.severity == Severity::warning)
// securitySeverity = 5.1; // We see potential undefined behavior
if (securitySeverity) {
properties["security-severity"] = picojson::value(securitySeverity);
const picojson::array tags{picojson::value("security")};
properties["tags"] = picojson::value(tags);
}
rule["properties"] = picojson::value(properties);
// rule.defaultConfiguration.level
picojson::object defaultConfiguration;
defaultConfiguration["level"] = picojson::value(sarifSeverity(finding));
rule["defaultConfiguration"] = picojson::value(defaultConfiguration);

ret.emplace_back(rule);
}
}
return ret;
}

static picojson::array serializeLocations(const ErrorMessage& finding) {
picojson::array ret;
for (const auto& location : finding.callStack) {
picojson::object physicalLocation;
picojson::object artifactLocation;
artifactLocation["uri"] = picojson::value(location.getfile(false));
physicalLocation["artifactLocation"] = picojson::value(artifactLocation);
picojson::object region;
region["startLine"] = picojson::value(static_cast<int64_t>(location.line < 1 ? 1 : location.line));
region["startColumn"] = picojson::value(static_cast<int64_t>(location.column < 1 ? 1 : location.column));
region["endLine"] = region["startLine"];
region["endColumn"] = region["startColumn"];
physicalLocation["region"] = picojson::value(region);
picojson::object loc;
loc["physicalLocation"] = picojson::value(physicalLocation);
ret.emplace_back(loc);
}
return ret;
}

picojson::array serializeResults() const {
picojson::array results;
for (const auto& finding : mFindings) {
// github only supports findings with locations
if (finding.callStack.empty())
continue;
picojson::object res;
res["level"] = picojson::value(sarifSeverity(finding));
res["locations"] = picojson::value(serializeLocations(finding));
picojson::object message;
message["text"] = picojson::value(finding.shortMessage());
res["message"] = picojson::value(message);
res["ruleId"] = picojson::value(finding.id);
results.emplace_back(res);
}
return results;
}

picojson::value serializeRuns(const std::string& productName, const std::string& version) const {
picojson::object driver;
driver["name"] = picojson::value(productName);
driver["semanticVersion"] = picojson::value(version);
driver["informationUri"] = picojson::value("https://cppcheck.sourceforge.io");
driver["rules"] = picojson::value(serializeRules());
picojson::object tool;
tool["driver"] = picojson::value(driver);
picojson::object run;
run["tool"] = picojson::value(tool);
run["results"] = picojson::value(serializeResults());
picojson::array runs{picojson::value(run)};
return picojson::value(runs);
}

std::string serialize(std::string productName) const {
const auto nameAndVersion = Settings::getNameAndVersion(productName);
productName = nameAndVersion.first.empty() ? "Cppcheck" : nameAndVersion.first;
std::string version = nameAndVersion.first.empty() ? CppCheck::version() : nameAndVersion.second;
if (version.find(' ') != std::string::npos)
version.erase(version.find(' '), std::string::npos);

picojson::object doc;
doc["version"] = picojson::value("2.1.0");
doc["$schema"] = picojson::value("https://docs.oasis-open.org/sarif/sarif/v2.1.0/errata01/os/schemas/sarif-schema-2.1.0.json");
doc["runs"] = serializeRuns(productName, version);

return picojson::value(doc).serialize(true);
}
private:

static std::string sarifSeverity(const ErrorMessage& errmsg) {
if (ErrorLogger::isCriticalErrorId(errmsg.id))
return "error";
switch (errmsg.severity) {
case Severity::error:
case Severity::warning:
case Severity::style:
case Severity::portability:
case Severity::performance:
return "warning";
case Severity::information:
case Severity::internal:
case Severity::debug:
case Severity::none:
return "note";
}
return "note";
}

static std::string sarifPrecision(const ErrorMessage& errmsg) {
if (errmsg.certainty == Certainty::inconclusive)
return "medium";
return "high";
}

std::vector<ErrorMessage> mFindings;
};

class CmdLineLoggerStd : public CmdLineLogger
{
public:
Expand Down Expand Up @@ -672,19 +523,21 @@ void StdLogger::reportErr(const ErrorMessage &msg)
mGuidelineMapping, msgCopy.severity);
msgCopy.classification = getClassification(msgCopy.guideline, mSettings.reportType);

// TODO: there should be no need for verbose and default messages here
const std::string msgStr = msgCopy.toString(mSettings.verbose, mSettings.templateFormat, mSettings.templateLocation);
if (mSettings.outputFormat == Settings::OutputFormat::sarif) {
mSarifReport.addFinding(std::move(msgCopy));
} else {
// TODO: there should be no need for verbose and default messages here
const std::string msgStr = msgCopy.toString(mSettings.verbose, mSettings.templateFormat, mSettings.templateLocation);

// Alert only about unique errors
if (!mSettings.emitDuplicates && !mShownErrors.insert(msgStr).second)
return;
// Alert only about unique errors
if (!mSettings.emitDuplicates && !mShownErrors.insert(msgStr).second)
return;

if (mSettings.outputFormat == Settings::OutputFormat::sarif)
mSarifReport.addFinding(std::move(msgCopy));
else if (mSettings.outputFormat == Settings::OutputFormat::xml)
reportErr(msgCopy.toXML());
else
reportErr(msgStr);
if (mSettings.outputFormat == Settings::OutputFormat::xml)
reportErr(msgCopy.toXML());
else
reportErr(msgStr);
}
}

/**
Expand Down
2 changes: 2 additions & 0 deletions lib/cppcheck.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@
<ClCompile Include="preprocessor.cpp" />
<ClCompile Include="programmemory.cpp" />
<ClCompile Include="reverseanalyzer.cpp" />
<ClCompile Include="sarifreport.cpp" />
<ClCompile Include="settings.cpp" />
<ClCompile Include="standards.cpp" />
<ClCompile Include="summaries.cpp" />
Expand Down Expand Up @@ -156,6 +157,7 @@
<ClInclude Include="preprocessor.h" />
<ClInclude Include="programmemory.h" />
<ClInclude Include="reverseanalyzer.h" />
<ClInclude Include="sarifreport.h" />
<ClInclude Include="settings.h" />
<ClInclude Include="smallvector.h" />
<ClInclude Include="sourcelocation.h" />
Expand Down
Loading