Fix 11096: FP knownConditionTrueFalse in do while loop (#4192)

* Check for loop

* Improve handling of exit values

* Add more checks to test

* Simplify

* Remove unnecessary test

* Fix typo

* Format

* Use simpleMatch
This commit is contained in:
Paul Fultz II 2022-06-10 13:42:02 -05:00 committed by GitHub
parent 829ca9ab7f
commit c9b85010f9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 49 additions and 2 deletions

View File

@ -4768,6 +4768,23 @@ static std::vector<const Token*> getConditions(const Token* tok, const char* op)
return conds;
}
static bool isBreakOrContinueScope(const Token* endToken)
{
if (!Token::simpleMatch(endToken, "}"))
return false;
return Token::Match(endToken->tokAt(-2), "break|continue ;");
}
static const Scope* getLoopScope(const Token* tok)
{
if (!tok)
return nullptr;
const Scope* scope = tok->scope();
while (scope && scope->type != Scope::eWhile && scope->type != Scope::eFor && scope->type != Scope::eDo)
scope = scope->nestedIn;
return scope;
}
//
static void valueFlowConditionExpressions(TokenList *tokenlist, SymbolDatabase* symboldatabase, ErrorLogger *errorLogger, const Settings *settings)
{
@ -4828,13 +4845,20 @@ static void valueFlowConditionExpressions(TokenList *tokenlist, SymbolDatabase*
// Check if the block terminates early
if (isEscapeScope(blockTok, tokenlist)) {
const Scope* scope2 = scope;
// If escaping a loop then only use the loop scope
if (isBreakOrContinueScope(blockTok->link())) {
scope2 = getLoopScope(blockTok->link());
if (!scope2)
continue;
}
for (const Token* condTok2:conds) {
ExpressionAnalyzer a1(condTok2, makeConditionValue(0, condTok2, false), tokenlist);
valueFlowGenericForward(startTok->link()->next(), scope->bodyEnd, a1, settings);
valueFlowGenericForward(startTok->link()->next(), scope2->bodyEnd, a1, settings);
if (is1) {
OppositeExpressionAnalyzer a2(true, condTok2, makeConditionValue(1, condTok2, false), tokenlist);
valueFlowGenericForward(startTok->link()->next(), scope->bodyEnd, a2, settings);
valueFlowGenericForward(startTok->link()->next(), scope2->bodyEnd, a2, settings);
}
}
}
@ -6049,6 +6073,27 @@ struct ConditionHandler {
}
if (values.empty())
return;
bool isKnown = std::any_of(values.begin(), values.end(), [&](const ValueFlow::Value& v) {
return v.isKnown() || v.isImpossible();
});
if (isKnown && isBreakOrContinueScope(after)) {
const Scope* loopScope = getLoopScope(cond.vartok);
if (loopScope) {
Analyzer::Result r = forward(after, loopScope->bodyEnd, cond.vartok, values, tokenlist);
if (r.terminate != Analyzer::Terminate::None)
return;
if (r.action.isModified())
return;
Token* start = const_cast<Token*>(loopScope->bodyEnd);
if (Token::simpleMatch(start, "} while (")) {
start = start->tokAt(2);
forward(start, start->link(), cond.vartok, values, tokenlist);
start = start->link();
}
values.remove_if(std::mem_fn(&ValueFlow::Value::isImpossible));
changeKnownToPossible(values);
}
}
forward(after, getEndOfExprScope(cond.vartok, scope), cond.vartok, values, tokenlist);
}
});

View File

@ -1444,6 +1444,8 @@ private:
" if (x) {}\n"
"}\n";
ASSERT_EQUALS(false, testValueOfX(code, 5U, 0));
ASSERT_EQUALS(false, testValueOfXKnown(code, 3U, 1));
TODO_ASSERT_EQUALS(true, false, testValueOfX(code, 6U, 0));
}
void valueFlowBeforeConditionAssignIncDec() { // assignment / increment