Avoid infinite recursion in getLifetimeVariable (#1634)

* Fix direct recursion

* Limit depth of getLifetimeVariable
This commit is contained in:
Paul Fultz II 2019-01-31 03:34:41 -06:00 committed by Daniel Marjamäki
parent 0b7414973d
commit c176775afb
3 changed files with 19 additions and 5 deletions

View File

@ -2662,11 +2662,13 @@ std::string lifetimeType(const Token *tok, const ValueFlow::Value *val)
return result; return result;
} }
const Variable *getLifetimeVariable(const Token *tok, ValueFlow::Value::ErrorPath &errorPath) const Variable *getLifetimeVariable(const Token *tok, ValueFlow::Value::ErrorPath &errorPath, int depth)
{ {
if (!tok) if (!tok)
return nullptr; return nullptr;
const Variable *var = tok->variable(); const Variable *var = tok->variable();
if (depth < 0)
return var;
if (var && var->declarationId() == tok->varId()) { if (var && var->declarationId() == tok->varId()) {
if (var->isReference() || var->isRValueReference()) { if (var->isReference() || var->isRValueReference()) {
if (!var->declEndToken()) if (!var->declEndToken())
@ -2680,7 +2682,7 @@ const Variable *getLifetimeVariable(const Token *tok, ValueFlow::Value::ErrorPat
if (vartok == tok) if (vartok == tok)
return nullptr; return nullptr;
if (vartok) if (vartok)
return getLifetimeVariable(vartok, errorPath); return getLifetimeVariable(vartok, errorPath, depth-1);
} else { } else {
return nullptr; return nullptr;
} }
@ -2694,7 +2696,9 @@ const Variable *getLifetimeVariable(const Token *tok, ValueFlow::Value::ErrorPat
const Token *returnTok = findSimpleReturn(f); const Token *returnTok = findSimpleReturn(f);
if (!returnTok) if (!returnTok)
return nullptr; return nullptr;
const Variable *argvar = getLifetimeVariable(returnTok, errorPath); if (returnTok == tok)
return var;
const Variable *argvar = getLifetimeVariable(returnTok, errorPath, depth-1);
if (!argvar) if (!argvar)
return nullptr; return nullptr;
if (argvar->isArgument() && (argvar->isReference() || argvar->isRValueReference())) { if (argvar->isArgument() && (argvar->isReference() || argvar->isRValueReference())) {
@ -2704,7 +2708,7 @@ const Variable *getLifetimeVariable(const Token *tok, ValueFlow::Value::ErrorPat
const Token *argTok = getArguments(tok->previous()).at(n); const Token *argTok = getArguments(tok->previous()).at(n);
errorPath.emplace_back(returnTok, "Return reference."); errorPath.emplace_back(returnTok, "Return reference.");
errorPath.emplace_back(tok->previous(), "Called function passing '" + argTok->str() + "'."); errorPath.emplace_back(tok->previous(), "Called function passing '" + argTok->str() + "'.");
return getLifetimeVariable(argTok, errorPath); return getLifetimeVariable(argTok, errorPath, depth-1);
} }
} }
return var; return var;

View File

@ -229,7 +229,7 @@ namespace ValueFlow {
std::string eitherTheConditionIsRedundant(const Token *condition); std::string eitherTheConditionIsRedundant(const Token *condition);
} }
const Variable *getLifetimeVariable(const Token *tok, ValueFlow::Value::ErrorPath &errorPath); const Variable *getLifetimeVariable(const Token *tok, ValueFlow::Value::ErrorPath &errorPath, int depth=20);
std::string lifetimeType(const Token *tok, const ValueFlow::Value *val); std::string lifetimeType(const Token *tok, const ValueFlow::Value *val);

View File

@ -112,6 +112,7 @@ private:
TEST_CASE(returnReferenceCalculation); TEST_CASE(returnReferenceCalculation);
TEST_CASE(returnReferenceLambda); TEST_CASE(returnReferenceLambda);
TEST_CASE(returnReferenceInnerScope); TEST_CASE(returnReferenceInnerScope);
TEST_CASE(returnReferenceRecursive);
TEST_CASE(danglingReference); TEST_CASE(danglingReference);
@ -1246,6 +1247,15 @@ private:
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
} }
void returnReferenceRecursive() {
check("int& f() { return f(); }");
ASSERT_EQUALS("", errout.str());
check("int& g(int& i) { return i; }\n"
"int& f() { return g(f()); }\n");
ASSERT_EQUALS("", errout.str());
}
void danglingReference() { void danglingReference() {
check("int f( int k )\n" check("int f( int k )\n"
"{\n" "{\n"