[clang] [WebKit checkers] Recognize NS_RETURNS_RETAINED and CF_RETURNS_RETAINED. (PR #157629)

Ryosuke Niwa via cfe-commits cfe-commits at lists.llvm.org
Thu Sep 11 13:01:18 PDT 2025


https://github.com/rniwa updated https://github.com/llvm/llvm-project/pull/157629

>From a2659637d558a25e73bc5984cecc2dae3b84ef32 Mon Sep 17 00:00:00 2001
From: Ryosuke Niwa <rniwa at webkit.org>
Date: Tue, 9 Sep 2025 02:06:03 -0700
Subject: [PATCH 1/2] [WebKit checkers] Recognize NS_RETURNS_RETAINED and
 CF_RETURNS_RETAINED.

This PR adds the support for treating a function return value to be safe
if the function is annotated with NS_RETURNS_RETAINED or CF_RETURNS_RETAINED.
---
 .../StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp   |  7 +++++++
 .../Checkers/WebKit/unretained-call-args.mm       | 14 ++++++++++++++
 .../Checkers/WebKit/unretained-local-vars.mm      | 15 +++++++++++++++
 3 files changed, 36 insertions(+)

diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp
index 478bd85177143..f43e5ac9af198 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp
@@ -91,6 +91,13 @@ bool tryToFindPtrOrigin(
       continue;
     }
     if (auto *call = dyn_cast<CallExpr>(E)) {
+      if (auto *Callee = call->getCalleeDecl()) {
+        if (Callee->hasAttr<CFReturnsRetainedAttr>() ||
+            Callee->hasAttr<NSReturnsRetainedAttr>()) {
+          return callback(E, true);
+        }
+      }
+
       if (auto *memberCall = dyn_cast<CXXMemberCallExpr>(call)) {
         if (auto *decl = memberCall->getMethodDecl()) {
           std::optional<bool> IsGetterOfRefCt = isGetterOfSafePtr(decl);
diff --git a/clang/test/Analysis/Checkers/WebKit/unretained-call-args.mm b/clang/test/Analysis/Checkers/WebKit/unretained-call-args.mm
index c69113c48806d..c44f209d80a4e 100644
--- a/clang/test/Analysis/Checkers/WebKit/unretained-call-args.mm
+++ b/clang/test/Analysis/Checkers/WebKit/unretained-call-args.mm
@@ -438,6 +438,20 @@ void use_const_local() {
 
 } // namespace const_global
 
+namespace ns_retained_return_value {
+
+NSString *provideNS() NS_RETURNS_RETAINED;
+CFDictionaryRef provideCF() CF_RETURNS_RETAINED;
+void consumeNS(NSString *);
+void consumeCF(CFDictionaryRef);
+
+void foo() {
+  consumeNS(provideNS());
+  consumeCF(provideCF());
+}
+
+} // namespace ns_retained_return_value
+
 @interface TestObject : NSObject
 - (void)doWork:(NSString *)msg, ...;
 - (void)doWorkOnSelf;
diff --git a/clang/test/Analysis/Checkers/WebKit/unretained-local-vars.mm b/clang/test/Analysis/Checkers/WebKit/unretained-local-vars.mm
index 10f7c9acb7a3c..0ad8f707e254c 100644
--- a/clang/test/Analysis/Checkers/WebKit/unretained-local-vars.mm
+++ b/clang/test/Analysis/Checkers/WebKit/unretained-local-vars.mm
@@ -408,6 +408,21 @@ void use_const_local() {
 
 } // namespace const_global
 
+namespace ns_retained_return_value {
+
+NSString *provideNS() NS_RETURNS_RETAINED;
+CFDictionaryRef provideCF() CF_RETURNS_RETAINED;
+void consumeNS(NSString *);
+void consumeCF(CFDictionaryRef);
+
+unsigned foo() {
+  auto *string = provideNS();
+  auto *dictionary = provideCF();
+  return string.length + CFDictionaryGetCount(dictionary);
+}
+
+} // namespace ns_retained_return_value
+
 bool doMoreWorkOpaque(OtherObj*);
 SomeObj* provide();
 

>From 6ad221ada85fd59427a08e22b1db763fa604534e Mon Sep 17 00:00:00 2001
From: Ryosuke Niwa <rniwa at webkit.org>
Date: Thu, 11 Sep 2025 13:00:05 -0700
Subject: [PATCH 2/2] Add a test case per review comment. Define a function
 which returns a retained value in a base class and call that in a derived
 class

---
 .../Analysis/Checkers/WebKit/unretained-call-args.mm | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/clang/test/Analysis/Checkers/WebKit/unretained-call-args.mm b/clang/test/Analysis/Checkers/WebKit/unretained-call-args.mm
index c44f209d80a4e..d1d2e511cad19 100644
--- a/clang/test/Analysis/Checkers/WebKit/unretained-call-args.mm
+++ b/clang/test/Analysis/Checkers/WebKit/unretained-call-args.mm
@@ -450,6 +450,18 @@ void foo() {
   consumeCF(provideCF());
 }
 
+struct Base {
+  NSString *provideStr() NS_RETURNS_RETAINED;
+};
+
+struct Derived : Base {
+  void consumeStr(NSString *);
+
+  void foo() {
+    consumeStr(provideStr());
+  }
+};
+
 } // namespace ns_retained_return_value
 
 @interface TestObject : NSObject



More information about the cfe-commits mailing list