* Fix #10779 FN: stlOutOfBounds (off by one) * Format * Simplify * Partial fix for #6615 FN buffer access out of bounds: std::vector * Undo * Format * Fix test case
This commit is contained in:
parent
0b0a8cad39
commit
7f682d544e
|
@ -7634,15 +7634,17 @@ static void valueFlowContainerSize(TokenList *tokenlist, SymbolDatabase* symbold
|
||||||
if (vnt->hasKnownValue(ValueFlow::Value::ValueType::CONTAINER_SIZE))
|
if (vnt->hasKnownValue(ValueFlow::Value::ValueType::CONTAINER_SIZE))
|
||||||
continue;
|
continue;
|
||||||
const bool isDecl = Token::Match(vnt, "%name% ;");
|
const bool isDecl = Token::Match(vnt, "%name% ;");
|
||||||
bool hasInitList = false, hasInitSize = false;
|
bool hasInitList = false, hasInitSize = false, isPointerInit = false;
|
||||||
if (!isDecl) {
|
if (!isDecl) {
|
||||||
hasInitList = Token::Match(vnt, "%name% {") && Token::simpleMatch(vnt->next()->link(), "} ;");
|
hasInitList = Token::Match(vnt, "%name% {") && Token::simpleMatch(vnt->next()->link(), "} ;");
|
||||||
if (!hasInitList)
|
if (!hasInitList)
|
||||||
hasInitList = Token::Match(vnt, "%name% ( {") && Token::simpleMatch(vnt->linkAt(2), "} ) ;");
|
hasInitList = Token::Match(vnt, "%name% ( {") && Token::simpleMatch(vnt->linkAt(2), "} ) ;");
|
||||||
if (!hasInitList)
|
if (!hasInitList)
|
||||||
hasInitSize = Token::Match(vnt, "%name% (|{ %num%|%var% )|}");
|
hasInitSize = Token::Match(vnt, "%name% (|{ %num%|%var% )|}");
|
||||||
|
if (!hasInitList && !hasInitSize)
|
||||||
|
isPointerInit = Token::Match(vnt, "%name% ( %var% ,");
|
||||||
}
|
}
|
||||||
if (!isDecl && !hasInitList && !hasInitSize)
|
if (!isDecl && !hasInitList && !hasInitSize && !isPointerInit)
|
||||||
continue;
|
continue;
|
||||||
if (vnt->astTop() && Token::Match(vnt->astTop()->previous(), "for|while"))
|
if (vnt->astTop() && Token::Match(vnt->astTop()->previous(), "for|while"))
|
||||||
known = !isVariableChanged(var, settings, true);
|
known = !isVariableChanged(var, settings, true);
|
||||||
|
@ -7667,6 +7669,27 @@ static void valueFlowContainerSize(TokenList *tokenlist, SymbolDatabase* symbold
|
||||||
continue;
|
continue;
|
||||||
values.back().intvalue = sizeTok->getKnownIntValue();
|
values.back().intvalue = sizeTok->getKnownIntValue();
|
||||||
}
|
}
|
||||||
|
else if (isPointerInit) { // (ptr, ptr + size)
|
||||||
|
const Token* commaTok = vnt->next()->astOperand2();
|
||||||
|
if (commaTok && commaTok->str() == "," && commaTok->astOperand1() && commaTok->astOperand2() && commaTok->astOperand2()->isArithmeticalOp() && commaTok->astOperand2()->str() == "+") {
|
||||||
|
const Token* varTok1 = commaTok->astOperand1();
|
||||||
|
const Token* plusTok = commaTok->astOperand2();
|
||||||
|
if (varTok1->varId() && plusTok->astOperand1() && plusTok->astOperand2() && varTok1->valueType() && varTok1->valueType()->pointer) {
|
||||||
|
const Token* sizeTok = nullptr;
|
||||||
|
if (varTok1->varId() == plusTok->astOperand1()->varId())
|
||||||
|
sizeTok = plusTok->astOperand2();
|
||||||
|
else if (varTok1->varId() == plusTok->astOperand2()->varId())
|
||||||
|
sizeTok = plusTok->astOperand1();
|
||||||
|
if (!sizeTok || !sizeTok->hasKnownIntValue())
|
||||||
|
continue;
|
||||||
|
values.back().intvalue = sizeTok->getKnownIntValue();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
continue;
|
||||||
|
}
|
||||||
for (const ValueFlow::Value& value : values)
|
for (const ValueFlow::Value& value : values)
|
||||||
valueFlowContainerForward(vnt->next(), vnt, value, tokenlist);
|
valueFlowContainerForward(vnt->next(), vnt, value, tokenlist);
|
||||||
}
|
}
|
||||||
|
|
|
@ -753,6 +753,40 @@ private:
|
||||||
"}\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",
|
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());
|
errout.str());
|
||||||
|
|
||||||
|
check("void f() {\n"
|
||||||
|
" char c[] = { 1, 2, 3 };\n"
|
||||||
|
" std::vector<char> v(c, sizeof(c) + c);\n"
|
||||||
|
" v[100] = 1;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("test.cpp:4:error:Out of bounds access in 'v[100]', if 'v' size is 3 and '100' is 100\n",
|
||||||
|
errout.str());
|
||||||
|
|
||||||
|
check("void f() {\n"
|
||||||
|
" char c[] = { 1, 2, 3 };\n"
|
||||||
|
" std::vector<char> v{ c, c + sizeof(c) };\n"
|
||||||
|
" v[100] = 1;\n"
|
||||||
|
"}\n");
|
||||||
|
TODO_ASSERT_EQUALS("test.cpp:4:error:Out of bounds access in 'v[100]', if 'v' size is 3 and '100' is 100\n",
|
||||||
|
"",
|
||||||
|
errout.str());
|
||||||
|
|
||||||
|
check("void f() {\n"
|
||||||
|
" int i[] = { 1, 2, 3 };\n"
|
||||||
|
" std::vector<int> v(i, i + sizeof(i) / 4);\n"
|
||||||
|
" v[100] = 1;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("test.cpp:4:error:Out of bounds access in 'v[100]', if 'v' size is 3 and '100' is 100\n",
|
||||||
|
errout.str());
|
||||||
|
|
||||||
|
check("void f() {\n" // #6615
|
||||||
|
" int i[] = { 1, 2, 3 };\n"
|
||||||
|
" std::vector<int> v(i, i + sizeof(i) / sizeof(int));\n"
|
||||||
|
" v[100] = 1;\n"
|
||||||
|
"}\n");
|
||||||
|
TODO_ASSERT_EQUALS("test.cpp:4:error:Out of bounds access in 'v[100]', if 'v' size is 3 and '100' is 100\n",
|
||||||
|
"",
|
||||||
|
errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void outOfBoundsSymbolic()
|
void outOfBoundsSymbolic()
|
||||||
|
|
Loading…
Reference in New Issue