[cfe-commits] r69982 - in /cfe/trunk: lib/Analysis/CFRefCount.cpp test/Analysis/delegates.m
Ted Kremenek
kremenek at apple.com
Fri Apr 24 10:50:37 PDT 2009
Author: kremenek
Date: Fri Apr 24 12:50:11 2009
New Revision: 69982
URL: http://llvm.org/viewvc/llvm-project?rev=69982&view=rev
Log:
retain/release checker:
- Fix summary lookup for class methods to now use the (optional)
ObjCInterfaceDecl associated with a message expression. This removes a
long-standing FIXME.
- Partial fix for <rdar://problem/6062730> by stop tracking objects that
are passed to [NSObject performSelector]. These methods are often used
for delegates, which the analyzer doesn't reason about well yet.
Added:
cfe/trunk/test/Analysis/delegates.m
Modified:
cfe/trunk/lib/Analysis/CFRefCount.cpp
Modified: cfe/trunk/lib/Analysis/CFRefCount.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFRefCount.cpp?rev=69982&r1=69981&r2=69982&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/CFRefCount.cpp (original)
+++ cfe/trunk/lib/Analysis/CFRefCount.cpp Fri Apr 24 12:50:11 2009
@@ -659,34 +659,51 @@
Selector S = GetNullarySelector(nullaryName, Ctx);
ObjCMethodSummaries[ObjCSummaryKey(ClsII, S)] = Summ;
}
-
- void addInstMethSummary(const char* Cls, RetainSummary* Summ, va_list argp) {
-
- IdentifierInfo* ClsII = &Ctx.Idents.get(Cls);
+
+ Selector generateSelector(va_list argp) {
llvm::SmallVector<IdentifierInfo*, 10> II;
-
+
while (const char* s = va_arg(argp, const char*))
II.push_back(&Ctx.Idents.get(s));
-
- Selector S = Ctx.Selectors.getSelector(II.size(), &II[0]);
- ObjCMethodSummaries[ObjCSummaryKey(ClsII, S)] = Summ;
+
+ return Ctx.Selectors.getSelector(II.size(), &II[0]);
+ }
+
+ void addMethodSummary(IdentifierInfo *ClsII, ObjCMethodSummariesTy& Summaries,
+ RetainSummary* Summ, va_list argp) {
+ Selector S = generateSelector(argp);
+ Summaries[ObjCSummaryKey(ClsII, S)] = Summ;
}
void addInstMethSummary(const char* Cls, RetainSummary* Summ, ...) {
va_list argp;
va_start(argp, Summ);
- addInstMethSummary(Cls, Summ, argp);
+ addMethodSummary(&Ctx.Idents.get(Cls), ObjCMethodSummaries, Summ, argp);
va_end(argp);
}
-
+
+ void addClsMethSummary(const char* Cls, RetainSummary* Summ, ...) {
+ va_list argp;
+ va_start(argp, Summ);
+ addMethodSummary(&Ctx.Idents.get(Cls),ObjCClassMethodSummaries, Summ, argp);
+ va_end(argp);
+ }
+
+ void addClsMethSummary(IdentifierInfo *II, RetainSummary* Summ, ...) {
+ va_list argp;
+ va_start(argp, Summ);
+ addMethodSummary(II, ObjCClassMethodSummaries, Summ, argp);
+ va_end(argp);
+ }
+
void addPanicSummary(const char* Cls, ...) {
RetainSummary* Summ = getPersistentSummary(0, RetEffect::MakeNoRet(),
DoNothing, DoNothing, true);
va_list argp;
va_start (argp, Cls);
- addInstMethSummary(Cls, Summ, argp);
+ addMethodSummary(&Ctx.Idents.get(Cls), ObjCMethodSummaries, Summ, argp);
va_end(argp);
- }
+ }
public:
@@ -1100,23 +1117,30 @@
}
RetainSummary*
-RetainSummaryManager::getClassMethodSummary(ObjCMessageExpr* ME) {
-
- // FIXME: Eventually we should properly do class method summaries, but
- // it requires us being able to walk the type hierarchy. Unfortunately,
- // we cannot do this with just an IdentifierInfo* for the class name.
- IdentifierInfo* ClsName = ME->getClassName();
+RetainSummaryManager::getClassMethodSummary(ObjCMessageExpr *ME) {
+
Selector S = ME->getSelector();
+ ObjCMethodSummariesTy::iterator I;
- // Look up a summary in our cache of Selectors -> Summaries.
- ObjCMethodSummariesTy::iterator I = ObjCClassMethodSummaries.find(ClsName, S);
+ if (ObjCInterfaceDecl *ID = ME->getClassInfo().first) {
+ // Lookup the method using the decl for the class @interface.
+ I = ObjCClassMethodSummaries.find(ID, S);
+ }
+ else {
+ // Fallback to using the class name.
+ IdentifierInfo *ClsName = ME->getClassName();
+
+ // Look up a summary in our cache of Selectors -> Summaries.
+ I = ObjCClassMethodSummaries.find(ClsName, S);
+ }
if (I != ObjCClassMethodSummaries.end())
return I->second;
RetainSummary* Summ =
getCommonMethodSummary(ME, S.getIdentifierInfoForSlot(0)->getName());
- ObjCClassMethodSummaries[ObjCSummaryKey(ClsName, S)] = Summ;
+
+ ObjCClassMethodSummaries[ObjCSummaryKey(ME->getClassName(), S)] = Summ;
return Summ;
}
@@ -1146,6 +1170,28 @@
GetUnarySelector("addObject", Ctx),
getPersistentSummary(RetEffect::MakeNoRet(),
DoNothing, Autorelease));
+
+ // Create the summaries for [NSObject performSelector...]. We treat
+ // these as 'stop tracking' for the arguments because they are often
+ // used for delegates that can release the object. When we have better
+ // inter-procedural analysis we can potentially do something better. This
+ // workaround is to remove false positives.
+ Summ = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, StopTracking);
+ IdentifierInfo *NSObjectII = &Ctx.Idents.get("NSObject");
+ addClsMethSummary(NSObjectII, Summ, "performSelector", "withObject",
+ "afterDelay", NULL);
+ addClsMethSummary(NSObjectII, Summ, "performSelector", "withObject",
+ "afterDelay", "inModes", NULL);
+ addClsMethSummary(NSObjectII, Summ, "performSelectorOnMainThread",
+ "withObject", "waitUntilDone", NULL);
+ addClsMethSummary(NSObjectII, Summ, "performSelectorOnMainThread",
+ "withObject", "waitUntilDone", "modes", NULL);
+ addClsMethSummary(NSObjectII, Summ, "performSelector", "onThread",
+ "withObject", "waitUntilDone", NULL);
+ addClsMethSummary(NSObjectII, Summ, "performSelector", "onThread",
+ "withObject", "waitUntilDone", "modes", NULL);
+ addClsMethSummary(NSObjectII, Summ, "performSelectorInBackground",
+ "withObject", NULL);
}
void RetainSummaryManager::InitializeMethodSummaries() {
@@ -2012,6 +2058,7 @@
else
Summ = Summaries.getClassMethodSummary(ME);
+
EvalSummary(Dst, Eng, Builder, ME, ME->getReceiver(), Summ,
ME->arg_begin(), ME->arg_end(), Pred);
}
Added: cfe/trunk/test/Analysis/delegates.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/delegates.m?rev=69982&view=auto
==============================================================================
--- cfe/trunk/test/Analysis/delegates.m (added)
+++ cfe/trunk/test/Analysis/delegates.m Fri Apr 24 12:50:11 2009
@@ -0,0 +1,114 @@
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -verify %s
+
+
+//===----------------------------------------------------------------------===//
+// The following code is reduced using delta-debugging from
+// Foundation.h (Mac OS X).
+//
+// It includes the basic definitions for the test cases below.
+// Not directly including Foundation.h directly makes this test case
+// both svelte and portable to non-Mac platforms.
+//===----------------------------------------------------------------------===//
+
+typedef const void * CFTypeRef;
+typedef const struct __CFString * CFStringRef;
+typedef const struct __CFAllocator * CFAllocatorRef;
+extern const CFAllocatorRef kCFAllocatorDefault;
+extern CFTypeRef CFRetain(CFTypeRef cf);
+void CFRelease(CFTypeRef cf);
+typedef const struct __CFDictionary * CFDictionaryRef;
+const void *CFDictionaryGetValue(CFDictionaryRef theDict, const void *key);
+extern CFStringRef CFStringCreateWithFormat(CFAllocatorRef alloc, CFDictionaryRef formatOptions, CFStringRef format, ...);
+typedef signed char BOOL;
+typedef int NSInteger;
+typedef unsigned int NSUInteger;
+typedef struct objc_selector *SEL;
+ at class NSString, Protocol;
+extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1, 2)));
+typedef NSInteger NSComparisonResult;
+typedef struct _NSZone NSZone;
+ at class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
+ at protocol NSObject
+- (BOOL)isEqual:(id)object;
+- (oneway void)release;
+- (Class)class;
+- (id)retain;
+ at end
+ at protocol NSCopying
+- (id)copyWithZone:(NSZone *)zone;
+ at end
+ at protocol NSMutableCopying
+- (id)mutableCopyWithZone:(NSZone *)zone;
+ at end
+ at protocol NSCoding
+- (void)encodeWithCoder:(NSCoder *)aCoder;
+ at end
+ at interface NSObject <NSObject> {}
+- (id)init;
++ (id)alloc;
++ (Class)class;
+- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait;
+ at end
+extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone);
+typedef struct {} NSFastEnumerationState;
+ at protocol NSFastEnumeration
+- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len;
+ at end
+ at class NSString;
+typedef struct _NSRange {} NSRange;
+ at interface NSArray : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration>
+- (NSUInteger)count;
+ at end
+ at interface NSMutableArray : NSArray
+- (void)addObject:(id)anObject;
+- (id)initWithCapacity:(NSUInteger)numItems;
+ at end
+typedef unsigned short unichar;
+ at class NSData, NSArray, NSDictionary, NSCharacterSet, NSData, NSURL, NSError, NSLocale;
+typedef NSUInteger NSStringCompareOptions;
+ at interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding> - (NSUInteger)length;
+- (NSComparisonResult)compare:(NSString *)string;
+- (NSComparisonResult)compare:(NSString *)string options:(NSStringCompareOptions)mask;
+- (NSComparisonResult)compare:(NSString *)string options:(NSStringCompareOptions)mask range:(NSRange)compareRange;
+- (NSComparisonResult)compare:(NSString *)string options:(NSStringCompareOptions)mask range:(NSRange)compareRange locale:(id)locale;
+- (NSComparisonResult)caseInsensitiveCompare:(NSString *)string;
+- (NSArray *)componentsSeparatedByCharactersInSet:(NSCharacterSet *)separator;
+ at end
+ at interface NSSimpleCString : NSString {} @end
+ at interface NSConstantString : NSSimpleCString @end
+extern void *_NSConstantStringClassReference;
+
+//===----------------------------------------------------------------------===//
+// Test cases.
+//===----------------------------------------------------------------------===//
+
+// <rdar://problem/6062730>
+// The analyzer doesn't perform any inter-procedural analysis, so delegates
+// involving [NSObject performSelector...] tend to lead to false positives.
+// For now the analyzer just stops tracking the reference count of the
+// receiver until we have better support for delegates.
+
+ at interface test_6062730 : NSObject
++ (void)postNotification:(NSString *)str;
+- (void)foo;
+- (void)bar;
+ at end
+
+ at implementation test_6062730
+- (void) foo {
+ NSString *str = [[NSString alloc] init];
+ [test_6062730 performSelectorOnMainThread:@selector(postNotification:) withObject:str waitUntilDone:1];
+}
+
+- (void) bar {
+ NSString *str = [[NSString alloc] init]; // expected-warning{{leak}}
+ // FIXME: We need to resolve [self class] to 'test_6062730'.
+ [[self class] performSelectorOnMainThread:@selector(postNotification:) withObject:str waitUntilDone:1];
+}
+
++ (void) postNotification:(NSString *)str {
+ [str release]; // no-warning
+}
+ at end
+
More information about the cfe-commits
mailing list