Fix issue 8869: false negative: (error) Invalid v.at() argument nr 1

This commit is contained in:
Paul 2020-09-06 23:46:31 -05:00
parent 136ac2c643
commit 04c85baf03
2 changed files with 40 additions and 3 deletions

View File

@ -59,6 +59,11 @@ static const struct CWE CWE825(825U); // Expired Pointer Dereference
static const struct CWE CWE833(833U); // Deadlock static const struct CWE CWE833(833U); // Deadlock
static const struct CWE CWE834(834U); // Excessive Iteration static const struct CWE CWE834(834U); // Excessive Iteration
static bool isElementAccessYield(const Library::Container::Yield& yield)
{
return yield == Library::Container::Yield::ITEM || yield == Library::Container::Yield::AT_INDEX;
}
void CheckStl::outOfBounds() void CheckStl::outOfBounds()
{ {
for (const Scope *function : mTokenizer->getSymbolDatabase()->functionScopes) { for (const Scope *function : mTokenizer->getSymbolDatabase()->functionScopes) {
@ -76,9 +81,27 @@ void CheckStl::outOfBounds()
continue; continue;
if (!value.errorSeverity() && !mSettings->isEnabled(Settings::WARNING)) if (!value.errorSeverity() && !mSettings->isEnabled(Settings::WARNING))
continue; continue;
if (value.intvalue == 0 && Token::Match(parent, ". %name% (") && container->getYield(parent->strAt(1)) == Library::Container::Yield::ITEM) { if (Token::Match(parent, ". %name% (") && isElementAccessYield(container->getYield(parent->strAt(1)))) {
outOfBoundsError(parent->tokAt(2), tok->expressionString(), &value, parent->strAt(1), nullptr); if (value.intvalue == 0) {
continue; outOfBoundsError(parent->tokAt(2), tok->expressionString(), &value, parent->strAt(1), nullptr);
continue;
}
const Token* indexTok = parent->tokAt(2)->astOperand2();
if (!indexTok)
continue;
const ValueFlow::Value *indexValue = indexTok ? indexTok->getMaxValue(false) : nullptr;
if (indexValue && indexValue->intvalue >= value.intvalue) {
outOfBoundsError(parent, tok->expressionString(), &value, indexTok->expressionString(), indexValue);
continue;
}
if (mSettings->isEnabled(Settings::WARNING)) {
indexValue = indexTok ? indexTok->getMaxValue(true) : nullptr;
if (indexValue && indexValue->intvalue >= value.intvalue) {
outOfBoundsError(parent, tok->expressionString(), &value, indexTok->expressionString(), indexValue);
continue;
}
}
} }
if (Token::Match(tok, "%name% . %name% (") && container->getYield(tok->strAt(2)) == Library::Container::Yield::START_ITERATOR) { if (Token::Match(tok, "%name% . %name% (") && container->getYield(tok->strAt(2)) == Library::Container::Yield::START_ITERATOR) {
const Token *fparent = tok->tokAt(3)->astParent(); const Token *fparent = tok->tokAt(3)->astParent();

View File

@ -347,6 +347,20 @@ private:
" x[0] = 2;\n" " x[0] = 2;\n"
"}\n"); "}\n");
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
checkNormal("void f(bool b) {\n"
" std::vector<int> v;\n"
" if(v.at(b?42:0)) {}\n"
"}\n");
ASSERT_EQUALS("test.cpp:3:error:Out of bounds access in expression 'v.at(b?42:0)' because 'v' is empty and 'at' may be non-zero.\n", errout.str());
checkNormal("void f(std::vector<int> v, bool b){\n"
" if (v.size() == 1)\n"
" if(v.at(b?42:0)) {}\n"
"}\n");
ASSERT_EQUALS("test.cpp:3:warning:Either the condition 'v.size()==1' is redundant or v size can be 1. Expression 'v.at' cause access out of bounds.\n"
"test.cpp:2:note:condition 'v.size()==1'\n"
"test.cpp:3:note:Access out of bounds\n", errout.str());
} }
void outOfBoundsIndexExpression() { void outOfBoundsIndexExpression() {