From ec89c57a902eb5359e1ee7d49a2aae2e7c53b846 Mon Sep 17 00:00:00 2001 From: Paul Fultz II Date: Tue, 25 Aug 2020 00:12:41 -0500 Subject: [PATCH] Fix issue 9849: false positive: containerOutOfBounds (#2753) --- lib/valueflow.cpp | 25 ++++++++++++++++--- test/testvalueflow.cpp | 55 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 3 deletions(-) diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index e1dd3520f..bc08d01ad 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -4158,6 +4158,17 @@ static void insertImpossible(std::list& values, const std::lis std::transform(input.begin(), input.end(), std::back_inserter(values), &asImpossible); } +static void insertNegateKnown(std::list& values, const std::list& input) +{ + for(ValueFlow::Value value:input) { + if (!value.isIntValue() && !value.isContainerSizeValue()) + continue; + value.intvalue = !value.intvalue; + value.setKnown(); + values.push_back(value); + } +} + static std::vector getExprVariables(const Token* expr, const TokenList* tokenlist, const SymbolDatabase* symboldatabase, @@ -4177,8 +4188,9 @@ struct ValueFlowConditionHandler { const Token *vartok; std::list true_values; std::list false_values; + bool inverted = false; - Condition() : vartok(nullptr), true_values(), false_values() {} + Condition() : vartok(nullptr), true_values(), false_values(), inverted(false) {} }; std::function& values, bool constValue)> forward; @@ -4278,17 +4290,23 @@ struct ValueFlowConditionHandler { std::list thenValues; std::list elseValues; - if (!Token::Match(tok, "!=|=") && tok != cond.vartok) { + if (!Token::Match(tok, "!=|=|(|.") && tok != cond.vartok) { thenValues.insert(thenValues.end(), cond.true_values.begin(), cond.true_values.end()); if (isConditionKnown(tok, false)) insertImpossible(elseValues, cond.false_values); } if (!Token::Match(tok, "==|!")) { elseValues.insert(elseValues.end(), cond.false_values.begin(), cond.false_values.end()); - if (isConditionKnown(tok, true)) + if (isConditionKnown(tok, true)) { insertImpossible(thenValues, cond.true_values); + if (Token::Match(tok, "(|.|%var%") && astIsBool(tok)) + insertNegateKnown(thenValues, cond.true_values); + } } + if (cond.inverted) + std::swap(thenValues, elseValues); + // start token of conditional code Token* startTokens[] = {nullptr, nullptr}; @@ -6020,6 +6038,7 @@ static void valueFlowContainerAfterCondition(TokenList *tokenlist, cond.true_values.emplace_back(value); cond.false_values.emplace_back(std::move(value)); cond.vartok = vartok; + cond.inverted = true; return cond; } // String compare diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index f6f6c59d3..0bd7f70d0 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -2479,6 +2479,39 @@ private: ASSERT_EQUALS(false, testValueOfX(code, 4U, 123)); ASSERT_EQUALS(false, testValueOfX(code, 4U, 124)); ASSERT_EQUALS(false, testValueOfX(code, 4U, 125)); + + code = "struct A {\n" + " bool g() const;\n" + "};\n" + "void f(A a) {\n" + " if (a.g()) {\n" + " bool x = a.g();\n" + " bool a = x;\n" + " }\n" + "}\n"; + ASSERT_EQUALS(false, testValueOfXKnown(code, 7U, 0)); + + code = "struct A {\n" + " bool g() const;\n" + "};\n" + "void f(A a) {\n" + " if (a.g()) {\n" + " bool x = !a.g();\n" + " bool a = x;\n" + " }\n" + "}\n"; + ASSERT_EQUALS(true, testValueOfXKnown(code, 7U, 0)); + + code = "struct A {\n" + " bool g() const;\n" + "};\n" + "void f(A a) {\n" + " if (!a.g()) {\n" + " bool x = a.g();\n" + " bool a = x;\n" + " }\n" + "}\n"; + ASSERT_EQUALS(true, testValueOfXKnown(code, 7U, 0)); } void valueFlowAfterConditionSeveralNot() { @@ -4111,6 +4144,28 @@ private: "}"; ASSERT(tokenValues(code, "params [ 2 ]").empty()); + // valueFlowAfterCondition + code = "void f(const std::vector& v) {\n" + " if(v.empty()) {\n" + " v.front();\n" + " }\n" + "}\n"; + ASSERT_EQUALS("", isKnownContainerSizeValue(tokenValues(code, "v . front"), 0)); + + code = "void f(const std::vector& v) {\n" + " if(!v.empty()) {\n" + " v.front();\n" + " }\n" + "}\n"; + ASSERT_EQUALS("", isImpossibleContainerSizeValue(tokenValues(code, "v . front"), 0)); + + code = "void f(const std::vector& v) {\n" + " if(!v.empty() && v[0] != \"\") {\n" + " v.front();\n" + " }\n" + "}\n"; + ASSERT_EQUALS("", isImpossibleContainerSizeValue(tokenValues(code, "v . front"), 0)); + // valueFlowContainerForward code = "void f(const std::list &ints) {\n" " if (ints.empty()) {}\n"