Fix issue 10214: FP: danglingTempReference doesn't account for reference lifetime extension (#3220)

* Fix issue 10214: FP: danglingTempReference doesn't account for reference lifetime extension
This commit is contained in:
Paul Fultz II 2021-04-19 07:20:29 -05:00 committed by GitHub
parent 59f7b937f1
commit db5f00a16a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 30 additions and 4 deletions

View File

@ -488,6 +488,18 @@ static bool isDanglingSubFunction(const Token* tokvalue, const Token* tok)
return exprDependsOnThis(parent);
}
static bool isAssignedToNonLocal(const Token* tok)
{
if (!Token::simpleMatch(tok->astParent(), "="))
return false;
if (!Token::Match(tok->astParent()->astOperand1(), "%var%"))
return false;
const Variable* var = tok->astParent()->astOperand1()->variable();
if (!var)
return false;
return !var->isLocal() || var->isStatic();
}
void CheckAutoVariables::checkVarLifetimeScope(const Token * start, const Token * end)
{
const bool printInconclusive = mSettings->certainty.isEnabled(Certainty::inconclusive);
@ -546,7 +558,8 @@ void CheckAutoVariables::checkVarLifetimeScope(const Token * start, const Token
if (!printInconclusive && val.isInconclusive())
continue;
const bool escape = Token::Match(tok->astParent(), "return|throw");
for (const LifetimeToken& lt : getLifetimeTokens(getParentLifetime(val.tokvalue), escape)) {
for (const LifetimeToken& lt :
getLifetimeTokens(getParentLifetime(val.tokvalue), escape || isAssignedToNonLocal(tok))) {
const Token * tokvalue = lt.token;
if (val.isLocalLifetimeValue()) {
if (escape) {

View File

@ -2693,10 +2693,10 @@ std::vector<LifetimeToken> getLifetimeTokens(const Token* tok, bool escape, Valu
} else if (Token::simpleMatch(var->declEndToken(), "=")) {
errorPath.emplace_back(var->declEndToken(), "Assigned to reference.");
const Token *vartok = var->declEndToken()->astOperand2();
const bool temporaryDefault = false; //If we can't tell then assume the value is not temporary as this will result in fewer false positives.
const bool temporary = isTemporary(true, vartok, nullptr, temporaryDefault);
const bool temporary = isTemporary(true, vartok, nullptr, true);
const bool nonlocal = var->isStatic() || var->isGlobal();
if (vartok == tok || (nonlocal && temporary) || (!escape && (var->isConst() || var->isRValueReference()) && temporary))
if (vartok == tok || (nonlocal && temporary) ||
(!escape && (var->isConst() || var->isRValueReference()) && temporary))
return {{tok, true, std::move(errorPath)}};
if (vartok)
return getLifetimeTokens(vartok, escape, std::move(errorPath), depth - 1);

View File

@ -2597,6 +2597,19 @@ private:
" return e;\n"
"}\n");
ASSERT_EQUALS("", errout.str());
// #10214
check("struct A {\n"
" std::string key;\n"
" const char *value;\n"
"};\n"
"const char *f(const std::string &key, const std::vector<A> &lookup) {\n"
" const auto &entry =\n"
" std::find_if(lookup.begin(), lookup.end(),\n"
" [key](const auto &v) { return v.key == key; });\n"
" return (entry == lookup.end()) ? \"\" : entry->value;\n"
"}\n");
ASSERT_EQUALS("", errout.str());
}
void danglingLifetimeFunction() {