From d4eaea8e96cdff19892a8339ab41be419c1268e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Mon, 11 Mar 2024 20:34:56 +0100 Subject: [PATCH] Fix #12462 (False positive: uninitialized data passed by const address, not used in subfunction) --- lib/astutils.cpp | 21 +++++++++++++++------ test/testuninitvar.cpp | 31 +++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 6 deletions(-) diff --git a/lib/astutils.cpp b/lib/astutils.cpp index 1e75552ec4d..d71444c61e9 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -3271,7 +3271,7 @@ bool isConstVarExpression(const Token *tok, const std::functionastParent() && tok->astParent()->isUnaryOp("&"); @@ -3284,10 +3284,19 @@ static ExprUsage getFunctionUsage(const Token* tok, int indirect, const Settings for (const Variable* arg : args) { if (!arg) continue; - if (arg->isReference()) - return ExprUsage::PassedByReference; - if (arg->isPointer() && indirect == 1) - return ExprUsage::PassedByReference; + if (arg->isReference() || (arg->isPointer() && indirect == 1)) { + if (!ftok->function()->hasBody()) + return ExprUsage::PassedByReference; + for (const Token* bodytok = ftok->function()->functionScope->bodyStart; bodytok != ftok->function()->functionScope->bodyEnd; bodytok = bodytok->next()) { + if (bodytok->variable() == arg) { + if (arg->isReference()) + return ExprUsage::PassedByReference; + if (Token::Match(bodytok->astParent(), "%comp%|!")) + return ExprUsage::NotUsed; + return ExprUsage::PassedByReference; + } + } + } } if (!args.empty() && indirect == 0 && !addressOf) return ExprUsage::Used; @@ -3369,7 +3378,7 @@ ExprUsage getExprUsage(const Token* tok, int indirect, const Settings* settings, (astIsLHS(tok) || Token::simpleMatch(parent, "( )"))) return ExprUsage::Used; } - return getFunctionUsage(tok, indirect, settings); + return getFunctionUsage(tok, indirect, settings, cpp); } static void getLHSVariablesRecursive(std::vector& vars, const Token* tok) diff --git a/test/testuninitvar.cpp b/test/testuninitvar.cpp index 845810084c7..6389d73431a 100644 --- a/test/testuninitvar.cpp +++ b/test/testuninitvar.cpp @@ -64,6 +64,7 @@ class TestUninitVar : public TestFixture { TEST_CASE(uninitvar2_value); // value flow TEST_CASE(valueFlowUninit2_value); TEST_CASE(valueFlowUninit_uninitvar2); + TEST_CASE(valueFlowUninit_functioncall); TEST_CASE(uninitStructMember); // struct members TEST_CASE(uninitvar2_while); TEST_CASE(uninitvar2_4494); // #4494 @@ -4319,6 +4320,36 @@ class TestUninitVar : public TestFixture { ASSERT_EQUALS("", errout.str()); } + void valueFlowUninit_functioncall() { + + // #12462 - pointer data is not read + valueFlowUninit("struct myst { int a; };\n" + "void bar(const void* p) {}\n" + "void foo() {\n" + " struct myst item;\n" + " bar(&item);\n" + "}", "test.c"); + ASSERT_EQUALS("", errout.str()); + + valueFlowUninit("struct myst { int a; };\n" + "void bar(const void* p) { a = (p != 0); }\n" + "void foo() {\n" + " struct myst item;\n" + " bar(&item);\n" + " a = item.a;\n" // <- item.a is not initialized + "}", "test.c"); + ASSERT_EQUALS("[test.c:6]: (error) Uninitialized variable: item.a\n", errout.str()); + + valueFlowUninit("struct myst { int a; };\n" + "void bar(struct myst* p) { p->a = 0; }\n" + "void foo() {\n" + " struct myst item;\n" + " bar(&item);\n" + " a = item.a;\n" + "}", "test.c"); + ASSERT_EQUALS("", errout.str()); + } + void uninitStructMember() { // struct members checkUninitVar("struct AB { int a; int b; };\n" "void f(void) {\n"