diff --git a/lib/checkuninitvar.cpp b/lib/checkuninitvar.cpp index 3b889e0e2..91fb60771 100644 --- a/lib/checkuninitvar.cpp +++ b/lib/checkuninitvar.cpp @@ -1308,6 +1308,11 @@ void CheckUninitVar::valueFlowUninit() continue; if (!isVariableUsage(tok, tok->variable()->isPointer(), tok->variable()->isArray() ? ARRAY : NO_ALLOC)) continue; + if (v->indirect > 1 || v->indirect < 0) + continue; + bool unknown; + if (v->indirect == 1 && !CheckNullPointer::isPointerDeRef(tok, unknown, mSettings)) + continue; if (!Token::Match(tok->astParent(), ". %name% (") && isVariableChanged(tok, mSettings, mTokenizer->isCPP())) continue; uninitvarError(tok, tok->str(), v->errorPath); diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 6ee2cdc3b..d107c3958 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -456,10 +456,18 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value, const Setti } if (value.isUninitValue()) { - if (parent->isUnaryOp("&")) - setTokenValue(parent, value, settings); - else if (Token::Match(parent, ". %var%") && parent->astOperand1() == tok) - setTokenValue(parent->astOperand2(), value, settings); + ValueFlow::Value pvalue = value; + if (parent->isUnaryOp("&")) { + pvalue.indirect++; + setTokenValue(parent, pvalue, settings); + } else if (Token::Match(parent, ". %var%") && parent->astOperand1() == tok) { + if (parent->originalName() == "->") + pvalue.indirect--; + setTokenValue(parent->astOperand2(), pvalue, settings); + } else if (parent->isUnaryOp("*") && pvalue.indirect > 0) { + pvalue.indirect--; + setTokenValue(parent, pvalue, settings); + } return; } @@ -5713,6 +5721,7 @@ ValueFlow::Value::Value(const Token *c, long long val) safe(false), conditional(false), defaultArg(false), + indirect(0), lifetimeKind(LifetimeKind::Object), lifetimeScope(LifetimeScope::Local), valueKind(ValueKind::Possible) diff --git a/lib/valueflow.h b/lib/valueflow.h index 87a93f3f0..7ebb03663 100644 --- a/lib/valueflow.h +++ b/lib/valueflow.h @@ -53,6 +53,7 @@ namespace ValueFlow { safe(false), conditional(false), defaultArg(false), + indirect(0), lifetimeKind(LifetimeKind::Object), lifetimeScope(LifetimeScope::Local), valueKind(ValueKind::Possible) @@ -100,6 +101,7 @@ namespace ValueFlow { varId == rhs.varId && conditional == rhs.conditional && defaultArg == rhs.defaultArg && + indirect == rhs.indirect && valueKind == rhs.valueKind; } @@ -175,6 +177,8 @@ namespace ValueFlow { /** Is this value passed as default parameter to the function? */ bool defaultArg; + int indirect; + enum class LifetimeKind {Object, Lambda, Iterator, Address} lifetimeKind; enum class LifetimeScope { Local, Argument } lifetimeScope; diff --git a/test/testcondition.cpp b/test/testcondition.cpp index 87d1f8e35..19b5bcd60 100644 --- a/test/testcondition.cpp +++ b/test/testcondition.cpp @@ -3197,7 +3197,7 @@ private: " }\n" "}\n"); ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:5]: (style) Condition 'array' is always true\n", errout.str()); - + check("void f(int *array, int size ) {\n" " for(int i = 0; i < size; ++i) {\n" " if(array == 0)\n" @@ -3206,7 +3206,7 @@ private: " }\n" "}\n"); ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:5]: (style) Condition 'array' is always true\n", errout.str()); - + // #9277 check("int f() {\n" " constexpr bool x = true;\n" diff --git a/test/testuninitvar.cpp b/test/testuninitvar.cpp index 175b1df06..59d87372a 100644 --- a/test/testuninitvar.cpp +++ b/test/testuninitvar.cpp @@ -4013,6 +4013,24 @@ private: "}\n"); ASSERT_EQUALS("", errout.str()); + valueFlowUninit("void f(bool * x) {\n" + " if (x != nullptr)\n" + " x = 1;\n" + "}\n" + "void g() {\n" + " bool x;\n" + " f(&x);\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + + valueFlowUninit("void f() {\n" + " bool b;\n" + " bool * x = &b;\n" + " if (x != nullptr)\n" + " x = 1;\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + valueFlowUninit("struct A { bool b; };" "void f(A * x) {\n" " x->b = false;\n"