[clang] [clang][analyzer] Add support for detecting uninitialized union fields (PR #191812)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Apr 13 08:21:57 PDT 2026
https://github.com/StepfenShawn updated https://github.com/llvm/llvm-project/pull/191812
>From 628a2b5afedf9b24008d09b61c05315e079f8f82 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=F0=9F=8D=8CShawn?= <m18824909883 at 163.com>
Date: Mon, 13 Apr 2026 21:02:51 +0800
Subject: [PATCH 1/5] Add support for uninitialized union fields check
Implement support for checking uninitialized union fields in FindUninitializedFields.
---
.../UninitializedObjectChecker.cpp | 26 +++++++++++++++++--
1 file changed, 24 insertions(+), 2 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
index 6d4389fda8753..a98b2d7f5f0ec 100644
--- a/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
@@ -374,8 +374,30 @@ bool FindUninitializedFields::isNonUnionUninit(const TypedValueRegion *R,
bool FindUninitializedFields::isUnionUninit(const TypedValueRegion *R) {
assert(R->getValueType()->isUnionType() &&
"This method only checks union objects!");
- // TODO: Implement support for union fields.
- return false;
+
+ const RecordDecl *RD = R->getValueType()->getAsRecordDecl()->getDefinition();
+
+ if (!RD)
+ return false;
+
+ // A union is considered initialized if at least one of its fields has a
+ // non-undefined value. If every field is undefined (or the union has no
+ // fields), we treat it as uninitialized.
+ for (const FieldDecl *FD : RD->fields()) {
+ if (FD->isUnnamedBitField())
+ continue;
+
+ const auto FieldVal = State->getLValue(FD, loc::MemRegionVal(R)).castAs<loc::MemRegionVal>();
+ SVal V = State->getSVal(FieldVal);
+
+ // If any field has a defined value, the union is initialized.
+ if (!V.isUndef()) {
+ IsAnyFieldInitialized = true;
+ return false;
+ }
+ }
+
+ return true;
}
bool FindUninitializedFields::isPrimitiveUninit(SVal V) {
>From 883142b8d8ac6f94cceab3e7a4570eeb7b43c48f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=F0=9F=8D=8CShawn?= <m18824909883 at 163.com>
Date: Mon, 13 Apr 2026 21:06:27 +0800
Subject: [PATCH 2/5] Implement tests for union field initialization warnings
Add tests for uninitialized union fields in structs/classes.
---
.../cxx-uninitialized-object-union-field.cpp | 57 +++++++++++++++++++
1 file changed, 57 insertions(+)
create mode 100644 clang/test/Analysis/cxx-uninitialized-object-union-field.cpp
diff --git a/clang/test/Analysis/cxx-uninitialized-object-union-field.cpp b/clang/test/Analysis/cxx-uninitialized-object-union-field.cpp
new file mode 100644
index 0000000000000..8f5f777111109
--- /dev/null
+++ b/clang/test/Analysis/cxx-uninitialized-object-union-field.cpp
@@ -0,0 +1,57 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,optin.cplusplus.UninitializedObject \
+// RUN: -analyzer-config optin.cplusplus.UninitializedObject:Pedantic=true -DPEDANTIC \
+// RUN: -std=c++11 -verify %s
+
+//===----------------------------------------------------------------------===//
+// Tests for union fields inside structs/classes.
+//===----------------------------------------------------------------------===//
+
+// A struct with an uninitialized union field -- should warn.
+struct WithUninitUnion {
+ union {
+ int i;
+ float f;
+ } u; // expected-note{{uninitialized field 'this->u'}}
+ int x;
+
+ WithUninitUnion(int val) : x(val) { // expected-warning{{1 uninitialized field at the end of the constructor call}}
+ // u is never initialized
+ }
+};
+
+void fWithUninitUnion() {
+ WithUninitUnion w(42);
+}
+
+// A struct where the union field IS initialized -- should not warn.
+struct WithInitUnion {
+ union {
+ int i;
+ float f;
+ } u;
+ int x;
+
+ WithInitUnion(int val) : x(val) {
+ u.i = val; // union is initialized via one of its members
+ }
+};
+
+void fWithInitUnion() {
+ WithInitUnion w(42); // no-warning
+}
+
+// A struct with only a union field, left uninitialized (pedantic mode).
+struct OnlyUninitUnion {
+ union {
+ int i;
+ char c;
+ } u; // expected-note{{uninitialized field 'this->u'}}
+
+ OnlyUninitUnion() { // expected-warning{{1 uninitialized field at the end of the constructor call}}
+ // u is never initialized
+ }
+};
+
+void fOnlyUninitUnion() {
+ OnlyUninitUnion o;
+}
>From e6cbe707576e20329a645ec8f41b14c9bf7cf980 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=F0=9F=8D=8CShawn?= <m18824909883 at 163.com>
Date: Mon, 13 Apr 2026 22:40:42 +0800
Subject: [PATCH 3/5] Fix uninitialized field warnings in union tests
---
clang/test/Analysis/cxx-uninitialized-object.cpp | 16 ++++++----------
1 file changed, 6 insertions(+), 10 deletions(-)
diff --git a/clang/test/Analysis/cxx-uninitialized-object.cpp b/clang/test/Analysis/cxx-uninitialized-object.cpp
index daaf6f418c7d1..8ce90b555b791 100644
--- a/clang/test/Analysis/cxx-uninitialized-object.cpp
+++ b/clang/test/Analysis/cxx-uninitialized-object.cpp
@@ -435,16 +435,14 @@ class ContainsSimpleUnionTest2 {
float uf;
int ui;
char uc;
- // TODO: we'd expect the note: {{uninitialized field 'this->u'}}
- } u; // no-note
+ } u; // expected-note{{uninitialized field 'this->u'}}
public:
- ContainsSimpleUnionTest2() {}
+ ContainsSimpleUnionTest2() {} // expected-warning{{1 uninitialized field at the end of the constructor call}}
};
void fContainsSimpleUnionTest2() {
- // TODO: we'd expect the warning: {{1 uninitialized field}}
- ContainsSimpleUnionTest2(); // no-warning
+ ContainsSimpleUnionTest2();
}
class UnionPointerTest1 {
@@ -479,17 +477,15 @@ class UnionPointerTest2 {
};
private:
- // TODO: we'd expect the note: {{uninitialized field 'this->uptr'}}
- SimpleUnion *uptr; // no-note
+ SimpleUnion *uptr; // expected-note{{uninitialized pointee 'this->uptr'}}
public:
- UnionPointerTest2(SimpleUnion *uptr, char) : uptr(uptr) {}
+ UnionPointerTest2(SimpleUnion *uptr, char) : uptr(uptr) {} // expected-warning{{1 uninitialized field at the end of the constructor call}}
};
void fUnionPointerTest2() {
UnionPointerTest2::SimpleUnion u;
- // TODO: we'd expect the warning: {{1 uninitialized field}}
- UnionPointerTest2(&u, int()); // no-warning
+ UnionPointerTest2(&u, int());
}
class ContainsUnionWithRecordTest1 {
>From ea966c251ccec9d91125120da5b99dc537bebdf6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=F0=9F=8D=8CShawn?= <m18824909883 at 163.com>
Date: Mon, 13 Apr 2026 23:12:17 +0800
Subject: [PATCH 4/5] Update cxx-uninitialized-object.cpp
---
.../Analysis/cxx-uninitialized-object.cpp | 20 +++++++++++++++----
1 file changed, 16 insertions(+), 4 deletions(-)
diff --git a/clang/test/Analysis/cxx-uninitialized-object.cpp b/clang/test/Analysis/cxx-uninitialized-object.cpp
index 8ce90b555b791..d727d59821f0b 100644
--- a/clang/test/Analysis/cxx-uninitialized-object.cpp
+++ b/clang/test/Analysis/cxx-uninitialized-object.cpp
@@ -435,10 +435,16 @@ class ContainsSimpleUnionTest2 {
float uf;
int ui;
char uc;
- } u; // expected-note{{uninitialized field 'this->u'}}
+ } u;
+#ifdef PEDANTIC
+ // expected-note at -1{{uninitialized field 'this->u'}}
+#endif
public:
- ContainsSimpleUnionTest2() {} // expected-warning{{1 uninitialized field at the end of the constructor call}}
+ ContainsSimpleUnionTest2() {}
+#ifdef PEDANTIC
+ // expected-warning at -1{{1 uninitialized field at the end of the constructor call}}
+#endif
};
void fContainsSimpleUnionTest2() {
@@ -477,10 +483,16 @@ class UnionPointerTest2 {
};
private:
- SimpleUnion *uptr; // expected-note{{uninitialized pointee 'this->uptr'}}
+ SimpleUnion *uptr;
+#ifdef PEDANTIC
+ // expected-note at -1{{uninitialized pointee 'this->uptr'}}
+#endif
public:
- UnionPointerTest2(SimpleUnion *uptr, char) : uptr(uptr) {} // expected-warning{{1 uninitialized field at the end of the constructor call}}
+ UnionPointerTest2(SimpleUnion *uptr, char) : uptr(uptr) {}
+#ifdef PEDANTIC
+ // expected-warning at -1{{1 uninitialized field at the end of the constructor call}}
+#endif
};
void fUnionPointerTest2() {
>From 0d8dc534370545c8f22c78f1915d04add7ce1953 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=F0=9F=8D=8CShawn?= <m18824909883 at 163.com>
Date: Mon, 13 Apr 2026 23:21:45 +0800
Subject: [PATCH 5/5] Update comments for uninitialized fields in tests
---
.../Analysis/cxx-uninitialized-object.cpp | 20 +++++++++++--------
1 file changed, 12 insertions(+), 8 deletions(-)
diff --git a/clang/test/Analysis/cxx-uninitialized-object.cpp b/clang/test/Analysis/cxx-uninitialized-object.cpp
index d727d59821f0b..6af295f84c8ad 100644
--- a/clang/test/Analysis/cxx-uninitialized-object.cpp
+++ b/clang/test/Analysis/cxx-uninitialized-object.cpp
@@ -435,15 +435,17 @@ class ContainsSimpleUnionTest2 {
float uf;
int ui;
char uc;
- } u;
#ifdef PEDANTIC
- // expected-note at -1{{uninitialized field 'this->u'}}
+ } u; // expected-note{{uninitialized field 'this->u'}}
+#else
+ } u;
#endif
public:
- ContainsSimpleUnionTest2() {}
#ifdef PEDANTIC
- // expected-warning at -1{{1 uninitialized field at the end of the constructor call}}
+ ContainsSimpleUnionTest2() {} // expected-warning{{1 uninitialized field at the end of the constructor call}}
+#else
+ ContainsSimpleUnionTest2() {}
#endif
};
@@ -483,15 +485,17 @@ class UnionPointerTest2 {
};
private:
- SimpleUnion *uptr;
#ifdef PEDANTIC
- // expected-note at -1{{uninitialized pointee 'this->uptr'}}
+ SimpleUnion *uptr; // expected-note{{uninitialized pointee 'this->uptr'}}
+#else
+ SimpleUnion *uptr;
#endif
public:
- UnionPointerTest2(SimpleUnion *uptr, char) : uptr(uptr) {}
#ifdef PEDANTIC
- // expected-warning at -1{{1 uninitialized field at the end of the constructor call}}
+ UnionPointerTest2(SimpleUnion *uptr, char) : uptr(uptr) {} // expected-warning{{1 uninitialized field at the end of the constructor call}}
+#else
+ UnionPointerTest2(SimpleUnion *uptr, char) : uptr(uptr) {}
#endif
};
More information about the cfe-commits
mailing list