Skip to content

Commit 38051d1

Browse files
committed
Support polyspace suppressions
1 parent 34b9c45 commit 38051d1

5 files changed

Lines changed: 321 additions & 2 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

lib/preprocessor.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,12 +200,19 @@ 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

211+
if (polyspace::isPolyspaceComment(tok->str())) {
212+
polyspaceParser.parse(tok->str(), tok->location.line, tokens.file(tok->location));
213+
continue;
214+
}
215+
209216
std::list<SuppressionList::Suppression> inlineSuppressions;
210217
if (!parseInlineSuppressionCommentToken(tokens, tok, inlineSuppressions, bad))
211218
continue;
@@ -310,6 +317,8 @@ static void addInlineSuppressions(const simplecpp::TokenList &tokens, const Sett
310317
for (const SuppressionList::Suppression & suppr: inlineSuppressionsBlockBegin)
311318
// cppcheck-suppress useStlAlgorithm
312319
bad.emplace_back(suppr.fileName, suppr.lineNumber, 0, "Suppress Begin: No matching end"); // TODO: set column
320+
321+
polyspaceParser.collect(suppressions);
313322
}
314323

315324
void Preprocessor::inlineSuppressions(SuppressionList &suppressions)

lib/suppressions.cpp

Lines changed: 261 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,263 @@ std::string SuppressionList::Suppression::toString() const
647648
}
648649
return s;
649650
}
651+
652+
std::string polyspace::Parser::peekToken()
653+
{
654+
if (!mHasPeeked) {
655+
mPeeked = nextToken();
656+
mHasPeeked = true;
657+
}
658+
return mPeeked;
659+
}
660+
661+
std::string polyspace::Parser::nextToken()
662+
{
663+
if (mHasPeeked) {
664+
mHasPeeked = false;
665+
return mPeeked;
666+
}
667+
668+
if (mComment.compare(0, 2, "/*") == 0 || mComment.compare(0, 2, "//") == 0)
669+
mComment = mComment.substr(2);
670+
671+
std::string::size_type pos = 0;
672+
while (mComment[pos] == ' ') {
673+
pos++;
674+
if (pos == mComment.size()) {
675+
mComment = "";
676+
return "";
677+
}
678+
}
679+
680+
if (mComment.compare(0, 2, "*/") == 0) {
681+
mComment = "";
682+
return "";
683+
}
684+
685+
if (mComment[pos] == ':') {
686+
mComment = mComment.substr(pos + 1);
687+
return ":";
688+
}
689+
690+
if (mComment[pos] == ',') {
691+
mComment = mComment.substr(pos + 1);
692+
return ",";
693+
}
694+
695+
const char *stopChars;
696+
std::string::size_type skip;
697+
switch (mComment[pos]) {
698+
case '\"':
699+
stopChars = "\"";
700+
skip = 1;
701+
break;
702+
case '[':
703+
stopChars = "]";
704+
skip = 1;
705+
break;
706+
default:
707+
stopChars = " :,";
708+
skip = 0;
709+
break;
710+
}
711+
712+
const std::string::size_type start = pos;
713+
pos += skip;
714+
715+
if (pos == mComment.size()) {
716+
mComment = "";
717+
return "";
718+
}
719+
720+
while (std::strchr(stopChars, mComment[pos]) == nullptr) {
721+
pos++;
722+
if (pos == mComment.size())
723+
break;
724+
}
725+
726+
if (pos == mComment.size())
727+
skip = 0;
728+
729+
const std::string token = mComment.substr(start, pos - start + skip);
730+
mComment = mComment.substr(pos + skip);
731+
732+
return token;
733+
}
734+
735+
void polyspace::Parser::finishSuppression()
736+
{
737+
Suppression suppr = { mFamily, mResultName, mFilename, 0, 0 };
738+
739+
switch (mKind) {
740+
case CommentKind::Regular:
741+
{
742+
suppr.lineBegin = mLine;
743+
suppr.lineEnd = mLine + mRange;
744+
mDone.push_back(suppr);
745+
return;
746+
}
747+
case CommentKind::Begin:
748+
{
749+
suppr.lineBegin = mLine;
750+
mStarted.push_back(suppr);
751+
return;
752+
}
753+
case CommentKind::End:
754+
{
755+
auto it = std::find_if(
756+
mStarted.begin(),
757+
mStarted.end(),
758+
[&] (const Suppression &other) {
759+
return suppr.matches(other);
760+
}
761+
);
762+
763+
if (it == mStarted.end())
764+
return;
765+
766+
suppr.lineBegin = it->lineBegin;
767+
suppr.lineEnd = mLine;
768+
mStarted.erase(it);
769+
mDone.push_back(suppr);
770+
return;
771+
}
772+
}
773+
}
774+
775+
bool polyspace::Parser::parseEntry()
776+
{
777+
mFamily = nextToken();
778+
if (mFamily.empty())
779+
return false;
780+
781+
if (nextToken() != ":")
782+
return false;
783+
784+
// Parse result name, multiple names may be separated by commas
785+
while (!mComment.empty()) {
786+
mResultName = nextToken();
787+
if (mResultName.empty())
788+
return false;
789+
790+
finishSuppression();
791+
792+
if (peekToken() == ",") {
793+
(void) nextToken();
794+
continue;
795+
}
796+
797+
break;
798+
}
799+
800+
// Skip status and severity
801+
if (!peekToken().empty() && mPeeked[0] == '[')
802+
(void) nextToken();
803+
804+
return true;
805+
}
806+
807+
void polyspace::Parser::collect(SuppressionList &suppressions) const
808+
{
809+
for (const auto &polyspaceSuppr : mDone) {
810+
SuppressionList::Suppression suppr;
811+
if (polyspaceSuppr.convert(mSettings, suppr))
812+
suppressions.addSuppression(std::move(suppr));
813+
}
814+
}
815+
816+
void polyspace::Parser::parse(const std::string &comment, int line, const std::string &filename)
817+
{
818+
mComment = comment;
819+
mLine = line;
820+
mFilename = filename;
821+
mHasPeeked = false;
822+
823+
while (true) {
824+
const std::string kindStr = nextToken();
825+
if (kindStr.empty())
826+
return;
827+
828+
if (kindStr == "polyspace") mKind = CommentKind::Regular;
829+
else if (kindStr == "polyspace-begin") mKind = CommentKind::Begin;
830+
else if (kindStr == "polyspace-end") mKind = CommentKind::End;
831+
else return;
832+
833+
mRange = 0;
834+
if (peekToken()[0] == '+') {
835+
try { mRange = std::stoi(mPeeked.substr(1)); } catch (...) { return; }
836+
(void) nextToken();
837+
}
838+
839+
while (parseEntry()) {
840+
if (peekToken().empty() || mPeeked[0] == '\"')
841+
break;
842+
}
843+
844+
if (!peekToken().empty() && mPeeked[0] == '\"') {
845+
(void) nextToken();
846+
if (peekToken().empty())
847+
return;
848+
continue;
849+
}
850+
851+
break;
852+
}
853+
}
854+
855+
bool polyspace::isPolyspaceComment(const std::string &comment)
856+
{
857+
const std::string polyspace = "polyspace";
858+
const std::string::size_type pos = comment.find_first_not_of("/* ");
859+
if (pos == std::string::npos)
860+
return false;
861+
return comment.compare(pos, polyspace.size(), polyspace, 0, polyspace.size()) == 0;
862+
}
863+
864+
bool polyspace::Suppression::matches(const polyspace::Suppression &other) const
865+
{
866+
return family == other.family && resultName == other.resultName;
867+
}
868+
869+
bool polyspace::Suppression::convert(const Settings &settings, SuppressionList::Suppression &suppr) const
870+
{
871+
static const std::map<std::string, std::string> map = {
872+
{ "MISRA-C-2023", "premium-misra-c-2023-" },
873+
{ "MISRA-CPP", "premium-misra-cpp-2008-" },
874+
{ "MISRA-CPP-2023", "premium-misra-cpp-2023-" },
875+
{ "CERT-C", "premium-cert-c-" },
876+
{ "CERT-CPP", "premium-cert-cpp-" },
877+
{ "AUTOSAR-CPP14", "premium-autosar-" },
878+
};
879+
880+
const auto it = map.find(family);
881+
std::string prefix;
882+
if (it == map.cend()) {
883+
if (family == "MISRA-C3" || family == "MISRA2012") {
884+
if (settings.premiumArgs.empty()) {
885+
prefix = "misra-c2012-";
886+
} else {
887+
prefix = "premium-misra-c-2012-";
888+
}
889+
} else {
890+
return false;
891+
}
892+
} else {
893+
prefix = it->second;
894+
}
895+
896+
suppr.errorId = prefix + resultName;
897+
suppr.isInline = true;
898+
suppr.fileName = filename;
899+
900+
suppr.lineNumber = lineBegin;
901+
if (lineBegin == lineEnd) {
902+
suppr.type = SuppressionList::Type::unique;
903+
} else {
904+
suppr.type = SuppressionList::Type::block;
905+
suppr.lineBegin = lineBegin;
906+
suppr.lineEnd = lineEnd;
907+
}
908+
909+
return true;
910+
}

