Fix issue 10216: FP containerOutOfBounds with std::array initialized with = {} (#3190)
This commit is contained in:
parent
9b974f1b8e
commit
182ae75290
|
@ -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)
|
static void valueFlowContainerSize(TokenList *tokenlist, SymbolDatabase* symboldatabase, ErrorLogger * /*errorLogger*/, const Settings *settings)
|
||||||
{
|
{
|
||||||
|
std::map<int, std::size_t> static_sizes;
|
||||||
// declaration
|
// declaration
|
||||||
for (const Variable *var : symboldatabase->variableList()) {
|
for (const Variable *var : symboldatabase->variableList()) {
|
||||||
if (!var || !var->isLocal() || var->isPointer() || var->isReference() || var->isStatic())
|
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% ;") &&
|
if (!Token::Match(var->nameToken(), "%name% ;") &&
|
||||||
!(Token::Match(var->nameToken(), "%name% {") && Token::simpleMatch(var->nameToken()->next()->link(), "} ;")))
|
!(Token::Match(var->nameToken(), "%name% {") && Token::simpleMatch(var->nameToken()->next()->link(), "} ;")))
|
||||||
continue;
|
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}};
|
std::vector<ValueFlow::Value> values{ValueFlow::Value{0}};
|
||||||
values.back().valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE;
|
values.back().valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE;
|
||||||
values.back().setKnown();
|
values.back().setKnown();
|
||||||
if (var->valueType()->container->size_templateArgNo >= 0) {
|
if (Token::simpleMatch(var->nameToken()->next(), "{")) {
|
||||||
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(), "{")) {
|
|
||||||
const Token* initList = var->nameToken()->next();
|
const Token* initList = var->nameToken()->next();
|
||||||
values = getInitListSize(initList, var->valueType()->container);
|
values = getInitListSize(initList, var->valueType()->container);
|
||||||
}
|
}
|
||||||
|
@ -6244,7 +6245,12 @@ static void valueFlowContainerSize(TokenList *tokenlist, SymbolDatabase* symbold
|
||||||
// after assignment
|
// after assignment
|
||||||
for (const Scope *functionScope : symboldatabase->functionScopes) {
|
for (const Scope *functionScope : symboldatabase->functionScopes) {
|
||||||
for (const Token *tok = functionScope->bodyStart; tok != functionScope->bodyEnd; tok = tok->next()) {
|
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();
|
const Token *containerTok = tok->next();
|
||||||
if (containerTok && containerTok->valueType() && containerTok->valueType()->container && containerTok->valueType()->container->stdStringLike) {
|
if (containerTok && containerTok->valueType() && containerTok->valueType()->container && containerTok->valueType()->container->stdStringLike) {
|
||||||
ValueFlow::Value value(Token::getStrLength(containerTok->tokAt(2)));
|
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), "} ;")) {
|
} else if (Token::Match(tok, "%name%|;|{|}|> %var% = {") && Token::simpleMatch(tok->linkAt(3), "} ;")) {
|
||||||
const Token* containerTok = tok->next();
|
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);
|
std::vector<ValueFlow::Value> values = getInitListSize(tok->tokAt(3), containerTok->valueType()->container);
|
||||||
for (const ValueFlow::Value& value : values)
|
for (const ValueFlow::Value& value : values)
|
||||||
valueFlowContainerForward(containerTok->next(), containerTok->variable(), value, tokenlist);
|
valueFlowContainerForward(containerTok->next(), containerTok->variable(), value, tokenlist);
|
||||||
|
|
|
@ -5008,6 +5008,13 @@ private:
|
||||||
"}\n";
|
"}\n";
|
||||||
ASSERT_EQUALS(0U, tokenValues(code, "str . front").size());
|
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"
|
code = "void f() {\n"
|
||||||
" std::vector<int> ints{};\n"
|
" std::vector<int> ints{};\n"
|
||||||
" ints.front();\n"
|
" ints.front();\n"
|
||||||
|
@ -5037,13 +5044,6 @@ private:
|
||||||
ASSERT_EQUALS("",
|
ASSERT_EQUALS("",
|
||||||
isKnownContainerSizeValue(tokenValues(code, "ints . front", ValueFlow::Value::ValueType::CONTAINER_SIZE), 0));
|
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"
|
code = "void f(std::string str) {\n"
|
||||||
" if (str == \"123\")\n"
|
" if (str == \"123\")\n"
|
||||||
" bool x = str.empty();\n"
|
" bool x = str.empty();\n"
|
||||||
|
@ -5051,6 +5051,13 @@ private:
|
||||||
ASSERT_EQUALS("",
|
ASSERT_EQUALS("",
|
||||||
isKnownContainerSizeValue(tokenValues(code, "str . empty", ValueFlow::Value::ValueType::CONTAINER_SIZE), 3));
|
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"
|
code = "void f(std::string str) {\n"
|
||||||
" if (str == \"123\") {\n"
|
" if (str == \"123\") {\n"
|
||||||
" bool x = (str == \"\");\n"
|
" bool x = (str == \"\");\n"
|
||||||
|
|
Loading…
Reference in New Issue