From 0f259a5dc67fe3d6af0cbc683f74e395271a1502 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Wed, 3 Nov 2021 20:16:44 +0100 Subject: [PATCH] Fixed #10222 (regression: arrayIndexOutOfBounds) --- lib/valueflow.cpp | 18 +++++++++++++++--- test/testvalueflow.cpp | 28 ++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index b10ae0d51..8df0ec091 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -3394,10 +3394,22 @@ static const Token* getEndOfVarScope(const Token* tok, const std::vectorisLocal() || var->isArgument()) && var->typeStartToken()->scope()->type != Scope::eNamespace) - endOfVarScope = var->typeStartToken()->scope()->bodyEnd; - else if (!endOfVarScope) - endOfVarScope = tok->scope()->bodyEnd; + varScope = var->typeStartToken()->scope(); + else if (!endOfVarScope) { + varScope = tok->scope(); + // A "local member" will be a expression like foo.x where foo is a local variable. + // A "global member" will be a member that belongs to a global object. + const bool globalMember = vars.size() == 1; // <- could check if it's a member here also but it seems redundant + if (var && (var->isGlobal() || var->isNamespace() || globalMember)) { + // Global variable => end of function + while (varScope->isLocal()) + varScope = varScope->nestedIn; + } + } + if (varScope && (!endOfVarScope || precedes(varScope->bodyEnd, endOfVarScope))) + endOfVarScope = varScope->bodyEnd; } return endOfVarScope; } diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index 8b1054c33..d20e928b8 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -2475,6 +2475,34 @@ private: " }\n" "};\n"; ASSERT_EQUALS(true, testValueOfXKnown(code, 7U, 1)); + + // global variable + code = "int x;\n" + "int foo(int y) {\n" + " if (y)\n" + " x = 10;\n" + " return x;\n" + "}"; + ASSERT_EQUALS(true, testValueOfX(code, 5U, 10)); + + code = "namespace A { int x; }\n" + "int foo(int y) {\n" + " if (y)\n" + " A::x = 10;\n" + " return A::x;\n" + "}"; + ASSERT_EQUALS(true, testValueOfX(code, 5U, 10)); + + // member variable + code = "struct Fred {\n" + " int x;\n" + " int foo(int y) {\n" + " if (y)\n" + " x = 10;\n" + " return x;\n" + " }\n" + "};"; + ASSERT_EQUALS(true, testValueOfX(code, 6U, 10)); } void valueFlowAfterSwap()