[clang] [alpha.webkit.RetainPtrCtorAdoptChecker] Don't treat assignment to an +1 out argument as a leak (PR #161633)
Ryosuke Niwa via cfe-commits
cfe-commits at lists.llvm.org
Mon Dec 8 16:54:10 PST 2025
https://github.com/rniwa updated https://github.com/llvm/llvm-project/pull/161633
>From 35ae9ac455dac75db1745984dc740cf276a9dcc8 Mon Sep 17 00:00:00 2001
From: Ryosuke Niwa <rniwa at webkit.org>
Date: Wed, 1 Oct 2025 23:41:54 -0700
Subject: [PATCH 1/2] [alpha.webkit.RetainPtrCtorAdoptChecker] Don't treat
assignment to an +1 out argument as a leak
Make RetainPtrCtorAdoptChecker recognize an assignment to an +1 out argument so that it won't
emit a memory leak warning.
---
.../WebKit/RetainPtrCtorAdoptChecker.cpp | 30 ++++++++++++++-----
.../WebKit/retain-ptr-ctor-adopt-use.mm | 8 +++++
2 files changed, 31 insertions(+), 7 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/RetainPtrCtorAdoptChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/RetainPtrCtorAdoptChecker.cpp
index e1f9a77f5a5ca..7440352d8482d 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/RetainPtrCtorAdoptChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/RetainPtrCtorAdoptChecker.cpp
@@ -355,14 +355,30 @@ class RetainPtrCtorAdoptChecker
void visitBinaryOperator(const BinaryOperator *BO) const {
if (!BO->isAssignmentOp())
return;
- if (!isa<ObjCIvarRefExpr>(BO->getLHS()))
- return;
+ auto *LHS = BO->getLHS();
auto *RHS = BO->getRHS()->IgnoreParenCasts();
- const Expr *Inner = nullptr;
- if (isAllocInit(RHS, &Inner)) {
- CreateOrCopyFnCall.insert(RHS);
- if (Inner)
- CreateOrCopyFnCall.insert(Inner);
+ if (isa<ObjCIvarRefExpr>(LHS)) {
+ const Expr *Inner = nullptr;
+ if (isAllocInit(RHS, &Inner)) {
+ CreateOrCopyFnCall.insert(RHS);
+ if (Inner)
+ CreateOrCopyFnCall.insert(Inner);
+ }
+ return;
+ } else if (auto *UO = dyn_cast<UnaryOperator>(LHS)) {
+ auto OpCode = UO->getOpcode();
+ if (OpCode == UO_Deref) {
+ if (auto *DerefTarget = UO->getSubExpr()) {
+ DerefTarget = DerefTarget->IgnoreParenCasts();
+ auto *DRE = dyn_cast<DeclRefExpr>(DerefTarget);
+ if (auto *Decl = DRE->getDecl()) {
+ if (!isa<ParmVarDecl>(Decl) || !isCreateOrCopy(RHS))
+ return;
+ if (Decl->hasAttr<CFReturnsRetainedAttr>())
+ CreateOrCopyFnCall.insert(RHS);
+ }
+ }
+ }
}
}
diff --git a/clang/test/Analysis/Checkers/WebKit/retain-ptr-ctor-adopt-use.mm b/clang/test/Analysis/Checkers/WebKit/retain-ptr-ctor-adopt-use.mm
index 769901778cdf0..3b0f19404097b 100644
--- a/clang/test/Analysis/Checkers/WebKit/retain-ptr-ctor-adopt-use.mm
+++ b/clang/test/Analysis/Checkers/WebKit/retain-ptr-ctor-adopt-use.mm
@@ -182,6 +182,14 @@ void adopt_retainptr() {
auto bar = adoptNS([allocSomeObj() init]);
}
+CFTypeRef make_cf_obj() CF_RETURNS_RETAINED {
+ return CFArrayCreateMutable(kCFAllocatorDefault, 1);
+}
+
+void get_cf_obj(CFTypeRef* CF_RETURNS_RETAINED result) {
+ *result = CFArrayCreateMutable(kCFAllocatorDefault, 1);
+}
+
RetainPtr<CFArrayRef> return_arg(CFArrayRef arg) {
return arg;
}
>From e7bff0869f8981eef6ae1fb4b3f3985e1ce9aed9 Mon Sep 17 00:00:00 2001
From: Ryosuke Niwa <rniwa at webkit.org>
Date: Mon, 8 Dec 2025 16:53:52 -0800
Subject: [PATCH 2/2] Address the review comment. Also turn nested ifs to early
exits.
---
.../WebKit/RetainPtrCtorAdoptChecker.cpp | 34 +++++++++++--------
1 file changed, 20 insertions(+), 14 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/RetainPtrCtorAdoptChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/RetainPtrCtorAdoptChecker.cpp
index 7440352d8482d..d98df2117739e 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/RetainPtrCtorAdoptChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/RetainPtrCtorAdoptChecker.cpp
@@ -365,21 +365,27 @@ class RetainPtrCtorAdoptChecker
CreateOrCopyFnCall.insert(Inner);
}
return;
- } else if (auto *UO = dyn_cast<UnaryOperator>(LHS)) {
- auto OpCode = UO->getOpcode();
- if (OpCode == UO_Deref) {
- if (auto *DerefTarget = UO->getSubExpr()) {
- DerefTarget = DerefTarget->IgnoreParenCasts();
- auto *DRE = dyn_cast<DeclRefExpr>(DerefTarget);
- if (auto *Decl = DRE->getDecl()) {
- if (!isa<ParmVarDecl>(Decl) || !isCreateOrCopy(RHS))
- return;
- if (Decl->hasAttr<CFReturnsRetainedAttr>())
- CreateOrCopyFnCall.insert(RHS);
- }
- }
- }
}
+ auto *UO = dyn_cast<UnaryOperator>(LHS);
+ if (!UO)
+ return;
+ auto OpCode = UO->getOpcode();
+ if (OpCode != UO_Deref)
+ return;
+ auto *DerefTarget = UO->getSubExpr();
+ if (!DerefTarget)
+ return;
+ DerefTarget = DerefTarget->IgnoreParenCasts();
+ auto *DRE = dyn_cast<DeclRefExpr>(DerefTarget);
+ if (!DRE)
+ return;
+ auto *Decl = DRE->getDecl();
+ if (!Decl)
+ return;
+ if (!isa<ParmVarDecl>(Decl) || !isCreateOrCopy(RHS))
+ return;
+ if (Decl->hasAttr<CFReturnsRetainedAttr>())
+ CreateOrCopyFnCall.insert(RHS);
}
void visitReturnStmt(const ReturnStmt *RS, const Decl *DeclWithIssue) const {
More information about the cfe-commits
mailing list