From 9de976b24311e8a326d31b7552c558e8135e27fc Mon Sep 17 00:00:00 2001 From: Paul Fultz II Date: Tue, 30 Mar 2021 04:22:56 -0500 Subject: [PATCH] Fix issue 10194: hang with followAllReferences() (#3189) * Decrease depth faster when there is multiple returns --- lib/astutils.cpp | 8 ++++---- lib/valueflow.cpp | 4 ++-- test/testvalueflow.cpp | 41 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 6 deletions(-) diff --git a/lib/astutils.cpp b/lib/astutils.cpp index 7cc0dd97d..322ff6efb 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -806,11 +806,11 @@ std::vector followAllReferences(const Token* tok, bool inconclus if (!Function::returnsReference(f)) return {{tok, std::move(errors)}}; std::set result; - for (const Token* returnTok : Function::findReturns(f)) { + std::vector returns = Function::findReturns(f); + for (const Token* returnTok : returns) { if (returnTok == tok) continue; - std::vector 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 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 refs = followAllReferences(argTok, inconclusive, std::move(er), depth - 1); + std::vector 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)}}; diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index be7a0ee7f..43a21b6cc 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -2663,7 +2663,7 @@ std::vector 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 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 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()); } } diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index 4501882be..e7e1f6375 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -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