Skip to content

Commit

Permalink
Merge branch 'main' into chr_unusedAllocatedMemory
Browse files Browse the repository at this point in the history
  • Loading branch information
chrchr-github authored Mar 22, 2024
2 parents 601e62d + 23ec401 commit 2270a0a
Show file tree
Hide file tree
Showing 42 changed files with 469 additions and 106 deletions.
6 changes: 3 additions & 3 deletions cfg/qt.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -5236,12 +5236,12 @@
<unusedvar>
<suppress>QApplication</suppress>
<suppress>QMutexLocker</suppress>
<check>QRectF</check>
<check>QSizeF</check>
<check>QPointF</check>
<check>QRect</check>
<check>QRectF</check>
<check>QSize</check>
<check>QSizeF</check>
<check>QPoint</check>
<check>QPointF</check>
<check>QRegion</check>
</unusedvar>
<operatorEqVarError>
Expand Down
13 changes: 13 additions & 0 deletions cfg/windows.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -4907,6 +4907,8 @@ HFONT CreateFont(
<not-bool/>
</arg>
</function>
<define name="CREATE_EVENT_INITIAL_SET" value="0x00000002"/>
<define name="CREATE_EVENT_MANUAL_RESET" value="0x00000001"/>
<!--HANDLE WINAPI OpenEvent(
_In_ DWORD dwDesiredAccess,
_In_ BOOL bInheritHandle,
Expand Down Expand Up @@ -5453,6 +5455,17 @@ HFONT CreateFont(
<not-null/>
</arg>
</function>
<define name="SECURITY_NULL_SID_AUTHORITY" value="0"/>
<define name="SECURITY_WORLD_SID_AUTHORITY" value="1"/>
<define name="SECURITY_LOCAL_SID_AUTHORITY" value="2"/>
<define name="SECURITY_CREATOR_SID_AUTHORITY" value="3"/>
<define name="SECURITY_NT_AUTHORITY" value="5"/>
<define name="SECURITY_NULL_RID" value="0"/>
<define name="SECURITY_WORLD_RID" value="0"/>
<define name="SECURITY_LOCAL_RID" value="0"/>
<define name="SECURITY_LOCAL_LOGON_RID" value="1"/>
<define name="SECURITY_CREATOR_OWNER_RID" value="0"/>
<define name="SECURITY_CREATOR_GROUP_RID" value="1"/>
<!--PVOID WINAPI FreeSid(_In_ PSID pSid);-->
<function name="FreeSid">
<noreturn>false</noreturn>
Expand Down
2 changes: 2 additions & 0 deletions cfg/wxwidgets.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
<check>wxRect</check>
<check>wxSize</check>
<check>wxPoint</check>
<check>wxPoint2DInt</check>
<check>wxPoint2DDouble</check>
<check>wxRealPoint</check>
<check>wxVersionInfo</check>
<check>wxRegion</check>
Expand Down
61 changes: 37 additions & 24 deletions cli/cmdlineparser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1071,44 +1071,57 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a
// Rule file
else if (std::strncmp(argv[i], "--rule-file=", 12) == 0) {
#ifdef HAVE_RULES
// TODO: improved error handling - unknown elements, wrong root node, etc.
// TODO: improved error handling - wrong root node, etc.
// TODO: consume unused "version" attribute
const std::string ruleFile = argv[i] + 12;
tinyxml2::XMLDocument doc;
const tinyxml2::XMLError err = doc.LoadFile(ruleFile.c_str());
if (err == tinyxml2::XML_SUCCESS) {
const tinyxml2::XMLElement *node = doc.FirstChildElement();
// TODO: this looks like legacy handling - deprecate it
// check if it is a single or multi rule configuration
if (node && strcmp(node->Value(), "rules") == 0)
node = node->FirstChildElement("rule");
for (; node && strcmp(node->Value(), "rule") == 0; node = node->NextSiblingElement()) {
Settings::Rule rule;

const tinyxml2::XMLElement *tokenlist = node->FirstChildElement("tokenlist");
if (tokenlist)
rule.tokenlist = tokenlist->GetText();

const tinyxml2::XMLElement *pattern = node->FirstChildElement("pattern");
if (pattern) {
rule.pattern = pattern->GetText();
for (const tinyxml2::XMLElement *subnode = node->FirstChildElement(); subnode; subnode = subnode->NextSiblingElement()) {
const char * const subtext = subnode->GetText();
if (std::strcmp(subnode->Name(), "tokenlist") == 0) {
rule.tokenlist = empty_if_null(subtext);
}
else if (std::strcmp(subnode->Name(), "pattern") == 0) {
rule.pattern = empty_if_null(subtext);
}
else if (std::strcmp(subnode->Name(), "message") == 0) {
for (const tinyxml2::XMLElement *msgnode = subnode->FirstChildElement(); msgnode; msgnode = msgnode->NextSiblingElement()) {
const char * const msgtext = msgnode->GetText();
if (std::strcmp(msgnode->Name(), "severity") == 0) {
rule.severity = severityFromString(empty_if_null(msgtext));
}
else if (std::strcmp(msgnode->Name(), "id") == 0) {
rule.id = empty_if_null(msgtext);
}
else if (std::strcmp(msgnode->Name(), "summary") == 0) {
rule.summary = empty_if_null(msgtext);
}
else {
mLogger.printError("unable to load rule-file '" + ruleFile + "' - unknown element '" + msgnode->Name() + "' encountered in 'message'.");
return Result::Fail;
}
}
}
else {
mLogger.printError("unable to load rule-file '" + ruleFile + "' - unknown element '" + subnode->Name() + "' encountered in 'rule'.");
return Result::Fail;
}
}

const tinyxml2::XMLElement *message = node->FirstChildElement("message");
if (message) {
const tinyxml2::XMLElement *severity = message->FirstChildElement("severity");
if (severity)
rule.severity = severityFromString(severity->GetText());

const tinyxml2::XMLElement *id = message->FirstChildElement("id");
if (id)
rule.id = id->GetText();

const tinyxml2::XMLElement *summary = message->FirstChildElement("summary");
if (summary)
rule.summary = summary->GetText() ? summary->GetText() : "";
if (rule.pattern.empty()) {
mLogger.printError("unable to load rule-file '" + ruleFile + "' - a rule is lacking a pattern.");
return Result::Fail;
}

if (!rule.pattern.empty())
mSettings.rules.emplace_back(std::move(rule));
mSettings.rules.emplace_back(std::move(rule));
}
} else {
mLogger.printError("unable to load rule-file '" + ruleFile + "' (" + tinyxml2::XMLDocument::ErrorIDToName(err) + ").");
Expand Down
15 changes: 11 additions & 4 deletions lib/checkother.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -944,6 +944,9 @@ void CheckOther::checkVariableScope()
if (!var || !var->isLocal() || var->isConst())
continue;

if (var->nameToken()->isExpandedMacro())
continue;

const bool isPtrOrRef = var->isPointer() || var->isReference();
const bool isSimpleType = var->typeStartToken()->isStandardType() || var->typeStartToken()->isEnumType() || (var->typeStartToken()->isC() && var->type() && var->type()->isStructType());
if (!isPtrOrRef && !isSimpleType && !astIsContainer(var->nameToken()))
Expand Down Expand Up @@ -1824,7 +1827,7 @@ static bool isConstant(const Token* tok) {
return tok && (tok->isEnumerator() || Token::Match(tok, "%bool%|%num%|%str%|%char%|nullptr|NULL"));
}

static bool isConstStatement(const Token *tok)
static bool isConstStatement(const Token *tok, bool isNestedBracket = false)
{
if (!tok)
return false;
Expand Down Expand Up @@ -1875,9 +1878,13 @@ static bool isConstStatement(const Token *tok)
if (Token::simpleMatch(tok, "?") && Token::simpleMatch(tok->astOperand2(), ":")) // ternary operator
return isConstStatement(tok->astOperand1()) && isConstStatement(tok->astOperand2()->astOperand1()) && isConstStatement(tok->astOperand2()->astOperand2());
if (isBracketAccess(tok) && isWithoutSideEffects(tok->astOperand1(), /*checkArrayAccess*/ true, /*checkReference*/ false)) {
if (Token::simpleMatch(tok->astParent(), "["))
return isConstStatement(tok->astOperand2()) && isConstStatement(tok->astParent());
return isConstStatement(tok->astOperand2());
const bool isChained = succeeds(tok->astParent(), tok);
if (Token::simpleMatch(tok->astParent(), "[")) {
if (isChained)
return isConstStatement(tok->astOperand2()) && isConstStatement(tok->astParent());
return isNestedBracket && isConstStatement(tok->astOperand2());
}
return isConstStatement(tok->astOperand2(), /*isNestedBracket*/ !isChained);
}
return false;
}
Expand Down
5 changes: 4 additions & 1 deletion lib/checktype.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ void CheckType::signConversionError(const Token *tok, const ValueFlow::Value *ne
//---------------------------------------------------------------------------
// Checking for long cast of int result const long x = var1 * var2;
//---------------------------------------------------------------------------
static bool checkTypeCombination(const ValueType& src, const ValueType& tgt, const Settings& settings)
static bool checkTypeCombination(ValueType src, ValueType tgt, const Settings& settings)
{
static const std::pair<ValueType::Type, ValueType::Type> typeCombinations[] = {
{ ValueType::Type::INT, ValueType::Type::LONG },
Expand All @@ -310,6 +310,9 @@ static bool checkTypeCombination(const ValueType& src, const ValueType& tgt, con
{ ValueType::Type::DOUBLE, ValueType::Type::LONGDOUBLE },
};

src.reference = Reference::None;
tgt.reference = Reference::None;

const std::size_t sizeSrc = ValueFlow::getSizeOf(src, settings);
const std::size_t sizeTgt = ValueFlow::getSizeOf(tgt, settings);
if (!(sizeSrc > 0 && sizeTgt > 0 && sizeSrc < sizeTgt))
Expand Down
11 changes: 8 additions & 3 deletions lib/checkunusedvar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -713,10 +713,12 @@ void CheckUnusedVar::checkFunctionVariableUsage_iterateScopes(const Scope* const
type = Variables::pointer;
else if (mTokenizer->isC() ||
i->typeEndToken()->isStandardType() ||
i->isStlType() ||
isRecordTypeWithoutSideEffects(i->type()) ||
mSettings->library.detectContainer(i->typeStartToken()) ||
i->isStlType())
mSettings->library.getTypeCheck("unusedvar", i->typeStartToken()->str()) == Library::TypeCheck::check)
type = Variables::standard;

if (type == Variables::none || isPartOfClassStructUnion(i->typeStartToken()))
continue;
const Token* defValTok = i->nameToken()->next();
Expand Down Expand Up @@ -1007,7 +1009,7 @@ void CheckUnusedVar::checkFunctionVariableUsage_iterateScopes(const Scope* const

// assignment
else if ((Token::Match(tok, "%name% [") && Token::simpleMatch(skipBracketsAndMembers(tok->next()), "=")) ||
(tok->isUnaryOp("*") && Token::simpleMatch(tok->astParent(), "=") && Token::simpleMatch(tok->astOperand1(), "+"))) {
(tok->isUnaryOp("*") && astIsLHS(tok) && Token::simpleMatch(tok->astParent(), "=") && Token::simpleMatch(tok->astOperand1(), "+"))) {
const Token *eq = tok;
while (eq && !eq->isAssignmentOp())
eq = eq->astParent();
Expand Down Expand Up @@ -1199,8 +1201,9 @@ void CheckUnusedVar::checkFunctionVariableUsage()
if (!isAssignment && !isInitialization && !isIncrementOrDecrement)
continue;

bool isTrivialInit = false;
if (isInitialization && Token::Match(tok, "%var% { }")) // don't warn for trivial initialization
continue;
isTrivialInit = true;

if (isIncrementOrDecrement && tok->astParent() && precedes(tok, tok->astOperand1()))
continue;
Expand Down Expand Up @@ -1306,6 +1309,8 @@ void CheckUnusedVar::checkFunctionVariableUsage()
reportLibraryCfgError(tok, bailoutTypeName);
continue;
}
if (isTrivialInit && findExpressionChanged(expr, start, scopeEnd, mSettings))
continue;

// warn
if (!expr->variable() || !expr->variable()->isMaybeUnused())
Expand Down
16 changes: 12 additions & 4 deletions lib/tokenize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4251,7 +4251,7 @@ static bool setVarIdParseDeclaration(Token** tok, const VariableMap& variableMap
bracket = true;
} else if (tok2->str() == "::") {
singleNameCount = 0;
} else if (tok2->str() != "*" && tok2->str() != "::" && tok2->str() != "...") {
} else if (tok2->str() != "*" && tok2->str() != "...") {
break;
}
tok2 = tok2->next();
Expand Down Expand Up @@ -4826,7 +4826,8 @@ void Tokenizer::setVarIdPass1()
// function declaration inside executable scope? Function declaration is of form: type name "(" args ")"
if (scopeStack.top().isExecutable && Token::Match(tok, "%name% [,)[]")) {
bool par = false;
const Token *start, *end;
const Token* start;
Token* end;

// search begin of function declaration
for (start = tok; Token::Match(start, "%name%|*|&|,|("); start = start->previous()) {
Expand All @@ -4850,9 +4851,11 @@ void Tokenizer::setVarIdPass1()
const bool isNotstartKeyword = start->next() && notstart.find(start->next()->str()) != notstart.end();

// now check if it is a function declaration
if (Token::Match(start, "[;{}] %type% %name%|*") && par && Token::simpleMatch(end, ") ;") && !isNotstartKeyword)
if (Token::Match(start, "[;{}] %type% %name%|*") && par && Token::simpleMatch(end, ") ;") && !isNotstartKeyword) {
// function declaration => don't set varid
tok = end;
continue;
}
}

if ((!scopeStack.top().isEnum || !(Token::Match(tok->previous(), "{|,") && Token::Match(tok->next(), ",|=|}"))) &&
Expand Down Expand Up @@ -8583,9 +8586,12 @@ void Tokenizer::findGarbageCode() const
bool match1 = Token::Match(tok, "%or%|%oror%|==|!=|+|-|/|!|>=|<=|~|^|++|--|::|sizeof");
bool match2 = Token::Match(tok->next(), "{|if|else|while|do|for|return|switch|break");
if (isCPP()) {
match1 = match1 || Token::Match(tok, "::|throw|decltype|typeof");
match1 = match1 || Token::Match(tok, "throw|decltype|typeof");
match2 = match2 || Token::Match(tok->next(), "try|catch|namespace");
}
if (match1 && !tok->isIncDecOp()) {
match2 = match2 || Token::Match(tok->next(), "%assign%");
}
if (match1 && match2)
syntaxError(tok);
}
Expand Down Expand Up @@ -8635,6 +8641,8 @@ void Tokenizer::findGarbageCode() const
syntaxError(tok);
if (Token::Match(tok, "==|!=|<=|>= %comp%") && tok->strAt(-1) != "operator")
syntaxError(tok, tok->str() + " " + tok->strAt(1));
if (Token::simpleMatch(tok, ":: ::"))
syntaxError(tok);
}

// ternary operator without :
Expand Down
5 changes: 4 additions & 1 deletion lib/tokenlist.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1758,7 +1758,10 @@ static Token * createAstAtToken(Token *tok)
void TokenList::createAst() const
{
for (Token *tok = mTokensFrontBack.front; tok; tok = tok ? tok->next() : nullptr) {
tok = createAstAtToken(tok);
Token* const nextTok = createAstAtToken(tok);
if (precedes(nextTok, tok))
throw InternalError(tok, "Syntax Error: Infinite loop when creating AST.", InternalError::AST);
tok = nextTok;
}
}

Expand Down
6 changes: 6 additions & 0 deletions lib/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -361,4 +361,10 @@ namespace cppcheck
}
}

template<typename T>
static inline T* empty_if_null(T* p)
{
return p ? p : "";
}

#endif
9 changes: 7 additions & 2 deletions lib/valueflow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4972,6 +4972,8 @@ static void valueFlowLifetime(TokenList &tokenlist, ErrorLogger *errorLogger, co
}
// address of
else if (tok->isUnaryOp("&")) {
if (Token::simpleMatch(tok->astParent(), "*"))
continue;
for (const ValueFlow::LifetimeToken& lt : ValueFlow::getLifetimeTokens(tok->astOperand1())) {
if (!settings.certainty.isEnabled(Certainty::inconclusive) && lt.inconclusive)
continue;
Expand Down Expand Up @@ -5334,16 +5336,19 @@ static const Scope* getLoopScope(const Token* tok)
//
static void valueFlowConditionExpressions(const TokenList &tokenlist, const SymbolDatabase& symboldatabase, ErrorLogger *errorLogger, const Settings &settings)
{
if (settings.checkLevel == Settings::CheckLevel::normal)
if (!settings.daca && (settings.checkLevel == Settings::CheckLevel::normal))
return;

for (const Scope * scope : symboldatabase.functionScopes) {
if (const Token* incompleteTok = findIncompleteVar(scope->bodyStart, scope->bodyEnd)) {
if (settings.debugwarnings)
bailoutIncompleteVar(tokenlist, errorLogger, incompleteTok, "Skipping function due to incomplete variable " + incompleteTok->str());
break;
continue;
}

if (settings.daca && (settings.checkLevel == Settings::CheckLevel::normal))
continue;

for (Token* tok = const_cast<Token*>(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) {
if (!Token::simpleMatch(tok, "if ("))
continue;
Expand Down
4 changes: 3 additions & 1 deletion releasenotes.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,6 @@ Other:
- Removed deprecated platform type 'Unspecified'. Please use 'unspecified' instead.
- Removed deprecated 'Makefile' option 'SRCDIR'.
- Added CMake option 'DISALLOW_THREAD_EXECUTOR' to control the inclusion of the executor which performs the analysis within a thread of the main process.
- Removed CMake option 'USE_THREADS' in favor of 'DISALLOW_THREAD_EXECUTOR'.
- Removed CMake option 'USE_THREADS' in favor of 'DISALLOW_THREAD_EXECUTOR'.
- Fixed crash with '--rule-file=' if some data was missing.
- '--rule-file' will now bail out if a rule could not be added or a file contains unexpected data.
5 changes: 1 addition & 4 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,6 @@ if (BUILD_TESTS)
else()
# TODO: remove missingInclude disabling when it no longer is implied by --enable=information
# TODO: add syntax check
# need to suppress unmatchedSuppression in case valueFlowBailout is not reported
add_test(NAME cfg-${TEST_NAME}
COMMAND $<TARGET_FILE:cppcheck>
--library=${LIBRARY}
Expand All @@ -129,9 +128,7 @@ if (BUILD_TESTS)
--disable=missingInclude
--inline-suppr
--debug-warnings
--suppress=valueFlowBailout
--suppress=purgedConfiguration
--suppress=unmatchedSuppression
--suppress=checkersReport
${CMAKE_CURRENT_SOURCE_DIR}/cfg/${CFG_TEST}
)
endif()
Expand Down
2 changes: 2 additions & 0 deletions test/cfg/boost.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
// No warnings about bad library configuration, unmatched suppressions, etc. exitcode=0
//

// cppcheck-suppress-file valueFlowBailout

#include <boost/config.hpp>
#include <boost/math/special_functions/round.hpp>
#include <boost/endian/conversion.hpp>
Expand Down
2 changes: 2 additions & 0 deletions test/cfg/bsd.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
// No warnings about bad library configuration, unmatched suppressions, etc. exitcode=0
//

// cppcheck-suppress-file valueFlowBailout

#include <string.h>
#include <stdlib.h>
#include <stdint.h>
Expand Down
2 changes: 2 additions & 0 deletions test/cfg/cppunit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
// No warnings about bad library configuration, unmatched suppressions, etc. exitcode=0
//

// cppcheck-suppress-file valueFlowBailout

#include <cppunit/TestAssert.h>

void cppunit_assert_equal(int x, double y)
Expand Down
Loading

0 comments on commit 2270a0a

Please sign in to comment.