Skip to content

[alpha.webkit.RetainPtrCtorAdoptChecker] An assortment of small enhancements #135329

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged

Conversation

rniwa
Copy link
Contributor

@rniwa rniwa commented Apr 11, 2025

This PR implements various small enhancements to alpha.webkit.RetainPtrCtorAdoptChecker:

  • Detect leaks from [[X alloc] init] when ARC is disabled.
  • Detect leaks from calling Create, Copy, and other +1 CF functions.
  • Recognize [allocX() init] pattern where allocX is a C/C++ function.
  • Recognize _init in addition to init as an init function.
  • Recognize [[[X alloc] init] autorelease].
  • Recognize CFBridgingRelease.
  • Support CF_RETRUNS_RETAINED on out arguments of a C function.
  • Support returning +1 object in Create, Copy, and other +1 functions or +1 selectors.
  • Support variadic Create, Copy, and other +1 C/C++ functions.

To make these enhancements, this PR introduces new visit functions for ObjCMessageExpr, ReturnStmt, VarDecl, and BinaryOperator. These functions look for a specific construct mentioned above and adds an expression such as [[X alloc] init] or CreateX to a DenseSet CreateOrCopyFnCall when the expression does not result in leaks. When the code to detect leaks such as the one in visitObjCMessageExpr later encounters this expression, it can bail out early if the expression is in the set.

…cements

This PR implements various small enhancements to alpha.webkit.RetainPtrCtorAdoptChecker:
 - Detect leaks from [[X alloc] init] when ARC is disabled.
 - Detect leaks from calling Create, Copy, and other +1 CF functions.
 - Recognize [allocX() init] pattern where allocX is a C/C++ function.
 - Recognize _init in addition to init as an init function.
 - Recognize [[[X alloc] init] autorelease].
 - Recognize CFBridgingRelease.
 - Support CF_RETRUNS_RETAINED on out arguments of a C function.
 - Support returning +1 object in Create, Copy, and other +1 functions or +1 selectors.
 - Support variadic Create, Copy, and other +1 C/C++ functions.

To make these enhancements, this PR introduces new visit functions for ObjCMessageExpr,
ReturnStmt, VarDecl, and BinaryOperator. These functions look for a specific construct
mentioned above and adds an expression such as [[X alloc] init] or CreateX to a DenseSet
CreateOrCopyFnCall when the expression does not result in leaks. When the code to detect
leaks such as the one in visitObjCMessageExpr later encounters this expression, it can
bail out early if the expression is in the set.
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:static analyzer labels Apr 11, 2025
@llvmbot
Copy link
Member

llvmbot commented Apr 11, 2025

@llvm/pr-subscribers-clang

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

Author: Ryosuke Niwa (rniwa)

Changes

This PR implements various small enhancements to alpha.webkit.RetainPtrCtorAdoptChecker:

  • Detect leaks from [[X alloc] init] when ARC is disabled.
  • Detect leaks from calling Create, Copy, and other +1 CF functions.
  • Recognize [allocX() init] pattern where allocX is a C/C++ function.
  • Recognize _init in addition to init as an init function.
  • Recognize [[[X alloc] init] autorelease].
  • Recognize CFBridgingRelease.
  • Support CF_RETRUNS_RETAINED on out arguments of a C function.
  • Support returning +1 object in Create, Copy, and other +1 functions or +1 selectors.
  • Support variadic Create, Copy, and other +1 C/C++ functions.

To make these enhancements, this PR introduces new visit functions for ObjCMessageExpr, ReturnStmt, VarDecl, and BinaryOperator. These functions look for a specific construct mentioned above and adds an expression such as [[X alloc] init] or CreateX to a DenseSet CreateOrCopyFnCall when the expression does not result in leaks. When the code to detect leaks such as the one in visitObjCMessageExpr later encounters this expression, it can bail out early if the expression is in the set.


Patch is 30.52 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/135329.diff

4 Files Affected:

  • (modified) clang/lib/StaticAnalyzer/Checkers/WebKit/RetainPtrCtorAdoptChecker.cpp (+243-32)
  • (modified) clang/test/Analysis/Checkers/WebKit/objc-mock-types.h (+9-1)
  • (modified) clang/test/Analysis/Checkers/WebKit/retain-ptr-ctor-adopt-use-arc.mm (+193-2)
  • (modified) clang/test/Analysis/Checkers/WebKit/retain-ptr-ctor-adopt-use.mm (+203-1)
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/RetainPtrCtorAdoptChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/RetainPtrCtorAdoptChecker.cpp
index d372c5d1ba626..348dc9752f8dc 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/RetainPtrCtorAdoptChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/RetainPtrCtorAdoptChecker.cpp
@@ -12,6 +12,7 @@
 #include "clang/AST/CXXInheritance.h"
 #include "clang/AST/RecursiveASTVisitor.h"
 #include "clang/AST/StmtVisitor.h"
+#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
 #include "clang/Analysis/RetainSummaryManager.h"
 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
@@ -90,6 +91,26 @@ class RetainPtrCtorAdoptChecker
         Checker->visitConstructExpr(CE, DeclWithIssue);
         return true;
       }
+
+      bool VisitObjCMessageExpr(const ObjCMessageExpr *ObjCMsgExpr) {
+        Checker->visitObjCMessageExpr(ObjCMsgExpr, DeclWithIssue);
+        return true;
+      }
+
+      bool VisitReturnStmt(const ReturnStmt *RS) {
+        Checker->visitReturnStmt(RS, DeclWithIssue);
+        return true;
+      }
+
+      bool VisitVarDecl(const VarDecl *VD) {
+        Checker->visitVarDecl(VD);
+        return true;
+      }
+
+      bool VisitBinaryOperator(const BinaryOperator *BO) {
+        Checker->visitBinaryOperator(BO);
+        return true;
+      }
     };
 
     LocalVisitor visitor(this);
@@ -101,13 +122,14 @@ class RetainPtrCtorAdoptChecker
   }
 
   bool isAdoptFn(const Decl *FnDecl) const {
-    auto Name = safeGetName(FnDecl);
-    return Name == "adoptNS" || Name == "adoptCF" || Name == "adoptNSArc" ||
-           Name == "adoptCFArc";
+    return isAdoptFnName(safeGetName(FnDecl));
   }
 
