From 9a290c959fe2e5ec235f59ac08ef478d1fa4ce6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sat, 17 Jun 2023 10:20:20 +0200 Subject: [PATCH] Fix #11776 (False positive: uninitialized variable, struct array member initialized in function) (#5165) --- lib/astutils.cpp | 4 ++++ lib/checkuninitvar.cpp | 4 +++- test/cfg/posix.c | 2 +- test/testuninitvar.cpp | 46 +++++++++++++++++++++++++++++++++++++----- 4 files changed, 49 insertions(+), 7 deletions(-) diff --git a/lib/astutils.cpp b/lib/astutils.cpp index c4ac0b967..379f4c032 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -3105,6 +3105,10 @@ static ExprUsage getFunctionUsage(const Token* tok, int indirect, const Settings } if (!args.empty() && indirect == 0 && !addressOf) return ExprUsage::Used; + } else if (ftok->isControlFlowKeyword()) { + return ExprUsage::Used; + } else if (ftok->str() == "{") { + return ExprUsage::Used; } else { const bool isnullbad = settings->library.isnullargbad(ftok, argnr + 1); if (indirect == 0 && astIsPointer(tok) && !addressOf && isnullbad) diff --git a/lib/checkuninitvar.cpp b/lib/checkuninitvar.cpp index e4e348fbf..6ffb0e4a8 100644 --- a/lib/checkuninitvar.cpp +++ b/lib/checkuninitvar.cpp @@ -1621,6 +1621,8 @@ void CheckUninitVar::valueFlowUninit() if (tok->variable()) { bool unknown; const bool isarray = tok->variable()->isArray(); + if (isarray && tok->variable()->isMember()) + continue; // Todo: this is a bailout const bool ispointer = astIsPointer(tok) && !isarray; const bool deref = CheckNullPointer::isPointerDeRef(tok, unknown, mSettings); if (ispointer && v->indirect == 1 && !deref) @@ -1633,7 +1635,7 @@ void CheckUninitVar::valueFlowUninit() continue; } const ExprUsage usage = getExprUsage(tok, v->indirect, mSettings); - if (usage == ExprUsage::NotUsed) + if (usage == ExprUsage::NotUsed || usage == ExprUsage::Inconclusive) continue; if (!v->subexpressions.empty() && usage == ExprUsage::PassedByReference) continue; diff --git a/test/cfg/posix.c b/test/cfg/posix.c index fc20159e2..3da495953 100644 --- a/test/cfg/posix.c +++ b/test/cfg/posix.c @@ -1261,7 +1261,7 @@ void timet_h(struct timespec* ptp1) clock_settime(clk_id2, ptp1); struct timespec tp; - // cppcheck-suppress uninitvar + // FIXME cppcheck-suppress uninitvar clock_settime(CLOCK_REALTIME, &tp); // #6577 - false negative // cppcheck-suppress uninitvar clock_settime(clk_id3, &tp); diff --git a/test/testuninitvar.cpp b/test/testuninitvar.cpp index 49f77695c..995a1c81c 100644 --- a/test/testuninitvar.cpp +++ b/test/testuninitvar.cpp @@ -5268,7 +5268,7 @@ private: " s.x = 42;\n" " bar(&s);\n" "}"); - ASSERT_EQUALS("[test.cpp:18]: (error) Uninitialized variable: &s.flag\n", errout.str()); + ASSERT_EQUALS("[test.cpp:18] -> [test.cpp:12] -> [test.cpp:8]: (warning) Uninitialized variable: s->flag\n", errout.str()); // Ticket #2207 - False negative valueFlowUninit("void foo() {\n" @@ -6136,7 +6136,7 @@ private: " someType_t gVar;\n" " bar(&gVar);\n" "}"); - ASSERT_EQUALS("[test.cpp:9]: (error) Uninitialized variable: &gVar\n", errout.str()); + ASSERT_EQUALS("[test.cpp:9] -> [test.cpp:5]: (warning) Uninitialized variable: p->flags\n", errout.str()); valueFlowUninit("typedef struct\n" "{\n" @@ -6146,7 +6146,8 @@ private: " someType_t gVar;\n" " if(gVar.flags[1] == 42){}\n" "}"); - ASSERT_EQUALS("[test.cpp:7]: (error) Uninitialized variable: gVar.flags\n", errout.str()); + // TODO : find bugs for member arrays + TODO_ASSERT_EQUALS("[test.cpp:7]: (error) Uninitialized variable: gVar.flags\n", "", errout.str()); valueFlowUninit("void foo() {\n" // #10293 " union {\n" @@ -6667,7 +6668,7 @@ private: " foo(123, &abc);\n" " return abc.b;\n" "}"); - ASSERT_EQUALS("[test.cpp:5]: (error) Uninitialized variable: &abc\n", errout.str()); + ASSERT_EQUALS("[test.cpp:6]: (error) Uninitialized variable: abc.b\n", errout.str()); valueFlowUninit("struct ABC { int a; int b; int c; };\n" "void foo() {\n" @@ -6899,7 +6900,7 @@ private: " abc.a = 1;\n" " setabc(123, &abc);\n" "}\n"); - ASSERT_EQUALS("[test.cpp:8]: (error) Uninitialized variables: &abc.b, &abc.c\n", errout.str()); + ASSERT_EQUALS("[test.cpp:8] -> [test.cpp:3]: (warning) Uninitialized variable: abc->b\n", errout.str()); valueFlowUninit("struct S { int* p; };\n" // #10463 "void f(S* in) {\n" @@ -6942,6 +6943,41 @@ private: " if (f < s.offset + sizeof(s)) {}\n" "}\n"); ASSERT_EQUALS("", errout.str()); + + // #11776 - function call initialises struct array member + valueFlowUninit("typedef struct {\n" + " int arr[1];\n" + " int count;\n" + "} arr_struct;\n" + "\n" + "void init(int *a, int b);\n" + "\n" + "void foo(arr_struct const *var);\n" // <- inconclusive if var->count is used + "\n" + "void uninitvar_FP7() {\n" + " arr_struct my_st;\n" + " init(my_st.arr, 12);\n" // <- assume that my_st.arr is written + " foo(&my_st);\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + + valueFlowUninit("typedef struct {\n" + " int arr[1];\n" + " int count;\n" + "} arr_struct;\n" + "\n" + "void init(int *a, int b);\n" + "\n" + "void foo(arr_struct const *var) {\n" + " x = var->arr[0];\n" + "}\n" + "\n" + "void uninitvar_FP7() {\n" + " arr_struct my_st;\n" + " init(my_st.arr, 12);\n" // <- assume that my_st.arr is written + " foo(&my_st);\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); } void uninitvar_memberfunction() {