Skip to content

Commit 1bfa431

Browse files
committed
fix 14367
1 parent 803fdfe commit 1bfa431

8 files changed

Lines changed: 591 additions & 17 deletions

File tree

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -652,7 +652,7 @@ $(libcppdir)/standards.o: lib/standards.cpp externals/simplecpp/simplecpp.h lib/
652652
$(libcppdir)/summaries.o: lib/summaries.cpp lib/addoninfo.h lib/analyzerinfo.h lib/checkers.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/summaries.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h
653653
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/summaries.cpp
654654

655-
$(libcppdir)/suppressions.o: lib/suppressions.cpp externals/tinyxml2/tinyxml2.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/mathlib.h lib/path.h lib/pathmatch.h lib/platform.h lib/smallvector.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h lib/xml.h
655+
$(libcppdir)/suppressions.o: lib/suppressions.cpp externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/checkers.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/pathmatch.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h lib/xml.h
656656
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/suppressions.cpp
657657

658658
$(libcppdir)/templatesimplifier.o: lib/templatesimplifier.cpp lib/addoninfo.h lib/checkers.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h

cli/cppcheckexecutor.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,8 @@ static bool reportUnmatchedSuppressions(const std::list<SuppressionList::Suppres
329329
if (!s.fileName.empty()) {
330330
callStack.emplace_back(s.fileName, s.lineNumber, 0);
331331
}
332-
errorLogger.reportErr(::ErrorMessage(std::move(callStack), "", Severity::information, "Unmatched suppression: " + s.errorId, "unmatchedSuppression", Certainty::normal));
332+
const std::string unmatchedSuppressionId = s.isPolyspace ? "unmatchedPolyspaceSuppression" : "unmatchedSuppression";
333+
errorLogger.reportErr(::ErrorMessage(std::move(callStack), "", Severity::information, "Unmatched suppression: " + s.errorId, unmatchedSuppressionId, Certainty::normal));
333334
err = true;
334335
}
335336
return err;