-  bool isAdoptNS(const Decl *FnDecl) const {
-    auto Name = safeGetName(FnDecl);
+  bool isAdoptFnName(const std::string& Name) const {
+    return isAdoptNS(Name) || Name == "adoptCF" || Name == "adoptCFArc";
+  }
+
+  bool isAdoptNS(const std::string& Name) const {
     return Name == "adoptNS" || Name == "adoptNSArc";
   }
 
@@ -116,44 +138,104 @@ class RetainPtrCtorAdoptChecker
     if (BR->getSourceManager().isInSystemHeader(CE->getExprLoc()))
       return;
 
-    auto *F = CE->getDirectCallee();
-    if (!F)
+    std::string FnName;
+    if (auto *F = CE->getDirectCallee()) {
+      FnName = safeGetName(F);
+      if (isAdoptFnName(FnName))
+        checkAdoptCall(CE, FnName, DeclWithIssue);
+      else {
+        checkCreateOrCopyFunction(CE, DeclWithIssue);
+        checkBridgingRelease(CE, F, DeclWithIssue);
+      }
       return;
+    }
 
-    if (!isAdoptFn(F) || !CE->getNumArgs()) {
-      checkCreateOrCopyFunction(CE, F, DeclWithIssue);
+    auto *CalleeExpr = CE->getCallee();
+    if (!CalleeExpr)
       return;
+    CalleeExpr = CalleeExpr->IgnoreParenCasts();
+    if (auto *UnresolvedExpr = dyn_cast<UnresolvedLookupExpr>(CalleeExpr)) {
+      auto Name = UnresolvedExpr->getName();
+      if (!Name.isIdentifier())
+        return;
+      FnName = Name.getAsString();
+      if (isAdoptFnName(FnName))
+        checkAdoptCall(CE, FnName, DeclWithIssue);
     }
+    checkCreateOrCopyFunction(CE, DeclWithIssue);
+  }
+
+  void checkAdoptCall(const CallExpr *CE, const std::string& FnName,
+                      const Decl *DeclWithIssue) const {
+    if (!CE->getNumArgs())
+      return;
 
     auto *Arg = CE->getArg(0)->IgnoreParenCasts();
     auto Result = isOwned(Arg);
-    auto Name = safeGetName(F);
     if (Result == IsOwnedResult::Unknown)
       Result = IsOwnedResult::NotOwned;
-    if (isAllocInit(Arg) || isCreateOrCopy(Arg)) {
+
+    const Expr *Inner = nullptr;
+    if (isAllocInit(Arg, &Inner) || isCreateOrCopy(Arg)) {
+      if (Inner)
+        CreateOrCopyFnCall.insert(Inner);
       CreateOrCopyFnCall.insert(Arg); // Avoid double reporting.
       return;
     }
-    if (Result == IsOwnedResult::Owned || Result == IsOwnedResult::Skip)
+    if (Result == IsOwnedResult::Owned || Result == IsOwnedResult::Skip) {
+      CreateOrCopyFnCall.insert(Arg);
       return;
+    }
 
     if (auto *DRE = dyn_cast<DeclRefExpr>(Arg)) {
       if (CreateOrCopyOutArguments.contains(DRE->getDecl()))
         return;
     }
-    if (RTC.isARCEnabled() && isAdoptNS(F))
-      reportUseAfterFree(Name, CE, DeclWithIssue, "when ARC is disabled");
+    if (RTC.isARCEnabled() && isAdoptFnName(FnName))
+      reportUseAfterFree(FnName, CE, DeclWithIssue, "when ARC is disabled");
     else
-      reportUseAfterFree(Name, CE, DeclWithIssue);
+      reportUseAfterFree(FnName, CE, DeclWithIssue);
   }
 
-  void checkCreateOrCopyFunction(const CallExpr *CE, const FunctionDecl *Callee,
-                                 const Decl *DeclWithIssue) const {
-    if (!isCreateOrCopyFunction(Callee))
+  void visitObjCMessageExpr(const ObjCMessageExpr *ObjCMsgExpr,
+                            const Decl *DeclWithIssue) const {
+    if (BR->getSourceManager().isInSystemHeader(ObjCMsgExpr->getExprLoc()))
       return;
 
-    bool hasOutArgument = false;
+    auto Selector = ObjCMsgExpr->getSelector();
+    if (Selector.getAsString() == "autorelease") {
+      auto *Receiver = ObjCMsgExpr->getInstanceReceiver()->IgnoreParenCasts();
+      if (!Receiver)
+        return;
+      ObjCMsgExpr = dyn_cast<ObjCMessageExpr>(Receiver);
+      if (!ObjCMsgExpr)
+        return;
+      const Expr *Inner = nullptr;
+      if (!isAllocInit(ObjCMsgExpr, &Inner))
+        return;
+      CreateOrCopyFnCall.insert(ObjCMsgExpr);
+      if (Inner)
+        CreateOrCopyFnCall.insert(Inner);
+      return;
+    }
+
+    const Expr *Inner = nullptr;
+    if (!isAllocInit(ObjCMsgExpr, &Inner))
+      return;
+    if (RTC.isARCEnabled())
+      return; // ARC never leaks.
+    if (CreateOrCopyFnCall.contains(ObjCMsgExpr))
+      return;
+    if (Inner)
+      CreateOrCopyFnCall.insert(Inner); // Avoid double reporting.
+    reportLeak(ObjCMsgExpr, DeclWithIssue);
+  }
+
+  void checkCreateOrCopyFunction(const CallExpr *CE,
+                                 const Decl *DeclWithIssue) const {
     unsigned ArgCount = CE->getNumArgs();
+    auto *CalleeDecl = CE->getCalleeDecl();
+    auto *FnDecl = CalleeDecl ? CalleeDecl->getAsFunction() : nullptr;
     for (unsigned ArgIndex = 0; ArgIndex < ArgCount; ++ArgIndex) {
       auto *Arg = CE->getArg(ArgIndex)->IgnoreParenCasts();
       auto *Unary = dyn_cast<UnaryOperator>(Arg);
@@ -170,13 +252,45 @@ class RetainPtrCtorAdoptChecker
       auto *Decl = DRE->getDecl();
       if (!Decl)
         continue;
-      CreateOrCopyOutArguments.insert(Decl);
-      hasOutArgument = true;
+      if (FnDecl && ArgIndex < FnDecl->getNumParams()) {
+        // Manually check attributes on argumenet since RetainSummaryManager
+        // basically ignores CF_RETRUNS_RETAINED on out arguments.
+        auto *ParamDecl = FnDecl->getParamDecl(ArgIndex);
+        if (ParamDecl->hasAttr<CFReturnsRetainedAttr>())
+          CreateOrCopyOutArguments.insert(Decl);
+      } else {
+        // No callee or a variadic argument. Conservatively assume it's an out argument.
+        if (RTC.isUnretained(Decl->getType()))
+          CreateOrCopyOutArguments.insert(Decl);
+      }
     }
-    if (!RTC.isUnretained(Callee->getReturnType()))
+    auto Summary = Summaries->getSummary(AnyCall(CE));
+    switch (Summary->getRetEffect().getKind()) {
+      case RetEffect::OwnedSymbol:
+      case RetEffect::OwnedWhenTrackedReceiver:
+        if (!CreateOrCopyFnCall.contains(CE))
+          reportLeak(CE, DeclWithIssue);
+        break;
+      default:
+        break;
+    }
+  }
+
+  void checkBridgingRelease(const CallExpr *CE, const FunctionDecl *Callee,
+                            const Decl *DeclWithIssue) const {
+    if (safeGetName(Callee) != "CFBridgingRelease" || CE->getNumArgs() != 1)
+      return;
+
+    auto *Arg = CE->getArg(0)->IgnoreParenCasts();
+    auto *InnerCE = dyn_cast<CallExpr>(Arg);
+    if (!InnerCE)
+      return;
+
+    auto *InnerF = InnerCE->getDirectCallee();
+    if (!InnerF || !isCreateOrCopyFunction(InnerF))
       return;
-    if (!hasOutArgument && !CreateOrCopyFnCall.contains(CE))
-      reportLeak(CE, DeclWithIssue);
+
+    CreateOrCopyFnCall.insert(InnerCE);
   }
 
   void visitConstructExpr(const CXXConstructExpr *CE,
@@ -207,6 +321,13 @@ class RetainPtrCtorAdoptChecker
     if (isCreateOrCopy(Arg))
       CreateOrCopyFnCall.insert(Arg); // Avoid double reporting.
 
+    const Expr *Inner = nullptr;
+    if (isAllocInit(Arg, &Inner)) {
+      CreateOrCopyFnCall.insert(Arg);
+      if (Inner)
+        CreateOrCopyFnCall.insert(Inner);
+    }
+
     if (Result == IsOwnedResult::Skip)
       return;
 
@@ -219,13 +340,95 @@ class RetainPtrCtorAdoptChecker
     else if (isCreateOrCopy(Arg))
       reportLeak(Name, CE, DeclWithIssue);
   }
+  
+  void visitVarDecl(const VarDecl *VD) const {
+    auto *Init = VD->getInit();
+    if (!Init || !RTC.isARCEnabled())
+      return;
+    Init = Init->IgnoreParenCasts();
+    const Expr *Inner = nullptr;
+    if (isAllocInit(Init, &Inner)) {
+      CreateOrCopyFnCall.insert(Init);
+      if (Inner)
+        CreateOrCopyFnCall.insert(Inner);
+    }
+  }
 
-  bool isAllocInit(const Expr *E) const {
+  void visitBinaryOperator(const BinaryOperator *BO) const {
+    if (!BO->isAssignmentOp())
+      return;
+    if (!isa<ObjCIvarRefExpr>(BO->getLHS()))
+      return;
+    auto *RHS = BO->getRHS()->IgnoreParenCasts();
+    const Expr *Inner = nullptr;
+    if (isAllocInit(RHS, &Inner)) {
+      CreateOrCopyFnCall.insert(RHS);
+      if (Inner)
+        CreateOrCopyFnCall.insert(Inner);
+    }
+  }
+
+  void visitReturnStmt(const ReturnStmt *RS, const Decl *DeclWithIssue) const {
+    if (!DeclWithIssue)
+      return;
+    auto *RetValue = RS->getRetValue();
+    if (!RetValue)
+      return;
+    RetValue = RetValue->IgnoreParenCasts();
+    std::optional<bool> retainsRet;
+    if (auto *FnDecl = dyn_cast<FunctionDecl>(DeclWithIssue))
+      retainsRet = retainsReturnValue(FnDecl);
+    else if (auto *MethodDecl = dyn_cast<ObjCMethodDecl>(DeclWithIssue))
+      retainsRet = retainsReturnValue(MethodDecl);
+    else
+      return;
+    if (!retainsRet || !*retainsRet) {
+      // Under ARC, returning [[X alloc] init] doesn't leak X.
+      if (RTC.isUnretained(RetValue->getType()))
+        return;
+    }
+    if (auto *CE = dyn_cast<CallExpr>(RetValue)) {
+      auto *Callee = CE->getDirectCallee();
+      if (!Callee || !isCreateOrCopyFunction(Callee))
+        return;
+      CreateOrCopyFnCall.insert(CE);
+      return;
+    }
+    const Expr *Inner = nullptr;
+    if (isAllocInit(RetValue, &Inner)) {
+      CreateOrCopyFnCall.insert(RetValue);
+      if (Inner)
+        CreateOrCopyFnCall.insert(Inner);
+    }
+  }
+
+  template <typename CallableType>
+  std::optional<bool> retainsReturnValue(const CallableType *FnDecl) const {
+    auto Summary = Summaries->getSummary(AnyCall(FnDecl));
+    auto RetEffect = Summary->getRetEffect();
+    switch (RetEffect.getKind()) {
+    case RetEffect::NoRet:
+      return std::nullopt;
+    case RetEffect::OwnedSymbol:
+      return true;
+    case RetEffect::NotOwnedSymbol:
+      return false;
+    case RetEffect::OwnedWhenTrackedReceiver:
+      return std::nullopt;
+    case RetEffect::NoRetHard:
+      return std::nullopt;
+    }
+    return std::nullopt;
+  }
+
+  bool isAllocInit(const Expr *E, const Expr **InnerExpr = nullptr) const {
     auto *ObjCMsgExpr = dyn_cast<ObjCMessageExpr>(E);
     if (auto *POE = dyn_cast<PseudoObjectExpr>(E)) {
       if (unsigned ExprCount = POE->getNumSemanticExprs()) {
         auto *Expr = POE->getSemanticExpr(ExprCount - 1)->IgnoreParenCasts();
         ObjCMsgExpr = dyn_cast<ObjCMessageExpr>(Expr);
+        if (InnerExpr)
+          *InnerExpr = ObjCMsgExpr;
       }
     }
     if (!ObjCMsgExpr)
@@ -235,17 +438,22 @@ class RetainPtrCtorAdoptChecker
     if (NameForFirstSlot == "alloc" || NameForFirstSlot.starts_with("copy") ||
         NameForFirstSlot.starts_with("mutableCopy"))
       return true;
-    if (!NameForFirstSlot.starts_with("init"))
+    if (!NameForFirstSlot.starts_with("init") &&
+        !NameForFirstSlot.starts_with("_init"))
       return false;
     if (!ObjCMsgExpr->isInstanceMessage())
       return false;
     auto *Receiver = ObjCMsgExpr->getInstanceReceiver()->IgnoreParenCasts();
     if (!Receiver)
       return false;
-    if (auto *InnerObjCMsgExpr = dyn_cast<ObjCMessageExpr>(Receiver)) {
-      auto InnerSelector = InnerObjCMsgExpr->getSelector();
+  if (auto *Inner = dyn_cast<ObjCMessageExpr>(Receiver)) {
+      if (InnerExpr)
+        *InnerExpr = Inner;
+      auto InnerSelector = Inner->getSelector();
       return InnerSelector.getNameForSlot(0) == "alloc";
     } else if (auto *CE = dyn_cast<CallExpr>(Receiver)) {
+      if (InnerExpr)
+        *InnerExpr = CE;
       if (auto *Callee = CE->getDirectCallee()) {
         auto CalleeName = Callee->getName();
         return CalleeName.starts_with("alloc");
@@ -354,6 +562,8 @@ class RetainPtrCtorAdoptChecker
         } else if (auto *CalleeExpr = CE->getCallee()) {
           if (isa<CXXDependentScopeMemberExpr>(CalleeExpr))
             return IsOwnedResult::Skip; // Wait for instantiation.
+          if (isa<UnresolvedLookupExpr>(CalleeExpr))
+            return IsOwnedResult::Skip; // Wait for instantiation.
         }
         auto Summary = Summaries->getSummary(AnyCall(CE));
         auto RetEffect = Summary->getRetEffect();
@@ -375,7 +585,7 @@ class RetainPtrCtorAdoptChecker
     return IsOwnedResult::Unknown;
   }
 
-  void reportUseAfterFree(std::string &Name, const CallExpr *CE,
+  void reportUseAfterFree(const std::string &Name, const CallExpr *CE,
                           const Decl *DeclWithIssue,
                           const char *condition = nullptr) const {
     SmallString<100> Buf;
@@ -417,16 +627,17 @@ class RetainPtrCtorAdoptChecker
     BR->emitReport(std::move(Report));
   }
 
-  void reportLeak(const CallExpr *CE, const Decl *DeclWithIssue) const {
+  template <typename ExprType>
+  void reportLeak(const ExprType *E, const Decl *DeclWithIssue) const {
     SmallString<100> Buf;
     llvm::raw_svector_ostream Os(Buf);
 
     Os << "The return value is +1 and results in a memory leak.";
 
-    PathDiagnosticLocation BSLoc(CE->getSourceRange().getBegin(),
+    PathDiagnosticLocation BSLoc(E->getSourceRange().getBegin(),
                                  BR->getSourceManager());
     auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
-    Report->addRange(CE->getSourceRange());
+    Report->addRange(E->getSourceRange());
     Report->setDeclWithIssue(DeclWithIssue);
     BR->emitReport(std::move(Report));
   }
diff --git a/clang/test/Analysis/Checkers/WebKit/objc-mock-types.h b/clang/test/Analysis/Checkers/WebKit/objc-mock-types.h
index 3f075ca0a6e5b..7700400be72cc 100644
--- a/clang/test/Analysis/Checkers/WebKit/objc-mock-types.h
+++ b/clang/test/Analysis/Checkers/WebKit/objc-mock-types.h
@@ -60,7 +60,7 @@ typedef struct CF_BRIDGED_TYPE(id) __CVBuffer *CVBufferRef;
 typedef CVBufferRef CVImageBufferRef;
 typedef CVImageBufferRef CVPixelBufferRef;
 typedef signed int CVReturn;
-CVReturn CVPixelBufferCreateWithIOSurface(CFAllocatorRef allocator, IOSurfaceRef surface, CFDictionaryRef pixelBufferAttributes, CVPixelBufferRef * pixelBufferOut);
+CVReturn CVPixelBufferCreateWithIOSurface(CFAllocatorRef allocator, IOSurfaceRef surface, CFDictionaryRef pixelBufferAttributes, CF_RETURNS_RETAINED CVPixelBufferRef * pixelBufferOut);
 
 CFRunLoopRef CFRunLoopGetCurrent(void);
 CFRunLoopRef CFRunLoopGetMain(void);
@@ -69,6 +69,12 @@ extern void CFRelease(CFTypeRef cf);
 #define CFSTR(cStr) ((CFStringRef) __builtin___CFStringMakeConstantString ("" cStr ""))
 extern Class NSClassFromString(NSString *aClassName);
 
+#if __has_feature(objc_arc)
+id CFBridgingRelease(CFTypeRef X) {
+    return (__bridge_transfer id)X;
+}
+#endif
+
 __attribute__((objc_root_class))
 @interface NSObject
 + (instancetype) alloc;
@@ -129,11 +135,13 @@ __attribute__((objc_root_class))
 
 @interface NSNumber : NSValue
 - (char)charValue;
+- (int)intValue;
 - (id)initWithInt:(int)value;
 + (NSNumber *)numberWithInt:(int)value;
 @end
 
 @interface SomeObj : NSObject
+- (instancetype)_init;
 - (SomeObj *)mutableCopy;
 - (SomeObj *)copyWithValue:(int)value;
 - (void)doWork;
diff --git a/clang/test/Analysis/Checkers/WebKit/retain-ptr-ctor-adopt-use-arc.mm b/clang/test/Analysis/Checkers/WebKit/retain-ptr-ctor-adopt-use-arc.mm
index 45db0506ae5f2..47203cbd27355 100644
--- a/clang/test/Analysis/Checkers/WebKit/retain-ptr-ctor-adopt-use-arc.mm
+++ b/clang/test/Analysis/Checkers/WebKit/retain-ptr-ctor-adopt-use-arc.mm
@@ -27,13 +27,78 @@ void basic_wrong() {
   RetainPtr<CFMutableArrayRef> cf1 = CFArrayCreateMutable(kCFAllocatorDefault, 10);
   // expected-warning@-1{{Incorrect use of RetainPtr constructor. The argument is +1 and results in a memory leak [alpha.webkit.RetainPtrCtorAdoptChecker]}}
   RetainPtr<CFMutableArrayRef> cf2 = adoptCF(provide_cf());
-  // expected-warning@-1{{Incorrect use of adoptCF. The argument is +0 and results in an use-after-free [alpha.webkit.RetainPtrCtorAdoptChecker]}}
+  // expected-warning@-1{{Incorrect use of adoptCF. The argument is +0 and results in an use-after-free when ARC is disabled [alpha.webkit.RetainPtrCtorAdoptChecker]}}
   RetainPtr<CFTypeRef> cf3 = SecTaskCreateFromSelf(kCFAllocatorDefault);
   // expected-warning@-1{{Incorrect use of RetainPtr constructor. The argument is +1 and results in a memory leak [alpha.webkit.RetainPtrCtorAdoptChecker]}}
   CFCopyArray(cf1);
   // expected-warning@-1{{The return value is +1 and results in a memory leak [alpha.webkit.RetainPtrCtorAdoptChecker]}}
 }
 
+void basic_correct_arc() {
+  auto *obj = [[SomeObj alloc] init];
+  [obj doWork];
+}
+
+@implementation SomeObj {
+  NSNumber *_number;
+  SomeObj *_next;
+  SomeObj *_other;
+}
+
+- (instancetype)_init {
+  self = [super init];
+  _number = nil;
+  _next = nil;
+  _other = nil;
+  return self;
+}
+
+- (SomeObj *)mutableCopy {
+  auto *copy = [[SomeObj alloc] init];
+  [copy setValue:_number];
+  [copy setNext:_next];
+  [copy setOther:_other];
+  return copy;
+}
+
+- (SomeObj *)copyWithValue:(int)value {
+  auto *copy = [[SomeObj alloc] init];
+  [copy setValue:_number];
+  [copy setNext:_next];
+  [copy setOther:_other];
+  return copy;
+}
+
+- (void)doWork {
+  _number = [[NSNumber alloc] initWithInt:5];
+}
+
+- (SomeObj *)other {
+  return _other;
+}
+
+- (void)setOther:(SomeObj *)obj {
+  _other = obj;
+}
+
+- (SomeObj *)next {
+  return _next;
+}
+
+- (void)setNext:(SomeObj *)obj {
+  _next = obj;
+}
+
+- (int)value {
+  return [_number intValue];
+}
+
+- (void)setValue:(NSNumber *)value {
+  _number = value;
+}
+
+@end;
+
 RetainPtr<CVPixelBufferRef> cf_out_argument() {
   auto surface = adoptCF(IOSurfaceCreate(nullptr));
   CVPixelBufferRef rawBuffer = nullptr;
@@ -60,7 +125,46 @@ void cast_retainptr() {
   RetainPtr<CFArrayRef> v = static_cast<CFArrayRef>(baz);
 }
 
-SomeObj* allocSomeObj();
+CFTypeRef CopyWrapper() {
+  return CopyValueForSomething();
+}
+
+CFTypeRef LeakWrapper() {
+  return CopyValueForSomething();
+  // expected-warning@-1{{The return value is +1 and results in a memory leak [alpha.webkit.RetainPtrCtorAdoptChecker]}}
+}
+
+NSArray *makeArray() NS_RETURNS_RETAINED {
+  return CFBridgingRelease(CFArrayCreateMutable(kCFAllocatorDefault, 10));
+}
+
+extern Class (*getNSArrayClass)();
+NSArray *allocArrayInstance() NS_RETURNS_RETAINED {
+  return [[getNSArrayClass() alloc] init];
+}
+
+extern int (*GetObj)(CF_RETURNS_RETAINED CFTypeRef* objOut);
+RetainPtr<CFTypeRef> getObject() {
+  CFTypeRef obj = nullptr;
+  if (GetObj(&obj))
+    return nullptr;
+  return adoptCF(obj);
+}
+
+CFArrayRef CreateSingleArray(CFStringRef);
+CFArrayRef CreateSingleArray(CFDictionaryRef);
+CFArrayRef CreateSingleArray(CFArrayRef);
+template <typename ElementType>
+static RetainPtr<CFArrayRef> makeArrayWithSingleEntry(ElementType arg) {
+  return adoptCF(CreateSingleArray(arg));
+}
+
+void callMakeArayWithSingleEntry() {
+  auto dictionary = adoptCF(CFDictionaryCreate(kCFAllocatorDefault, nullptr, nullptr, 0));
+  makeArrayWithSingleEntry(dictionary.get());
+}
+
+SomeObj* allocSomeObj() CF_RETURNS_RETAINED;
 
 void adopt_retainptr() {
   RetainPtr<NSObject> foo = adoptNS([[Som...
[truncated]

Copy link

github-actions bot commented Apr 11, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

@rniwa rniwa requested a review from t-rasmud April 11, 2025 08:59
@t-rasmud
Copy link
Contributor

@llvm-ci test

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 Apr 27, 2025

Thanks for the review!

@rniwa rniwa merged commit 16e5c3d into llvm:main Apr 27, 2025
11 checks passed
@rniwa rniwa deleted the webkit-retainptr-ctor-adopt-checker-enhancements branch April 27, 2025 21:24
rniwa added a commit to rniwa/llvm-project that referenced this pull request Apr 27, 2025
…cements (llvm#135329)

This PR implements various small enhancements to
alpha.webkit.RetainPtrCtorAdoptChecker:
 - Detect leaks from [[X alloc] init] when ARC is disabled.
 - Detect leaks from calling Create, Copy, and other +1 CF functions.
 - Recognize [allocX() init] pattern where allocX is a C/C++ function.
 - Recognize _init in addition to init as an init function.
 - Recognize [[[X alloc] init] autorelease].
 - Recognize CFBridgingRelease.
 - Support CF_RETRUNS_RETAINED on out arguments of a C function.
- Support returning +1 object in Create, Copy, and other +1 functions or
+1 selectors.
 - Support variadic Create, Copy, and other +1 C/C++ functions.

To make these enhancements, this PR introduces new visit functions for
ObjCMessageExpr, ReturnStmt, VarDecl, and BinaryOperator. These
functions look for a specific construct mentioned above and adds an
expression such as [[X alloc] init] or CreateX to a DenseSet
CreateOrCopyFnCall when the expression does not result in leaks. When
the code to detect leaks such as the one in visitObjCMessageExpr later
encounters this expression, it can bail out early if the expression is
in the set.
@llvm-ci
Copy link
Collaborator

llvm-ci commented Apr 27, 2025

LLVM Buildbot has detected a new failure on builder openmp-offload-amdgpu-runtime-2 running on rocm-worker-hw-02 while building clang at step 7 "Add check check-clang".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/10/builds/4242

Here is the relevant piece of the build log for the reference
Step 7 (Add check check-clang) failure: test (failure)
******************** TEST 'Clang :: Analysis/Checkers/WebKit/retain-ptr-ctor-adopt-use-arc.mm' FAILED ********************
Exit Code: 134

Command Output (stderr):
--
/home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.build/bin/clang -cc1 -internal-isystem /home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.build/lib/clang/21/include -nostdsysteminc -analyze -analyzer-constraints=range -setup-static-analyzer -analyzer-checker=alpha.webkit.RetainPtrCtorAdoptChecker -fobjc-arc -verify /home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.src/clang/test/Analysis/Checkers/WebKit/retain-ptr-ctor-adopt-use-arc.mm # RUN: at line 2
+ /home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.build/bin/clang -cc1 -internal-isystem /home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.build/lib/clang/21/include -nostdsysteminc -analyze -analyzer-constraints=range -setup-static-analyzer -analyzer-checker=alpha.webkit.RetainPtrCtorAdoptChecker -fobjc-arc -verify /home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.src/clang/test/Analysis/Checkers/WebKit/retain-ptr-ctor-adopt-use-arc.mm
clang: /home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.src/llvm/include/llvm/Support/Casting.h:662: decltype(auto) llvm::dyn_cast(From*) [with To = clang::ParenExpr; From = clang::Expr]: Assertion `detail::isPresent(Val) && "dyn_cast on a non-existent value"' failed.
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace, preprocessed source, and associated run script.
Stack dump:
0.	Program arguments: /home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.build/bin/clang -cc1 -internal-isystem /home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.build/lib/clang/21/include -nostdsysteminc -analyze -analyzer-constraints=range -setup-static-analyzer -analyzer-checker=alpha.webkit.RetainPtrCtorAdoptChecker -fobjc-arc -verify /home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.src/clang/test/Analysis/Checkers/WebKit/retain-ptr-ctor-adopt-use-arc.mm
1.	<eof> parser at end of file
 #0 0x00007aa266df2000 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.build/lib/libLLVMSupport.so.21.0git+0x1f2000)
 #1 0x00007aa266def40f llvm::sys::RunSignalHandlers() (/home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.build/lib/libLLVMSupport.so.21.0git+0x1ef40f)
 #2 0x00007aa266def55a SignalHandler(int, siginfo_t*, void*) Signals.cpp:0:0
 #3 0x00007aa266442520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
 #4 0x00007aa2664969fc __pthread_kill_implementation ./nptl/pthread_kill.c:44:76
 #5 0x00007aa2664969fc __pthread_kill_internal ./nptl/pthread_kill.c:78:10
 #6 0x00007aa2664969fc pthread_kill ./nptl/pthread_kill.c:89:10
 #7 0x00007aa266442476 gsignal ./signal/../sysdeps/posix/raise.c:27:6
 #8 0x00007aa2664287f3 abort ./stdlib/abort.c:81:7
 #9 0x00007aa26642871b _nl_load_domain ./intl/loadmsgcat.c:1177:9
#10 0x00007aa266439e96 (/lib/x86_64-linux-gnu/libc.so.6+0x39e96)
#11 0x00007aa26481c721 (/home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.build/lib/libclangAST.so.21.0git+0x61c721)
#12 0x00007aa264826468 clang::Expr::IgnoreParenCasts() (/home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.build/lib/libclangAST.so.21.0git+0x626468)
#13 0x00007aa2628619e9 (anonymous namespace)::RetainPtrCtorAdoptChecker::isAllocInit(clang::Expr const*, clang::Expr const**) const (.constprop.0) RetainPtrCtorAdoptChecker.cpp:0:0
#14 0x00007aa26287767a clang::RecursiveASTVisitor<(anonymous namespace)::RetainPtrCtorAdoptChecker::checkASTDecl(clang::TranslationUnitDecl const*, clang::ento::AnalysisManager&, clang::ento::BugReporter&) const::LocalVisitor>::TraverseObjCMessageExpr(clang::ObjCMessageExpr*, llvm::SmallVectorImpl<llvm::PointerIntPair<clang::Stmt*, 1u, bool, llvm::PointerLikeTypeTraits<clang::Stmt*>, llvm::PointerIntPairInfo<clang::Stmt*, 1u, llvm::PointerLikeTypeTraits<clang::Stmt*>>>>*) RetainPtrCtorAdoptChecker.cpp:0:0
#15 0x00007aa2628723c9 clang::RecursiveASTVisitor<(anonymous namespace)::RetainPtrCtorAdoptChecker::checkASTDecl(clang::TranslationUnitDecl const*, clang::ento::AnalysisManager&, clang::ento::BugReporter&) const::LocalVisitor>::TraverseStmt(clang::Stmt*, llvm::SmallVectorImpl<llvm::PointerIntPair<clang::Stmt*, 1u, bool, llvm::PointerLikeTypeTraits<clang::Stmt*>, llvm::PointerIntPairInfo<clang::Stmt*, 1u, llvm::PointerLikeTypeTraits<clang::Stmt*>>>>*) (.constprop.0) RetainPtrCtorAdoptChecker.cpp:0:0
#16 0x00007aa26287a400 clang::RecursiveASTVisitor<(anonymous namespace)::RetainPtrCtorAdoptChecker::checkASTDecl(clang::TranslationUnitDecl const*, clang::ento::AnalysisManager&, clang::ento::BugReporter&) const::LocalVisitor>::TraverseObjCMethodDecl(clang::ObjCMethodDecl*) RetainPtrCtorAdoptChecker.cpp:0:0
#17 0x00007aa26286a64e clang::RecursiveASTVisitor<(anonymous namespace)::RetainPtrCtorAdoptChecker::checkASTDecl(clang::TranslationUnitDecl const*, clang::ento::AnalysisManager&, clang::ento::BugReporter&) const::LocalVisitor>::TraverseDeclContextHelper(clang::DeclContext*) (.part.0) RetainPtrCtorAdoptChecker.cpp:0:0
#18 0x00007aa262868dbe clang::RecursiveASTVisitor<(anonymous namespace)::RetainPtrCtorAdoptChecker::checkASTDecl(clang::TranslationUnitDecl const*, clang::ento::AnalysisManager&, clang::ento::BugReporter&) const::LocalVisitor>::TraverseDecl(clang::Decl*) RetainPtrCtorAdoptChecker.cpp:0:0
#19 0x00007aa26286a64e clang::RecursiveASTVisitor<(anonymous namespace)::RetainPtrCtorAdoptChecker::checkASTDecl(clang::TranslationUnitDecl const*, clang::ento::AnalysisManager&, clang::ento::BugReporter&) const::LocalVisitor>::TraverseDeclContextHelper(clang::DeclContext*) (.part.0) RetainPtrCtorAdoptChecker.cpp:0:0
#20 0x00007aa26287a2db clang::RecursiveASTVisitor<(anonymous namespace)::RetainPtrCtorAdoptChecker::checkASTDecl(clang::TranslationUnitDecl const*, clang::ento::AnalysisManager&, clang::ento::BugReporter&) const::LocalVisitor>::TraverseTranslationUnitDecl(clang::TranslationUnitDecl*) RetainPtrCtorAdoptChecker.cpp:0:0
#21 0x00007aa26286afd5 void clang::ento::check::ASTDecl<clang::TranslationUnitDecl>::_checkDecl<(anonymous namespace)::RetainPtrCtorAdoptChecker>(void*, clang::Decl const*, clang::ento::AnalysisManager&, clang::ento::BugReporter&) RetainPtrCtorAdoptChecker.cpp:0:0
#22 0x00007aa262103749 clang::ento::CheckerManager::runCheckersOnASTDecl(clang::Decl const*, clang::ento::AnalysisManager&, clang::ento::BugReporter&) (/home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.build/lib/libclangStaticAnalyzerCore.so.21.0git+0x103749)
#23 0x00007aa26bd65a49 (anonymous namespace)::AnalysisConsumer::HandleTranslationUnit(clang::ASTContext&) AnalysisConsumer.cpp:0:0
#24 0x00007aa265e76b6c clang::ParseAST(clang::Sema&, bool, bool) (/home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.build/lib/libclangParse.so.21.0git+0x40b6c)
#25 0x00007aa2697438a9 clang::FrontendAction::Execute() (/home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.build/lib/libclangFrontend.so.21.0git+0x1438a9)
#26 0x00007aa2696b3825 clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) (/home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.build/lib/libclangFrontend.so.21.0git+0xb3825)
#27 0x00007aa26e580bf8 clang::ExecuteCompilerInvocation(clang::CompilerInstance*) (/home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.build/lib/libclangFrontendTool.so.21.0git+0x5bf8)
#28 0x000056d59d32f847 cc1_main(llvm::ArrayRef<char const*>, char const*, void*) (/home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.build/bin/clang+0x17847)
#29 0x000056d59d32576a ExecuteCC1Tool(llvm::SmallVectorImpl<char const*>&, llvm::ToolContext const&) driver.cpp:0:0
#30 0x000056d59d32a3ee clang_main(int, char**, llvm::ToolContext const&) (/home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.build/bin/clang+0x123ee)
#31 0x000056d59d324e3b main (/home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.build/bin/clang+0xce3b)
#32 0x00007aa266429d90 __libc_start_call_main ./csu/../sysdeps/nptl/libc_start_call_main.h:58:16
#33 0x00007aa266429e40 call_init ./csu/../csu/libc-start.c:128:20
#34 0x00007aa266429e40 __libc_start_main ./csu/../csu/libc-start.c:379:5
#35 0x000056d59d324e95 _start (/home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.build/bin/clang+0xce95)
/home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.build/tools/clang/test/Analysis/Checkers/WebKit/Output/retain-ptr-ctor-adopt-use-arc.mm.script: line 1: 1316832 Aborted                 (core dumped) /home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.build/bin/clang -cc1 -internal-isystem /home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.build/lib/clang/21/include -nostdsysteminc -analyze -analyzer-constraints=range -setup-static-analyzer -analyzer-checker=alpha.webkit.RetainPtrCtorAdoptChecker -fobjc-arc -verify /home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.src/clang/test/Analysis/Checkers/WebKit/retain-ptr-ctor-adopt-use-arc.mm

...

@llvm-ci
Copy link
Collaborator

llvm-ci commented Apr 27, 2025

LLVM Buildbot has detected a new failure on builder llvm-clang-x86_64-sie-ubuntu-fast running on sie-linux-worker while building clang at step 6 "test-build-unified-tree-check-all".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/144/builds/23727

Here is the relevant piece of the build log for the reference
Step 6 (test-build-unified-tree-check-all) failure: test (failure)
******************** TEST 'Clang :: Analysis/Checkers/WebKit/retain-ptr-ctor-adopt-use-arc.mm' FAILED ********************
Exit Code: 134

Command Output (stderr):
--
/home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/build/bin/clang -cc1 -internal-isystem /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/build/lib/clang/21/include -nostdsysteminc -analyze -analyzer-constraints=range -setup-static-analyzer -analyzer-checker=alpha.webkit.RetainPtrCtorAdoptChecker -fobjc-arc -verify /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/llvm-project/clang/test/Analysis/Checkers/WebKit/retain-ptr-ctor-adopt-use-arc.mm # RUN: at line 2
+ /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/build/bin/clang -cc1 -internal-isystem /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/build/lib/clang/21/include -nostdsysteminc -analyze -analyzer-constraints=range -setup-static-analyzer -analyzer-checker=alpha.webkit.RetainPtrCtorAdoptChecker -fobjc-arc -verify /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/llvm-project/clang/test/Analysis/Checkers/WebKit/retain-ptr-ctor-adopt-use-arc.mm
clang: /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/llvm-project/llvm/include/llvm/Support/Casting.h:662: decltype(auto) llvm::dyn_cast(From*) [with To = clang::ParenExpr; From = clang::Expr]: Assertion `detail::isPresent(Val) && "dyn_cast on a non-existent value"' failed.
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace, preprocessed source, and associated run script.
Stack dump:
0.	Program arguments: /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/build/bin/clang -cc1 -internal-isystem /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/build/lib/clang/21/include -nostdsysteminc -analyze -analyzer-constraints=range -setup-static-analyzer -analyzer-checker=alpha.webkit.RetainPtrCtorAdoptChecker -fobjc-arc -verify /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/llvm-project/clang/test/Analysis/Checkers/WebKit/retain-ptr-ctor-adopt-use-arc.mm
1.	<eof> parser at end of file
 #0 0x00005d3415b394c0 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/build/bin/clang+0x21fa4c0)
 #1 0x00005d3415b368cf llvm::sys::RunSignalHandlers() (/home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/build/bin/clang+0x21f78cf)
 #2 0x00005d3415b36a1a SignalHandler(int, siginfo_t*, void*) Signals.cpp:0:0
 #3 0x000074d1ac377520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
 #4 0x000074d1ac3cb9fc __pthread_kill_implementation ./nptl/pthread_kill.c:44:76
 #5 0x000074d1ac3cb9fc __pthread_kill_internal ./nptl/pthread_kill.c:78:10
 #6 0x000074d1ac3cb9fc pthread_kill ./nptl/pthread_kill.c:89:10
 #7 0x000074d1ac377476 gsignal ./signal/../sysdeps/posix/raise.c:27:6
 #8 0x000074d1ac35d7f3 abort ./stdlib/abort.c:81:7
 #9 0x000074d1ac35d71b _nl_load_domain ./intl/loadmsgcat.c:1177:9
#10 0x000074d1ac36ee96 (/lib/x86_64-linux-gnu/libc.so.6+0x39e96)
#11 0x00005d3418689bb4 (/home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/build/bin/clang+0x4d4abb4)
#12 0x00005d34191d4f78 clang::Expr::IgnoreParenCasts() (/home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/build/bin/clang+0x5895f78)
#13 0x00005d3417d53639 (anonymous namespace)::RetainPtrCtorAdoptChecker::isAllocInit(clang::Expr const*, clang::Expr const**) const (.constprop.0) RetainPtrCtorAdoptChecker.cpp:0:0
#14 0x00005d3417d692ea clang::RecursiveASTVisitor<(anonymous namespace)::RetainPtrCtorAdoptChecker::checkASTDecl(clang::TranslationUnitDecl const*, clang::ento::AnalysisManager&, clang::ento::BugReporter&) const::LocalVisitor>::TraverseObjCMessageExpr(clang::ObjCMessageExpr*, llvm::SmallVectorImpl<llvm::PointerIntPair<clang::Stmt*, 1u, bool, llvm::PointerLikeTypeTraits<clang::Stmt*>, llvm::PointerIntPairInfo<clang::Stmt*, 1u, llvm::PointerLikeTypeTraits<clang::Stmt*>>>>*) RetainPtrCtorAdoptChecker.cpp:0:0
#15 0x00005d3417d64029 clang::RecursiveASTVisitor<(anonymous namespace)::RetainPtrCtorAdoptChecker::checkASTDecl(clang::TranslationUnitDecl const*, clang::ento::AnalysisManager&, clang::ento::BugReporter&) const::LocalVisitor>::TraverseStmt(clang::Stmt*, llvm::SmallVectorImpl<llvm::PointerIntPair<clang::Stmt*, 1u, bool, llvm::PointerLikeTypeTraits<clang::Stmt*>, llvm::PointerIntPairInfo<clang::Stmt*, 1u, llvm::PointerLikeTypeTraits<clang::Stmt*>>>>*) (.constprop.0) RetainPtrCtorAdoptChecker.cpp:0:0
#16 0x00005d3417d6c070 clang::RecursiveASTVisitor<(anonymous namespace)::RetainPtrCtorAdoptChecker::checkASTDecl(clang::TranslationUnitDecl const*, clang::ento::AnalysisManager&, clang::ento::BugReporter&) const::LocalVisitor>::TraverseObjCMethodDecl(clang::ObjCMethodDecl*) RetainPtrCtorAdoptChecker.cpp:0:0
#17 0x00005d3417d5c2ae clang::RecursiveASTVisitor<(anonymous namespace)::RetainPtrCtorAdoptChecker::checkASTDecl(clang::TranslationUnitDecl const*, clang::ento::AnalysisManager&, clang::ento::BugReporter&) const::LocalVisitor>::TraverseDeclContextHelper(clang::DeclContext*) (.part.0) RetainPtrCtorAdoptChecker.cpp:0:0
#18 0x00005d3417d5aa1e clang::RecursiveASTVisitor<(anonymous namespace)::RetainPtrCtorAdoptChecker::checkASTDecl(clang::TranslationUnitDecl const*, clang::ento::AnalysisManager&, clang::ento::BugReporter&) const::LocalVisitor>::TraverseDecl(clang::Decl*) RetainPtrCtorAdoptChecker.cpp:0:0
#19 0x00005d3417d5c2ae clang::RecursiveASTVisitor<(anonymous namespace)::RetainPtrCtorAdoptChecker::checkASTDecl(clang::TranslationUnitDecl const*, clang::ento::AnalysisManager&, clang::ento::BugReporter&) const::LocalVisitor>::TraverseDeclContextHelper(clang::DeclContext*) (.part.0) RetainPtrCtorAdoptChecker.cpp:0:0
#20 0x00005d3417d6bf4b clang::RecursiveASTVisitor<(anonymous namespace)::RetainPtrCtorAdoptChecker::checkASTDecl(clang::TranslationUnitDecl const*, clang::ento::AnalysisManager&, clang::ento::BugReporter&) const::LocalVisitor>::TraverseTranslationUnitDecl(clang::TranslationUnitDecl*) RetainPtrCtorAdoptChecker.cpp:0:0
#21 0x00005d3417d5cc35 void clang::ento::check::ASTDecl<clang::TranslationUnitDecl>::_checkDecl<(anonymous namespace)::RetainPtrCtorAdoptChecker>(void*, clang::Decl const*, clang::ento::AnalysisManager&, clang::ento::BugReporter&) RetainPtrCtorAdoptChecker.cpp:0:0
#22 0x00005d3417deb399 clang::ento::CheckerManager::runCheckersOnASTDecl(clang::Decl const*, clang::ento::AnalysisManager&, clang::ento::BugReporter&) (/home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/build/bin/clang+0x44ac399)
#23 0x00005d34179bace9 (anonymous namespace)::AnalysisConsumer::HandleTranslationUnit(clang::ASTContext&) AnalysisConsumer.cpp:0:0
#24 0x00005d3417f8547c clang::ParseAST(clang::Sema&, bool, bool) (/home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/build/bin/clang+0x464647c)
#25 0x00005d34167bee19 clang::FrontendAction::Execute() (/home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/build/bin/clang+0x2e7fe19)
#26 0x00005d341673a805 clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) (/home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/build/bin/clang+0x2dfb805)
#27 0x00005d34168a6688 clang::ExecuteCompilerInvocation(clang::CompilerInstance*) (/home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/build/bin/clang+0x2f67688)
#28 0x00005d3414601967 cc1_main(llvm::ArrayRef<char const*>, char const*, void*) (/home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/build/bin/clang+0xcc2967)
#29 0x00005d34145f787a ExecuteCC1Tool(llvm::SmallVectorImpl<char const*>&, llvm::ToolContext const&) driver.cpp:0:0
#30 0x00005d34145fc4fe clang_main(int, char**, llvm::ToolContext const&) (/home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/build/bin/clang+0xcbd4fe)
#31 0x00005d34144e5c5b main (/home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/build/bin/clang+0xba6c5b)
#32 0x000074d1ac35ed90 __libc_start_call_main ./csu/../sysdeps/nptl/libc_start_call_main.h:58:16
#33 0x000074d1ac35ee40 call_init ./csu/../csu/libc-start.c:128:20
#34 0x000074d1ac35ee40 __libc_start_main ./csu/../csu/libc-start.c:379:5
#35 0x00005d34145f6fa5 _start (/home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/build/bin/clang+0xcb7fa5)
/home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/build/tools/clang/test/Analysis/Checkers/WebKit/Output/retain-ptr-ctor-adopt-use-arc.mm.script: line 1: 1246584 Aborted                 (core dumped) /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/build/bin/clang -cc1 -internal-isystem /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/build/lib/clang/21/include -nostdsysteminc -analyze -analyzer-constraints=range -setup-static-analyzer -analyzer-checker=alpha.webkit.RetainPtrCtorAdoptChecker -fobjc-arc -verify /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/llvm-project/clang/test/Analysis/Checkers/WebKit/retain-ptr-ctor-adopt-use-arc.mm

...

@rniwa
Copy link
Contributor Author

rniwa commented Apr 27, 2025

Oops, fixing the assertion failure in #137556.

jyli0116 pushed a commit to jyli0116/llvm-project that referenced this pull request Apr 28, 2025
…cements (llvm#135329)

This PR implements various small enhancements to
alpha.webkit.RetainPtrCtorAdoptChecker:
 - Detect leaks from [[X alloc] init] when ARC is disabled.
 - Detect leaks from calling Create, Copy, and other +1 CF functions.
 - Recognize [allocX() init] pattern where allocX is a C/C++ function.
 - Recognize _init in addition to init as an init function.
 - Recognize [[[X alloc] init] autorelease].
 - Recognize CFBridgingRelease.
 - Support CF_RETRUNS_RETAINED on out arguments of a C function.
- Support returning +1 object in Create, Copy, and other +1 functions or
+1 selectors.
 - Support variadic Create, Copy, and other +1 C/C++ functions.

To make these enhancements, this PR introduces new visit functions for
ObjCMessageExpr, ReturnStmt, VarDecl, and BinaryOperator. These
functions look for a specific construct mentioned above and adds an
expression such as [[X alloc] init] or CreateX to a DenseSet
CreateOrCopyFnCall when the expression does not result in leaks. When
the code to detect leaks such as the one in visitObjCMessageExpr later
encounters this expression, it can bail out early if the expression is
in the set.
IanWood1 pushed a commit to IanWood1/llvm-project that referenced this pull request May 6, 2025
…cements (llvm#135329)

This PR implements various small enhancements to
alpha.webkit.RetainPtrCtorAdoptChecker:
 - Detect leaks from [[X alloc] init] when ARC is disabled.
 - Detect leaks from calling Create, Copy, and other +1 CF functions.
 - Recognize [allocX() init] pattern where allocX is a C/C++ function.
 - Recognize _init in addition to init as an init function.
 - Recognize [[[X alloc] init] autorelease].
 - Recognize CFBridgingRelease.
 - Support CF_RETRUNS_RETAINED on out arguments of a C function.
- Support returning +1 object in Create, Copy, and other +1 functions or
+1 selectors.
 - Support variadic Create, Copy, and other +1 C/C++ functions.

To make these enhancements, this PR introduces new visit functions for
ObjCMessageExpr, ReturnStmt, VarDecl, and BinaryOperator. These
functions look for a specific construct mentioned above and adds an
expression such as [[X alloc] init] or CreateX to a DenseSet
CreateOrCopyFnCall when the expression does not result in leaks. When
the code to detect leaks such as the one in visitObjCMessageExpr later
encounters this expression, it can bail out early if the expression is
in the set.
IanWood1 pushed a commit to IanWood1/llvm-project that referenced this pull request May 6, 2025
…cements (llvm#135329)

This PR implements various small enhancements to
alpha.webkit.RetainPtrCtorAdoptChecker:
 - Detect leaks from [[X alloc] init] when ARC is disabled.
 - Detect leaks from calling Create, Copy, and other +1 CF functions.
 - Recognize [allocX() init] pattern where allocX is a C/C++ function.
 - Recognize _init in addition to init as an init function.
 - Recognize [[[X alloc] init] autorelease].
 - Recognize CFBridgingRelease.
 - Support CF_RETRUNS_RETAINED on out arguments of a C function.
- Support returning +1 object in Create, Copy, and other +1 functions or
+1 selectors.
 - Support variadic Create, Copy, and other +1 C/C++ functions.

To make these enhancements, this PR introduces new visit functions for
ObjCMessageExpr, ReturnStmt, VarDecl, and BinaryOperator. These
functions look for a specific construct mentioned above and adds an
expression such as [[X alloc] init] or CreateX to a DenseSet
CreateOrCopyFnCall when the expression does not result in leaks. When
the code to detect leaks such as the one in visitObjCMessageExpr later
encounters this expression, it can bail out early if the expression is
in the set.
IanWood1 pushed a commit to IanWood1/llvm-project that referenced this pull request May 6, 2025
…cements (llvm#135329)

This PR implements various small enhancements to
alpha.webkit.RetainPtrCtorAdoptChecker:
 - Detect leaks from [[X alloc] init] when ARC is disabled.
 - Detect leaks from calling Create, Copy, and other +1 CF functions.
 - Recognize [allocX() init] pattern where allocX is a C/C++ function.
 - Recognize _init in addition to init as an init function.
 - Recognize [[[X alloc] init] autorelease].
 - Recognize CFBridgingRelease.
 - Support CF_RETRUNS_RETAINED on out arguments of a C function.
- Support returning +1 object in Create, Copy, and other +1 functions or
+1 selectors.
 - Support variadic Create, Copy, and other +1 C/C++ functions.

To make these enhancements, this PR introduces new visit functions for
ObjCMessageExpr, ReturnStmt, VarDecl, and BinaryOperator. These
functions look for a specific construct mentioned above and adds an
expression such as [[X alloc] init] or CreateX to a DenseSet
CreateOrCopyFnCall when the expression does not result in leaks. When
the code to detect leaks such as the one in visitObjCMessageExpr later
encounters this expression, it can bail out early if the expression is
in the set.
Ankur-0429 pushed a commit to Ankur-0429/llvm-project that referenced this pull request May 9, 2025
…cements (llvm#135329)

This PR implements various small enhancements to
alpha.webkit.RetainPtrCtorAdoptChecker:
 - Detect leaks from [[X alloc] init] when ARC is disabled.
 - Detect leaks from calling Create, Copy, and other +1 CF functions.
 - Recognize [allocX() init] pattern where allocX is a C/C++ function.
 - Recognize _init in addition to init as an init function.
 - Recognize [[[X alloc] init] autorelease].
 - Recognize CFBridgingRelease.
 - Support CF_RETRUNS_RETAINED on out arguments of a C function.
- Support returning +1 object in Create, Copy, and other +1 functions or
+1 selectors.
 - Support variadic Create, Copy, and other +1 C/C++ functions.

To make these enhancements, this PR introduces new visit functions for
ObjCMessageExpr, ReturnStmt, VarDecl, and BinaryOperator. These
functions look for a specific construct mentioned above and adds an
expression such as [[X alloc] init] or CreateX to a DenseSet
CreateOrCopyFnCall when the expression does not result in leaks. When
the code to detect leaks such as the one in visitObjCMessageExpr later
encounters this expression, it can bail out early if the expression is
in the set.
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.

4 participants