diff --git a/lib/checkuninitvar.cpp b/lib/checkuninitvar.cpp index 56ec2e86d..88645b392 100644 --- a/lib/checkuninitvar.cpp +++ b/lib/checkuninitvar.cpp @@ -1492,6 +1492,22 @@ void CheckUninitVar::uninitStructMemberError(const Token *tok, const std::string "$symbol:" + membername + "\nUninitialized struct member: $symbol", CWE_USE_OF_UNINITIALIZED_VARIABLE, Certainty::normal); } +static bool isUsedByFunction(const Token* tok, int indirect, const Settings* settings) +{ + const bool addressOf = tok->astParent() && tok->astParent()->isUnaryOp("&"); + + int argnr; + const Token* ftok = getTokenArgumentFunction(tok, argnr); + if (!ftok) + return false; + const bool isnullbad = settings->library.isnullargbad(ftok, argnr + 1); + if (indirect == 0 && astIsPointer(tok) && !addressOf && isnullbad) + return true; + bool hasIndirect = false; + const bool isuninitbad = settings->library.isuninitargbad(ftok, argnr + 1, indirect, &hasIndirect); + return isuninitbad && (!addressOf || isnullbad); +} + static bool isLeafDot(const Token* tok) { if (!tok) @@ -1557,12 +1573,14 @@ void CheckUninitVar::valueFlowUninit() if (Token::Match(tok->astParent(), ". %var%") && !isleaf) continue; } - if (!(Token::Match(tok->astParent(), ". %name% (") && uninitderef) && - isVariableChanged(tok, v->indirect, mSettings, mTokenizer->isCPP())) - continue; - bool inconclusive = false; - if (isVariableChangedByFunctionCall(tok, v->indirect, mSettings, &inconclusive) || inconclusive) - continue; + if (!isUsedByFunction(tok, v->indirect, mSettings)) { + if (!(Token::Match(tok->astParent(), ". %name% (") && uninitderef) && + isVariableChanged(tok, v->indirect, mSettings, mTokenizer->isCPP())) + continue; + bool inconclusive = false; + if (isVariableChangedByFunctionCall(tok, v->indirect, mSettings, &inconclusive) || inconclusive) + continue; + } uninitvarError(tok, tok->expressionString(), v->errorPath); ids.insert(tok->exprId()); if (v->tokvalue) diff --git a/test/testuninitvar.cpp b/test/testuninitvar.cpp index 4c1b1e4a2..d4d54424f 100644 --- a/test/testuninitvar.cpp +++ b/test/testuninitvar.cpp @@ -4400,6 +4400,47 @@ private: void valueFlowUninit() { + // Ticket #2207 - False negative + valueFlowUninit("void foo() {\n" + " int a;\n" + " b = c - a;\n" + "}"); + ASSERT_EQUALS("[test.cpp:3]: (error) Uninitialized variable: a\n", errout.str()); + + valueFlowUninit("void foo() {\n" + " int a;\n" + " b = a - c;\n" + "}"); + ASSERT_EQUALS("[test.cpp:3]: (error) Uninitialized variable: a\n", errout.str()); + + // Ticket #6455 - some compilers allow const variables to be uninitialized + // extracttests.disable + valueFlowUninit("void foo() {\n" + " const int a;\n" + " b = c - a;\n" + "}"); + ASSERT_EQUALS("[test.cpp:3]: (error) Uninitialized variable: a\n", errout.str()); + // extracttests.enable + + valueFlowUninit("void foo() {\n" + " int *p;\n" + " realloc(p,10);\n" + "}"); + ASSERT_EQUALS("[test.cpp:3]: (error) Uninitialized variable: p\n", errout.str()); + + valueFlowUninit("void foo() {\n" // #5240 + " char *p = malloc(100);\n" + " char *tmp = realloc(p,1000);\n" + " if (!tmp) free(p);\n" + "}"); + ASSERT_EQUALS("", errout.str()); + + valueFlowUninit("void foo() {\n" + " int *p = NULL;\n" + " realloc(p,10);\n" + "}"); + ASSERT_EQUALS("", errout.str()); + valueFlowUninit("void f() {\n" " int x;\n" " switch (x) {}\n"