* Fix #10779 FN: stlOutOfBounds (off by one) * Format * Simplify
This commit is contained in:
parent
2dd6c75b35
commit
27baa20f38
|
@ -7628,14 +7628,23 @@ static void valueFlowContainerSize(TokenList *tokenlist, SymbolDatabase* symbold
|
||||||
continue;
|
continue;
|
||||||
if (!var->valueType() || !var->valueType()->container)
|
if (!var->valueType() || !var->valueType()->container)
|
||||||
continue;
|
continue;
|
||||||
if (!astIsContainer(var->nameToken()))
|
const Token* const vnt = var->nameToken();
|
||||||
|
if (!astIsContainer(vnt))
|
||||||
continue;
|
continue;
|
||||||
if (var->nameToken()->hasKnownValue(ValueFlow::Value::ValueType::CONTAINER_SIZE))
|
if (vnt->hasKnownValue(ValueFlow::Value::ValueType::CONTAINER_SIZE))
|
||||||
continue;
|
continue;
|
||||||
if (!Token::Match(var->nameToken(), "%name% ;") &&
|
const bool isDecl = Token::Match(vnt, "%name% ;");
|
||||||
!(Token::Match(var->nameToken(), "%name% {") && Token::simpleMatch(var->nameToken()->next()->link(), "} ;")))
|
bool hasInitList = false, hasInitSize = false;
|
||||||
|
if (!isDecl) {
|
||||||
|
hasInitList = Token::Match(vnt, "%name% {") && Token::simpleMatch(vnt->next()->link(), "} ;");
|
||||||
|
if (!hasInitList)
|
||||||
|
hasInitList = Token::Match(vnt, "%name% ( {") && Token::simpleMatch(vnt->linkAt(2), "} ) ;");
|
||||||
|
if (!hasInitList)
|
||||||
|
hasInitSize = Token::Match(vnt, "%name% (|{ %num%|%var% )|}");
|
||||||
|
}
|
||||||
|
if (!isDecl && !hasInitList && !hasInitSize)
|
||||||
continue;
|
continue;
|
||||||
if (var->nameToken()->astTop() && Token::Match(var->nameToken()->astTop()->previous(), "for|while"))
|
if (vnt->astTop() && Token::Match(vnt->astTop()->previous(), "for|while"))
|
||||||
known = !isVariableChanged(var, settings, true);
|
known = !isVariableChanged(var, settings, true);
|
||||||
if (var->valueType()->container->size_templateArgNo >= 0) {
|
if (var->valueType()->container->size_templateArgNo >= 0) {
|
||||||
if (var->dimensions().size() == 1 && var->dimensions().front().known)
|
if (var->dimensions().size() == 1 && var->dimensions().front().known)
|
||||||
|
@ -7646,12 +7655,20 @@ static void valueFlowContainerSize(TokenList *tokenlist, SymbolDatabase* symbold
|
||||||
values.back().valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE;
|
values.back().valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE;
|
||||||
if (known)
|
if (known)
|
||||||
values.back().setKnown();
|
values.back().setKnown();
|
||||||
if (Token::simpleMatch(var->nameToken()->next(), "{")) {
|
if (hasInitList) {
|
||||||
const Token* initList = var->nameToken()->next();
|
const Token* initList = vnt->next();
|
||||||
|
if (Token::simpleMatch(initList, "("))
|
||||||
|
initList = initList->next();
|
||||||
values = getInitListSize(initList, var->valueType()->container, known);
|
values = getInitListSize(initList, var->valueType()->container, known);
|
||||||
}
|
}
|
||||||
|
else if (hasInitSize) {
|
||||||
|
const Token* sizeTok = vnt->next()->astOperand2();
|
||||||
|
if (!sizeTok || !sizeTok->hasKnownIntValue())
|
||||||
|
continue;
|
||||||
|
values.back().intvalue = sizeTok->getKnownIntValue();
|
||||||
|
}
|
||||||
for (const ValueFlow::Value& value : values)
|
for (const ValueFlow::Value& value : values)
|
||||||
valueFlowContainerForward(var->nameToken()->next(), var->nameToken(), value, tokenlist);
|
valueFlowContainerForward(vnt->next(), vnt, value, tokenlist);
|
||||||
}
|
}
|
||||||
|
|
||||||
// after assignment
|
// after assignment
|
||||||
|
|
|
@ -729,6 +729,30 @@ private:
|
||||||
"test.cpp:2:note:condition 'v.empty()'\n"
|
"test.cpp:2:note:condition 'v.empty()'\n"
|
||||||
"test.cpp:2:note:Access out of bounds\n",
|
"test.cpp:2:note:Access out of bounds\n",
|
||||||
errout.str());
|
errout.str());
|
||||||
|
|
||||||
|
check("std::vector<int> g() {\n" // #10779
|
||||||
|
" std::vector<int> v(10);\n"
|
||||||
|
" for(int i = 0; i <= 10; ++i)\n"
|
||||||
|
" v[i] = 42;\n"
|
||||||
|
" return v;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("test.cpp:4:error:Out of bounds access in 'v[i]', if 'v' size is 10 and 'i' is 10\n",
|
||||||
|
errout.str());
|
||||||
|
|
||||||
|
check("void f() {\n"
|
||||||
|
" int s = 2;\n"
|
||||||
|
" std::vector <int> v(s);\n"
|
||||||
|
" v[100] = 1;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("test.cpp:4:error:Out of bounds access in 'v[100]', if 'v' size is 2 and '100' is 100\n",
|
||||||
|
errout.str());
|
||||||
|
|
||||||
|
check("void f() {\n"
|
||||||
|
" std::vector <int> v({ 1, 2, 3 });\n"
|
||||||
|
" v[100] = 1;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("test.cpp:3:error:Out of bounds access in 'v[100]', if 'v' size is 3 and '100' is 100\n",
|
||||||
|
errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void outOfBoundsSymbolic()
|
void outOfBoundsSymbolic()
|
||||||
|
|
|
@ -6026,6 +6026,18 @@ private:
|
||||||
"}\n";
|
"}\n";
|
||||||
ASSERT_EQUALS(
|
ASSERT_EQUALS(
|
||||||
"", isKnownContainerSizeValue(tokenValues(code, "v [", ValueFlow::Value::ValueType::CONTAINER_SIZE), 0));
|
"", isKnownContainerSizeValue(tokenValues(code, "v [", ValueFlow::Value::ValueType::CONTAINER_SIZE), 0));
|
||||||
|
|
||||||
|
code = "void f() {\n"
|
||||||
|
" std::vector<int> v(3);\n"
|
||||||
|
" v.size();\n"
|
||||||
|
"}";
|
||||||
|
ASSERT_EQUALS("", isKnownContainerSizeValue(tokenValues(code, "v . size"), 3));
|
||||||
|
|
||||||
|
code = "void f() {\n"
|
||||||
|
" std::vector<int> v({ 1, 2, 3 });\n"
|
||||||
|
" v.size();\n"
|
||||||
|
"}";
|
||||||
|
ASSERT_EQUALS("", isKnownContainerSizeValue(tokenValues(code, "v . size"), 3));
|
||||||
}
|
}
|
||||||
|
|
||||||
void valueFlowDynamicBufferSize() {
|
void valueFlowDynamicBufferSize() {
|
||||||
|
|
Loading…
Reference in New Issue