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:
parent
59f7b937f1
commit
db5f00a16a
|
@ -488,6 +488,18 @@ static bool isDanglingSubFunction(const Token* tokvalue, const Token* tok)
|
||||||
return exprDependsOnThis(parent);
|
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)
|
void CheckAutoVariables::checkVarLifetimeScope(const Token * start, const Token * end)
|
||||||
{
|
{
|
||||||
const bool printInconclusive = mSettings->certainty.isEnabled(Certainty::inconclusive);
|
const bool printInconclusive = mSettings->certainty.isEnabled(Certainty::inconclusive);
|
||||||
|
@ -546,7 +558,8 @@ void CheckAutoVariables::checkVarLifetimeScope(const Token * start, const Token
|
||||||
if (!printInconclusive && val.isInconclusive())
|
if (!printInconclusive && val.isInconclusive())
|
||||||
continue;
|
continue;
|
||||||
const bool escape = Token::Match(tok->astParent(), "return|throw");
|
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;
|
const Token * tokvalue = lt.token;
|
||||||
if (val.isLocalLifetimeValue()) {
|
if (val.isLocalLifetimeValue()) {
|
||||||
if (escape) {
|
if (escape) {
|
||||||
|
|
|
@ -2693,10 +2693,10 @@ std::vector<LifetimeToken> getLifetimeTokens(const Token* tok, bool escape, Valu
|
||||||
} else if (Token::simpleMatch(var->declEndToken(), "=")) {
|
} else if (Token::simpleMatch(var->declEndToken(), "=")) {
|
||||||
errorPath.emplace_back(var->declEndToken(), "Assigned to reference.");
|
errorPath.emplace_back(var->declEndToken(), "Assigned to reference.");
|
||||||
const Token *vartok = var->declEndToken()->astOperand2();
|
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, true);
|
||||||
const bool temporary = isTemporary(true, vartok, nullptr, temporaryDefault);
|
|
||||||
const bool nonlocal = var->isStatic() || var->isGlobal();
|
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)}};
|
return {{tok, true, std::move(errorPath)}};
|
||||||
if (vartok)
|
if (vartok)
|
||||||
return getLifetimeTokens(vartok, escape, std::move(errorPath), depth - 1);
|
return getLifetimeTokens(vartok, escape, std::move(errorPath), depth - 1);
|
||||||
|
|
|
@ -2597,6 +2597,19 @@ private:
|
||||||
" return e;\n"
|
" return e;\n"
|
||||||
"}\n");
|
"}\n");
|
||||||
ASSERT_EQUALS("", errout.str());
|
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() {
|
void danglingLifetimeFunction() {
|
||||||
|
|
Loading…
Reference in New Issue