From a2659637d558a25e73bc5984cecc2dae3b84ef32 Mon Sep 17 00:00:00 2001 From: Ryosuke Niwa 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(E)) { + if (auto *Callee = call->getCalleeDecl()) { + if (Callee->hasAttr() || + Callee->hasAttr()) { + return callback(E, true); + } + } + if (auto *memberCall = dyn_cast(call)) { if (auto *decl = memberCall->getMethodDecl()) { std::optional 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 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