lib/preprocessor.cpp

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -200,27 +200,33 @@ static void addInlineSuppressions(const simplecpp::TokenList &tokens, const Sett
200200

201201
bool onlyComments = true;
202202

203+
polyspace::Parser polyspaceParser(settings);
204+
203205
for (const simplecpp::Token *tok = tokens.cfront(); tok; tok = tok->next) {
204206
if (!tok->comment) {
205207
onlyComments = false;
206208
continue;
207209
}
208210

209211
std::list<SuppressionList::Suppression> inlineSuppressions;
210-
if (!parseInlineSuppressionCommentToken(tokens, tok, inlineSuppressions, bad))
211-
continue;
212+
if (polyspace::isPolyspaceComment(tok->str())) {
213+
inlineSuppressions = polyspaceParser.parse(tok->str(), tok->location.line, getRelativeFilename(tokens, tok, settings));
214+
} else {
215+
if (!parseInlineSuppressionCommentToken(tokens, tok, inlineSuppressions, bad))
216+
continue;
212217

213-
if (!sameline(tok->previous, tok)) {
214-
// find code after comment..
215-
if (tok->next) {
216-
tok = tok->next;
218+
if (!sameline(tok->previous, tok)) {
219+
// find code after comment..
220+
if (tok->next) {
221+
tok = tok->next;
217222

218-
while (tok->comment) {
219-
parseInlineSuppressionCommentToken(tokens, tok, inlineSuppressions, bad);
220-
if (tok->next) {
221-
tok = tok->next;
222-
} else {
223-
break;
223+
while (tok->comment) {
224+
parseInlineSuppressionCommentToken(tokens, tok, inlineSuppressions, bad);
225+
if (tok->next) {
226+
tok = tok->next;
227+
} else {
228+
break;
229+
}
224230
}
225231
}
226232
}
@@ -249,8 +255,9 @@ static void addInlineSuppressions(const simplecpp::TokenList &tokens, const Sett
249255
for (SuppressionList::Suppression &suppr : inlineSuppressions) {
250256
suppr.fileName = relativeFilename;
251257

252-
if (SuppressionList::Type::blockBegin == suppr.type)
253-
{
258+
if (SuppressionList::Type::block == suppr.type) {
259+
suppressions.addSuppression(std::move(suppr));
260+
} else if (SuppressionList::Type::blockBegin == suppr.type) {
254261
inlineSuppressionsBlockBegin.push_back(std::move(suppr));
255262
} else if (SuppressionList::Type::blockEnd == suppr.type) {
256263
bool throwError = true;

lib/suppressions.cpp

Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "token.h"
2727
#include "tokenize.h"
2828
#include "tokenlist.h"
29+
#include "settings.h"
2930

3031
#include <algorithm>
3132
#include <cctype> // std::isdigit, std::isalnum, etc
@@ -647,3 +648,230 @@ std::string SuppressionList::Suppression::toString() const
647648
}
648649
return s;
649650
}
651+
652+
polyspace::Parser::Parser(const Settings &settings)
653+
{
654+
const bool haveMisraAddon = std::any_of(settings.addonInfos.cbegin(),
655+
settings.addonInfos.cend(),
656+
[] (const AddonInfo &info) {
657+
return info.name == "misra";
658+
});
659+
660+
if (haveMisraAddon) {
661+
mFamilyMap["MISRA-C3"] = "misra-c2012-";
662+
mFamilyMap["MISRA2012"] = "misra-c2012-";
663+
}
664+
665+
const auto matchArg = [&](const std::string &arg) {
666+
const std::string args = settings.premiumArgs;
667+
const std::string::size_type pos = args.find(arg);
668+
669+
if (pos == std::string::npos)
670+
return false;
671+
672+
const char prevChar = (pos > 0) ? args[pos - 1] : ' ';
673+
const char nextChar = (pos + arg.size() < args.size()) ? args[pos + arg.size()] : ' ';
674+
675+
return prevChar == ' ' && (nextChar == ' ' || nextChar == ':');
676+
};
677+
678+
if (matchArg("--misra-c-2012")) {
679+
mFamilyMap["MISRA-C3"] = "premium-misra-c-2012-";
680+
mFamilyMap["MISRA2012"] = "premium-misra-c-2012-";
681+
}
682+
683+
if (matchArg("--misra-c-2023"))
684+
mFamilyMap["MISRA-C-2023"] = "premium-misra-c-2023-";
685+
686+
if (matchArg("--misra-cpp-2008") || matchArg("--misra-c++-2008"))
687+
mFamilyMap["MISRA-CPP"] = "premium-misra-cpp-2008-";
688+
689+
if (matchArg("--misra-cpp-2023") || matchArg("--misra-c++-2023"))
690+
mFamilyMap["MISRA-CPP-2023"] = "premium-misra-cpp-2023-";
691+
692+
if (matchArg("--cert-c") || matchArg("--cert-c-2016"))
693+
mFamilyMap["CERT-C"] = "premium-cert-c-";
694+
695+
if (matchArg("--cert-cpp") || matchArg("--cert-c++") ||
696+
matchArg("--cert-cpp-2016") || matchArg("--cert-c++-2016"))
697+
mFamilyMap["CERT-CPP"] = "premium-cert-cpp-";
698+
699+
if (matchArg("--autosar"))
700+
mFamilyMap["AUTOSAR-CPP14"] = "premium-autosar-";
701+
}
702+
703+
polyspace::CommentKind polyspace::Parser::parseKind(const std::string& comment, std::string::size_type& pos)
704+
{
705+
const std::string::size_type pos1 = pos;
706+
pos = comment.find_first_of(" \t", pos);
707+
if (pos >= comment.size())
708+
return CommentKind::Invalid;
709+
710+
const std::string token = comment.substr(pos1, pos-pos1);
711+
712+
if (token == "polyspace")
713+
return CommentKind::Regular;
714+
715+
if (token == "polyspace-begin")
716+
return CommentKind::Begin;
717+
718+
if (token == "polyspace-end")
719+
return CommentKind::End;
720+
721+
return CommentKind::Invalid;
722+
}
723+
724+
725+
std::list<SuppressionList::Suppression> polyspace::Parser::parse(const std::string &comment, int line, const std::string &filename)
726+
{
727+
std::list<SuppressionList::Suppression> ret;
728+
729+
if (mFamilyMap.empty())
730+
return ret;
731+
732+
for (std::string::size_type pos = comment.find_first_not_of("/* "); pos < comment.size();) {
733+
// polyspace
734+
const auto polyspaceKind = parseKind(comment, pos);
735+
if (polyspaceKind == CommentKind::Invalid)
736+
break;
737+
738+
// optional range
739+
pos = comment.find_first_not_of(" \t", pos);
740+
if (pos >= comment.size())
741+
break;
742+
int rangeValue = 0;
743+
if (comment[pos] == '+') {
744+
const std::string::size_type posRangeStart = pos + 1;
745+
pos = comment.find_first_of(" \t", posRangeStart);
746+
if (pos > comment.size())
747+
break;
748+
const std::string range = comment.substr(posRangeStart, pos-posRangeStart);
749+
// TODO check that range is an integer
750+
rangeValue = std::stoi(range);
751+
}
752+
753+
// ids..
754+
const std::set<std::string> ids = parseIds(comment, pos);
755+
756+
// skip justification
757+
if (pos < comment.size() && comment[pos] == '[') {
758+
pos = comment.find(']',pos+1);
759+
if (pos >= comment.size())
760+
break;
761+
pos = comment.find_first_not_of(" \t", pos+1);
762+
if (pos >= comment.size())
763+
break;
764+
}
765+
766+
// extra comment
767+
std::string extraComment;
768+
if (pos < comment.size() && comment[pos] == '\"') {
769+
const std::string::size_type p1 = pos + 1;
770+
pos = comment.find('\"',p1);
771+
if (pos >= comment.size())
772+
break;
773+
extraComment = comment.substr(p1, pos-p1);
774+
pos = comment.find("polyspace", pos + 1);
775+
}
776+
777+
for (const std::string& errorId: ids) {
778+
SuppressionList::Suppression suppr;
779+
suppr.errorId = errorId;
780+
suppr.isInline = true;
781+
suppr.isPolyspace = true;
782+
suppr.fileName = filename;
783+
suppr.lineNumber = line;
784+
suppr.extraComment = extraComment;
785+
786+
if (rangeValue > 0) {
787+
suppr.type = SuppressionList::Type::block;
788+
suppr.lineBegin = line;
789+
suppr.lineEnd = line + rangeValue;
790+
}
791+
else if (polyspaceKind == polyspace::CommentKind::Regular)
792+
suppr.type = SuppressionList::Type::unique;
793+
else if (polyspaceKind == polyspace::CommentKind::Begin)
794+
suppr.type = SuppressionList::Type::blockBegin;
795+
else
796+
suppr.type = SuppressionList::Type::blockEnd;
797+
798+
ret.emplace_back(suppr);
799+
}
800+
}
801+
802+
return ret;
803+
}
804+
805+
std::vector<std::pair<std::string, std::string>> polyspace::Parser::parseFamilyRules(const std::string& comment, std::string::size_type& pos) {
806+
std::vector<std::pair<std::string, std::string>> fr;
807+
std::string family;
808+
std::string rule;
809+
enum class State: uint8_t { family, colon, rule, rule_or_family } state = State::family;
810+
const std::string::size_type endpos = startsWith(comment, "/*") ? comment.size() - 2 : comment.size();
811+
for (; pos <= endpos; ++pos) {
812+
const char c = comment[pos];
813+
if (std::strchr("[\"", c))
814+
break;
815+
switch (state) {
816+
case State::family:
817+
if (std::isalnum(c) || std::strchr("-_.",c))
818+
family += c;
819+
else if (!family.empty() && std::strchr(" \t:",c))
820+
state = State::colon;
821+
break;
822+
case State::colon:
823+
if (!std::strchr(" \t:", c)) {
824+
rule.clear();
825+
--pos;
826+
state = State::rule;
827+
}
828+
break;
829+
case State::rule:
830+
if (std::strchr(", \t",c)) {
831+
if (!rule.empty()) {
832+
fr.emplace_back(family,rule);
833+
rule.clear();
834+
if (c != ',')
835+
state = State::rule_or_family;
836+
}
837+
}
838+
else
839+
rule += c;
840+
break;
841+
case State::rule_or_family:
842+
rule.clear();
843+
if (std::isalnum(c)) {
844+
--pos;
845+
family.clear();
846+
state = State::family;
847+
} else if (c == ',') {
848+
--pos;
849+
state = State::rule;
850+
}
851+
break;
852+
}
853+
}
854+
if (!family.empty() && !rule.empty())
855+
fr.emplace_back(family,rule);
856+
return fr;
857+
}
858+
859+
std::set<std::string> polyspace::Parser::parseIds(const std::string& comment, std::string::size_type& pos) const {
860+
std::set<std::string> ids;
861+
for (const auto& fr: parseFamilyRules(comment,pos)) {
862+
const auto it = mFamilyMap.find(fr.first);
863+
if (it != mFamilyMap.cend())
864+
ids.emplace(it->second + fr.second);
865+
}
866+
return ids;
867+
}
868+
869+
870+
bool polyspace::isPolyspaceComment(const std::string &comment)
871+
{
872+
const std::string polyspace = "polyspace";
873+
const std::string::size_type pos = comment.find_first_not_of("/* ");
874+
if (pos == std::string::npos)
875+
return false;
876+
return comment.compare(pos, polyspace.size(), polyspace, 0, polyspace.size()) == 0;
877+
}

lib/suppressions.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,13 @@
3131
#include <string>
3232
#include <utility>
3333
#include <vector>
34+
#include <map>
3435

3536
class Tokenizer;
3637
class ErrorMessage;
3738
enum class Certainty : std::uint8_t;
3839
class FileWithDetails;
40+
class Settings;
3941

4042
/// @addtogroup Core
4143
/// @{
@@ -160,6 +162,7 @@ class CPPCHECKLIB SuppressionList {
160162
bool matched{}; /** This suppression was fully matched in an isSuppressed() call */
161163
bool checked{}; /** This suppression applied to code which was being analyzed but did not match the error in an isSuppressed() call */
162164
bool isInline{};
165+
bool isPolyspace{};
163166

164167
enum : std::int8_t { NO_LINE = -1 };
165168
};
@@ -294,6 +297,34 @@ struct Suppressions
294297
SuppressionList nofail;
295298
};
296299

300+
namespace polyspace {
301+
302+
enum class CommentKind : std::uint8_t {
303+
Invalid, Regular, Begin, End,
304+
};
305+
306+
class CPPCHECKLIB Parser {
307+
public:
308+
Parser() = delete;
309+
explicit Parser(const Settings &settings);
310+
311+
std::list<SuppressionList::Suppression> parse(const std::string &comment, int line, const std::string &filename);
312+
313+
static std::vector<std::pair<std::string, std::string>> parseFamilyRules(const std::string& comment, std::string::size_type& pos);
314+
315+
private:
316+
std::set<std::string> parseIds(const std::string& comment, std::string::size_type& pos) const;
317+
318+
static CommentKind parseKind(const std::string& token, std::string::size_type& pos);
319+
int parseRange();
320+
321+
std::map<std::string, std::string> mFamilyMap;
322+
};
323+
324+
bool CPPCHECKLIB isPolyspaceComment(const std::string &comment);
325+
326+
}
327+
297328
/// @}
298329
//---------------------------------------------------------------------------
299330
#endif // suppressionsH

oss-fuzz/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,7 @@ $(libcppdir)/standards.o: ../lib/standards.cpp ../externals/simplecpp/simplecpp.
332332
$(libcppdir)/summaries.o: ../lib/summaries.cpp ../lib/addoninfo.h ../lib/analyzerinfo.h ../lib/checkers.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/summaries.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h
333333
$(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/summaries.cpp
334334

335-
$(libcppdir)/suppressions.o: ../lib/suppressions.cpp ../externals/tinyxml2/tinyxml2.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/filesettings.h ../lib/mathlib.h ../lib/path.h ../lib/pathmatch.h ../lib/platform.h ../lib/smallvector.h ../lib/standards.h ../lib/suppressions.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h ../lib/xml.h
335+
$(libcppdir)/suppressions.o: ../lib/suppressions.cpp ../externals/tinyxml2/tinyxml2.h ../lib/addoninfo.h ../lib/checkers.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/filesettings.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/pathmatch.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/standards.h ../lib/suppressions.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h ../lib/xml.h
336336
$(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/suppressions.cpp
337337

338338
$(libcppdir)/templatesimplifier.o: ../lib/templatesimplifier.cpp ../lib/addoninfo.h ../lib/checkers.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/standards.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h

0 commit comments

Comments
 (0)