https://github.com/Tedlion updated 
https://github.com/llvm/llvm-project/pull/145066

>From 03004d9a9348e365a2d2d05e69f83fc404ddb605 Mon Sep 17 00:00:00 2001
From: tangwy <ted_l...@qq.com>
Date: Sat, 21 Jun 2025 00:22:10 +0800
Subject: [PATCH 1/3] [clang][analyzer] Fix the false positive
 ArgInitializedness warning on unnamed bit-field

For the following code:
 struct B{
   int i  :2;
   int    :30;  // unnamed bit-field
 };

 extern void consume_B(B);

 void bitfield_B_init(void) {
   B b1;
   b1.i = 1; // b1 is initialized
   consume_B(b1);
 }

The current clang static analyzer gives false positive warning "Passed-by-value 
struct argument contains uninitialized data (e.g., field: '') 
[core.CallAndMessage]" when taking the source as C code. However, no such 
warning is generated when clang takes the source as C++ code.

After comparing the CallAndMessageChecker's different behaviors between C and 
C++, the reason is found:
When FindUninitializedField::Find(const TypedValueRegion *R) is invoked, the 
concrete type of R is different. In C, 'b1' is considered to be a 
'StackLocalsSpaceRegion', which makes 'StoreMgr.getBinding(store, 
loc::MemRegionVal(FR))' return an 'UndefinedVal'. While in c++, 'b1' is 
considered to be a 'tackArgumentsSpaceRegion', which finally makes the 
'getBinding' return a SymbolVal. I am not quite sure about the region 
difference, maybe in C++ there is an implicit copy constructor function?

 Anyway, the unnamed bit-field is undefined, for it cannot be written unless 
using memory operation such
as 'memset'. So a special check FD->isUnnamedBitField() is added in 
RegionStoreManager::getBindingForField in
file RegionStore.cpp.

To handle the false warning, a check isUnnamedBitField is also added in 
FindUninitializedField::Find in file CallAndMessageChecker.cpp.

Testcases of unnamed bit-field are added in file call-and-message.c and 
call-and-message.cpp. I do not know what to do on the hash, so it may be 
updated?
---
 .../Checkers/CallAndMessageChecker.cpp        |  2 +-
 clang/lib/StaticAnalyzer/Core/RegionStore.cpp | 15 ++++++++++-
 clang/test/Analysis/call-and-message.c        | 27 ++++++++++++++++++-
 clang/test/Analysis/call-and-message.cpp      | 16 +++++++++++
 4 files changed, 57 insertions(+), 3 deletions(-)

