This revision was automatically updated to reflect the committed changes.
Closed by commit rG7113271528a4: [analyzer] ObjCAutoreleaseWriteChecker: 
Support explicit autoreleasepools. (authored by Paul Pelzl 
<ppe...@apple.com>, committed by dergachev.a).
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D81072/new/

https://reviews.llvm.org/D81072

Files:
  clang/lib/StaticAnalyzer/Checkers/ObjCAutoreleaseWriteChecker.cpp
  clang/test/Analysis/autoreleasewritechecker_test.m

Index: clang/test/Analysis/autoreleasewritechecker_test.m
===================================================================
--- clang/test/Analysis/autoreleasewritechecker_test.m
+++ clang/test/Analysis/autoreleasewritechecker_test.m
@@ -83,6 +83,10 @@
 - (BOOL) writeToErrorInBlockMultipleTimes:(NSError *__autoreleasing *)error;
 - (BOOL) writeToError:(NSError *__autoreleasing *)error;
 - (BOOL) writeToErrorWithDispatchGroup:(NSError *__autoreleasing *)error;
+- (BOOL)writeToErrorInAutoreleasePool:(NSError *__autoreleasing *)error;
+- (BOOL)writeToStrongErrorInAutoreleasePool:(NSError *__strong *)error;
+- (BOOL)writeToLocalErrorInAutoreleasePool:(NSError *__autoreleasing *)error;
+- (BOOL)writeToErrorInAutoreleasePoolMultipleTimes:(NSError *__autoreleasing *)error;
 @end
 
 @implementation I
@@ -162,6 +166,58 @@
     return 0;
 }
 
+- (BOOL)writeToErrorInAutoreleasePool:(NSError *__autoreleasing *)error {
+  @autoreleasepool {
+    if (error) {
+      *error = [NSError errorWithDomain:1]; // expected-warning{{Write to autoreleasing out parameter inside locally-scoped autorelease pool; consider writing first to a strong local variable declared outside of the autorelease pool}}
+    }
+  }
+
+  return 0;
+}
+
+- (BOOL)writeToStrongErrorInAutoreleasePool:(NSError *__strong *)error {
+  @autoreleasepool {
+    if (error) {
+      *error = [NSError errorWithDomain:1]; // no-warning
+    }
+  }
+
+  return 0;
+}
+
+- (BOOL)writeToLocalErrorInAutoreleasePool:(NSError *__autoreleasing *)error {
+  NSError *localError;
+  @autoreleasepool {
+    localError = [NSError errorWithDomain:1]; // no-warning
+  }
+
+  if (error) {
+    *error = localError; // no-warning
+  }
+
+  return 0;
+}
+
+- (BOOL)writeToErrorInAutoreleasePoolMultipleTimes:(NSError *__autoreleasing *)error {
+  @autoreleasepool {
+    if (error) {
+      *error = [NSError errorWithDomain:1]; // expected-warning{{Write to autoreleasing out parameter inside locally-scoped autorelease pool; consider writing first to a strong local variable declared outside of the autorelease pool}}
+    }
+  }
+  if (error) {
+    *error = [NSError errorWithDomain:1]; // no-warning
+  }
+  @autoreleasepool {
+    if (error) {
+      *error = [NSError errorWithDomain:1]; // expected-warning{{Write to autoreleasing out parameter inside locally-scoped autorelease pool; consider writing first to a strong local variable declared outside of the autorelease pool}}
+      *error = [NSError errorWithDomain:1]; // expected-warning{{Write to autoreleasing out parameter inside locally-scoped autorelease pool; consider writing first to a strong local variable declared outside of the autorelease pool}}
+    }
+  }
+
+  return 0;
+}
+
 - (BOOL) writeToError:(NSError *__autoreleasing *)error {
     *error = [NSError errorWithDomain:1]; // no-warning
     return 0;
@@ -181,6 +237,15 @@
   return 0;
 }
 
+BOOL writeIntoErrorInAutoreleasePoolFromCFunc(NSError *__autoreleasing *error) {
+  @autoreleasepool {
+    if (error) {
+      *error = [NSError errorWithDomain:1]; // expected-warning{{Write to autoreleasing out parameter inside locally-scoped autorelease pool; consider writing first to a strong local variable declared outside of the autorelease pool}}
+    }
+  }
+  return 0;
+}
+
 BOOL writeToErrorNoWarning(NSError *__autoreleasing* error) {
   *error = [NSError errorWithDomain:1]; // no-warning
   return 0;
Index: clang/lib/StaticAnalyzer/Checkers/ObjCAutoreleaseWriteChecker.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/ObjCAutoreleaseWriteChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/ObjCAutoreleaseWriteChecker.cpp
@@ -30,6 +30,7 @@
 #include "clang/ASTMatchers/ASTMatchFinder.h"
 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h"
 #include "clang/StaticAnalyzer/Core/Checker.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
 #include "llvm/ADT/Twine.h"
@@ -44,6 +45,7 @@
 const char *CapturedBind = "capturedbind";
 const char *ParamBind = "parambind";
 const char *IsMethodBind = "ismethodbind";
+const char *IsARPBind = "isautoreleasepoolbind";
 
 class ObjCAutoreleaseWriteChecker : public Checker<check::ASTCodeBody> {
 public:
@@ -128,21 +130,39 @@
   SourceRange Range = MarkedStmt->getSourceRange();
   PathDiagnosticLocation Location = PathDiagnosticLocation::createBegin(
       MarkedStmt, BR.getSourceManager(), ADC);
+
   bool IsMethod = Match.getNodeAs<ObjCMethodDecl>(IsMethodBind) != nullptr;
-  const char *Name = IsMethod ? "method" : "function";
-
-  BR.EmitBasicReport(
-      ADC->getDecl(), Checker,
-      /*Name=*/(llvm::Twine(ActionMsg)
-                + " autoreleasing out parameter inside autorelease pool").str(),
-      /*BugCategory=*/"Memory",
-      (llvm::Twine(ActionMsg) + " autoreleasing out parameter " +
-       (IsCapture ? "'" + PVD->getName() + "'" + " " : "") + "inside " +
-       "autorelease pool that may exit before " + Name + " returns; consider "
-       "writing first to a strong local variable declared outside of the block")
-          .str(),
-      Location,
-      Range);
+  const char *FunctionDescription = IsMethod ? "method" : "function";
+  bool IsARP = Match.getNodeAs<ObjCAutoreleasePoolStmt>(IsARPBind) != nullptr;
+
+  llvm::SmallString<128> BugNameBuf;
+  llvm::raw_svector_ostream BugName(BugNameBuf);
+  BugName << ActionMsg
+          << " autoreleasing out parameter inside autorelease pool";
+
+  llvm::SmallString<128> BugMessageBuf;
+  llvm::raw_svector_ostream BugMessage(BugMessageBuf);
+  BugMessage << ActionMsg << " autoreleasing out parameter ";
+  if (IsCapture)
+    BugMessage << "'" + PVD->getName() + "' ";
+
+  BugMessage << "inside ";
+  if (IsARP)
+    BugMessage << "locally-scoped autorelease pool;";
+  else
+    BugMessage << "autorelease pool that may exit before "
+               << FunctionDescription << " returns;";
+
+  BugMessage << " consider writing first to a strong local variable"
+                " declared outside ";
+  if (IsARP)
+    BugMessage << "of the autorelease pool";
+  else
+    BugMessage << "of the block";
+
+  BR.EmitBasicReport(ADC->getDecl(), Checker, BugName.str(),
+                     categories::MemoryRefCount, BugMessage.str(), Location,
+                     Range);
 }
 
 void ObjCAutoreleaseWriteChecker::checkASTCodeBody(const Decl *D,
@@ -188,9 +208,16 @@
        WritesOrCapturesInBlockM))
   ));
 
-  auto HasParamAndWritesInMarkedFuncM = allOf(
-      hasAnyParameter(DoublePointerParamM),
-      forEachDescendant(BlockPassedToMarkedFuncM));
+  // WritesIntoM happens inside an explicit @autoreleasepool.
+  auto WritesOrCapturesInPoolM =
+      autoreleasePoolStmt(
+          forEachDescendant(stmt(anyOf(WritesIntoM, CapturedInParamM))))
+          .bind(IsARPBind);
+
+  auto HasParamAndWritesInMarkedFuncM =
+      allOf(hasAnyParameter(DoublePointerParamM),
+            anyOf(forEachDescendant(BlockPassedToMarkedFuncM),
+                  forEachDescendant(WritesOrCapturesInPoolM)));
 
   auto MatcherM = decl(anyOf(
       objcMethodDecl(HasParamAndWritesInMarkedFuncM).bind(IsMethodBind),
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to