https://github.com/gamesh411 updated https://github.com/llvm/llvm-project/pull/198345
From 7a868ce932ce706d2bd808a24854199f9288f843 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Endre=20F=C3=BCl=C3=B6p?= <[email protected]> Date: Mon, 18 May 2026 15:59:01 +0200 Subject: [PATCH 1/3] [analyzer] Fix misleading 'initialized here' note for uninitialized declarations When a variable is declared without an initializer, the BugReporterVisitor would emit 'initialized here' as a note, which is confusing because the variable was never initialized. Change the note to 'declared without an initial value' for declarations that have no initializer. Global-storage variables are are also taken into consideration. --- .../Core/BugReporterVisitors.cpp | 30 +++++++++---------- .../test/Analysis/cstring-uninitread-notes.c | 2 +- clang/test/Analysis/placement-new.cpp | 22 +++++++------- ...functions-arg-constraints-tracking-notes.c | 4 +-- .../std-c-library-functions-arg-constraints.c | 8 ++--- clang/test/Analysis/uninit-const.c | 10 +++---- clang/test/Analysis/uninit-vals.m | 8 ++--- 7 files changed, 41 insertions(+), 43 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp index 5294a0bedf898..2892c12261515 100644 --- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp +++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp @@ -1281,23 +1281,21 @@ static void showBRDiagnostics(llvm::raw_svector_ostream &OS, StoreInfo SI) { // We don't need to check here, all these conditions were // checked by StoreSiteFinder, when it figured out that it is // initialization. - const auto *DS = - cast<DeclStmt>(SI.StoreSite->getLocationAs<PostStmt>()->getStmt()); - - if (SI.Value.isUndef()) { - if (isa<VarRegion>(SI.Dest)) { - const auto *VD = cast<VarDecl>(DS->getSingleDecl()); - - if (VD->getInit()) { - OS << (HasPrefix ? "initialized" : "Initializing") - << " to a garbage value"; - } else { - OS << (HasPrefix ? "declared" : "Declaring") - << " without an initial value"; - } + const auto *VR = dyn_cast<VarRegion>(SI.Dest); + if (VR) { + const auto *VD = VR->getDecl(); + bool HasInit = VD->getInit(); + bool HasGlobalStorage = VD->hasGlobalStorage(); + + if (SI.Value.isUndef() && HasInit) { + OS << (HasPrefix ? "initialized" : "Initializing") + << " to a garbage value"; + } else if (!HasInit && !HasGlobalStorage) { + OS << (HasPrefix ? "declared" : "Declared") + << " without an initial value"; + } else { + OS << (HasPrefix ? "initialized" : "Initialized") << " here"; } - } else { - OS << (HasPrefix ? "initialized" : "Initialized") << " here"; } } } diff --git a/clang/test/Analysis/cstring-uninitread-notes.c b/clang/test/Analysis/cstring-uninitread-notes.c index b62519a85c8cc..087ab2ba6260a 100644 --- a/clang/test/Analysis/cstring-uninitread-notes.c +++ b/clang/test/Analysis/cstring-uninitread-notes.c @@ -14,7 +14,7 @@ void maybeWrite(const char *src, unsigned size, int *dst) { } // expected-note{{Returning without writing to '*dst'}} void returning_without_writing_to_memcpy(const char *src, unsigned size) { - int block[8 * 8]; // expected-note{{'block' initialized here}} + int block[8 * 8]; // expected-note{{'block' declared without an initial value}} // expected-note@+1{{Calling 'maybeWrite'}} maybeWrite(src, size, block); // expected-note{{Returning from 'maybeWrite'}} diff --git a/clang/test/Analysis/placement-new.cpp b/clang/test/Analysis/placement-new.cpp index 50bbde29cfd59..292ea40b150b8 100644 --- a/clang/test/Analysis/placement-new.cpp +++ b/clang/test/Analysis/placement-new.cpp @@ -38,7 +38,7 @@ void f(void *place) { (void)lp; } void g() { - char buf[2]; // expected-note {{'buf' initialized here}} + char buf[2]; // expected-note {{'buf' declared without an initial value}} f(&buf); // expected-note 2 {{}} } } // namespace testArrayBuffer @@ -78,7 +78,7 @@ void g() { namespace testPtrToArrayAsPlace { void f() { //char *st = new char [8]; - char buf[3]; // expected-note {{'buf' initialized here}} + char buf[3]; // expected-note {{'buf' declared without an initial value}} void *st = buf; // expected-note {{'st' initialized here}} long *lp = ::new (st) long; // expected-warning{{Storage provided to placement new is only 3 bytes, whereas the allocated type requires 8 bytes}} expected-note 1 {{}} (void)lp; @@ -87,7 +87,7 @@ void f() { namespace testPtrToArrayWithOffsetAsPlace { void f() { - int buf[3]; // expected-note {{'buf' initialized here}} + int buf[3]; // expected-note {{'buf' declared without an initial value}} long *lp = ::new (buf + 2) long; // expected-warning{{Storage provided to placement new is only 4 bytes, whereas the allocated type requires 8 bytes}} expected-note 1 {{}} (void)lp; } @@ -95,7 +95,7 @@ void f() { namespace testZeroSize { void f() { - int buf[3]; // expected-note {{'buf' initialized here}} + int buf[3]; // expected-note {{'buf' declared without an initial value}} long *lp = ::new (buf + 3) long; // expected-warning{{Storage provided to placement new is only 0 bytes, whereas the allocated type requires 8 bytes}} expected-note 1 {{}} (void)lp; } @@ -103,7 +103,7 @@ void f() { namespace testNegativeSize { void f() { - int buf[3]; // expected-note {{'buf' initialized here}} + int buf[3]; // expected-note {{'buf' declared without an initial value}} long *lp = ::new (buf + 4) long; // expected-warning{{Storage provided to placement new is only -4 bytes, whereas the allocated type requires 8 bytes}} expected-note 1 {{}} (void)lp; } @@ -123,7 +123,7 @@ void g2() { namespace testMultiDimensionalArray { void f() { - char buf[2][3]; // expected-note {{'buf' initialized here}} + char buf[2][3]; // expected-note {{'buf' declared without an initial value}} long *lp = ::new (buf) long; // expected-warning{{Storage provided to placement new is only 6 bytes, whereas the allocated type requires 8 bytes}} expected-note 1 {{}} (void)lp; } @@ -131,7 +131,7 @@ void f() { namespace testMultiDimensionalArray2 { void f() { - char buf[2][3]; // expected-note {{'buf' initialized here}} + char buf[2][3]; // expected-note {{'buf' declared without an initial value}} long *lp = ::new (buf + 1) long; // expected-warning{{Storage provided to placement new is only 3 bytes, whereas the allocated type requires 8 bytes}} expected-note 1 {{}} (void)lp; } @@ -139,7 +139,7 @@ void f() { namespace testMultiDimensionalArray3 { void f() { - char buf[2][3]; // expected-note {{'buf' initialized here}} + char buf[2][3]; // expected-note {{'buf' declared without an initial value}} long *lp = ::new (&buf[1][1]) long; // expected-warning{{Storage provided to placement new is only 2 bytes, whereas the allocated type requires 8 bytes}} expected-note 1 {{}} (void)lp; } @@ -251,13 +251,13 @@ void f4() { } void f5() { - short b[10]; // expected-note {{'b' initialized here}} + short b[10]; // expected-note {{'b' declared without an initial value}} ::new (&b) long; // expected-warning{{Storage type is aligned to 2 bytes but allocated type is aligned to 8 bytes}} expected-note 1 {{}} } void f6() { - short b[10]; // expected-note {{'b' initialized here}} + short b[10]; // expected-note {{'b' declared without an initial value}} // bad (same as previous but checks ElementRegion case) ::new (&b[0]) long; // expected-warning{{Storage type is aligned to 2 bytes but allocated type is aligned to 8 bytes}} expected-note 1 {{}} @@ -271,7 +271,7 @@ void f7() { } void f8() { - alignas(alignof(long)) short b[10]; // expected-note {{'b' initialized here}} + alignas(alignof(long)) short b[10]; // expected-note {{'b' declared without an initial value}} // ok. aligned to long(ok). offset 3*2(ok) ::new (&b[3]) long; // expected-warning{{Storage type is aligned to 6 bytes but allocated type is aligned to 8 bytes}} expected-note 1 {{}} diff --git a/clang/test/Analysis/std-c-library-functions-arg-constraints-tracking-notes.c b/clang/test/Analysis/std-c-library-functions-arg-constraints-tracking-notes.c index 0a66e49be9b2a..f63cd5d9b48f7 100644 --- a/clang/test/Analysis/std-c-library-functions-arg-constraints-tracking-notes.c +++ b/clang/test/Analysis/std-c-library-functions-arg-constraints-tracking-notes.c @@ -12,7 +12,7 @@ typedef typeof(sizeof(int)) size_t; int __buf_size_arg_constraint(const void *, size_t); void test_buf_size_concrete(void) { - char buf[3]; // bugpath-note{{'buf' initialized here}} + char buf[3]; // bugpath-note{{'buf' declared without an initial value}} int s = 4; // bugpath-note{{'s' initialized to 4}} __buf_size_arg_constraint(buf, s); // \ // bugpath-warning{{The 1st argument to '__buf_size_arg_constraint' is a buffer with size 3 but should be a buffer with size equal to or greater than the value of the 2nd argument}} \ @@ -21,7 +21,7 @@ void test_buf_size_concrete(void) { int __buf_size_arg_constraint_mul(const void *, size_t, size_t); void test_buf_size_concrete_with_multiplication(void) { - short buf[3]; // bugpath-note{{'buf' initialized here}} + short buf[3]; // bugpath-note{{'buf' declared without an initial value}} int s1 = 4; // bugpath-note{{'s1' initialized to 4}} int s2 = sizeof(short); // bugpath-note{{'s2' initialized to}} __buf_size_arg_constraint_mul(buf, s1, s2); // \ diff --git a/clang/test/Analysis/std-c-library-functions-arg-constraints.c b/clang/test/Analysis/std-c-library-functions-arg-constraints.c index 0b817dda98c72..2cefa80341fc4 100644 --- a/clang/test/Analysis/std-c-library-functions-arg-constraints.c +++ b/clang/test/Analysis/std-c-library-functions-arg-constraints.c @@ -237,7 +237,7 @@ void test_no_node_after_bug(FILE *fp, size_t size, size_t n, void *buf) { // This is one test case for the ARR38-C SEI-CERT rule. void ARR38_C_F(FILE *file) { enum { BUFFER_SIZE = 1024 }; - wchar_t wbuf[BUFFER_SIZE]; // bugpath-note{{'wbuf' initialized here}} + wchar_t wbuf[BUFFER_SIZE]; // bugpath-note{{'wbuf' declared without an initial value}} const size_t size = sizeof(*wbuf); // bugpath-note{{'size' initialized to}} const size_t nitems = sizeof(wbuf); // bugpath-note{{'nitems' initialized to}} @@ -287,7 +287,7 @@ void test_arg_constraint_on_variadic_fun(void) { int __buf_size_arg_constraint(const void *, size_t); void test_buf_size_concrete(void) { - char buf[3]; // bugpath-note{{'buf' initialized here}} + char buf[3]; // bugpath-note{{'buf' declared without an initial value}} __buf_size_arg_constraint(buf, 4); // \ // report-warning{{The 1st argument to '__buf_size_arg_constraint' is a buffer with size 3 but should be a buffer with size equal to or greater than the value of the 2nd argument (which is 4)}} \ // bugpath-warning{{The 1st argument to '__buf_size_arg_constraint' is a buffer with size 3 but should be a buffer with size equal to or greater than the value of the 2nd argument (which is 4)}} \ @@ -314,7 +314,7 @@ void test_buf_size_symbolic_and_offset(int s) { int __buf_size_arg_constraint_mul(const void *, size_t, size_t); void test_buf_size_concrete_with_multiplication(void) { - short buf[3]; // bugpath-note{{'buf' initialized here}} + short buf[3]; // bugpath-note{{'buf' declared without an initial value}} __buf_size_arg_constraint_mul(buf, 4, sizeof(short)); // \ // report-warning{{The 1st argument to '__buf_size_arg_constraint_mul' is a buffer with size 6 but should be a buffer with size equal to or greater than the value of the 2nd argument (which is 4) times the 3rd argument (which is 2)}} \ // bugpath-warning{{The 1st argument to '__buf_size_arg_constraint_mul' is a buffer with size 6 but should be a buffer with size equal to or greater than the value of the 2nd argument (which is 4) times the 3rd argument (which is 2)}} \ @@ -340,7 +340,7 @@ void test_buf_size_symbolic_and_offset_with_multiplication(size_t s) { // The minimum buffer size for this function is set to 10. int __buf_size_arg_constraint_concrete(const void *); void test_min_buf_size(void) { - char buf[9];// bugpath-note{{'buf' initialized here}} + char buf[9];// bugpath-note{{'buf' declared without an initial value}} __buf_size_arg_constraint_concrete(buf); // \ // report-warning{{The 1st argument to '__buf_size_arg_constraint_concrete' is a buffer with size 9 but should be a buffer with size equal to or greater than 10}} \ // bugpath-warning{{The 1st argument to '__buf_size_arg_constraint_concrete' is a buffer with size 9 but should be a buffer with size equal to or greater than 10}} \ diff --git a/clang/test/Analysis/uninit-const.c b/clang/test/Analysis/uninit-const.c index 1ddf2c89ae59a..f8c89644dd306 100644 --- a/clang/test/Analysis/uninit-const.c +++ b/clang/test/Analysis/uninit-const.c @@ -69,14 +69,14 @@ void f_4(void) { } void f_5(void) { - int ta[5]; // expected-note {{'ta' initialized here}} + int ta[5]; // expected-note {{'ta' declared without an initial value}} int *tp = ta; // expected-note {{'tp' initialized here}} doStuff_pointerToConstInt(tp); // expected-warning {{1st function call argument is a pointer to uninitialized value}} // expected-note@-1 {{1st function call argument is a pointer to uninitialized value}} } void f_5_1(void) { - int ta[5]; // expected-note {{'ta' initialized here}} + int ta[5]; // expected-note {{'ta' declared without an initial value}} doStuff_pointerToConstInt(ta); // expected-warning {{1st function call argument is a pointer to uninitialized value}} // expected-note@-1 {{1st function call argument is a pointer to uninitialized value}} } @@ -106,20 +106,20 @@ void f_8(void) { } void f_9(void) { - int a[6]; // expected-note {{'a' initialized here}} + int a[6]; // expected-note {{'a' declared without an initial value}} int const *ptau = a; // expected-note {{'ptau' initialized here}} doStuff_arrayOfConstInt(ptau); // expected-warning {{1st function call argument is a pointer to uninitialized value}} // expected-note@-1 {{1st function call argument is a pointer to uninitialized value}} } void f_10(void) { - int a[6]; // expected-note {{'a' initialized here}} + int a[6]; // expected-note {{'a' declared without an initial value}} doStuff_arrayOfConstInt(a); // expected-warning {{1st function call argument is a pointer to uninitialized value}} // expected-note@-1 {{1st function call argument is a pointer to uninitialized value}} } void f_11(void) { - int t[10]; //expected-note {{'t' initialized here}} + int t[10]; //expected-note {{'t' declared without an initial value}} doStuff_constStaticSizedArray(t); // expected-warning {{1st function call argument is a pointer to uninitialized value}} // expected-note@-1 {{1st function call argument is a pointer to uninitialized value}} } diff --git a/clang/test/Analysis/uninit-vals.m b/clang/test/Analysis/uninit-vals.m index eef2600b97f56..f754f65605d1a 100644 --- a/clang/test/Analysis/uninit-vals.m +++ b/clang/test/Analysis/uninit-vals.m @@ -59,7 +59,7 @@ void test_uninit_neg(void) { extern void test_uninit_struct_arg_aux(struct TestUninit arg); void test_uninit_struct_arg(void) { - struct TestUninit x; // expected-note{{'x' initialized here}} + struct TestUninit x; // expected-note{{'x' declared without an initial value}} test_uninit_struct_arg_aux(x); // expected-warning{{Passed-by-value struct argument contains uninitialized data (e.g., field: 'x')}} // expected-note@-1{{Passed-by-value struct argument contains uninitialized data (e.g., field: 'x')}} } @@ -68,7 +68,7 @@ @interface Foo - (void) passVal:(struct TestUninit)arg; @end void testFoo(Foo *o) { - struct TestUninit x; // expected-note{{'x' initialized here}} + struct TestUninit x; // expected-note{{'x' declared without an initial value}} [o passVal:x]; // expected-warning{{Passed-by-value struct argument contains uninitialized data (e.g., field: 'x')}} // expected-note@-1{{Passed-by-value struct argument contains uninitialized data (e.g., field: 'x')}} } @@ -402,7 +402,7 @@ void testSmallStructBitfieldsFirstUnnamed(void) { struct { int : 4; int y : 4; - } a, b, c; // expected-note{{'c' initialized here}} + } a, b, c; // expected-note{{'c' declared without an initial value}} a.y = 2; @@ -419,7 +419,7 @@ void testSmallStructBitfieldsSecondUnnamed(void) { struct { int x : 4; int : 4; - } a, b, c; // expected-note{{'c' initialized here}} + } a, b, c; // expected-note{{'c' declared without an initial value}} a.x = 1; From 56d9db0bfd53f4e694449ab8cc8a155e5b250dbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Endre=20F=C3=BCl=C3=B6p?= <[email protected]> Date: Mon, 18 May 2026 19:36:42 +0200 Subject: [PATCH 2/3] fixup: emit 'initialized here' for non-VarRegion destinations Without this fallback, field regions (e.g., 'w.a') would get a note with only the prefix and no message text. --- clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp index 2892c12261515..02a9c21e2945c 100644 --- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp +++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp @@ -1296,6 +1296,8 @@ static void showBRDiagnostics(llvm::raw_svector_ostream &OS, StoreInfo SI) { } else { OS << (HasPrefix ? "initialized" : "Initialized") << " here"; } + } else { + OS << (HasPrefix ? "initialized" : "Initialized") << " here"; } } } From 0e63ad0a423948f34ea7fe7b02f140aec4138fb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Endre=20F=C3=BCl=C3=B6p?= <[email protected]> Date: Wed, 20 May 2026 15:26:29 +0200 Subject: [PATCH 3/3] fixup: address review - spell out type, add garbage-value test --- .../StaticAnalyzer/Core/BugReporterVisitors.cpp | 11 ++++------- clang/test/Analysis/uninit-val-init-from-garbage.c | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 7 deletions(-) create mode 100644 clang/test/Analysis/uninit-val-init-from-garbage.c diff --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp index 02a9c21e2945c..4e133a9c81d91 100644 --- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp +++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp @@ -1281,16 +1281,13 @@ static void showBRDiagnostics(llvm::raw_svector_ostream &OS, StoreInfo SI) { // We don't need to check here, all these conditions were // checked by StoreSiteFinder, when it figured out that it is // initialization. - const auto *VR = dyn_cast<VarRegion>(SI.Dest); - if (VR) { - const auto *VD = VR->getDecl(); - bool HasInit = VD->getInit(); - bool HasGlobalStorage = VD->hasGlobalStorage(); + if (const auto *VR = dyn_cast<VarRegion>(SI.Dest)) { + const VarDecl *VD = VR->getDecl(); - if (SI.Value.isUndef() && HasInit) { + if (SI.Value.isUndef() && VD->getInit()) { OS << (HasPrefix ? "initialized" : "Initializing") << " to a garbage value"; - } else if (!HasInit && !HasGlobalStorage) { + } else if (!VD->getInit() && !VD->hasGlobalStorage()) { OS << (HasPrefix ? "declared" : "Declared") << " without an initial value"; } else { diff --git a/clang/test/Analysis/uninit-val-init-from-garbage.c b/clang/test/Analysis/uninit-val-init-from-garbage.c new file mode 100644 index 0000000000000..4ecfb3cd2a38f --- /dev/null +++ b/clang/test/Analysis/uninit-val-init-from-garbage.c @@ -0,0 +1,14 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=core.uninitialized.Branch \ +// RUN: -analyzer-output=text -verify %s + +// Test that 'initialized to a garbage value' note is emitted when a variable +// is initialized from an uninitialized source and later used in a branch. +void testInitFromGarbage(int cond) { + int y; // expected-note{{'y' declared without an initial value}} + if (cond) // expected-note{{Assuming 'cond' is 0}} + // expected-note@-1{{Taking false branch}} + y = 1; + int x = y; // expected-note{{'x' initialized to a garbage value}} + if (x > 0) {} // expected-warning{{Branch condition evaluates to a garbage value}} + // expected-note@-1{{Branch condition evaluates to a garbage value}} +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
