Index: lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp +++ lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp @@ -1722,6 +1722,17 @@ } }; + class BadReleaseByBlock : public CFRefBug { + public: + BadReleaseByBlock(const CheckerBase *checker) + : CFRefBug(checker, "Bad release") {} + + const char *getDescription() const override { + return "Incorrect decrement of the reference count of an object that is " + "not owned at this point by the current block"; + } + }; + class DeallocGC : public CFRefBug { public: DeallocGC(const CheckerBase *checker) @@ -2560,7 +2571,8 @@ check::RegionChanges, eval::Assume, eval::Call > { - mutable std::unique_ptr useAfterRelease, releaseNotOwned; + mutable std::unique_ptr useAfterRelease; + mutable std::unique_ptr releaseNotOwned, releaseNotOwnedByBlock; mutable std::unique_ptr deallocGC, deallocNotOwned; mutable std::unique_ptr overAutorelease, returnNotOwnedForOwned; mutable std::unique_ptr leakWithinFunction, leakAtReturn; @@ -3396,9 +3408,15 @@ BT = useAfterRelease.get(); break; case RefVal::ErrorReleaseNotOwned: - if (!releaseNotOwned) - releaseNotOwned.reset(new BadRelease(this)); - BT = releaseNotOwned.get(); + if (isa(C.getLocationContext()->getDecl())) { + if (!releaseNotOwnedByBlock) + releaseNotOwnedByBlock.reset(new BadReleaseByBlock(this)); + BT = releaseNotOwnedByBlock.get(); + } else { + if (!releaseNotOwned) + releaseNotOwned.reset(new BadRelease(this)); + BT = releaseNotOwned.get(); + } break; case RefVal::ErrorDeallocGC: if (!deallocGC) Index: test/Analysis/retain-release.m =================================================================== --- test/Analysis/retain-release.m +++ test/Analysis/retain-release.m @@ -2300,6 +2300,23 @@ CFRelease(obj); } +//===----------------------------------------------------------------------===// +// When warning within blocks make it obvious that warnings refer to blocks. +//===----------------------------------------------------------------------===// + +int useBlock(int (^block)()); +void rdar31699502_hardToNoticeBlocks() { + if (useBlock(^{ + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; + NSArray *array = [NSArray array]; + [array release]; // expected-warning{{Incorrect decrement of the reference count of an object that is not owned at this point by the current block}} + [pool drain]; + return 0; + })) { + return; + } +} + // CHECK: diagnostics // CHECK-NEXT: // CHECK-NEXT: