From 3d6c453058a850c86d69882f96528d4163d028bc Mon Sep 17 00:00:00 2001 From: Anton Lindqvist Date: Fri, 26 May 2023 11:59:10 +0200 Subject: [PATCH] Fix uninitvar false positive in designed initializers (#5079) Stop interpreting struct fields in designed initializers as usage of local variables which can happen if they share the same name. ``` $ cat test.c struct a { int b; }; int main() { char *b; extern int foo(struct a *); return foo(&(struct a){.b = 0}); } $ cppcheck --quiet test.c test.c:5:27: error: Uninitialized variable: b [legacyUninitvar] return foo(&(struct a){.b = 0}); ``` --- lib/checkuninitvar.cpp | 4 ++++ test/testuninitvar.cpp | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/lib/checkuninitvar.cpp b/lib/checkuninitvar.cpp index 9ef52b334..05c7cc79f 100644 --- a/lib/checkuninitvar.cpp +++ b/lib/checkuninitvar.cpp @@ -1123,6 +1123,10 @@ const Token* CheckUninitVar::isVariableUsage(bool cpp, const Token *vartok, cons // (type &)x else if (valueExpr->astParent()->isCast() && valueExpr->astParent()->isUnaryOp("(") && Token::simpleMatch(valueExpr->astParent()->link()->previous(), "& )")) valueExpr = valueExpr->astParent(); + // designated initializers: {.x | { ... , .x + else if (Token::simpleMatch(valueExpr->astParent(), ".") && + Token::Match(valueExpr->astParent()->previous(), ",|{")) + valueExpr = valueExpr->astParent(); else break; } diff --git a/test/testuninitvar.cpp b/test/testuninitvar.cpp index 032d86f98..bdcaed7cd 100644 --- a/test/testuninitvar.cpp +++ b/test/testuninitvar.cpp @@ -94,6 +94,7 @@ private: TEST_CASE(uninitvar_ipa); TEST_CASE(uninitvar_memberfunction); TEST_CASE(uninitvar_nonmember); // crash in ycmd test + TEST_CASE(uninitvarDesignatedInitializers); TEST_CASE(isVariableUsageDeref); // *p TEST_CASE(isVariableUsageDerefValueflow); // *p @@ -6955,6 +6956,24 @@ private: ASSERT_EQUALS("[test.cpp:7]: (error) Uninitialized variable: foo\n", errout.str()); } + void uninitvarDesignatedInitializers() { + checkUninitVar("struct a { int b; };\n" + "int main() {\n" + " char *b;\n" + " extern int f(struct a *);\n" + " return f(&(struct a){.b = 0});\n" + "}"); + ASSERT_EQUALS("", errout.str()); + + checkUninitVar("struct a { int b, c; };\n" + "int main() {\n" + " char *c;\n" + " extern int f(struct a *);\n" + " return f(&(struct a){.b = 0, .c = 0});\n" + "}"); + ASSERT_EQUALS("", errout.str()); + } + void isVariableUsageDeref() { // *p checkUninitVar("void f() {\n"