]> granicus.if.org Git - clang/commitdiff
[analyzer] Bugfix for autorelease + main run loop leak checker
authorGeorge Karpenkov <ekarpenkov@apple.com>
Mon, 30 Jul 2018 22:18:21 +0000 (22:18 +0000)
committerGeorge Karpenkov <ekarpenkov@apple.com>
Mon, 30 Jul 2018 22:18:21 +0000 (22:18 +0000)
Do not warn when the other message-send-expression is correctly wrapped
in a different autorelease pool.

Differential Revision: https://reviews.llvm.org/D49921

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@338314 91177308-0d34-0410-b5e6-96231b3b80d8

lib/StaticAnalyzer/Checkers/RunLoopAutoreleaseLeakChecker.cpp
test/Analysis/Checkers/RunLoopAutoreleaseLeakChecker.m

index 5c5785441911fdf3f32835dbb9eb046d4a5fd7c4..55516a34d1a78e450e14fbf7c10f049d67837f0d 100644 (file)
@@ -45,6 +45,7 @@ const char * RunLoopBind = "NSRunLoopM";
 const char * RunLoopRunBind = "RunLoopRunM";
 const char * OtherMsgBind = "OtherMessageSentM";
 const char * AutoreleasePoolBind = "AutoreleasePoolM";
+const char * OtherStmtAutoreleasePoolBind = "OtherAutoreleasePoolM";
 
 class RunLoopAutoreleaseLeakChecker : public Checker<check::ASTCodeBody> {
 
@@ -111,17 +112,20 @@ static void emitDiagnostics(BoundNodes &Match,
 
   const auto *AP =
       Match.getNodeAs<ObjCAutoreleasePoolStmt>(AutoreleasePoolBind);
+  const auto *OAP =
+      Match.getNodeAs<ObjCAutoreleasePoolStmt>(OtherStmtAutoreleasePoolBind);
   bool HasAutoreleasePool = (AP != nullptr);
 
   const auto *RL = Match.getNodeAs<ObjCMessageExpr>(RunLoopBind);
   const auto *RLR = Match.getNodeAs<Stmt>(RunLoopRunBind);
   assert(RLR && "Run loop launch not found");
-
   assert(ME != RLR);
-  if (HasAutoreleasePool && seenBefore(AP, RLR, ME))
+
+  // Launch of run loop occurs before the message-sent expression is seen.
+  if (seenBefore(DeclBody, RLR, ME))
     return;
 
-  if (!HasAutoreleasePool && seenBefore(DeclBody, RLR, ME))
+  if (HasAutoreleasePool && (OAP != AP))
     return;
 
   PathDiagnosticLocation Location = PathDiagnosticLocation::createBegin(
@@ -170,7 +174,8 @@ static void
 checkTempObjectsInSamePool(const Decl *D, AnalysisManager &AM, BugReporter &BR,
                            const RunLoopAutoreleaseLeakChecker *Chkr) {
   StatementMatcher RunLoopRunM = getRunLoopRunM();
-  StatementMatcher OtherMessageSentM = getOtherMessageSentM();
+  StatementMatcher OtherMessageSentM = getOtherMessageSentM(
+    hasAncestor(autoreleasePoolStmt().bind(OtherStmtAutoreleasePoolBind)));
 
   StatementMatcher RunLoopInAutorelease =
       autoreleasePoolStmt(
index 32fc2206a31cd8c39516cb1e1da53415dcf88bf7..b00d71b1a4d093ca3353b101011a985845200422 100644 (file)
@@ -29,6 +29,17 @@ void runloop_init_before() { // Warning: object created before the loop.
   }
 }
 
+void runloop_init_before_separate_pool() { // No warning: separate autorelease pool.
+  @autoreleasepool {
+    NSObject *object;
+    @autoreleasepool {
+      object = [[NSObject alloc] init]; // no-warning
+    }
+    (void) object;
+    [[NSRunLoop mainRunLoop] run]; 
+  }
+}
+
 void xpcmain_init_before() { // Warning: object created before the loop.
   @autoreleasepool {
     NSObject *object = [[NSObject alloc] init]; // expected-warning{{Temporary objects allocated in the autorelease pool followed by the launch of xpc_main may never get released; consider moving them to a separate autorelease pool}}