From 182ae75290ceead287ec72d9a1f2a5fc7c650a64 Mon Sep 17 00:00:00 2001 From: Paul Fultz II Date: Wed, 31 Mar 2021 15:07:54 -0500 Subject: [PATCH] Fix issue 10216: FP containerOutOfBounds with std::array initialized with = {} (#3190) --- lib/valueflow.cpp | 22 ++++++++++++++-------- test/testvalueflow.cpp | 21 ++++++++++++++------- 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 38d760afd..a7b269663 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -6212,6 +6212,7 @@ static std::vector getInitListSize(const Token* tok, const Lib static void valueFlowContainerSize(TokenList *tokenlist, SymbolDatabase* symboldatabase, ErrorLogger * /*errorLogger*/, const Settings *settings) { + std::map static_sizes; // declaration for (const Variable *var : symboldatabase->variableList()) { if (!var || !var->isLocal() || var->isPointer() || var->isReference() || var->isStatic()) @@ -6225,15 +6226,15 @@ static void valueFlowContainerSize(TokenList *tokenlist, SymbolDatabase* symbold if (!Token::Match(var->nameToken(), "%name% ;") && !(Token::Match(var->nameToken(), "%name% {") && Token::simpleMatch(var->nameToken()->next()->link(), "} ;"))) continue; + if (var->valueType()->container->size_templateArgNo >= 0) { + if (var->dimensions().size() == 1 && var->dimensions().front().known) + static_sizes[var->declarationId()] = var->dimensions().front().num; + continue; + } std::vector values{ValueFlow::Value{0}}; values.back().valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE; values.back().setKnown(); - if (var->valueType()->container->size_templateArgNo >= 0) { - if (var->dimensions().size() == 1 && var->dimensions().front().known) - values.back().intvalue = var->dimensions().front().num; - else - continue; - } else if (Token::simpleMatch(var->nameToken()->next(), "{")) { + if (Token::simpleMatch(var->nameToken()->next(), "{")) { const Token* initList = var->nameToken()->next(); values = getInitListSize(initList, var->valueType()->container); } @@ -6244,7 +6245,12 @@ static void valueFlowContainerSize(TokenList *tokenlist, SymbolDatabase* symbold // after assignment for (const Scope *functionScope : symboldatabase->functionScopes) { for (const Token *tok = functionScope->bodyStart; tok != functionScope->bodyEnd; tok = tok->next()) { - if (Token::Match(tok, "%name%|;|{|} %var% = %str% ;")) { + if (static_sizes.count(tok->varId()) > 0) { + ValueFlow::Value value(static_sizes.at(tok->varId())); + value.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE; + value.setKnown(); + setTokenValue(const_cast(tok), value, settings); + } else if (Token::Match(tok, "%name%|;|{|} %var% = %str% ;")) { const Token *containerTok = tok->next(); if (containerTok && containerTok->valueType() && containerTok->valueType()->container && containerTok->valueType()->container->stdStringLike) { ValueFlow::Value value(Token::getStrLength(containerTok->tokAt(2))); @@ -6254,7 +6260,7 @@ static void valueFlowContainerSize(TokenList *tokenlist, SymbolDatabase* symbold } } else if (Token::Match(tok, "%name%|;|{|}|> %var% = {") && Token::simpleMatch(tok->linkAt(3), "} ;")) { const Token* containerTok = tok->next(); - if (astIsContainer(containerTok)) { + if (astIsContainer(containerTok) && containerTok->valueType()->container->size_templateArgNo < 0) { std::vector values = getInitListSize(tok->tokAt(3), containerTok->valueType()->container); for (const ValueFlow::Value& value : values) valueFlowContainerForward(containerTok->next(), containerTok->variable(), value, tokenlist); diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index 611595c90..2147193a9 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -5008,6 +5008,13 @@ private: "}\n"; ASSERT_EQUALS(0U, tokenValues(code, "str . front").size()); + code = "void f() {\n" + " std::vector ints{};\n" + " ints.front();\n" + "}"; + ASSERT_EQUALS("", + isKnownContainerSizeValue(tokenValues(code, "ints . front", ValueFlow::Value::ValueType::CONTAINER_SIZE), 0)); + code = "void f() {\n" " std::vector ints{};\n" " ints.front();\n" @@ -5037,19 +5044,19 @@ private: ASSERT_EQUALS("", isKnownContainerSizeValue(tokenValues(code, "ints . front", ValueFlow::Value::ValueType::CONTAINER_SIZE), 0)); - code = "void f() {\n" - " std::vector ints = {1};\n" - " ints.front();\n" - "}"; - ASSERT_EQUALS("", - isKnownContainerSizeValue(tokenValues(code, "ints . front", ValueFlow::Value::ValueType::CONTAINER_SIZE), 1)); - code = "void f(std::string str) {\n" " if (str == \"123\")\n" " bool x = str.empty();\n" "}\n"; ASSERT_EQUALS("", isKnownContainerSizeValue(tokenValues(code, "str . empty", ValueFlow::Value::ValueType::CONTAINER_SIZE), 3)); + + code = "int f() {\n" + " std::array a = {};\n" + " return a.front();\n" + "}\n"; + ASSERT_EQUALS("", + isKnownContainerSizeValue(tokenValues(code, "a . front", ValueFlow::Value::ValueType::CONTAINER_SIZE), 10)); code = "void f(std::string str) {\n" " if (str == \"123\") {\n"