Fix issue 10194: hang with followAllReferences() (#3189)

* Decrease depth faster when there is multiple returns
This commit is contained in:
Paul Fultz II 2021-03-30 04:22:56 -05:00 committed by GitHub
parent 77716ee398
commit 9de976b243
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 47 additions and 6 deletions

View File

@ -806,11 +806,11 @@ std::vector<ReferenceToken> followAllReferences(const Token* tok, bool inconclus
if (!Function::returnsReference(f))
return {{tok, std::move(errors)}};
std::set<ReferenceToken, ReferenceTokenLess> result;
for (const Token* returnTok : Function::findReturns(f)) {
std::vector<const Token*> returns = Function::findReturns(f);
for (const Token* returnTok : returns) {
if (returnTok == tok)
continue;
std::vector<ReferenceToken> argvarRt = followAllReferences(returnTok, inconclusive, errors, depth - 1);
for (const ReferenceToken& rt:followAllReferences(returnTok, inconclusive, errors, depth - 1)) {
for (const ReferenceToken& rt:followAllReferences(returnTok, inconclusive, errors, depth - returns.size())) {
const Variable* argvar = rt.token->variable();
if (!argvar)
return {{tok, std::move(errors)}};
@ -825,7 +825,7 @@ std::vector<ReferenceToken> followAllReferences(const Token* tok, bool inconclus
ErrorPath er = errors;
er.emplace_back(returnTok, "Return reference.");
er.emplace_back(tok->previous(), "Called function passing '" + argTok->expressionString() + "'.");
std::vector<ReferenceToken> refs = followAllReferences(argTok, inconclusive, std::move(er), depth - 1);
std::vector<ReferenceToken> refs = followAllReferences(argTok, inconclusive, std::move(er), depth - returns.size());
result.insert(refs.begin(), refs.end());
if (!inconclusive && result.size() > 1)
return {{tok, std::move(errors)}};

View File

@ -2663,7 +2663,7 @@ std::vector<LifetimeToken> getLifetimeTokens(const Token* tok, bool escape, Valu
for (const Token* returnTok : returns) {
if (returnTok == tok)
continue;
for (LifetimeToken& lt : getLifetimeTokens(returnTok, escape, errorPath, depth - 1)) {
for (LifetimeToken& lt : getLifetimeTokens(returnTok, escape, errorPath, depth - returns.size())) {
const Token* argvarTok = lt.token;
const Variable* argvar = argvarTok->variable();
if (!argvar)
@ -2680,7 +2680,7 @@ std::vector<LifetimeToken> getLifetimeTokens(const Token* tok, bool escape, Valu
lt.errorPath.emplace_back(returnTok, "Return reference.");
lt.errorPath.emplace_back(tok->previous(), "Called function passing '" + argTok->expressionString() + "'.");
std::vector<LifetimeToken> arglts = LifetimeToken::setInconclusive(
getLifetimeTokens(argTok, escape, std::move(lt.errorPath), depth - 1), returns.size() > 1);
getLifetimeTokens(argTok, escape, std::move(lt.errorPath), depth - returns.size()), returns.size() > 1);
result.insert(result.end(), arglts.begin(), arglts.end());
}
}

View File

@ -5447,6 +5447,47 @@ private:
" &b}}}};\n"
"}\n";
valueOfTok(code, "x");
code = "int &a(int &);\n"
"int &b(int &);\n"
"int &c(int &);\n"
"int &d(int &e) {\n"
" if (!e)\n"
" return a(e);\n"
" if (e > 0)\n"
" return b(e);\n"
" if (e < 0)\n"
" return c(e);\n"
" return e;\n"
"}\n"
"int &a(int &e) { \n"
" if (!e)\n"
" return d(e); \n"
" if (e > 0)\n"
" return b(e);\n"
" if (e < 0)\n"
" return c(e);\n"
" return e;\n"
"}\n"
"int &b(int &e) { \n"
" if (!e)\n"
" return a(e); \n"
" if (e > 0)\n"
" return c(e);\n"
" if (e < 0)\n"
" return d(e);\n"
" return e;\n"
"}\n"
"int &c(int &e) { \n"
" if (!e)\n"
" return a(e); \n"
" if (e > 0)\n"
" return b(e);\n"
" if (e < 0)\n"
" return d(e);\n"
" return e;\n"
"}\n";
valueOfTok(code, "x");
}
void valueFlowCrashConstructorInitialization() { // #9577