diff --git a/lib/astutils.cpp b/lib/astutils.cpp index 1be4c9be50e..b238827dad1 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -1001,29 +1001,43 @@ bool isAliasOf(const Token *tok, nonneg int varid, bool* inconclusive) return false; } -bool isAliasOf(const Token* tok, const Token* expr, bool* inconclusive) +bool isAliasOf(const Token* tok, const Token* expr, int* indirect, bool* inconclusive) { - const bool pointer = astIsPointer(tok); const ValueFlow::Value* value = nullptr; - const Token* r = findAstNode(expr, [&](const Token* childTok) { - for (const ValueFlow::Value& val : tok->values()) { - if (val.isImpossible()) - continue; - if (val.isLocalLifetimeValue() || (pointer && val.isSymbolicValue() && val.intvalue == 0)) { - if (findAstNode(val.tokvalue, - [&](const Token* aliasTok) { - return aliasTok->exprId() == childTok->exprId(); - })) { - if (val.isInconclusive() && inconclusive != nullptr) { - value = &val; - } else { - return true; + const Token* r = nullptr; + if (indirect) + *indirect = 1; + for (const ReferenceToken& ref : followAllReferences(tok)) { + const bool pointer = astIsPointer(ref.token); + r = findAstNode(expr, [&](const Token* childTok) { + if (childTok->exprId() == 0) + return false; + if (ref.token != tok && expr->exprId() == childTok->exprId()) { + if (indirect) + *indirect = 0; + return true; + } + for (const ValueFlow::Value& val : ref.token->values()) { + if (val.isImpossible()) + continue; + if (val.isLocalLifetimeValue() || (pointer && val.isSymbolicValue() && val.intvalue == 0)) { + if (findAstNode(val.tokvalue, + [&](const Token* aliasTok) { + return aliasTok->exprId() == childTok->exprId(); + })) { + if (val.isInconclusive() && inconclusive != nullptr) { + value = &val; + } else { + return true; + } } } } - } - return false; - }); + return false; + }); + if (r) + break; + } if (!r && value && inconclusive) *inconclusive = true; return r || value; @@ -2728,16 +2742,17 @@ static bool isExpressionChangedAt(const F& getExprTok, if (globalvar && !tok->isKeyword() && Token::Match(tok, "%name% (") && !(tok->function() && tok->function()->isAttributePure())) // TODO: Is global variable really changed by function call? return true; + int i = 1; bool aliased = false; // If we can't find the expression then assume it is an alias auto expr = getExprTok(); if (!expr) aliased = true; if (!aliased) - aliased = isAliasOf(tok, expr); + aliased = isAliasOf(tok, expr, &i); if (!aliased) return false; - if (isVariableChanged(tok, indirect + 1, settings, cpp, depth)) + if (isVariableChanged(tok, indirect + i, settings, cpp, depth)) return true; // TODO: Try to traverse the lambda function if (Token::Match(tok, "%var% (")) diff --git a/lib/astutils.h b/lib/astutils.h index fdcc713d767..95a8896a6de 100644 --- a/lib/astutils.h +++ b/lib/astutils.h @@ -356,7 +356,7 @@ bool isExpressionChangedAt(const Token* expr, /// If token is an alias if another variable bool isAliasOf(const Token *tok, nonneg int varid, bool* inconclusive = nullptr); -bool isAliasOf(const Token* tok, const Token* expr, bool* inconclusive = nullptr); +bool isAliasOf(const Token* tok, const Token* expr, int* indirect = nullptr, bool* inconclusive = nullptr); bool isAliased(const Variable *var); diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index ea30d13c7e2..396879b90d4 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -8039,7 +8039,7 @@ static void valueFlowUninit(TokenList& tokenlist, const Settings* settings) } } -static bool isContainerSizeChanged(nonneg int varId, +static bool isContainerSizeChanged(const Token* expr, const Token* start, const Token* end, int indirect, @@ -8088,7 +8088,7 @@ static bool isContainerSizeChangedByFunction(const Token* tok, if (!arg->nameToken()) return false; if (depth > 0) - return isContainerSizeChanged(arg->declarationId(), + return isContainerSizeChanged(arg->nameToken(), scope->bodyStart, scope->bodyEnd, addressOf ? indirect + 1 : indirect, @@ -8342,7 +8342,7 @@ bool ValueFlow::isContainerSizeChanged(const Token* tok, int indirect, const Set return isContainerSizeChangedByFunction(tok, indirect, settings, depth); } -static bool isContainerSizeChanged(nonneg int varId, +static bool isContainerSizeChanged(const Token* expr, const Token* start, const Token* end, int indirect, @@ -8350,7 +8350,7 @@ static bool isContainerSizeChanged(nonneg int varId, int depth) { for (const Token *tok = start; tok != end; tok = tok->next()) { - if (tok->varId() != varId) + if (tok->exprId() != expr->exprId() && !isAliasOf(tok, expr)) continue; if (ValueFlow::isContainerSizeChanged(tok, indirect, settings, depth)) return true; diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index e1302d9ce73..788b96f7623 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -6643,6 +6643,18 @@ class TestValueFlow : public TestFixture { code = "int f() { auto a = std::array{}; return a[1]; }"; ASSERT_EQUALS("values.size():0", isKnownContainerSizeValue(tokenValues(code, "a ["), 0)); + + code = "void g(std::vector* w) {\n" + " std::vector &r = *w;\n" + " r.push_back(0);\n" + "}\n" + "int f() {\n" + " std::vector v;\n" + " g(&v);\n" + " return v[0];\n" + "}\n"; + ASSERT(!isKnownContainerSizeValue(tokenValues(code, "v ["), 0).empty()); + ASSERT(!isPossibleContainerSizeValue(tokenValues(code, "v ["), 0).empty()); } void valueFlowContainerElement()