Fix issue 10216: FP containerOutOfBounds with std::array initialized with = {} (#3190)

This commit is contained in:
Paul Fultz II 2021-03-31 15:07:54 -05:00 committed by GitHub
parent 9b974f1b8e
commit 182ae75290
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 28 additions and 15 deletions

View File

@ -6212,6 +6212,7 @@ static std::vector<ValueFlow::Value> getInitListSize(const Token* tok, const Lib
static void valueFlowContainerSize(TokenList *tokenlist, SymbolDatabase* symboldatabase, ErrorLogger * /*errorLogger*/, const Settings *settings)
{
std::map<int, std::size_t> 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<ValueFlow::Value> 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<Token*>(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<ValueFlow::Value> values = getInitListSize(tok->tokAt(3), containerTok->valueType()->container);
for (const ValueFlow::Value& value : values)
valueFlowContainerForward(containerTok->next(), containerTok->variable(), value, tokenlist);

View File

@ -5008,6 +5008,13 @@ private:
"}\n";
ASSERT_EQUALS(0U, tokenValues(code, "str . front").size());
code = "void f() {\n"
" std::vector<int> ints{};\n"
" ints.front();\n"
"}";
ASSERT_EQUALS("",
isKnownContainerSizeValue(tokenValues(code, "ints . front", ValueFlow::Value::ValueType::CONTAINER_SIZE), 0));
code = "void f() {\n"
" std::vector<int> 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<int> 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<int, 10> 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"