From 04c85baf030bdac59d51177faace7f7c71d5d72d Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 6 Sep 2020 23:46:31 -0500 Subject: [PATCH] Fix issue 8869: false negative: (error) Invalid v.at() argument nr 1 --- lib/checkstl.cpp | 29 ++++++++++++++++++++++++++--- test/teststl.cpp | 14 ++++++++++++++ 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/lib/checkstl.cpp b/lib/checkstl.cpp index 9787d203c..2a7339bf9 100644 --- a/lib/checkstl.cpp +++ b/lib/checkstl.cpp @@ -59,6 +59,11 @@ static const struct CWE CWE825(825U); // Expired Pointer Dereference static const struct CWE CWE833(833U); // Deadlock 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() { for (const Scope *function : mTokenizer->getSymbolDatabase()->functionScopes) { @@ -76,9 +81,27 @@ void CheckStl::outOfBounds() continue; if (!value.errorSeverity() && !mSettings->isEnabled(Settings::WARNING)) continue; - if (value.intvalue == 0 && Token::Match(parent, ". %name% (") && container->getYield(parent->strAt(1)) == Library::Container::Yield::ITEM) { - outOfBoundsError(parent->tokAt(2), tok->expressionString(), &value, parent->strAt(1), nullptr); - continue; + if (Token::Match(parent, ". %name% (") && isElementAccessYield(container->getYield(parent->strAt(1)))) { + if (value.intvalue == 0) { + 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) { const Token *fparent = tok->tokAt(3)->astParent(); diff --git a/test/teststl.cpp b/test/teststl.cpp index 4fc0226d1..96ee25a9b 100644 --- a/test/teststl.cpp +++ b/test/teststl.cpp @@ -347,6 +347,20 @@ private: " x[0] = 2;\n" "}\n"); ASSERT_EQUALS("", errout.str()); + + checkNormal("void f(bool b) {\n" + " std::vector 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 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() {