diff --git a/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
index 86476b32309c3..677cc6ee57ad2 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
@@ -259,7 +259,7 @@ class FindUninitializedField {
         if (T->getAsStructureType()) {
           if (Find(FR))
             return true;
-        } else {
+        } else if (!I->isUnnamedBitField()){
           SVal V = StoreMgr.getBinding(store, loc::MemRegionVal(FR));
           if (V.isUndef())
             return true;
diff --git a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp 
b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
index 388034b087789..1208036700f32 100644
--- a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -2122,8 +2122,21 @@ SVal 
RegionStoreManager::getBindingForField(RegionBindingsConstRef B,
   if (const std::optional<SVal> &V = B.getDirectBinding(R))
     return *V;
 
-  // If the containing record was initialized, try to get its constant value.
+  // UnnamedBitField is always Undefined unless using memory operation such
+  // as 'memset'.
+  // For example, for code
+  //    typedef struct {
+  //      int i  :2;
+  //      int    :30;  // unnamed bit-field
+  //    } A;
+  //    A a = {1};
+  // The bits of the unnamed bit-field in local variable a can be anything.
   const FieldDecl *FD = R->getDecl();
+  if (FD->isUnnamedBitField()) {
+      return UndefinedVal();
+  }
+
+  // If the containing record was initialized, try to get its constant value.
   QualType Ty = FD->getType();
   const MemRegion* superR = R->getSuperRegion();
   if (const auto *VR = dyn_cast<VarRegion>(superR)) {
diff --git a/clang/test/Analysis/call-and-message.c 
b/clang/test/Analysis/call-and-message.c
index b79ec8c344b6c..e2fba55d3343d 100644
--- a/clang/test/Analysis/call-and-message.c
+++ b/clang/test/Analysis/call-and-message.c
@@ -1,12 +1,19 @@
 // RUN: %clang_analyze_cc1 %s -verify \
 // RUN:   -analyzer-checker=core \
 // RUN:   -analyzer-config core.CallAndMessage:ArgPointeeInitializedness=true \
+// RUN:   -analyzer-config core.CallAndMessage:ArgInitializedness=false \
 // RUN:   -analyzer-output=plist -o %t.plist
 // RUN: cat %t.plist | FileCheck %s
 
 // RUN: %clang_analyze_cc1 %s -verify=no-pointee \
 // RUN:   -analyzer-checker=core \
-// RUN:   -analyzer-config core.CallAndMessage:ArgPointeeInitializedness=false
+// RUN:   -analyzer-config core.CallAndMessage:ArgPointeeInitializedness=false 
\
+// RUN:   -analyzer-config core.CallAndMessage:ArgInitializedness=false
+
+// RUN: %clang_analyze_cc1 %s -verify=arg-init \
+// RUN:   -analyzer-checker=core \
+// RUN:   -analyzer-config core.CallAndMessage:ArgPointeeInitializedness=false 
\
+// RUN:   -analyzer-config core.CallAndMessage:ArgInitializedness=true
 
 // no-pointee-no-diagnostics
 
@@ -22,3 +29,21 @@ void pointee_uninit(void) {
 // checker, as described in the CallAndMessage comments!
 // CHECK: <key>issue_hash_content_of_line_in_context</key>
 // CHECK-SAME: <string>97a74322d64dca40aa57303842c745a1</string>
+
+typedef struct {
+  int i  :2;
+  int    :30;  // unnamed bit-field
+} B;
+
+extern void consume_B(B);
+
+void bitfield_B_init(void) {
+  B b1;
+  b1.i = 1; // b1 is initialized
+  consume_B(b1);
+}
+
+void bitfield_B_uninit(void) {
+  B b2;
+  consume_B(b2); // arg-init-warning{{Passed-by-value struct argument contains 
uninitialized data (e.g., field: 'i') [core.CallAndMessage]}}
+}
\ No newline at end of file
diff --git a/clang/test/Analysis/call-and-message.cpp 
b/clang/test/Analysis/call-and-message.cpp
index 25ae23833478b..1e76973f49e13 100644
--- a/clang/test/Analysis/call-and-message.cpp
+++ b/clang/test/Analysis/call-and-message.cpp
@@ -169,4 +169,20 @@ void record_uninit() {
 // CHECK-SAME: <string>a46bb5c1ee44d4611ffeb13f7f499605</string>
 // CHECK: <key>issue_hash_content_of_line_in_context</key>
 // CHECK-SAME: <string>e0e0d30ea5a7b2e3a71e1931fa0768a5</string>
+
+struct B{
+  int i  :2;
+  int    :30;  // unnamed bit-field
+};
+
+void bitfield_B_init(void) {
+  B b1;
+  b1.i = 1; // b1 is initialized
+  consume(b1);
+}
+
+void bitfield_B_uninit(void) {
+  B b2;
+  consume(b2); // arg-init-warning{{Passed-by-value struct argument contains 
uninitialized data (e.g., field: 'i') [core.CallAndMessage]}}
+}
 } // namespace uninit_arg

>From c54bc995d80056f950eb64200ccff81c2adcedcb Mon Sep 17 00:00:00 2001
From: tangwy <ted_l...@qq.com>
Date: Fri, 27 Jun 2025 19:49:11 +0800
Subject: [PATCH 2/3] Replacing the else-if check with early-continue in
 CallAndMessageChecker.cpp. Fix formatting issues.

---
 clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp | 5 ++++-
 clang/lib/StaticAnalyzer/Core/RegionStore.cpp               | 2 +-
 2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
index 677cc6ee57ad2..053a6e1312e24 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
@@ -253,13 +253,16 @@ class FindUninitializedField {
       const RecordDecl *RD = RT->getDecl()->getDefinition();
       assert(RD && "Referred record has no definition");
       for (const auto *I : RD->fields()) {
+        if (I->isUnnamedBitField()) {
+          continue;
+        }
         const FieldRegion *FR = MrMgr.getFieldRegion(I, R);
         FieldChain.push_back(I);
         T = I->getType();
         if (T->getAsStructureType()) {
           if (Find(FR))
             return true;
-        } else if (!I->isUnnamedBitField()){
+        } else {
           SVal V = StoreMgr.getBinding(store, loc::MemRegionVal(FR));
           if (V.isUndef())
             return true;
diff --git a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp 
b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
index 1208036700f32..2e509d09cc9ba 100644
--- a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -2133,7 +2133,7 @@ SVal 
RegionStoreManager::getBindingForField(RegionBindingsConstRef B,
   // The bits of the unnamed bit-field in local variable a can be anything.
   const FieldDecl *FD = R->getDecl();
   if (FD->isUnnamedBitField()) {
-      return UndefinedVal();
+    return UndefinedVal();
   }
 
   // If the containing record was initialized, try to get its constant value.

>From db350f607a6792ef87c83d2b501e0cdf7cae4b83 Mon Sep 17 00:00:00 2001
From: Tedlion <813055...@qq.com>
Date: Fri, 27 Jun 2025 20:58:32 +0800
Subject: [PATCH 3/3] Update
 clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp

remove braces on simple single statement bodies

Co-authored-by: Baranov Victor <bar.victor.2...@gmail.com>
---
 clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
index 053a6e1312e24..23935647a5826 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
@@ -253,9 +253,8 @@ class FindUninitializedField {
       const RecordDecl *RD = RT->getDecl()->getDefinition();
       assert(RD && "Referred record has no definition");
       for (const auto *I : RD->fields()) {
-        if (I->isUnnamedBitField()) {
+        if (I->isUnnamedBitField())
           continue;
-        }
         const FieldRegion *FR = MrMgr.getFieldRegion(I, R);
         FieldChain.push_back(I);
         T = I->getType();

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to