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});
```
This commit is contained in:
Anton Lindqvist 2023-05-26 11:59:10 +02:00 committed by GitHub
parent fb850a844b
commit 3d6c453058
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 23 additions and 0 deletions

View File

@ -1123,6 +1123,10 @@ const Token* CheckUninitVar::isVariableUsage(bool cpp, const Token *vartok, cons
// (type &)x // (type &)x
else if (valueExpr->astParent()->isCast() && valueExpr->astParent()->isUnaryOp("(") && Token::simpleMatch(valueExpr->astParent()->link()->previous(), "& )")) else if (valueExpr->astParent()->isCast() && valueExpr->astParent()->isUnaryOp("(") && Token::simpleMatch(valueExpr->astParent()->link()->previous(), "& )"))
valueExpr = valueExpr->astParent(); valueExpr = valueExpr->astParent();
// designated initializers: {.x | { ... , .x
else if (Token::simpleMatch(valueExpr->astParent(), ".") &&
Token::Match(valueExpr->astParent()->previous(), ",|{"))
valueExpr = valueExpr->astParent();
else else
break; break;
} }

View File

@ -94,6 +94,7 @@ private:
TEST_CASE(uninitvar_ipa); TEST_CASE(uninitvar_ipa);
TEST_CASE(uninitvar_memberfunction); TEST_CASE(uninitvar_memberfunction);
TEST_CASE(uninitvar_nonmember); // crash in ycmd test TEST_CASE(uninitvar_nonmember); // crash in ycmd test
TEST_CASE(uninitvarDesignatedInitializers);
TEST_CASE(isVariableUsageDeref); // *p TEST_CASE(isVariableUsageDeref); // *p
TEST_CASE(isVariableUsageDerefValueflow); // *p TEST_CASE(isVariableUsageDerefValueflow); // *p
@ -6955,6 +6956,24 @@ private:
ASSERT_EQUALS("[test.cpp:7]: (error) Uninitialized variable: foo\n", errout.str()); 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() { void isVariableUsageDeref() {
// *p // *p
checkUninitVar("void f() {\n" checkUninitVar("void f() {\n"