r286694 - [analyzer] Improve misleading RetainCountChcker diagnostic under ARC
Devin Coughlin via cfe-commits
cfe-commits at lists.llvm.org
Fri Nov 11 17:03:06 PST 2016
Author: dcoughlin
Date: Fri Nov 11 19:03:06 2016
New Revision: 286694
URL: http://llvm.org/viewvc/llvm-project?rev=286694&view=rev
Log:
[analyzer] Improve misleading RetainCountChcker diagnostic under ARC
Under automated reference counting the analyzer treats a methods -- even those
starting with 'copy' and friends -- as returning an unowned value. This is
because ownership of CoreFoundation objects must be transferred to ARC
with __bridge_transfer or CFBridgingRelease() before being returned as
ARC-managed bridged objects.
Unfortunately this could lead to a poor diagnostic inside copy methods under
ARC where the analyzer would complain about a leak of a returned CF value inside
a method "whose name does not start with 'copy'" -- even though the name did
start with 'copy'.
This commit improves the diagnostic under ARC to say inside a method "returned
from a method managed by Automated Reference Counting".
rdar://problem/28849667
Added:
cfe/trunk/test/Analysis/retain-release-arc.m
Modified:
cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp?rev=286694&r1=286693&r2=286694&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp Fri Nov 11 19:03:06 2016
@@ -2367,10 +2367,15 @@ CFRefLeakReportVisitor::getEndPath(BugRe
os << "that is annotated as NS_RETURNS_NOT_RETAINED";
else {
if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
- os << "whose name ('" << MD->getSelector().getAsString()
- << "') does not start with 'copy', 'mutableCopy', 'alloc' or 'new'."
- " This violates the naming convention rules"
- " given in the Memory Management Guide for Cocoa";
+ if (BRC.getASTContext().getLangOpts().ObjCAutoRefCount) {
+ os << "managed by Automated Reference Counting";
+ } else {
+ os << "whose name ('" << MD->getSelector().getAsString()
+ << "') does not start with "
+ "'copy', 'mutableCopy', 'alloc' or 'new'."
+ " This violates the naming convention rules"
+ " given in the Memory Management Guide for Cocoa";
+ }
}
else {
const FunctionDecl *FD = cast<FunctionDecl>(D);
Added: cfe/trunk/test/Analysis/retain-release-arc.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/retain-release-arc.m?rev=286694&view=auto
==============================================================================
--- cfe/trunk/test/Analysis/retain-release-arc.m (added)
+++ cfe/trunk/test/Analysis/retain-release-arc.m Fri Nov 11 19:03:06 2016
@@ -0,0 +1,86 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -fobjc-arc -fblocks -verify -Wno-objc-root-class %s -analyzer-output=text
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -fblocks -verify -Wno-objc-root-class %s -analyzer-output=text
+
+#define HAS_ARC __has_feature(objc_arc)
+
+typedef unsigned long long CFOptionFlags;
+typedef signed long long CFIndex;
+
+typedef CFIndex CFPropertyListFormat; enum {
+ kCFPropertyListOpenStepFormat = 1,
+ kCFPropertyListXMLFormat_v1_0 = 100,
+ kCFPropertyListBinaryFormat_v1_0 = 200
+};
+
+typedef const struct __CFAllocator * CFAllocatorRef;
+extern const CFAllocatorRef kCFAllocatorDefault;
+typedef struct __CFDictionary * CFDictionaryRef;
+typedef struct __CFError * CFErrorRef;
+typedef struct __CFDataRef * CFDataRef;
+typedef void * CFPropertyListRef;
+
+CFPropertyListRef CFPropertyListCreateWithData(CFAllocatorRef allocator, CFDataRef data, CFOptionFlags options, CFPropertyListFormat *format, CFErrorRef *error);
+
+typedef signed char BOOL;
+typedef struct _NSZone NSZone;
+ at class NSDictionary;
+ at class NSData;
+ at class NSString;
+
+ at protocol NSObject
+- (BOOL)isEqual:(id)object;
+- (id)retain;
+- (oneway void)release;
+- (id)autorelease;
+- (NSString *)description;
+- (id)init;
+ at end
+ at interface NSObject <NSObject> {}
++ (id)allocWithZone:(NSZone *)zone;
++ (id)alloc;
++ (id)new;
+- (void)dealloc;
+ at end
+
+ at interface NSDictionary : NSObject
+ at end
+
+ at interface SomeClass
+ at end
+
+ at implementation SomeClass
+- (NSDictionary *)copyTestWithBridgeReturningRetainable:(NSData *)plistData {
+ CFErrorRef error;
+ CFDictionaryRef testDict = CFPropertyListCreateWithData(kCFAllocatorDefault, (__bridge CFDataRef)plistData, 0, 0, &error);
+#if HAS_ARC
+ // expected-note at -2 {{Call to function 'CFPropertyListCreateWithData' returns a Core Foundation object with a +1 retain count}}
+#endif
+ return (__bridge NSDictionary *)testDict;
+#if HAS_ARC
+ // expected-warning at -2 {{Potential leak of an object stored into 'testDict'}}
+ // expected-note at -3 {{Object returned to caller as an owning reference (single retain count transferred to caller)}}
+ // expected-note at -4 {{Object leaked: object allocated and stored into 'testDict' is returned from a method managed by Automated Reference Counting}}
+#endif
+}
+
+- (NSDictionary *)copyTestWithoutBridgeReturningRetainable:(NSData *)plistData {
+ NSDictionary *testDict = [[NSDictionary alloc] init];
+ return testDict; // no-warning
+}
+
+- (NSDictionary *)copyTestWithBridgeTransferReturningRetainable:(NSData *)plistData {
+ CFErrorRef error;
+ CFDictionaryRef testDict = CFPropertyListCreateWithData(kCFAllocatorDefault, (__bridge CFDataRef)plistData, 0, 0, &error);
+ return (__bridge_transfer NSDictionary *)testDict; // no-warning under ARC
+#if !HAS_ARC
+ // expected-warning at -2 {{'__bridge_transfer' casts have no effect when not using ARC}} // Warning from Sema
+#endif
+}
+
+- (CFDictionaryRef)copyTestReturningCoreFoundation:(NSData *)plistData {
+ CFErrorRef error;
+ CFDictionaryRef testDict = CFPropertyListCreateWithData(kCFAllocatorDefault, (__bridge CFDataRef)plistData, 0, 0, &error);
+ return testDict;
+}
+ at end
+
More information about the cfe-commits
mailing list