Skip to content

Conversation

@rniwa
Copy link
Contributor

@rniwa rniwa commented Mar 24, 2025

This PR fixes the bug that we weren't generating warnings when a raw poiner is used to point to a NS type in Objective-C ivars. Also fix the bug that we weren't suppressing this warning in system headers.

…ive-C types in ivars.

This PR fixes the bug that we weren't generating warnings when a raw poiner is used to
point to a NS type in Objective-C ivars. Also fix the bug that we weren't suppressing this
warning in system headers.
@rniwa rniwa requested review from haoNoQ and t-rasmud March 24, 2025 21:24
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:static analyzer labels Mar 24, 2025
@llvmbot
Copy link
Member

llvmbot commented Mar 24, 2025

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

Author: Ryosuke Niwa (rniwa)

Changes

This PR fixes the bug that we weren't generating warnings when a raw poiner is used to point to a NS type in Objective-C ivars. Also fix the bug that we weren't suppressing this warning in system headers.


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

3 Files Affected:

  • (modified) clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefMemberChecker.cpp (+10)
  • (modified) clang/test/Analysis/Checkers/WebKit/mock-system-header.h (+11)
  • (modified) clang/test/Analysis/Checkers/WebKit/unretained-members.mm (+11-1)
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefMemberChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefMemberChecker.cpp
index dc4e2c7d168fb..6d20869043358 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefMemberChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefMemberChecker.cpp
@@ -111,6 +111,8 @@ class RawPtrRefMemberChecker
   }
 
   void visitObjCDecl(const ObjCContainerDecl *CD) const {
+    if (BR->getSourceManager().isInSystemHeader(CD->getLocation()))
+      return;
     if (auto *ID = dyn_cast<ObjCInterfaceDecl>(CD)) {
       for (auto *Ivar : ID->ivars())
         visitIvarDecl(CD, Ivar);
@@ -133,6 +135,14 @@ class RawPtrRefMemberChecker
       std::optional<bool> IsCompatible = isPtrCompatible(QT, IvarCXXRD);
       if (IsCompatible && *IsCompatible)
         reportBug(Ivar, IvarType, IvarCXXRD, CD);
+    } else {
+      std::optional<bool> IsCompatible = isPtrCompatible(QT, nullptr);
+      auto *PointeeType = IvarType->getPointeeType().getTypePtrOrNull();
+      if (IsCompatible && *IsCompatible) {
+        auto *Desugared = PointeeType->getUnqualifiedDesugaredType();
+        if (auto *ObjCType = dyn_cast_or_null<ObjCInterfaceType>(Desugared))
+          reportBug(Ivar, IvarType, ObjCType->getDecl(), CD);
+      }
     }
   }
 
