From 255f273c46074d79a782cd7f2b0a88d69383ec45 Mon Sep 17 00:00:00 2001 From: Paul Fultz II Date: Fri, 9 Apr 2021 00:43:54 -0500 Subject: [PATCH] Fix issue 10088: ValueFlow: Array size, wrong known value (#3204) --- lib/valueflow.cpp | 29 ++++++++++++++++++++++------- test/testvalueflow.cpp | 16 ++++++++++++++++ 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 8d13e8503..570fd9bc1 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -4476,7 +4476,6 @@ struct ConditionHandler { // start token of conditional code Token* startTokens[] = {nullptr, nullptr}; - bool inverted = false; // if astParent is "!" we need to invert codeblock { const Token* tok2 = tok; @@ -4484,10 +4483,8 @@ struct ConditionHandler { const Token* parent = tok2->astParent(); while (parent && parent->str() == "&&") parent = parent->astParent(); - if (parent && (parent->str() == "!" || Token::simpleMatch(parent, "== false"))) { - inverted = true; + if (parent && (parent->str() == "!" || Token::simpleMatch(parent, "== false"))) std::swap(thenValues, elseValues); - } tok2 = parent; } } @@ -4569,8 +4566,25 @@ struct ConditionHandler { std::mem_fn(&ValueFlow::Value::isPossible)); } + if (values.empty()) + return; + if (dead_if || dead_else) { - if (!inverted && Token::Match(tok->astParent(), "&&|&")) { + const Token* parent = tok->astParent(); + // Skip the not operator + while (Token::simpleMatch(parent, "!")) + parent = parent->astParent(); + bool possible = false; + if (Token::Match(parent, "&&|%oror%")) { + std::string op = parent->str(); + while (parent && parent->str() == op) + parent = parent->astParent(); + if (Token::simpleMatch(parent, "!") || Token::simpleMatch(parent, "== false")) + possible = op == "||"; + else + possible = op == "&&"; + } + if (possible) { values.remove_if(std::mem_fn(&ValueFlow::Value::isImpossible)); changeKnownToPossible(values); } else { @@ -4578,8 +4592,9 @@ struct ConditionHandler { valueFlowSetConditionToKnown(tok, values, false); } } - if (!values.empty()) - forward(after, scope->bodyEnd, cond.vartok, values, tokenlist, settings); + if (values.empty()) + return; + forward(after, scope->bodyEnd, cond.vartok, values, tokenlist, settings); } } }); diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index 935be5156..638c24e80 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -5063,6 +5063,22 @@ private: ASSERT_EQUALS("", isKnownContainerSizeValue(tokenValues(code, "a . front", ValueFlow::Value::ValueType::CONTAINER_SIZE), 10)); + code = "int f(const std::vector& x) {\n" + " if (!x.empty() && x[0] == 0)\n" + " return 2;\n" + " return x.front();\n" + "}\n"; + ASSERT_EQUALS("", + isPossibleContainerSizeValue(tokenValues(code, "x . front", ValueFlow::Value::ValueType::CONTAINER_SIZE), 0)); + + code = "int f(const std::vector& x) {\n" + " if (!(x.empty() || x[0] != 0))\n" + " return 2;\n" + " return x.front();\n" + "}\n"; + ASSERT_EQUALS("", + isPossibleContainerSizeValue(tokenValues(code, "x . front", ValueFlow::Value::ValueType::CONTAINER_SIZE), 0)); + code = "void f(std::string str) {\n" " if (str == \"123\") {\n" " bool x = (str == \"\");\n"