Skip to content

Commit c9569af

Browse files
committed
Fix #8983 FN containerOutOfBounds (passing empty init list)
1 parent 514dc56 commit c9569af

2 files changed

Lines changed: 59 additions & 11 deletions

File tree

lib/valueflow.cpp

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6884,11 +6884,33 @@ static void valueFlowContainerSize(const TokenList& tokenlist,
68846884
}
68856885
for (const ValueFlow::Value& value : values)
68866886
setTokenValue(tok, value, settings);
6887-
} else if (Token::Match(tok, ";|{|} %var% =") && Token::Match(tok->tokAt(2)->astOperand2(), "[({]") &&
6888-
// init list
6889-
((tok->tokAt(2) == tok->tokAt(2)->astOperand2()->astParent() && !tok->tokAt(2)->astOperand2()->astOperand2() && tok->tokAt(2)->astOperand2()->str() == "{") ||
6890-
// constructor
6891-
(!Token::simpleMatch(tok->tokAt(2)->astOperand2()->astOperand1(), ".") && settings.library.detectContainer(tok->tokAt(3))))) {
6887+
}
6888+
else if (Token::Match(tok->previous(), ",|( {")) {
6889+
int nArg{};
6890+
if (const Token* funcTok = getTokenArgumentFunction(tok, nArg)) {
6891+
if (const Function* func = funcTok->function()) {
6892+
if (const Variable* var = func->getArgumentVar(nArg)) {
6893+
if (var->valueType() && var->valueType()->container && var->valueType()->container->size_templateArgNo < 0) {
6894+
std::vector<ValueFlow::Value> values = getInitListSize(tok, var->valueType(), settings, true);
6895+
ValueFlow::Value value;
6896+
value.valueType = ValueFlow::Value::ValueType::TOK;
6897+
value.tokvalue = tok;
6898+
value.setKnown();
6899+
values.push_back(std::move(value));
6900+
6901+
for (const ValueFlow::Value &value : values)
6902+
setTokenValue(tok, value, settings);
6903+
}
6904+
}
6905+
}
6906+
}
6907+
}
6908+
else if (Token::Match(tok, ";|{|} %var% =") && Token::Match(tok->tokAt(2)->astOperand2(), "[({]") &&
6909+
// init list
6910+
((tok->tokAt(2) == tok->tokAt(2)->astOperand2()->astParent() && !tok->tokAt(2)->astOperand2()->astOperand2() && tok->tokAt(2)->astOperand2()->str() == "{") ||
6911+
// constructor
6912+
(!Token::simpleMatch(tok->tokAt(2)->astOperand2()->astOperand1(), ".") && settings.library.detectContainer(tok->tokAt(3)))))
6913+
{
68926914
Token* containerTok = tok->next();
68936915
if (containerTok->exprId() == 0)
68946916
continue;
@@ -6899,8 +6921,10 @@ static void valueFlowContainerSize(const TokenList& tokenlist,
68996921
for (const ValueFlow::Value& value : values)
69006922
valueFlowForward(containerTok->next(), containerTok, value, tokenlist, errorLogger, settings);
69016923
}
6902-
} else if (Token::Match(tok, ". %name% (") && tok->astOperand1() && tok->astOperand1()->valueType() &&
6903-
tok->astOperand1()->valueType()->container) {
6924+
}
6925+
else if (Token::Match(tok, ". %name% (") && tok->astOperand1() && tok->astOperand1()->valueType() &&
6926+
tok->astOperand1()->valueType()->container)
6927+
{
69046928
const Token* containerTok = tok->astOperand1();
69056929
if (containerTok->exprId() == 0)
69066930
continue;
@@ -6925,14 +6949,16 @@ static void valueFlowContainerSize(const TokenList& tokenlist,
69256949
valueFlowForward(tok->linkAt(2), containerTok, std::move(value), tokenlist, errorLogger, settings);
69266950
}
69276951
// TODO: handle more actions?
6928-
6929-
} else if (tok->str() == "+=" && astIsContainer(tok->astOperand1())) {
6952+
}
6953+
else if (tok->str() == "+=" && astIsContainer(tok->astOperand1()))
6954+
{
69306955
const Token* containerTok = tok->astOperand1();
69316956
const Token* valueTok = tok->astOperand2();
69326957
const MathLib::bigint size = ValueFlow::valueFlowGetStrLength(valueTok);
69336958
forwardMinimumContainerSize(size, tok, containerTok);
6934-
6935-
} else if (tok->str() == "=" && Token::simpleMatch(tok->astOperand2(), "+") && astIsContainerString(tok)) {
6959+
}
6960+
else if (tok->str() == "=" && Token::simpleMatch(tok->astOperand2(), "+") && astIsContainerString(tok))
6961+
{
69366962
const Token* tok2 = tok->astOperand2();
69376963
MathLib::bigint size = 0;
69386964
while (Token::simpleMatch(tok2, "+") && tok2->astOperand2()) {

test/teststl.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -945,6 +945,28 @@ class TestStl : public TestFixture {
945945
" (void)v[0];\n"
946946
"}\n");
947947
ASSERT_EQUALS("", errout_str());
948+
949+
checkNormal("int f(const std::vector<int>& v) {\n" // #8983
950+
" return v[2];\n"
951+
"}\n"
952+
"int g() {\n"
953+
" return f({});\n"
954+
"}\n"
955+
"int h() {\n"
956+
" return f({ 1, 2 });\n"
957+
"}\n");
958+
ASSERT_EQUALS("[test.cpp:2:13]: error: Out of bounds access in 'v[2]', if 'v' size is 2 and '2' is 2 [containerOutOfBounds]\n"
959+
"[test.cpp:2:13]: error: Out of bounds access in expression 'v[2]' because 'v' is empty. [containerOutOfBounds]\n",
960+
errout_str());
961+
962+
checkNormal("int f(int x, const std::vector<int>& v) {\n"
963+
" return x + v[0];\n"
964+
"}\n"
965+
"int g() {\n"
966+
" return f(1, {});\n"
967+
"}\n");
968+
ASSERT_EQUALS("[test.cpp:2:17]: error: Out of bounds access in expression 'v[0]' because 'v' is empty. [containerOutOfBounds]\n",
969+
errout_str());
948970
}
949971

950972
void outOfBoundsSymbolic()

0 commit comments

Comments
 (0)