Fix 11673: FP uninitvar when capturing by reference (#4984)

* Fix 11673: FP uninitvar when capturing by reference

* Format

* Fix tests
This commit is contained in:
Paul Fultz II 2023-05-03 23:03:47 -05:00 committed by GitHub
parent b5ce2c708b
commit 9770dd7e0b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 117 additions and 16 deletions

View File

@ -7751,23 +7751,115 @@ static void addToErrorPath(ValueFlow::Value& value, const ValueFlow::Value& from
}); });
} }
static std::vector<Token*> findAllUsages(const Variable* var, Token* start) // cppcheck-suppress constParameterPointer // FP template<class Found, class Predicate>
bool findTokenSkipDeadCodeImpl(const Library* library, Token* start, const Token* end, Predicate pred, Found found)
{
for (Token* tok = start; precedes(tok, end); tok = tok->next()) {
if (pred(tok)) {
if (found(tok))
return true;
}
if (Token::simpleMatch(tok, "if (")) {
const Token* condTok = tok->next()->astOperand2();
if (!condTok)
continue;
if (!condTok->hasKnownIntValue())
continue;
if (!Token::simpleMatch(tok->linkAt(1), ") {"))
continue;
if (findTokenSkipDeadCodeImpl(library, tok->next(), tok->linkAt(1), pred, found))
return true;
Token* thenStart = tok->linkAt(1)->next();
Token* elseStart = nullptr;
if (Token::simpleMatch(thenStart->link(), "} else {"))
elseStart = thenStart->link()->tokAt(2);
int r = condTok->values().front().intvalue;
if (r == 0) {
if (elseStart) {
if (findTokenSkipDeadCodeImpl(library, elseStart, elseStart->link(), pred, found))
return true;
if (isReturnScope(elseStart->link(), library))
return true;
tok = elseStart->link();
} else {
tok = thenStart->link();
}
} else {
if (findTokenSkipDeadCodeImpl(library, thenStart, thenStart->link(), pred, found))
return true;
if (isReturnScope(thenStart->link(), library))
return true;
tok = thenStart->link();
}
} else if (Token::Match(tok->astParent(), "&&|?|%oror%") && astIsLHS(tok) && tok->hasKnownIntValue()) {
int r = tok->values().front().intvalue;
Token* next = nullptr;
if ((r == 0 && Token::simpleMatch(tok->astParent(), "||")) ||
(r != 0 && Token::simpleMatch(tok->astParent(), "&&"))) {
next = nextAfterAstRightmostLeaf(tok->astParent());
} else if (Token::simpleMatch(tok->astParent(), "?")) {
Token* colon = tok->astParent()->astOperand2();
if (r == 0) {
next = colon;
} else {
if (findTokenSkipDeadCodeImpl(library, tok->astParent()->next(), colon, pred, found))
return true;
next = nextAfterAstRightmostLeaf(colon);
}
}
if (next)
tok = next;
} else if (Token::simpleMatch(tok, "} else {")) {
const Token* condTok = getCondTokFromEnd(tok);
if (!condTok)
continue;
if (!condTok->hasKnownIntValue())
continue;
if (isReturnScope(tok->link(), library))
return true;
int r = condTok->values().front().intvalue;
if (r != 0) {
tok = tok->linkAt(1);
}
} else if (Token::simpleMatch(tok, "[") && Token::Match(tok->link(), "] (|{")) {
Token* afterCapture = tok->link()->next();
if (Token::simpleMatch(afterCapture, "(") && afterCapture->link())
tok = afterCapture->link()->next();
else
tok = afterCapture;
}
}
return false;
}
template<class Predicate>
std::vector<Token*> findTokensSkipDeadCode(const Library* library, Token* start, const Token* end, Predicate pred)
{ {
std::vector<Token*> result; std::vector<Token*> result;
const Scope* scope = var->scope(); findTokenSkipDeadCodeImpl(library, start, end, pred, [&](Token* tok) {
if (!scope) result.push_back(tok);
return result; return false;
Token* tok2 = Token::findmatch(start, "%varid%", scope->bodyEnd, var->declarationId()); });
while (tok2) {
result.push_back(tok2);
tok2 = Token::findmatch(tok2->next(), "%varid%", scope->bodyEnd, var->declarationId());
}
return result; return result;
} }
static Token* findStartToken(const Variable* var, Token* start) static std::vector<Token*> findAllUsages(const Variable* var,
Token* start, // cppcheck-suppress constParameterPointer // FP
const Library* library)
{ {
std::vector<Token*> uses = findAllUsages(var, start); // std::vector<Token*> result;
const Scope* scope = var->scope();
if (!scope)
return {};
return findTokensSkipDeadCode(library, start, scope->bodyEnd, [&](const Token* tok) {
return tok->varId() == var->declarationId();
});
}
static Token* findStartToken(const Variable* var, Token* start, const Library* library)
{
std::vector<Token*> uses = findAllUsages(var, start, library);
if (uses.empty()) if (uses.empty())
return start; return start;
Token* first = uses.front(); Token* first = uses.front();
@ -7823,7 +7915,7 @@ static void valueFlowUninit(TokenList* tokenlist, SymbolDatabase* /*symbolDataba
bool partial = false; bool partial = false;
Token* start = findStartToken(var, tok->next()); Token* start = findStartToken(var, tok->next(), &settings->library);
std::map<Token*, ValueFlow::Value> partialReads; std::map<Token*, ValueFlow::Value> partialReads;
if (const Scope* scope = var->typeScope()) { if (const Scope* scope = var->typeScope()) {

View File

@ -3498,7 +3498,7 @@ private:
" }\n" " }\n"
"}", "}",
"test.cpp"); "test.cpp");
TODO_ASSERT_EQUALS("", "[test.cpp:6]: (error) Uninitialized variable: i\n", errout.str()); ASSERT_EQUALS("", errout.str());
valueFlowUninit("void f() {\n" valueFlowUninit("void f() {\n"
" int i, y;\n" " int i, y;\n"
@ -3509,7 +3509,7 @@ private:
" }\n" " }\n"
"}", "}",
"test.cpp"); "test.cpp");
TODO_ASSERT_EQUALS("", "[test.cpp:6]: (error) Uninitialized variable: i\n", errout.str()); ASSERT_EQUALS("", errout.str());
valueFlowUninit("void f() {\n" valueFlowUninit("void f() {\n"
" int i, y;\n" " int i, y;\n"
@ -5970,6 +5970,15 @@ private:
"}\n"); "}\n");
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
// #11673
valueFlowUninit("void f() {\n"
" bool b;\n"
" auto g = [&b]() {\n"
" b = true;\n"
" };\n"
"}\n");
ASSERT_EQUALS("", errout.str());
// #6619 // #6619
valueFlowUninit("void f() {\n" valueFlowUninit("void f() {\n"
" int nok, i;\n" " int nok, i;\n"
@ -5979,7 +5988,7 @@ private:
" }\n" " }\n"
" printf(\"nok = %d\\n\", nok);\n" " printf(\"nok = %d\\n\", nok);\n"
"}\n"); "}\n");
ASSERT_EQUALS("[test.cpp:7]: (warning) Uninitialized variable: nok\n", errout.str()); ASSERT_EQUALS("[test.cpp:7]: (error) Uninitialized variable: nok\n", errout.str());
// #7475 // #7475
valueFlowUninit("struct S {\n" valueFlowUninit("struct S {\n"

View File

@ -5445,7 +5445,7 @@ private:
" }\n" " }\n"
"}\n"; "}\n";
values = tokenValues(code, "i ++", ValueFlow::Value::ValueType::UNINIT); values = tokenValues(code, "i ++", ValueFlow::Value::ValueType::UNINIT);
TODO_ASSERT_EQUALS(0, 1, values.size()); ASSERT_EQUALS(0, values.size());
} }
void valueFlowConditionExpressions() { void valueFlowConditionExpressions() {