From 8324caf8b9bd12fbd58ea57403689e156343cb48 Mon Sep 17 00:00:00 2001 From: Paul Fultz II Date: Thu, 16 Mar 2023 09:00:27 -0500 Subject: [PATCH] Fix 11557: FP derefInvalidIteratorRedundantCheck in and/or condition (#4892) --- lib/valueflow.cpp | 63 ++++++++++++++++++++++++++++++----------------- test/teststl.cpp | 10 ++++++++ 2 files changed, 50 insertions(+), 23 deletions(-) diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 3bf26415d..36f2bef9f 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -5970,6 +5970,39 @@ struct ConditionHandler { return findPath(true_values) | findPath(false_values); } + Token* getContextAndValues(Token* condTok, + std::list& thenValues, + std::list& elseValues, + bool known = false) const + { + const MathLib::bigint path = getPath(); + const bool allowKnown = path == 0; + const bool allowImpossible = impossible && allowKnown; + + bool inverted2 = inverted; + Token* ctx = skipNotAndCasts(condTok, &inverted2); + bool then = !inverted || !inverted2; + + if (!Token::Match(condTok, "!=|=|(|.") && condTok != vartok) { + thenValues.insert(thenValues.end(), true_values.cbegin(), true_values.cend()); + if (allowImpossible && (known || isConditionKnown(ctx, !then))) + insertImpossible(elseValues, false_values); + } + if (!Token::Match(condTok, "==|!")) { + elseValues.insert(elseValues.end(), false_values.cbegin(), false_values.cend()); + if (allowImpossible && (known || isConditionKnown(ctx, then))) { + insertImpossible(thenValues, true_values); + if (isBool()) + insertNegateKnown(thenValues, true_values); + } + } + + if (inverted2) + std::swap(thenValues, elseValues); + + return ctx; + } + Condition() : vartok(nullptr), true_values(), false_values(), inverted(false), impossible(true) {} }; @@ -6198,31 +6231,11 @@ struct ConditionHandler { const MathLib::bigint path = cond.getPath(); const bool allowKnown = path == 0; - const bool allowImpossible = cond.impossible && allowKnown; std::list thenValues; std::list elseValues; - bool inverted = cond.inverted; - Token* ctx = skipNotAndCasts(condTok, &inverted); - bool then = cond.inverted ? !inverted : true; - - if (!Token::Match(condTok, "!=|=|(|.") && condTok != cond.vartok) { - thenValues.insert(thenValues.end(), cond.true_values.cbegin(), cond.true_values.cend()); - if (allowImpossible && isConditionKnown(ctx, !then)) - insertImpossible(elseValues, cond.false_values); - } - if (!Token::Match(condTok, "==|!")) { - elseValues.insert(elseValues.end(), cond.false_values.cbegin(), cond.false_values.cend()); - if (allowImpossible && isConditionKnown(ctx, then)) { - insertImpossible(thenValues, cond.true_values); - if (cond.isBool()) - insertNegateKnown(thenValues, cond.true_values); - } - } - - if (inverted) - std::swap(thenValues, elseValues); + Token* ctx = cond.getContextAndValues(condTok, thenValues, elseValues); if (Token::Match(ctx->astParent(), "%oror%|&&")) { Token* parent = ctx->astParent(); @@ -6237,12 +6250,16 @@ struct ConditionHandler { if (astIsLHS(parent) && parent->astParent() && parent->astParent()->str() == parent->str()) { nextExprs.push_back(parent->astParent()->astOperand2()); } + std::list andValues; + std::list orValues; + cond.getContextAndValues(condTok, andValues, orValues, true); + const std::string& op(parent->str()); std::list values; if (op == "&&") - values = thenValues; + values = andValues; else if (op == "||") - values = elseValues; + values = orValues; if (allowKnown && (Token::Match(condTok, "==|!=") || cond.isBool())) changePossibleToKnown(values); if (astIsFloat(cond.vartok, false) || diff --git a/test/teststl.cpp b/test/teststl.cpp index 7009e8e44..4c48aa2b6 100644 --- a/test/teststl.cpp +++ b/test/teststl.cpp @@ -4740,6 +4740,16 @@ private: " return debug_valueflow(it)->second;\n" "}\n"); ASSERT_EQUALS("", errout.str()); + + // #11557 + check("bool f(const std::vector& v, std::vector::iterator it, bool b) {\n" + " if (it == v.end())\n" + " return false;\n" + " if (b && ((it + 1) == v.end() || (*(it + 1)) != nullptr))\n" + " return false;\n" + " return true;\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); } void dereferenceInvalidIterator2() {