CI: Add selfcheck using Cppcheck Premium. Activates Misra C++ 2008 and Cert C++ 2016 checkers. (#5623)

This commit is contained in:
Daniel Marjamäki 2023-11-06 15:31:47 +01:00 committed by GitHub
parent 83ac6bfa0f
commit fc8c244675
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 268 additions and 30 deletions

43
.github/workflows/cppcheck-premium.yml vendored Normal file
View File

@ -0,0 +1,43 @@
name: cppcheck-premium
on:
push:
branches:
- 'main'
- 'releases/**'
tags:
- '2.*'
pull_request:
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-22.04 # run on the latest image only
env:
PREMIUM_VERSION: devdrop-20231105
steps:
- uses: actions/checkout@v3
- name: Download cppcheckpremium
run: |
wget https://files.cppchecksolutions.com/cppcheckpremium-${{ env.PREMIUM_VERSION }}-amd64.tar.gz
tar xzf cppcheckpremium-${{ env.PREMIUM_VERSION }}-amd64.tar.gz
- name: Generate a license file
run: |
echo cppcheck > cppcheck.lic
echo 231231 >> cppcheck.lic
echo 80000 >> cppcheck.lic
echo 57e08c39523ab54d >> cppcheck.lic
echo path:lib >> cppcheck.lic
- name: Check
run: |
cppcheckpremium-${{ env.PREMIUM_VERSION }}/premiumaddon --check-loc-license cppcheck.lic > cppcheck-premium-loc
cppcheckpremium-${{ env.PREMIUM_VERSION }}/cppcheck -j$(nproc) -D__GNUC__ -D__CPPCHECK__ --suppressions-list=cppcheckpremium-suppressions --platform=unix64 --enable=style --premium=misra-c++-2008 --premium=cert-c++-2016 --error-exitcode=1 lib

View File

@ -0,0 +1,186 @@
# False positives
premium-misra-cpp-2008-5-17-1
premium-misra-cpp-2008-5-0-6
premium-misra-cpp-2008-7-2-1
premium-misra-cpp-2008-3-3-2
# open source warnings are handled by the selfcheck.yml
noExplicitConstructor
postfixOperator
shadowFunction
useStlAlgorithm
# we need to declare reserved identifier _CRTDBG_MAP_ALLOC
premium-cert-dcl51-cpp
# TODO: Is there unsafe allocations, in case of exceptions) in cppcheck
premium-cert-err58-cpp
# we have global objects
premium-cert-err58-cpp
# TODO: Exception objects must be nothrow copy constructible.
premium-cert-err60-cpp
# TODO should we throw Token?
premium-cert-err61-cpp
# TODO: Detect errors when converting a string to a number. The library function 'atoi()' shall not be used.
premium-cert-err62-cpp
# TODO: Can we reduce some const_cast?
premium-cert-exp55-cpp
# sometimes a void function does not have side effects
premium-misra-cpp-2008-0-1-8
# unused arguments, misra rules are too strict
premium-misra-cpp-2008-0-1-11
premium-misra-cpp-2008-0-1-12
# we sometimes don't care about return value from functions
premium-misra-cpp-2008-0-1-7
# TODO: can we prevent commented out code?
premium-misra-cpp-2008-2-7-2
premium-misra-cpp-2008-2-7-3
# NA
premium-misra-cpp-2008-2-10-1
# objects of a class often has the lowercase name of the class.
premium-misra-cpp-2008-2-10-4
# flag |= ..
premium-misra-cpp-2008-4-5-1
# Token/Variable flags are enum constants and we use those in bitwise operations by intention.
premium-misra-cpp-2008-4-5-2
# intentional addition of char to string: const std::string end(':' + cfg + ':' + Path::simplifyPath(sourcefile));
premium-misra-cpp-2008-4-5-3
# too strict operator precedence warnings
premium-misra-cpp-2008-5-0-2
# we are less strict about signedness. what bug is there here: unsigned int col = 0
premium-misra-cpp-2008-5-0-4
# intentional integral-to-float conversion
premium-misra-cpp-2008-5-0-5
# intentional addition of char literal: c = 'a' + (temp - 10);
premium-misra-cpp-2008-5-0-11
# conversion of char-to-int is intentional sometimes
premium-misra-cpp-2008-5-0-12
# pointer-to-bool conversion is common
premium-misra-cpp-2008-5-0-14
# pointer arithmetic is not uncommon in cppcheck code
premium-misra-cpp-2008-5-0-15
# it's only a problem if signed expression is negative
premium-misra-cpp-2008-5-0-21
# Intentional safe operands of &&: return !stdValue.empty() && str == getCPP();
premium-misra-cpp-2008-5-2-1
# const_cast performs intentional const casting
premium-misra-cpp-2008-5-2-5
# safe code: const char *next = static_cast<const char*>(std::memchr(pattern, ' ', pattern_len));
premium-misra-cpp-2008-5-2-8
# we intentionally cast pointer to integer when creating id for dumpfile
premium-misra-cpp-2008-5-2-9
# we intentionally mix increment with other operators in expressions
premium-misra-cpp-2008-5-2-10
# intentional array-to-pointer decay
premium-misra-cpp-2008-5-2-12
# we write !pointer by intention
premium-misra-cpp-2008-5-3-1
# for (;;)
premium-misra-cpp-2008-6-2-3
# it's not a bug to not put default at the end of a switch body
premium-misra-cpp-2008-6-4-6
# looping linked list => not well formed for loop
premium-misra-cpp-2008-6-5-1
premium-misra-cpp-2008-6-5-2
premium-misra-cpp-2008-6-5-3
premium-misra-cpp-2008-6-5-4
premium-misra-cpp-2008-6-5-5
premium-misra-cpp-2008-6-5-6
# we like early returns
premium-misra-cpp-2008-6-6-3
premium-misra-cpp-2008-6-6-4
premium-misra-cpp-2008-6-6-5
# we have local functions by intention
premium-misra-cpp-2008-7-3-1
# intentional: return reference from method to non-const reference parameter
premium-misra-cpp-2008-7-5-3
# intentional declaration of multiple variables
premium-misra-cpp-2008-8-0-1
# we intentionally don't use & before function names
premium-misra-cpp-2008-8-4-4
# cppcheck does not care about this enumerator rule
premium-misra-cpp-2008-8-5-3
# TODO Fix these
premium-misra-cpp-2008-9-3-1
# we use unions by intention sometimes
premium-misra-cpp-2008-9-5-1
# overridden methods is safe
premium-misra-cpp-2008-10-3-1
# some classes have public members by intention
premium-misra-cpp-2008-11-0-1
# rule should not apply to deleted copy assignment operator
premium-misra-cpp-2008-12-8-2
# TODO: this can be fixed by refactoring the code.
premium-misra-cpp-2008-14-6-2
# function specializations: TODO check if we should refactor
premium-misra-cpp-2008-14-8-2
# we use preprocessor when it makes sense
premium-misra-cpp-2008-16-0-1
premium-misra-cpp-2008-16-2-1
premium-misra-cpp-2008-16-2-2
premium-misra-cpp-2008-16-3-2
# TODO do we need to catch string conversion errors (using atoi)?
premium-misra-cpp-2008-18-0-2
# what standard alternative is there for std::getenv
premium-misra-cpp-2008-18-0-3
# <ctime> is used by intention
premium-misra-cpp-2008-18-0-4
# code is safe. we use std::strcmp by intention
premium-misra-cpp-2008-18-0-5
# we do avoid using new/delete
premium-misra-cpp-2008-18-4-1
# <cstdio> is used by intention
premium-misra-cpp-2008-27-0-1

View File

@ -33,6 +33,8 @@ struct Analyzer {
struct Action {
Action() = default;
Action(const Action&) = default;
Action& operator=(const Action& rhs) = default;
template<class T,
REQUIRES("T must be convertible to unsigned int", std::is_convertible<T, unsigned int> ),

View File

@ -2241,7 +2241,7 @@ bool isScopeBracket(const Token* tok)
}
template<class T, REQUIRES("T must be a Token class", std::is_convertible<T*, const Token*> )>
T* getTokenArgumentFunctionImpl(T* tok, int& argn)
static T* getTokenArgumentFunctionImpl(T* tok, int& argn)
{
argn = -1;
{
@ -2892,13 +2892,13 @@ const Token* findThisChanged(const Token* start, const Token* end, int indirect,
}
template<class Find>
const Token* findExpressionChangedImpl(const Token* expr,
const Token* start,
const Token* end,
const Settings* settings,
bool cpp,
int depth,
Find find)
static const Token* findExpressionChangedImpl(const Token* expr,
const Token* start,
const Token* end,
const Settings* settings,
bool cpp,
int depth,
Find find)
{
if (depth < 0)
return start;
@ -3095,7 +3095,7 @@ const Token *findLambdaStartToken(const Token *last)
}
template<class T>
T* findLambdaEndTokenGeneric(T* first)
static T* findLambdaEndTokenGeneric(T* first)
{
auto maybeLambda = [](T* tok) -> bool {
while (Token::Match(tok, "*|%name%|::|>")) {

View File

@ -995,7 +995,7 @@ static bool checkFloatRelation(const std::string &op, const double value1, const
}
template<class T>
T getvalue3(const T value1, const T value2)
static T getvalue3(const T value1, const T value2)
{
const T min = std::min(value1, value2);
if (min== std::numeric_limits<T>::max())

View File

@ -16,7 +16,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#ifndef checkersH
#define checkersH
#include <map>
#include <string>
@ -44,4 +45,4 @@ namespace checkers {
extern CPPCHECKLIB const std::map<std::string, std::string> misraRuleSeverity;
}
#endif

View File

@ -16,7 +16,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#ifndef checkersReportH
#define checkersReportH
#include "config.h"
@ -44,4 +45,4 @@ private:
int mAllCheckersCount = 0;
};
#endif

View File

@ -2178,6 +2178,10 @@ Variable& Variable::operator=(const Variable &var)
if (this == &var)
return *this;
ValueType* vt = nullptr;
if (var.mValueType)
vt = new ValueType(*var.mValueType);
mNameToken = var.mNameToken;
mTypeStartToken = var.mTypeStartToken;
mTypeEndToken = var.mTypeEndToken;
@ -2188,9 +2192,7 @@ Variable& Variable::operator=(const Variable &var)
mScope = var.mScope;
mDimensions = var.mDimensions;
delete mValueType;
mValueType = nullptr;
if (var.mValueType)
mValueType = new ValueType(*var.mValueType);
mValueType = vt;
return *this;
}
@ -2344,9 +2346,9 @@ void Variable::setValueType(const ValueType &valueType)
if (declType && !declType->next()->valueType())
return;
}
ValueType* vt = new ValueType(valueType);
delete mValueType;
mValueType = nullptr;
mValueType = new ValueType(valueType);
mValueType = vt;
if ((mValueType->pointer > 0) && (!isArray() || Token::Match(mNameToken->previous(), "( * %name% )")))
setFlag(fIsPointer, true);
setFlag(fIsConst, mValueType->constness & (1U << mValueType->pointer));
@ -6359,7 +6361,7 @@ static void setAutoTokenProperties(Token * const autoTok)
autoTok->isStandardType(true);
}
bool isContainerYieldElement(Library::Container::Yield yield)
static bool isContainerYieldElement(Library::Container::Yield yield)
{
return yield == Library::Container::Yield::ITEM || yield == Library::Container::Yield::AT_INDEX ||
yield == Library::Container::Yield::BUFFER || yield == Library::Container::Yield::BUFFER_NT;

View File

@ -618,7 +618,6 @@ namespace {
std::pair<Token*, Token*> mRangeType;
std::pair<Token*, Token*> mRangeTypeQualifiers;
std::pair<Token*, Token*> mRangeAfterVar;
std::string mTypedefName; // Name of typedef type
Token* mNameToken{nullptr};
bool mFail = false;
bool mReplaceFailed = false;
@ -643,7 +642,6 @@ namespace {
if (Token::Match(nameToken, "%name% ;")) {
mRangeType = rangeBefore;
mRangeTypeQualifiers = rangeQualifiers;
mTypedefName = nameToken->str();
Token* typeName = rangeBefore.second->previous();
if (typeName->isKeyword()) {
(void)num;

View File

@ -2237,7 +2237,7 @@ struct SingleRange {
};
template<class T>
SingleRange<T> MakeSingleRange(T& x)
static SingleRange<T> MakeSingleRange(T& x)
{
return {&x};
}
@ -6804,7 +6804,7 @@ ValuePtr<InferModel> ValueFlow::makeIntegralInferModel() {
return IntegralInferModel{};
}
ValueFlow::Value inferCondition(const std::string& op, const Token* varTok, MathLib::bigint val)
static ValueFlow::Value inferCondition(const std::string& op, const Token* varTok, MathLib::bigint val)
{
if (!varTok)
return ValueFlow::Value{};
@ -7374,7 +7374,7 @@ struct MultiValueFlowAnalyzer : ValueFlowAnalyzer {
};
template<class Key, class F>
bool productParams(const Settings* settings, const std::unordered_map<Key, std::list<ValueFlow::Value>>& vars, F f)
static bool productParams(const Settings* settings, const std::unordered_map<Key, std::list<ValueFlow::Value>>& vars, F f)
{
using Args = std::vector<std::unordered_map<Key, ValueFlow::Value>>;
Args args(1);
@ -7607,7 +7607,7 @@ struct IteratorRange
};
template<class Iterator>
IteratorRange<Iterator> MakeIteratorRange(Iterator start, Iterator last)
static IteratorRange<Iterator> MakeIteratorRange(Iterator start, Iterator last)
{
return {start, last};
}
@ -8260,7 +8260,7 @@ static const Token* solveExprValue(const Token* expr, ValueFlow::Value& value)
value);
}
ValuePtr<Analyzer> makeAnalyzer(const Token* exprTok, ValueFlow::Value value, const TokenList& tokenlist, const Settings* settings)
static ValuePtr<Analyzer> makeAnalyzer(const Token* exprTok, ValueFlow::Value value, const TokenList& tokenlist, const Settings* settings)
{
if (value.isContainerSizeValue())
return ContainerExpressionAnalyzer(exprTok, std::move(value), tokenlist, settings);
@ -8268,7 +8268,7 @@ ValuePtr<Analyzer> makeAnalyzer(const Token* exprTok, ValueFlow::Value value, co
return ExpressionAnalyzer(expr, std::move(value), tokenlist, settings);
}
ValuePtr<Analyzer> makeReverseAnalyzer(const Token* exprTok, ValueFlow::Value value, const TokenList& tokenlist, const Settings* settings)
static ValuePtr<Analyzer> makeReverseAnalyzer(const Token* exprTok, ValueFlow::Value value, const TokenList& tokenlist, const Settings* settings)
{
if (value.isContainerSizeValue())
return ContainerExpressionAnalyzer(exprTok, std::move(value), tokenlist, settings);
@ -9380,7 +9380,7 @@ struct ValueFlowPassAdaptor : ValueFlowPass {
const char* mName = nullptr;
bool mCPP = false;
F mRun;
ValueFlowPassAdaptor(const char* pname, bool pcpp, F prun) : mName(pname), mCPP(pcpp), mRun(prun) {}
ValueFlowPassAdaptor(const char* pname, bool pcpp, F prun) : ValueFlowPass(), mName(pname), mCPP(pcpp), mRun(prun) {}
const char* name() const override {
return mName;
}
@ -9394,7 +9394,7 @@ struct ValueFlowPassAdaptor : ValueFlowPass {
};
template<class F>
ValueFlowPassAdaptor<F> makeValueFlowPassAdaptor(const char* name, bool cpp, F run)
static ValueFlowPassAdaptor<F> makeValueFlowPassAdaptor(const char* name, bool cpp, F run)
{
return {name, cpp, run};
}

View File

@ -1,6 +1,9 @@
// For a release version x.y.z the MAJOR should be x and both MINOR and DEVMINOR should be y.
// After a release the DEVMINOR is incremented. MAJOR=x MINOR=y, DEVMINOR=y+1
#ifndef versionH
#define versionH
#define CPPCHECK_MAJOR_VERSION 2
#define CPPCHECK_MINOR_VERSION 12
#define CPPCHECK_DEVMINOR_VERSION 13
@ -16,3 +19,5 @@
#define CPPCHECK_VERSION CPPCHECK_MAJOR_VERSION,CPPCHECK_MINOR_VERSION,99,0
#endif
#define LEGALCOPYRIGHT L"Copyright (C) 2007-2023 Cppcheck team."
#endif