Fix issue 9996: false negative: containerOutOfBounds with std::vector::front() and c++11 braced initializer (#2958)
This commit is contained in:
parent
0b98053790
commit
b044f9ba96
|
@ -5970,6 +5970,24 @@ static void valueFlowIteratorInfer(TokenList *tokenlist, const Settings *setting
|
|||
}
|
||||
}
|
||||
|
||||
static std::vector<ValueFlow::Value> getInitListSize(const Token* tok)
|
||||
{
|
||||
std::vector<const Token*> args = getArguments(tok);
|
||||
if ((args.size() == 1 && astIsContainer(args[0]) && args[0]->valueType()->container == tok->valueType()->container) ||
|
||||
(args.size() == 2 && astIsIterator(args[0]) && astIsIterator(args[1]))) {
|
||||
std::vector<ValueFlow::Value> values;
|
||||
std::copy_if(args[0]->values().begin(),
|
||||
args[0]->values().end(),
|
||||
std::back_inserter(values),
|
||||
std::mem_fn(&ValueFlow::Value::isContainerSizeValue));
|
||||
return values;
|
||||
}
|
||||
ValueFlow::Value value(args.size());
|
||||
value.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE;
|
||||
value.setKnown();
|
||||
return {value};
|
||||
}
|
||||
|
||||
static void valueFlowContainerSize(TokenList *tokenlist, SymbolDatabase* symboldatabase, ErrorLogger * /*errorLogger*/, const Settings *settings)
|
||||
{
|
||||
// declaration
|
||||
|
@ -5978,21 +5996,26 @@ static void valueFlowContainerSize(TokenList *tokenlist, SymbolDatabase* symbold
|
|||
continue;
|
||||
if (!var->valueType() || !var->valueType()->container)
|
||||
continue;
|
||||
if (!Token::Match(var->nameToken(), "%name% ;"))
|
||||
continue;
|
||||
if (!astIsContainer(var->nameToken()))
|
||||
continue;
|
||||
if (var->nameToken()->hasKnownValue())
|
||||
continue;
|
||||
ValueFlow::Value value(0);
|
||||
if (!Token::Match(var->nameToken(), "%name% ;") &&
|
||||
!(Token::Match(var->nameToken(), "%name% {") && Token::simpleMatch(var->nameToken()->next()->link(), "} ;")))
|
||||
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)
|
||||
value.intvalue = var->dimensions().front().num;
|
||||
values.back().intvalue = var->dimensions().front().num;
|
||||
else
|
||||
continue;
|
||||
} else if (Token::simpleMatch(var->nameToken()->next(), "{")) {
|
||||
const Token* initList = var->nameToken()->next();
|
||||
values = getInitListSize(initList);
|
||||
}
|
||||
value.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE;
|
||||
value.setKnown();
|
||||
for (const ValueFlow::Value& value : values)
|
||||
valueFlowContainerForward(var->nameToken()->next(), var, value, tokenlist);
|
||||
}
|
||||
|
||||
|
@ -6007,6 +6030,13 @@ static void valueFlowContainerSize(TokenList *tokenlist, SymbolDatabase* symbold
|
|||
value.setKnown();
|
||||
valueFlowContainerForward(containerTok->next(), containerTok->variable(), value, tokenlist);
|
||||
}
|
||||
} else if (Token::Match(tok, "%name%|;|{|}|> %var% = {") && Token::simpleMatch(tok->linkAt(3), "} ;")) {
|
||||
const Token* containerTok = tok->next();
|
||||
if (astIsContainer(containerTok)) {
|
||||
std::vector<ValueFlow::Value> values = getInitListSize(tok->tokAt(3));
|
||||
for (const ValueFlow::Value& value : values)
|
||||
valueFlowContainerForward(containerTok->next(), containerTok->variable(), value, tokenlist);
|
||||
}
|
||||
} else if (Token::Match(tok, "%var% . %name% (") && tok->valueType() && tok->valueType()->container) {
|
||||
Library::Container::Action action = tok->valueType()->container->getAction(tok->strAt(2));
|
||||
if (action == Library::Container::Action::CLEAR) {
|
||||
|
|
|
@ -4703,6 +4703,42 @@ private:
|
|||
" }\n"
|
||||
"}\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::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::CONTAINER_SIZE), 1));
|
||||
|
||||
code = "void f() {\n"
|
||||
" std::vector<int> ints{1};\n"
|
||||
" std::vector<int> ints2{ints.begin(), ints.end()};\n"
|
||||
" ints2.front();\n"
|
||||
"}";
|
||||
ASSERT_EQUALS(
|
||||
"", isKnownContainerSizeValue(tokenValues(code, "ints2 . front", ValueFlow::Value::CONTAINER_SIZE), 1));
|
||||
|
||||
code = "void f() {\n"
|
||||
" std::vector<int> ints = {};\n"
|
||||
" ints.front();\n"
|
||||
"}";
|
||||
ASSERT_EQUALS("",
|
||||
isKnownContainerSizeValue(tokenValues(code, "ints . front", ValueFlow::Value::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::CONTAINER_SIZE), 1));
|
||||
}
|
||||
|
||||
void valueFlowDynamicBufferSize() {
|
||||
|
|
Loading…
Reference in New Issue