lib/suppressions.h

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ class Tokenizer;
3636
class ErrorMessage;
3737
enum class Certainty : std::uint8_t;
3838
class FileWithDetails;
39+
class Settings;
3940

4041
/// @addtogroup Core
4142
/// @{
@@ -294,6 +295,54 @@ struct Suppressions
294295
SuppressionList nofail;
295296
};
296297

298+
namespace polyspace {
299+
300+
struct CPPCHECKLIB Suppression {
301+
std::string family;
302+
std::string resultName;
303+
std::string filename;
304+
int lineBegin;
305+
int lineEnd;
306+
307+
bool matches(const Suppression &other) const;
308+
bool convert(const Settings &settings, SuppressionList::Suppression &suppr) const;
309+
};
310+
311+
class CPPCHECKLIB Parser {
312+
public:
313+
Parser() = delete;
314+
explicit Parser(const Settings &settings) : mSettings(settings) {}
315+
void collect(SuppressionList &suppressions) const;
316+
void parse(const std::string &comment, int line, const std::string &filename);
317+
318+
private:
319+
std::string peekToken();
320+
std::string nextToken();
321+
void finishSuppression();
322+
bool parseEntry();
323+
324+
enum class CommentKind : std::uint8_t {
325+
Regular, Begin, End,
326+
};
327+
328+
std::list<Suppression> mStarted;
329+
std::list<Suppression> mDone;
330+
std::string mComment;
331+
std::string mFilename;
332+
int mLine{};
333+
int mRange{};
334+
CommentKind mKind{};
335+
std::string mFamily;
336+
std::string mResultName;
337+
std::string mPeeked;
338+
bool mHasPeeked{};
339+
const Settings &mSettings;
340+
};
341+
342+
bool CPPCHECKLIB isPolyspaceComment(const std::string &comment);
343+
344+
}
345+
297346
/// @}
298347
//---------------------------------------------------------------------------
299348
#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)