Skip to content

Conversation

@balazske
Copy link
Collaborator

CallAndMessageChecker did have a warning for the case when pointer to uninitialized data is passed to a function when the argument type is pointer to const. This did not work for struct types. The check is improved to handle cases when struct with uninitialized data is passed to a function.

… struct

CallAndMessageChecker did have a warning for the case when pointer to
uninitialized data is passed to a function when the argument type is
pointer to const. This did not work for struct types. The check is
improved to handle cases when struct with uninitialized data is
passed to a function.
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:static analyzer labels Oct 22, 2025
@llvmbot
Copy link
Member

llvmbot commented Oct 22, 2025

@llvm/pr-subscribers-clang-static-analyzer-1

Author: Balázs Kéri (balazske)

Changes

CallAndMessageChecker did have a warning for the case when pointer to uninitialized data is passed to a function when the argument type is pointer to const. This did not work for struct types. The check is improved to handle cases when struct with uninitialized data is passed to a function.


Full diff: https://github.com/llvm/llvm-project/pull/164600.diff

3 Files Affected:

  • (modified) clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp (+8-4)
  • (modified) clang/test/Analysis/PR40625.cpp (+2-2)
  • (modified) clang/test/Analysis/call-and-message.c (+12)
diff --git a/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
index 7cc146ed29d0d..cd24b1e816e01 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
@@ -183,8 +183,6 @@ bool CallAndMessageChecker::uninitRefOrPointer(
     CheckerContext &C, SVal V, SourceRange ArgRange, const Expr *ArgEx,
     const BugType &BT, const ParmVarDecl *ParamDecl, int ArgumentNumber) const {
 
-  // The pointee being uninitialized is a sign of code smell, not a bug, no need
-  // to sink here.
   if (!ChecksEnabled[CK_ArgPointeeInitializedness])
     return false;
 
@@ -212,8 +210,14 @@ bool CallAndMessageChecker::uninitRefOrPointer(
 
   if (const MemRegion *SValMemRegion = V.getAsRegion()) {
     const ProgramStateRef State = C.getState();
-    const SVal PSV = State->getSVal(SValMemRegion, C.getASTContext().CharTy);
-    if (PSV.isUndef()) {
+    QualType T = ParamDecl->getType()->getPointeeType();
+    if (T->isVoidType())
+      T = C.getASTContext().CharTy;
+    const SVal PSV = State->getSVal(SValMemRegion, T);
+    bool IsUndef = PSV.isUndef();
+    if (auto LCV = PSV.getAs<nonloc::LazyCompoundVal>())
+      IsUndef = LCV->getStore() == nullptr;
+    if (IsUndef) {
       if (ExplodedNode *N = C.generateErrorNode()) {
         auto R = std::make_unique<PathSensitiveBugReport>(BT, Os.str(), N);
         R->addRange(ArgRange);
diff --git a/clang/test/Analysis/PR40625.cpp b/clang/test/Analysis/PR40625.cpp
index 5ebe2122945e6..ab3faa328298a 100644
--- a/clang/test/Analysis/PR40625.cpp
+++ b/clang/test/Analysis/PR40625.cpp
@@ -5,11 +5,11 @@
 void f(const int *end);
 
 void g(const int (&arrr)[10]) {
-  f(arrr); // expected-warning{{1st function call argument is a pointer to uninitialized value}}
+  f(arrr);
 }
 
 void h() {
   int arr[10];
 
-  g(arr);
+  g(arr); // expected-warning{{1st function call argument is an uninitialized value}}
 }
diff --git a/clang/test/Analysis/call-and-message.c b/clang/test/Analysis/call-and-message.c
index ade51145e2a93..fdac77176569b 100644
--- a/clang/test/Analysis/call-and-message.c
+++ b/clang/test/Analysis/call-and-message.c
@@ -24,6 +24,18 @@ void pointee_uninit(void) {
   doStuff_pointerToConstInt(p); // expected-warning{{1st function call argument is a pointer to uninitialized value [core.CallAndMessage]}}
 }
 
+typedef struct S {
+  int a;
+  short b;
+} S;
+
+void doStuff_pointerToConstStruct(const S *s){};
+void pointee_uninit_struct(void) {
+  S s;
+  S *p = &s;
+  doStuff_pointerToConstStruct(p); // expected-warning{{1st function call argument is a pointer to uninitialized value [core.CallAndMessage]}}
+}
+
 // TODO: If this hash ever changes, turn
 // core.CallAndMessage:ArgPointeeInitializedness from a checker option into a
 // checker, as described in the CallAndMessage comments!

@llvmbot
Copy link
Member

llvmbot commented Oct 22, 2025

@llvm/pr-subscribers-clang

Author: Balázs Kéri (balazske)

Changes

CallAndMessageChecker did have a warning for the case when pointer to uninitialized data is passed to a function when the argument type is pointer to const. This did not work for struct types. The check is improved to handle cases when struct with uninitialized data is passed to a function.


Full diff: https://github.com/llvm/llvm-project/pull/164600.diff

3 Files Affected:

  • (modified) clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp (+8-4)
  • (modified) clang/test/Analysis/PR40625.cpp (+2-2)
  • (modified) clang/test/Analysis/call-and-message.c (+12)
diff --git a/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
index 7cc146ed29d0d..cd24b1e816e01 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
@@ -183,8 +183,6 @@ bool CallAndMessageChecker::uninitRefOrPointer(
     CheckerContext &C, SVal V, SourceRange ArgRange, const Expr *ArgEx,
     const BugType &BT, const ParmVarDecl *ParamDecl, int ArgumentNumber) const {
 
-  // The pointee being uninitialized is a sign of code smell, not a bug, no need
-  // to sink here.
   if (!ChecksEnabled[CK_ArgPointeeInitializedness])
     return false;
 
@@ -212,8 +210,14 @@ bool CallAndMessageChecker::uninitRefOrPointer(
 
   if (const MemRegion *SValMemRegion = V.getAsRegion()) {
     const ProgramStateRef State = C.getState();
-    const SVal PSV = State->getSVal(SValMemRegion, C.getASTContext().CharTy);
-    if (PSV.isUndef()) {
+    QualType T = ParamDecl->getType()->getPointeeType();
+    if (T->isVoidType())
+      T = C.getASTContext().CharTy;
+    const SVal PSV = State->getSVal(SValMemRegion, T);
+    bool IsUndef = PSV.isUndef();
+    if (auto LCV = PSV.getAs<nonloc::LazyCompoundVal>())
+      IsUndef = LCV->getStore() == nullptr;
+    if (IsUndef) {
       if (ExplodedNode *N = C.generateErrorNode()) {
         auto R = std::make_unique<PathSensitiveBugReport>(BT, Os.str(), N);
         R->addRange(ArgRange);
diff --git a/clang/test/Analysis/PR40625.cpp b/clang/test/Analysis/PR40625.cpp
index 5ebe2122945e6..ab3faa328298a 100644
--- a/clang/test/Analysis/PR40625.cpp
+++ b/clang/test/Analysis/PR40625.cpp
@@ -5,11 +5,11 @@
 void f(const int *end);
 
 void g(const int (&arrr)[10]) {
-  f(arrr); // expected-warning{{1st function call argument is a pointer to uninitialized value}}
+  f(arrr);
 }
 
 void h() {
   int arr[10];
 
-  g(arr);
+  g(arr); // expected-warning{{1st function call argument is an uninitialized value}}
 }
diff --git a/clang/test/Analysis/call-and-message.c b/clang/test/Analysis/call-and-message.c
index ade51145e2a93..fdac77176569b 100644
--- a/clang/test/Analysis/call-and-message.c
+++ b/clang/test/Analysis/call-and-message.c
@@ -24,6 +24,18 @@ void pointee_uninit(void) {
   doStuff_pointerToConstInt(p); // expected-warning{{1st function call argument is a pointer to uninitialized value [core.CallAndMessage]}}
 }
 
+typedef struct S {
+  int a;
+  short b;
+} S;
+
+void doStuff_pointerToConstStruct(const S *s){};
+void pointee_uninit_struct(void) {
+  S s;
+  S *p = &s;
+  doStuff_pointerToConstStruct(p); // expected-warning{{1st function call argument is a pointer to uninitialized value [core.CallAndMessage]}}
+}
+
 // TODO: If this hash ever changes, turn
 // core.CallAndMessage:ArgPointeeInitializedness from a checker option into a
 // checker, as described in the CallAndMessage comments!

@balazske
Copy link
Collaborator Author

Do we need more tests for this checker option (and in cpp mode)?

const SVal PSV = State->getSVal(SValMemRegion, T);
bool IsUndef = PSV.isUndef();
if (auto LCV = PSV.getAs<nonloc::LazyCompoundVal>())
IsUndef = LCV->getStore() == nullptr;
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did not find information about if this is the correct way of detecting that the value is not initialized.

void pointee_uninit_struct(void) {
S s;
S *p = &s;
doStuff_pointerToConstStruct(p); // expected-warning{{1st function call argument is a pointer to uninitialized value [core.CallAndMessage]}}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do I understand it correctly that this testcase wouldn't pass without your change in the checker?

Copy link
Contributor

@NagyDonat NagyDonat left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I admit that my first impression is that "I don't know" -- I'm not familiar enough with the possible representations of undefined values in the analyzer to form an opinion about this PR. I could research this if it is really needed -- but perhaps @steakhal @haoNoQ or @Xazax-hun could say something wise more directly?

My first guess is that the old code should have been sufficient to detect whether the memory area is undefined -- and it is a bit sad that you need to write this more elaborate code. In general, I tend to notice a pattern that LazyCompoundVal is too opaque and its performance benefits come with lots of added code complexity as we always need to explicitly check for it. (However I don't know enough, perhaps this is still the least wrong approach.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clang:static analyzer clang Clang issues not falling into any other category

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants