Skip to content

Commit 887b5d2

Browse files
pfultz2Your Name
andauthored
Fix issue 13682: false negative: nullPointerRedundantCheck (multiple conditions, regression) (#8669)
Co-authored-by: Your Name <you@example.com>
1 parent 6640a7c commit 887b5d2

11 files changed

Lines changed: 175 additions & 22 deletions

.selfcheck_suppressions

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,4 @@ useStlAlgorithm:externals/simplecpp/simplecpp.cpp
7979
funcArgNamesDifferentUnnamed:externals/simplecpp/simplecpp.h
8080
missingMemberCopy:externals/simplecpp/simplecpp.h
8181
shadowFunction:externals/simplecpp/simplecpp.h
82+
knownConditionTrueFalse:externals/simplecpp/simplecpp.cpp

lib/astutils.cpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -495,8 +495,6 @@ bool isTemporary(const Token* tok, const Library* library, bool unknown)
495495
}
496496
return unknown;
497497
}
498-
if (tok->isCast())
499-
return false;
500498
// Currying a function is unknown in cppcheck
501499
if (Token::simpleMatch(tok, "(") && Token::simpleMatch(tok->astOperand1(), "("))
502500
return unknown;
@@ -1543,8 +1541,6 @@ bool isUsedAsBool(const Token* const tok, const Settings& settings)
15431541
return true;
15441542
if (parent->isCast())
15451543
return !Token::simpleMatch(parent->astOperand1(), "dynamic_cast") && isUsedAsBool(parent, settings);
1546-
if (parent->isUnaryOp("*"))
1547-
return isUsedAsBool(parent, settings);
15481544
if (Token::Match(parent, "==|!=") && tok->valueType() && tok->valueType()->pointer &&
15491545
tok->astSibling()->hasKnownIntValue() && tok->astSibling()->getKnownIntValue() == 0)
15501546
return true;

lib/checkclass.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3452,9 +3452,14 @@ void CheckClassImpl::checkUselessOverride()
34523452