diff --git a/clang/test/Analysis/Checkers/WebKit/mock-system-header.h b/clang/test/Analysis/Checkers/WebKit/mock-system-header.h
index e993fd697ffab..b377f5098c002 100644
--- a/clang/test/Analysis/Checkers/WebKit/mock-system-header.h
+++ b/clang/test/Analysis/Checkers/WebKit/mock-system-header.h
@@ -29,3 +29,14 @@ enum os_log_type_t : uint8_t {
 typedef struct os_log_s *os_log_t;
 os_log_t os_log_create(const char *subsystem, const char *category);
 void os_log_msg(os_log_t oslog, os_log_type_t type, const char *msg, ...);
+
+typedef const struct __attribute__((objc_bridge(NSString))) __CFString * CFStringRef;
+
+#ifdef __OBJC__
+@class NSString;
+@interface SystemObject : NSObject {
+  NSString *ns_string;
+  CFStringRef cf_string;
+}
+@end
+#endif
diff --git a/clang/test/Analysis/Checkers/WebKit/unretained-members.mm b/clang/test/Analysis/Checkers/WebKit/unretained-members.mm
index e068a583c18c5..79f7a05caa1be 100644
--- a/clang/test/Analysis/Checkers/WebKit/unretained-members.mm
+++ b/clang/test/Analysis/Checkers/WebKit/unretained-members.mm
@@ -1,7 +1,8 @@
 // RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.NoUnretainedMemberChecker -verify %s
 
 #include "objc-mock-types.h"
-
+#include "mock-system-header.h"
+#if 0
 namespace members {
 
   struct Foo {
@@ -58,3 +59,12 @@ void forceTmplToInstantiate(FooTmpl<SomeObj, CFMutableArrayRef>) {}
 
   void forceTmplToInstantiate(RefPtr<SomeObj>) {}
 }
+#endif
+
+@interface AnotherObject : NSObject {
+  NSString *ns_string;
+  // expected-warning@-1{{Instance variable 'ns_string' in 'AnotherObject' is a raw pointer to retainable type 'NSString'; member variables must be a RetainPtr}}
+  CFStringRef cf_string;
+  // expected-warning@-1{{Instance variable 'cf_string' in 'AnotherObject' is a retainable type 'CFStringRef'; member variables must be a RetainPtr}}
+}
+@end

@llvmbot
Copy link
Member

llvmbot commented Mar 24, 2025

@llvm/pr-subscribers-clang

Author: Ryosuke Niwa (rniwa)

Changes

This PR fixes the bug that we weren't generating warnings when a raw poiner is used to point to a NS type in Objective-C ivars. Also fix the bug that we weren't suppressing this warning in system headers.


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

3 Files Affected:

  • (modified) clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefMemberChecker.cpp (+10)
  • (modified) clang/test/Analysis/Checkers/WebKit/mock-system-header.h (+11)
  • (modified) clang/test/Analysis/Checkers/WebKit/unretained-members.mm (+11-1)
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefMemberChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefMemberChecker.cpp
index dc4e2c7d168fb..6d20869043358 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefMemberChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefMemberChecker.cpp
@@ -111,6 +111,8 @@ class RawPtrRefMemberChecker
   }
 
   void visitObjCDecl(const ObjCContainerDecl *CD) const {
+    if (BR->getSourceManager().isInSystemHeader(CD->getLocation()))
+      return;
     if (auto *ID = dyn_cast<ObjCInterfaceDecl>(CD)) {
       for (auto *Ivar : ID->ivars())
         visitIvarDecl(CD, Ivar);
@@ -133,6 +135,14 @@ class RawPtrRefMemberChecker
       std::optional<bool> IsCompatible = isPtrCompatible(QT, IvarCXXRD);
       if (IsCompatible && *IsCompatible)
         reportBug(Ivar, IvarType, IvarCXXRD, CD);
+    } else {
+      std::optional<bool> IsCompatible = isPtrCompatible(QT, nullptr);
+      auto *PointeeType = IvarType->getPointeeType().getTypePtrOrNull();
+      if (IsCompatible && *IsCompatible) {
+        auto *Desugared = PointeeType->getUnqualifiedDesugaredType();
+        if (auto *ObjCType = dyn_cast_or_null<ObjCInterfaceType>(Desugared))
+          reportBug(Ivar, IvarType, ObjCType->getDecl(), CD);
+      }
     }
   }
 
diff --git a/clang/test/Analysis/Checkers/WebKit/mock-system-header.h b/clang/test/Analysis/Checkers/WebKit/mock-system-header.h
index e993fd697ffab..b377f5098c002 100644
--- a/clang/test/Analysis/Checkers/WebKit/mock-system-header.h
+++ b/clang/test/Analysis/Checkers/WebKit/mock-system-header.h
@@ -29,3 +29,14 @@ enum os_log_type_t : uint8_t {
 typedef struct os_log_s *os_log_t;
 os_log_t os_log_create(const char *subsystem, const char *category);
 void os_log_msg(os_log_t oslog, os_log_type_t type, const char *msg, ...);
+
+typedef const struct __attribute__((objc_bridge(NSString))) __CFString * CFStringRef;
+
+#ifdef __OBJC__
+@class NSString;
+@interface SystemObject : NSObject {
+  NSString *ns_string;
+  CFStringRef cf_string;
+}
+@end
+#endif
diff --git a/clang/test/Analysis/Checkers/WebKit/unretained-members.mm b/clang/test/Analysis/Checkers/WebKit/unretained-members.mm
index e068a583c18c5..79f7a05caa1be 100644
--- a/clang/test/Analysis/Checkers/WebKit/unretained-members.mm
+++ b/clang/test/Analysis/Checkers/WebKit/unretained-members.mm
@@ -1,7 +1,8 @@
 // RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.NoUnretainedMemberChecker -verify %s
 
 #include "objc-mock-types.h"
-
+#include "mock-system-header.h"
+#if 0
 namespace members {
 
   struct Foo {
@@ -58,3 +59,12 @@ void forceTmplToInstantiate(FooTmpl<SomeObj, CFMutableArrayRef>) {}
 
   void forceTmplToInstantiate(RefPtr<SomeObj>) {}
 }
+#endif
+
+@interface AnotherObject : NSObject {
+  NSString *ns_string;
+  // expected-warning@-1{{Instance variable 'ns_string' in 'AnotherObject' is a raw pointer to retainable type 'NSString'; member variables must be a RetainPtr}}
+  CFStringRef cf_string;
+  // expected-warning@-1{{Instance variable 'cf_string' in 'AnotherObject' is a retainable type 'CFStringRef'; member variables must be a RetainPtr}}
+}
+@end

CFStringRef cf_string;
// expected-warning@-1{{Instance variable 'cf_string' in 'AnotherObject' is a retainable type 'CFStringRef'; member variables must be a RetainPtr}}
}
@end
Copy link
Contributor

Choose a reason for hiding this comment

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

This is more of a question for my understanding: Do we expect the same behavior for raw pointers that are properties?

@interface AnotherObject : NSObject
@property(nonatomic,strong) NSString *prop_string;
@end

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think so.

Copy link
Contributor

Choose a reason for hiding this comment

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

Can we add a test case for properties?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Turns out I have to enumerate properties separately from ivars. Added a test with code fix.

Copy link
Contributor

@t-rasmud t-rasmud left a comment

Choose a reason for hiding this comment

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

LGTM!

@rniwa
Copy link
Contributor Author

rniwa commented Mar 28, 2025

Thanks for the review!

return;
if (auto *PropCXXRD = PropType->getPointeeCXXRecordDecl()) {
std::optional<bool> IsCompatible = isPtrCompatible(QT, PropCXXRD);
fprintf(stderr, "IsCompatible=%d\n", IsCompatible ? *IsCompatible : -1);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh oops, I forgot to remove this.

@rniwa rniwa merged commit 304b3c5 into llvm:main Mar 29, 2025
11 checks passed
@rniwa rniwa deleted the fix-RawPtrRefMemberChecker-retainable-ivar branch March 29, 2025 00:34
rniwa added a commit to rniwa/llvm-project that referenced this pull request Apr 22, 2025
…ive-C types in ivars. (llvm#132833)

This PR fixes the bug that we weren't generating warnings when a raw
poiner is used to point to a NS type in Objective-C ivars. Also fix the
bug that we weren't suppressing this warning in system headers.
rniwa added a commit to rniwa/llvm-project that referenced this pull request Aug 21, 2025
…ive-C types in ivars. (llvm#132833)

This PR fixes the bug that we weren't generating warnings when a raw
poiner is used to point to a NS type in Objective-C ivars. Also fix the
bug that we weren't suppressing this warning in system headers.
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