Fix 10348: FP knownConditionTrueFalse with condition variable in do ... while loop (#3422)

This commit is contained in:
Paul Fultz II 2021-08-26 22:46:57 -05:00 committed by GitHub
parent 712ff1c073
commit 740becbddf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 61 additions and 12 deletions

View File

@ -385,23 +385,27 @@ struct ForwardTraversal {
std::tie(checkThen, checkElse) = evalCond(condTok, isDoWhile ? endBlock->previous() : nullptr); std::tie(checkThen, checkElse) = evalCond(condTok, isDoWhile ? endBlock->previous() : nullptr);
if (checkElse && exit) if (checkElse && exit)
return Progress::Continue; return Progress::Continue;
Analyzer::Action bodyAnalysis = analyzeScope(endBlock);
Analyzer::Action allAnalysis = bodyAnalysis;
Analyzer::Action condAnalysis;
if (condTok) {
condAnalysis = analyzeRecursive(condTok);
allAnalysis |= condAnalysis;
}
if (stepTok)
allAnalysis |= analyzeRecursive(stepTok);
actions |= allAnalysis;
// do while(false) is not really a loop // do while(false) is not really a loop
if (checkElse && isDoWhile) { if (checkElse && isDoWhile &&
(condTok->hasKnownIntValue() || (!bodyAnalysis.isModified() && condAnalysis.isRead()))) {
if (updateRange(endBlock->link(), endBlock) == Progress::Break) if (updateRange(endBlock->link(), endBlock) == Progress::Break)
return Break(); return Break();
return updateRecursive(condTok); return updateRecursive(condTok);
} }
Analyzer::Action bodyAnalysis = analyzeScope(endBlock);
Analyzer::Action allAnalysis = bodyAnalysis;
if (condTok)
allAnalysis |= analyzeRecursive(condTok);
if (stepTok)
allAnalysis |= analyzeRecursive(stepTok);
actions |= allAnalysis;
if (allAnalysis.isInconclusive()) { if (allAnalysis.isInconclusive()) {
if (!analyzer->lowerToInconclusive()) if (!analyzer->lowerToInconclusive())
return Break(Analyzer::Terminate::Bail); return Break(Analyzer::Terminate::Bail);
} else if (allAnalysis.isModified()) { } else if (allAnalysis.isModified() || (exit && allAnalysis.isIdempotent())) {
if (!analyzer->lowerToPossible()) if (!analyzer->lowerToPossible())
return Break(Analyzer::Terminate::Bail); return Break(Analyzer::Terminate::Bail);
} }
@ -417,6 +421,9 @@ struct ForwardTraversal {
if (checkElse) if (checkElse)
return Progress::Continue; return Progress::Continue;
if (checkThen || isDoWhile) { if (checkThen || isDoWhile) {
// Since we are re-entering the loop then assume the condition is true to update the state
if (exit)
analyzer->assume(condTok, true, Analyzer::Assume::Quiet | Analyzer::Assume::Absolute);
if (updateInnerLoop(endBlock, stepTok, condTok) == Progress::Break) if (updateInnerLoop(endBlock, stepTok, condTok) == Progress::Break)
return Break(); return Break();
// If loop re-enters then it could be modified again // If loop re-enters then it could be modified again

View File

@ -284,9 +284,12 @@ static void fillProgramMemoryFromAssignments(ProgramMemory& pm, const Token* tok
} }
if (tok2->str() == "{") { if (tok2->str() == "{") {
if (indentlevel <= 0) if (indentlevel <= 0) {
break; // Keep progressing with anonymous/do scopes
--indentlevel; if (!Token::Match(tok2->previous(), "do|; {"))
break;
} else
--indentlevel;
if (Token::simpleMatch(tok2->previous(), "else {")) if (Token::simpleMatch(tok2->previous(), "else {"))
tok2 = tok2->linkAt(-2)->previous(); tok2 = tok2->linkAt(-2)->previous();
} }

View File

@ -2383,6 +2383,8 @@ struct ValueFlowAnalyzer : Analyzer {
if (isCondBlock) { if (isCondBlock) {
const Token* startBlock = parent->link()->next(); const Token* startBlock = parent->link()->next();
if (Token::simpleMatch(startBlock, ";") && Token::simpleMatch(parent->tokAt(-2), "} while ("))
startBlock = parent->linkAt(-2);
const Token* endBlock = startBlock->link(); const Token* endBlock = startBlock->link();
pms.removeModifiedVars(endBlock); pms.removeModifiedVars(endBlock);
if (state) if (state)

View File

@ -117,6 +117,8 @@ private:
TEST_CASE(alwaysTrue); TEST_CASE(alwaysTrue);
TEST_CASE(alwaysTrueSymbolic); TEST_CASE(alwaysTrueSymbolic);
TEST_CASE(alwaysTrueInfer); TEST_CASE(alwaysTrueInfer);
TEST_CASE(alwaysTrueContainer);
TEST_CASE(alwaysTrueLoop);
TEST_CASE(multiConditionAlwaysTrue); TEST_CASE(multiConditionAlwaysTrue);
TEST_CASE(duplicateCondition); TEST_CASE(duplicateCondition);
@ -4032,6 +4034,40 @@ private:
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
} }
void alwaysTrueLoop()
{
check("long foo() {\n"
" bool bUpdated = false;\n"
" long Ret{};\n"
" do {\n"
" Ret = bar();\n"
" if (Ret == 0) {\n"
" if (bUpdated)\n"
" return 1;\n"
" bUpdated = true;\n"
" }\n"
" else\n"
" bUpdated = false;\n"
" }\n"
" while (bUpdated);\n"
" return Ret;\n"
"}\n");
ASSERT_EQUALS("", errout.str());
check("bool foo() {\n"
" bool bFirst = true;\n"
" do {\n"
" if (bFirst)\n"
" bar();\n"
" if (baz())\n"
" break; \n"
" bFirst = false;\n"
" } while (true);\n"
" return bFirst;\n"
"}\n");
ASSERT_EQUALS("", errout.str());
}
void multiConditionAlwaysTrue() { void multiConditionAlwaysTrue() {
check("void f() {\n" check("void f() {\n"
" int val = 0;\n" " int val = 0;\n"

View File

@ -2172,6 +2172,7 @@ private:
" } while (1);\n" " } while (1);\n"
"}"; "}";
ASSERT_EQUALS(false, testValueOfX(code, 4U, 0)); ASSERT_EQUALS(false, testValueOfX(code, 4U, 0));
ASSERT_EQUALS(true, testValueOfX(code, 4U, 3));
// pointer/reference to x // pointer/reference to x
code = "int f(void) {\n" code = "int f(void) {\n"