diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 5e899695a..0ac2a58de 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -7628,14 +7628,23 @@ static void valueFlowContainerSize(TokenList *tokenlist, SymbolDatabase* symbold continue; if (!var->valueType() || !var->valueType()->container) continue; - if (!astIsContainer(var->nameToken())) + const Token* const vnt = var->nameToken(); + if (!astIsContainer(vnt)) continue; - if (var->nameToken()->hasKnownValue(ValueFlow::Value::ValueType::CONTAINER_SIZE)) + if (vnt->hasKnownValue(ValueFlow::Value::ValueType::CONTAINER_SIZE)) continue; - if (!Token::Match(var->nameToken(), "%name% ;") && - !(Token::Match(var->nameToken(), "%name% {") && Token::simpleMatch(var->nameToken()->next()->link(), "} ;"))) + const bool isDecl = Token::Match(vnt, "%name% ;"); + bool hasInitList = false, hasInitSize = false; + if (!isDecl) { + hasInitList = Token::Match(vnt, "%name% {") && Token::simpleMatch(vnt->next()->link(), "} ;"); + if (!hasInitList) + hasInitList = Token::Match(vnt, "%name% ( {") && Token::simpleMatch(vnt->linkAt(2), "} ) ;"); + if (!hasInitList) + hasInitSize = Token::Match(vnt, "%name% (|{ %num%|%var% )|}"); + } + if (!isDecl && !hasInitList && !hasInitSize) continue; - if (var->nameToken()->astTop() && Token::Match(var->nameToken()->astTop()->previous(), "for|while")) + if (vnt->astTop() && Token::Match(vnt->astTop()->previous(), "for|while")) known = !isVariableChanged(var, settings, true); if (var->valueType()->container->size_templateArgNo >= 0) { if (var->dimensions().size() == 1 && var->dimensions().front().known) @@ -7646,12 +7655,20 @@ static void valueFlowContainerSize(TokenList *tokenlist, SymbolDatabase* symbold values.back().valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE; if (known) values.back().setKnown(); - if (Token::simpleMatch(var->nameToken()->next(), "{")) { - const Token* initList = var->nameToken()->next(); + if (hasInitList) { + const Token* initList = vnt->next(); + if (Token::simpleMatch(initList, "(")) + initList = initList->next(); values = getInitListSize(initList, var->valueType()->container, known); } + else if (hasInitSize) { + const Token* sizeTok = vnt->next()->astOperand2(); + if (!sizeTok || !sizeTok->hasKnownIntValue()) + continue; + values.back().intvalue = sizeTok->getKnownIntValue(); + } for (const ValueFlow::Value& value : values) - valueFlowContainerForward(var->nameToken()->next(), var->nameToken(), value, tokenlist); + valueFlowContainerForward(vnt->next(), vnt, value, tokenlist); } // after assignment diff --git a/test/teststl.cpp b/test/teststl.cpp index b7bb7a4e5..5da53f3cd 100644 --- a/test/teststl.cpp +++ b/test/teststl.cpp @@ -729,6 +729,30 @@ private: "test.cpp:2:note:condition 'v.empty()'\n" "test.cpp:2:note:Access out of bounds\n", errout.str()); + + check("std::vector g() {\n" // #10779 + " std::vector v(10);\n" + " for(int i = 0; i <= 10; ++i)\n" + " v[i] = 42;\n" + " return v;\n" + "}\n"); + ASSERT_EQUALS("test.cpp:4:error:Out of bounds access in 'v[i]', if 'v' size is 10 and 'i' is 10\n", + errout.str()); + + check("void f() {\n" + " int s = 2;\n" + " std::vector v(s);\n" + " v[100] = 1;\n" + "}\n"); + ASSERT_EQUALS("test.cpp:4:error:Out of bounds access in 'v[100]', if 'v' size is 2 and '100' is 100\n", + errout.str()); + + check("void f() {\n" + " std::vector v({ 1, 2, 3 });\n" + " v[100] = 1;\n" + "}\n"); + ASSERT_EQUALS("test.cpp:3:error:Out of bounds access in 'v[100]', if 'v' size is 3 and '100' is 100\n", + errout.str()); } void outOfBoundsSymbolic() diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index 4c17858ec..ec6ada870 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -6026,6 +6026,18 @@ private: "}\n"; ASSERT_EQUALS( "", isKnownContainerSizeValue(tokenValues(code, "v [", ValueFlow::Value::ValueType::CONTAINER_SIZE), 0)); + + code = "void f() {\n" + " std::vector v(3);\n" + " v.size();\n" + "}"; + ASSERT_EQUALS("", isKnownContainerSizeValue(tokenValues(code, "v . size"), 3)); + + code = "void f() {\n" + " std::vector v({ 1, 2, 3 });\n" + " v.size();\n" + "}"; + ASSERT_EQUALS("", isKnownContainerSizeValue(tokenValues(code, "v . size"), 3)); } void valueFlowDynamicBufferSize() {