34533453
if (isSameCode) {
34543454
// bailout for shadowed members
3455-
if (!classScope->definedType ||
3456-
!getDuplInheritedMembersRecursive(classScope->definedType, classScope->definedType, /*skipPrivate*/ false).empty() ||
3457-
!getDuplInheritedMemberFunctionsRecursive(classScope->definedType, classScope->definedType, /*skipPrivate*/ false).empty())
3455+
if (!getDuplInheritedMembersRecursive(classScope->definedType,
3456+
classScope->definedType,
3457+
/*skipPrivate*/ false)
3458+
.empty() ||
3459+
!getDuplInheritedMemberFunctionsRecursive(classScope->definedType,
3460+
classScope->definedType,
3461+
/*skipPrivate*/ false)
3462+
.empty())
34583463
continue;
34593464
uselessOverrideError(baseFunc, &func, true);
34603465
continue;

lib/checkcondition.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -455,7 +455,7 @@ bool CheckConditionImpl::isOverlappingCond(const Token * const cond1, const Toke
455455
if (!num1->isNumber() || MathLib::isNegative(num1->str()))
456456
return false;
457457

458-
if (!Token::Match(cond2, "&|==") || !cond2->astOperand1() || !cond2->astOperand2())
458+
if (!Token::Match(cond2, "&|==") || !cond2->astOperand1())
459459
return false;
460460
const Token *expr2 = cond2->astOperand1();
461461
const Token *num2 = cond2->astOperand2();

lib/checkstl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -549,7 +549,7 @@ void CheckStlImpl::iterators()
549549
}
550550

551551
// Not different containers if a reference is used..
552-
if (containerToken && containerToken->variable() && containerToken->variable()->isReference()) {
552+
if (containerToken->variable() && containerToken->variable()->isReference()) {
553553
const Token *nameToken = containerToken->variable()->nameToken();
554554
if (Token::Match(nameToken, "%name% =")) {
555555
const Token *name1 = nameToken->tokAt(2);

lib/forwardanalyzer.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -782,7 +782,7 @@ namespace {
782782
} else if (thenBranch.check) {
783783
return Break();
784784
} else {
785-
if (analyzer->isConditional() && stopUpdates())
785+
if (stopOnCondition(condTok) && stopUpdates())
786786
return Break(Analyzer::Terminate::Conditional);
787787
analyzer->assume(condTok, false);
788788
}

lib/reverseanalyzer.cpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -340,9 +340,6 @@ namespace {
340340
valueFlowGenericForward(condTok, analyzer, tokenlist, errorLogger, settings);
341341
else if (condAction.isRead())
342342
break;
343-
// If the condition modifies the variable then bail
344-
if (condAction.isModified())
345-
break;
346343
tok = jumpToStart(tok->link());
347344
continue;
348345
}

lib/symboldatabase.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1043,10 +1043,8 @@ void SymbolDatabase::createSymbolDatabaseNeedInitialization()
10431043
scope.definedType->needInitialization = Type::NeedInitialization::True;
10441044
else if (!unknown)
10451045
scope.definedType->needInitialization = Type::NeedInitialization::False;
1046-
else {
1047-
if (scope.definedType->needInitialization == Type::NeedInitialization::Unknown)
1048-
unknowns++;
1049-
}
1046+
else
1047+
unknowns++;
10501048
}
10511049
} else if (scope.type == ScopeType::eUnion && scope.definedType->needInitialization == Type::NeedInitialization::Unknown)
10521050
scope.definedType->needInitialization = Type::NeedInitialization::True;

lib/tokenize.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2711,7 +2711,7 @@ namespace {
27112711
{
27122712
Token *tok1 = tok;
27132713

2714-
if (tok1 && tok1->str() != nameToken->str())
2714+
if (!tok1 || tok1->str() != nameToken->str())
27152715
return false;
27162716

27172717
// skip this using

lib/vf_analyzers.cpp

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1198,18 +1198,40 @@ struct SingleValueFlowAnalyzer : ValueFlowAnalyzer {
11981198

11991199
bool stopOnCondition(const Token* condTok) const override
12001200
{
1201-
if (value.isNonValue())
1202-
return false;
12031201
if (value.isImpossible())
12041202
return false;
1205-
if (isConditional() && !value.isKnown())
1203+
// lifetime values must keep flowing to properly track aliases
1204+
if (value.isLifetimeValue())
1205+
return false;
1206+
// 'conditional' flag (uninit, or lowered after a modifying branch): may depend on a
1207+
// condition that doesn't mention the variable -> stop
1208+
if (value.conditional && !value.isKnown())
12061209
return true;
1207-
if (value.isSymbolicValue())
1210+
if (value.isNonValue())
12081211
return false;
1212+
if (value.isSymbolicValue())
1213+
return isConditional() && !value.isKnown();
1214+
// conditional via the originating 'condition' (e.g. possible null after 'if (p && ...)'): only flow
1215+
// if the condition references the value, else a correlation we can't follow (e.g.
1216+
// 'bool ok = (p != nullptr); if (!ok)') could make a later deref safe -> stop
1217+
if (value.condition && !value.isKnown() && !conditionReferencesValue(condTok))
1218+
return true;
12091219
ConditionState cs = analyzeCondition(condTok);
12101220
return cs.isUnknownDependent();
12111221
}
12121222

1223+
// Does the condition mention the tracked value, either directly or through a symbolic alias?
1224+
bool conditionReferencesValue(const Token* condTok) const
1225+
{
1226+
return findAstNode(condTok, [&](const Token* tok) {
1227+
if (match(tok))
1228+
return true;
1229+
return std::any_of(tok->values().cbegin(), tok->values().cend(), [&](const ValueFlow::Value& v) {
1230+
return v.isSymbolicValue() && !v.isImpossible() && v.tokvalue && match(v.tokvalue);
1231+
});
1232+
}) != nullptr;
1233+
}
1234+
12131235
bool updateScope(const Token* endBlock, bool /*modified*/) const override {
12141236
const Scope* scope = endBlock->scope();
12151237
if (!scope)

0 commit comments

Comments
 (0)