[cfe-commits] r62106 - in /cfe/trunk: lib/Analysis/CFRefCount.cpp test/Analysis/CFDate.m test/Analysis/CFDateGC.m test/Analysis/CFString.c test/Analysis/retain-release.m
Ted Kremenek
kremenek at apple.com
Mon Jan 12 13:45:02 PST 2009
Author: kremenek
Date: Mon Jan 12 15:45:02 2009
New Revision: 62106
URL: http://llvm.org/viewvc/llvm-project?rev=62106&view=rev
Log:
retain/release checker:
- Refactor a bunch of logic in the retain/release checker, making it more
condense and easier to read.
- Add support for "Create" methods in the DiskArbitration framework
retain/release tests:
- Rename CFDate.m to retain-release.m, and move test from CFString.c to
retain-release.m
- Add DiskArbitration framework tests cases.
- Add/refine and few more retain/release GC test cases.
Added:
cfe/trunk/test/Analysis/retain-release.m
Removed:
cfe/trunk/test/Analysis/CFDate.m
cfe/trunk/test/Analysis/CFString.c
Modified:
cfe/trunk/lib/Analysis/CFRefCount.cpp
cfe/trunk/test/Analysis/CFDateGC.m
Modified: cfe/trunk/lib/Analysis/CFRefCount.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFRefCount.cpp?rev=62106&r1=62105&r2=62106&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/CFRefCount.cpp (original)
+++ cfe/trunk/lib/Analysis/CFRefCount.cpp Mon Jan 12 15:45:02 2009
@@ -83,50 +83,45 @@
// Type querying functions.
//===----------------------------------------------------------------------===//
-static bool isCFRefType(QualType T) {
-
- if (!T->isPointerType())
- return false;
-
- // Check the typedef for the name "CF" and the substring "Ref".
- TypedefType* TD = dyn_cast<TypedefType>(T.getTypePtr());
-
- if (!TD)
- return false;
-
- const char* TDName = TD->getDecl()->getIdentifier()->getName();
- assert (TDName);
+static bool hasPrefix(const char* s, const char* prefix) {
+ if (!prefix)
+ return true;
- if (TDName[0] != 'C' || TDName[1] != 'F')
- return false;
+ char c = *s;
+ char cP = *prefix;
- if (strstr(TDName, "Ref") == 0)
- return false;
+ while (c != '\0' && cP != '\0') {
+ if (c != cP) break;
+ c = *(++s);
+ cP = *(++prefix);
+ }
- return true;
+ return cP == '\0';
}
-static bool isCGRefType(QualType T) {
-
- if (!T->isPointerType())
- return false;
-
- // Check the typedef for the name "CG" and the substring "Ref".
- TypedefType* TD = dyn_cast<TypedefType>(T.getTypePtr());
-
- if (!TD)
- return false;
-
- const char* TDName = TD->getDecl()->getIdentifier()->getName();
- assert (TDName);
+static bool hasSuffix(const char* s, const char* suffix) {
+ const char* loc = strstr(s, suffix);
+ return loc && strcmp(suffix, loc) == 0;
+}
+
+static bool isRefType(QualType RetTy, const char* prefix,
+ ASTContext* Ctx = 0, const char* name = 0) {
- if (TDName[0] != 'C' || TDName[1] != 'G')
+ if (TypedefType* TD = dyn_cast<TypedefType>(RetTy.getTypePtr())) {
+ const char* TDName = TD->getDecl()->getIdentifier()->getName();
+ return hasPrefix(TDName, prefix) && hasSuffix(TDName, "Ref");
+ }
+
+ if (!Ctx || !name)
return false;
-
- if (strstr(TDName, "Ref") == 0)
+
+ // Is the type void*?
+ const PointerType* PT = RetTy->getAsPointerType();
+ if (!(PT->getPointeeType().getUnqualifiedType() == Ctx->VoidTy))
return false;
-
- return true;
+
+ // Does the name start with the prefix?
+ return hasPrefix(name, prefix);
}
//===----------------------------------------------------------------------===//
@@ -507,15 +502,11 @@
enum UnaryFuncKind { cfretain, cfrelease, cfmakecollectable };
public:
- RetainSummary* getUnarySummary(FunctionDecl* FD, UnaryFuncKind func);
-
- RetainSummary* getNSSummary(FunctionDecl* FD, const char* FName);
- RetainSummary* getCFSummary(FunctionDecl* FD, const char* FName);
- RetainSummary* getCGSummary(FunctionDecl* FD, const char* FName);
+ RetainSummary* getUnarySummary(FunctionType* FT, UnaryFuncKind func);
RetainSummary* getCFSummaryCreateRule(FunctionDecl* FD);
RetainSummary* getCFSummaryGetRule(FunctionDecl* FD);
- RetainSummary* getCFCreateGetRuleSummary(FunctionDecl* FD, const char* FName);
+ RetainSummary* getCFCreateGetRuleSummary(FunctionDecl* FD, const char* FName);
RetainSummary* getPersistentSummary(ArgEffects* AE, RetEffect RetEff,
ArgEffect ReceiverEff = DoNothing,
@@ -713,6 +704,16 @@
// Summary creation for functions (largely uses of Core Foundation).
//===----------------------------------------------------------------------===//
+static bool isRetain(FunctionDecl* FD, const char* FName) {
+ const char* loc = strstr(FName, "Retain");
+ return loc && loc[sizeof("Retain")-1] == '\0';
+}
+
+static bool isRelease(FunctionDecl* FD, const char* FName) {
+ const char* loc = strstr(FName, "Release");
+ return loc && loc[sizeof("Release")-1] == '\0';
+}
+
RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) {
SourceLocation Loc = FD->getLocation();
@@ -727,50 +728,90 @@
return I->second;
// No summary. Generate one.
- const char* FName = FD->getIdentifier()->getName();
+ RetainSummary *S = 0;
- RetainSummary *S = 0;
- FunctionType* FT = dyn_cast<FunctionType>(FD->getType());
-
do {
- if (FT) {
-
- QualType T = FT->getResultType();
-
- if (isCFRefType(T)) {
- S = getCFSummary(FD, FName);
+ // We generate "stop" summaries for implicitly defined functions.
+ if (FD->isImplicit()) {
+ S = getPersistentStopSummary();
+ break;
+ }
+
+ FunctionType* FT = cast<FunctionType>(FD->getType());
+ const char* FName = FD->getIdentifier()->getName();
+
+ // Inspect the result type.
+ QualType RetTy = FT->getResultType();
+
+ // FIXME: This should all be refactored into a chain of "summary lookup"
+ // filters.
+ if (strcmp(FName, "IOServiceGetMatchingServices") == 0) {
+ // FIXES: <rdar://problem/6326900>
+ // This should be addressed using a API table. This strcmp is also
+ // a little gross, but there is no need to super optimize here.
+ assert (ScratchArgs.empty());
+ ScratchArgs.push_back(std::make_pair(1, DecRef));
+ S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing);
+ break;
+ }
+
+ // Handle: id NSMakeCollectable(CFTypeRef)
+ if (strcmp(FName, "NSMakeCollectable") == 0) {
+ S = (RetTy == Ctx.getObjCIdType())
+ ? getUnarySummary(FT, cfmakecollectable)
+ : getPersistentStopSummary();
+
+ break;
+ }
+
+ if (RetTy->isPointerType()) {
+ // For CoreFoundation ('CF') types.
+ if (isRefType(RetTy, "CF", &Ctx, FName)) {
+ if (isRetain(FD, FName))
+ S = getUnarySummary(FT, cfretain);
+ else if (strstr(FName, "MakeCollectable"))
+ S = getUnarySummary(FT, cfmakecollectable);
+ else
+ S = getCFCreateGetRuleSummary(FD, FName);
+
break;
}
-
- if (isCGRefType(T)) {
- S = getCGSummary(FD, FName );
+
+ // For CoreGraphics ('CG') types.
+ if (isRefType(RetTy, "CG", &Ctx, FName)) {
+ if (isRetain(FD, FName))
+ S = getUnarySummary(FT, cfretain);
+ else
+ S = getCFCreateGetRuleSummary(FD, FName);
+
break;
}
-
- // FIXME: This should all be refactored into a chain of "summary lookup"
- // filters.
- if (strcmp(FName, "IOServiceGetMatchingServices") == 0) {
- // FIXES: <rdar://problem/6326900>
- // This should be addressed using a API table. This strcmp is also
- // a little gross, but there is no need to super optimize here.
- assert (ScratchArgs.empty());
- ScratchArgs.push_back(std::make_pair(1, DecRef));
- S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing);
+
+ // For the Disk Arbitration API (DiskArbitration/DADisk.h)
+ if (isRefType(RetTy, "DADisk") ||
+ isRefType(RetTy, "DADissenter") ||
+ isRefType(RetTy, "DASessionRef")) {
+ S = getCFCreateGetRuleSummary(FD, FName);
break;
}
+
+ break;
}
-
- // Ignore the prefix '_'
- while (*FName == '_') ++FName;
- if (FName[0] == 'C') {
- if (FName[1] == 'F')
- S = getCFSummary(FD, FName);
- else if (FName[1] == 'G')
- S = getCGSummary(FD, FName);
+ // Check for release functions, the only kind of functions that we care
+ // about that don't return a pointer type.
+ if (FName[0] == 'C' && (FName[1] == 'F' || FName[1] == 'G')) {
+ if (isRelease(FD, FName+2))
+ S = getUnarySummary(FT, cfrelease);
+ else {
+ // For CoreFoundation and CoreGraphics functions we assume they
+ // follow the ownership idiom strictly and thus do not cause
+ // ownership to "escape".
+ assert (ScratchArgs.empty());
+ S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing,
+ DoNothing);
+ }
}
- else if (FName[0] == 'N' && FName[1] == 'S')
- S = getNSSummary(FD, FName);
}
while (0);
@@ -778,58 +819,6 @@
return S;
}
-RetainSummary* RetainSummaryManager::getNSSummary(FunctionDecl* FD,
- const char* FName) {
- FName += 2;
-
- if (strcmp(FName, "MakeCollectable") == 0)
- return getUnarySummary(FD, cfmakecollectable);
-
- return 0;
-}
-
-static bool isRetain(FunctionDecl* FD, const char* FName) {
- const char* loc = strstr(FName, "Retain");
- return loc && loc[sizeof("Retain")-1] == '\0';
-}
-
-static bool isRelease(FunctionDecl* FD, const char* FName) {
- const char* loc = strstr(FName, "Release");
- return loc && loc[sizeof("Release")-1] == '\0';
-}
-
-RetainSummary* RetainSummaryManager::getCFSummary(FunctionDecl* FD,
- const char* FName) {
- if (FName[0] == 'C' && FName[1] == 'F')
- FName += 2;
-
- if (isRetain(FD, FName))
- return getUnarySummary(FD, cfretain);
-
- if (isRelease(FD, FName))
- return getUnarySummary(FD, cfrelease);
-
- if (strcmp(FName, "MakeCollectable") == 0)
- return getUnarySummary(FD, cfmakecollectable);
-
- return getCFCreateGetRuleSummary(FD, FName);
-}
-
-RetainSummary* RetainSummaryManager::getCGSummary(FunctionDecl* FD,
- const char* FName) {
-
- if (FName[0] == 'C' && FName[1] == 'G')
- FName += 2;
-
- if (isRelease(FD, FName))
- return getUnarySummary(FD, cfrelease);
-
- if (isRetain(FD, FName))
- return getUnarySummary(FD, cfretain);
-
- return getCFCreateGetRuleSummary(FD, FName);
-}
-
RetainSummary*
RetainSummaryManager::getCFCreateGetRuleSummary(FunctionDecl* FD,
const char* FName) {
@@ -844,29 +833,17 @@
}
RetainSummary*
-RetainSummaryManager::getUnarySummary(FunctionDecl* FD, UnaryFuncKind func) {
-
- FunctionTypeProto* FT =
- dyn_cast<FunctionTypeProto>(FD->getType().getTypePtr());
-
- if (FT) {
-
- if (FT->getNumArgs() != 1)
- return 0;
-
- TypedefType* ArgT = dyn_cast<TypedefType>(FT->getArgType(0).getTypePtr());
-
- if (!ArgT)
- return 0;
-
- if (!ArgT->isPointerType())
- return NULL;
- }
+RetainSummaryManager::getUnarySummary(FunctionType* FT, UnaryFuncKind func) {
+ // Sanity check that this is *really* a unary function. This can
+ // happen if people do weird things.
+ FunctionTypeProto* FTP = dyn_cast<FunctionTypeProto>(FT);
+ if (!FTP || FTP->getNumArgs() != 1)
+ return getPersistentStopSummary();
assert (ScratchArgs.empty());
switch (func) {
- case cfretain: {
+ case cfretain: {
ScratchArgs.push_back(std::make_pair(0, IncRef));
return getPersistentSummary(RetEffect::MakeAlias(0),
DoNothing, DoNothing);
@@ -893,17 +870,6 @@
}
RetainSummary* RetainSummaryManager::getCFSummaryCreateRule(FunctionDecl* FD) {
-
- FunctionType* FT =
- dyn_cast<FunctionType>(FD->getType().getTypePtr());
-
- if (FT) {
- QualType ResTy = FT->getResultType();
-
- if (!isCFRefType(ResTy) && !isCGRefType(ResTy))
- return getPersistentSummary(RetEffect::MakeNoRet());
- }
-
assert (ScratchArgs.empty());
if (FD->getIdentifier() == CFDictionaryCreateII) {
@@ -915,26 +881,6 @@
}
RetainSummary* RetainSummaryManager::getCFSummaryGetRule(FunctionDecl* FD) {
-
- FunctionType* FT =
- dyn_cast<FunctionType>(FD->getType().getTypePtr());
-
- if (FT) {
- QualType RetTy = FT->getResultType();
-
- // FIXME: For now we assume that all pointer types returned are referenced
- // counted. Since this is the "Get" rule, we assume non-ownership, which
- // works fine for things that are not reference counted. We do this because
- // some generic data structures return "void*". We need something better
- // in the future.
-
- if (!isCFRefType(RetTy) && !RetTy->isPointerType())
- return getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing);
- }
-
- // FIXME: Add special-cases for functions that retain/release. For now
- // just handle the default case.
-
assert (ScratchArgs.empty());
return getPersistentSummary(RetEffect::MakeNotOwned(), DoNothing, DoNothing);
}
Removed: cfe/trunk/test/Analysis/CFDate.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/CFDate.m?rev=62105&view=auto
==============================================================================
--- cfe/trunk/test/Analysis/CFDate.m (original)
+++ cfe/trunk/test/Analysis/CFDate.m (removed)
@@ -1,143 +0,0 @@
-// RUN: clang -checker-cfref -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 including Foundation.h directly makes this test case both svelte and
-// portable to non-Mac platforms.
-//===----------------------------------------------------------------------===//
-
-typedef const struct __CFAllocator * CFAllocatorRef;
-typedef double CFTimeInterval;
-typedef CFTimeInterval CFAbsoluteTime;
-typedef const struct __CFDate * CFDateRef;
-extern CFDateRef CFDateCreate(CFAllocatorRef allocator, CFAbsoluteTime at);
-typedef struct objc_object {} *id;
-typedef signed char BOOL;
-typedef unsigned int NSUInteger;
-typedef struct _NSZone NSZone;
- at class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
- at protocol NSObject - (BOOL)isEqual:(id)object; - (id)retain; - (oneway void)release; @end
- at protocol NSCopying - (id)copyWithZone:(NSZone *)zone; @end
- at protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; @end
- at interface NSObject <NSObject> {} @end
-extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone);
-typedef double NSTimeInterval;
- at interface NSDate : NSObject <NSCopying, NSCoding> - (NSTimeInterval)timeIntervalSinceReferenceDate; @end
- at class NSString, NSArray, NSTimeZone;
-
-//===----------------------------------------------------------------------===//
-// Test cases.
-//===----------------------------------------------------------------------===//
-
-CFAbsoluteTime f1() {
- CFAbsoluteTime t = CFAbsoluteTimeGetCurrent();
- CFDateRef date = CFDateCreate(0, t);
- CFRetain(date);
- CFRelease(date);
- CFDateGetAbsoluteTime(date); // no-warning
- CFRelease(date);
- t = CFDateGetAbsoluteTime(date); // expected-warning{{Reference-counted object is used after it is released.}}
- return t;
-}
-
-CFAbsoluteTime f2() {
- CFAbsoluteTime t = CFAbsoluteTimeGetCurrent();
- CFDateRef date = CFDateCreate(0, t);
- [((NSDate*) date) retain];
- CFRelease(date);
- CFDateGetAbsoluteTime(date); // no-warning
- [((NSDate*) date) release];
- t = CFDateGetAbsoluteTime(date); // expected-warning{{Reference-counted object is used after it is released.}}
- return t;
-}
-
-
-NSDate* global_x;
-
- // Test to see if we supresss an error when we store the pointer
- // to a global.
-
-CFAbsoluteTime f3() {
- CFAbsoluteTime t = CFAbsoluteTimeGetCurrent();
- CFDateRef date = CFDateCreate(0, t);
- [((NSDate*) date) retain];
- CFRelease(date);
- CFDateGetAbsoluteTime(date); // no-warning
- global_x = (NSDate*) date;
- [((NSDate*) date) release];
- t = CFDateGetAbsoluteTime(date); // no-warning
- return t;
-}
-
-// Test to see if we supresss an error when we store the pointer
-// to a struct.
-
-struct foo {
- NSDate* f;
-};
-
-CFAbsoluteTime f4() {
- struct foo x;
-
- CFAbsoluteTime t = CFAbsoluteTimeGetCurrent();
- CFDateRef date = CFDateCreate(0, t);
- [((NSDate*) date) retain];
- CFRelease(date);
- CFDateGetAbsoluteTime(date); // no-warning
- x.f = (NSDate*) date;
- [((NSDate*) date) release];
- t = CFDateGetAbsoluteTime(date); // no-warning
- return t;
-}
-
-// Test a leak.
-
-CFAbsoluteTime f5(int x) {
- CFAbsoluteTime t = CFAbsoluteTimeGetCurrent();
- CFDateRef date = CFDateCreate(0, t);
-
- if (x)
- CFRelease(date);
-
- return t; // expected-warning{{leak}}
-}
-
-// Test a leak involving the return.
-
-CFDateRef f6(int x) {
- CFDateRef date = CFDateCreate(0, CFAbsoluteTimeGetCurrent());
- CFRetain(date);
- return date; // expected-warning{{leak}}
-}
-
-// Test a leak involving an overwrite.
-
-CFDateRef f7() {
- CFDateRef date = CFDateCreate(0, CFAbsoluteTimeGetCurrent());
- CFRetain(date); //expected-warning{{leak}}
- date = CFDateCreate(0, CFAbsoluteTimeGetCurrent());
- return date;
-}
-
-// Generalization of Create rule. MyDateCreate returns a CFXXXTypeRef, and
-// has the word create.
-
-CFDateRef MyDateCreate();
-
-CFDateRef f8() {
- CFDateRef date = MyDateCreate();
- CFRetain(date);
- return date; // expected-warning{{leak}}
-}
-
-CFDateRef f9() {
- CFDateRef date = CFDateCreate(0, CFAbsoluteTimeGetCurrent());
- int *p = 0;
- // test that the checker assumes that CFDateCreate returns a non-null
- // pointer
- if (!date) *p = 1; // no-warning
- return date;
-}
Modified: cfe/trunk/test/Analysis/CFDateGC.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/CFDateGC.m?rev=62106&r1=62105&r2=62106&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/CFDateGC.m (original)
+++ cfe/trunk/test/Analysis/CFDateGC.m Mon Jan 12 15:45:02 2009
@@ -10,24 +10,28 @@
//===----------------------------------------------------------------------===//
typedef const void * CFTypeRef;
+void CFRelease(CFTypeRef cf);
+CFTypeRef CFRetain(CFTypeRef cf);
+CFTypeRef CFMakeCollectable(CFTypeRef cf);
typedef const struct __CFAllocator * CFAllocatorRef;
typedef double CFTimeInterval;
typedef CFTimeInterval CFAbsoluteTime;
typedef const struct __CFDate * CFDateRef;
extern CFDateRef CFDateCreate(CFAllocatorRef allocator, CFAbsoluteTime at);
+extern CFAbsoluteTime CFDateGetAbsoluteTime(CFDateRef theDate);
+typedef struct objc_object {} *id;
typedef signed char BOOL;
-typedef unsigned int NSUInteger;
-typedef struct _NSZone NSZone;
static __inline__ __attribute__((always_inline)) id NSMakeCollectable(CFTypeRef cf) {}
- at protocol NSObject - (BOOL)isEqual:(id)object; - (oneway void)release; @end
-extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone);
-CFTypeRef CFMakeCollectable(CFTypeRef cf);
+ at protocol NSObject - (BOOL)isEqual:(id)object;
+- (oneway void)release;
+ at end
+ at class NSArray;
//===----------------------------------------------------------------------===//
// Test cases.
//===----------------------------------------------------------------------===//
-CFAbsoluteTime f1() {
+CFAbsoluteTime f1_use_after_release() {
CFAbsoluteTime t = CFAbsoluteTimeGetCurrent();
CFDateRef date = CFDateCreate(0, t);
CFRetain(date);
@@ -38,7 +42,20 @@
return t;
}
-CFAbsoluteTime f1b() {
+// The following two test cases verifies that CFMakeCollectable is a no-op
+// in non-GC mode and a "release" in GC mode.
+CFAbsoluteTime f2_leak() {
+ CFAbsoluteTime t = CFAbsoluteTimeGetCurrent();
+ CFDateRef date = CFDateCreate(0, t);
+ CFRetain(date);
+ [(id) CFMakeCollectable(date) release];
+ CFDateGetAbsoluteTime(date); // no-warning
+ CFRelease(date);
+ t = CFDateGetAbsoluteTime(date); // expected-warning{{Reference-counted object is used after it is released.}}
+ return t;
+}
+
+CFAbsoluteTime f2_noleak() {
CFAbsoluteTime t = CFAbsoluteTimeGetCurrent();
CFDateRef date = CFDateCreate(0, t);
CFRetain(date);
@@ -49,4 +66,12 @@
return t;
}
-
+// The following test case verifies that we "stop tracking" a retained object
+// when it is passed as an argument to an implicitly defined function.
+CFAbsoluteTime f4() {
+ CFAbsoluteTime t = CFAbsoluteTimeGetCurrent();
+ CFDateRef date = CFDateCreate(0, t);
+ CFRetain(date);
+ some_implicitly_defined_function_stop_tracking(date); // no-warning
+ return t;
+}
Removed: cfe/trunk/test/Analysis/CFString.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/CFString.c?rev=62105&view=auto
==============================================================================
--- cfe/trunk/test/Analysis/CFString.c (original)
+++ cfe/trunk/test/Analysis/CFString.c (removed)
@@ -1,60 +0,0 @@
-// RUN: clang -checker-cfref -pedantic -verify %s
-
-//===----------------------------------------------------------------------===//
-// The following code is reduced using delta-debugging from
-// CoreFoundation.h (Mac OS X).
-//
-// It includes the basic definitions for the test cases below.
-// Not directly including CoreFoundation.h directly makes this test case
-// both svelte and portable to non-Mac platforms.
-//===----------------------------------------------------------------------===//
-
-typedef unsigned long UInt32;
-typedef unsigned char Boolean;
-typedef signed long CFIndex;
-typedef const void * CFTypeRef;
-typedef const struct __CFString * CFStringRef;
-typedef struct { CFIndex location; } CFRange;
-typedef const struct __CFAllocator * CFAllocatorRef;
-extern void CFRelease(CFTypeRef cf);
-typedef Boolean (*CFArrayEqualCallBack)(const void *value1, const void *value2);
-typedef struct { CFArrayEqualCallBack equal; } CFArrayCallBacks;
-extern const CFArrayCallBacks kCFTypeArrayCallBacks;
-typedef const struct __CFArray * CFArrayRef;
-typedef struct __CFArray * CFMutableArrayRef;
-extern CFMutableArrayRef CFArrayCreateMutable(CFAllocatorRef allocator, CFIndex capacity, const CFArrayCallBacks *callBacks);
-extern const void *CFArrayGetValueAtIndex(CFArrayRef theArray, CFIndex idx);
-extern void CFArrayAppendValue(CFMutableArrayRef theArray, const void *value);
-typedef UInt32 CFStringEncoding;
-enum { kCFStringEncodingMacRoman = 0, kCFStringEncodingWindowsLatin1 = 0x0500, kCFStringEncodingISOLatin1 = 0x0201, kCFStringEncodingNextStepLatin = 0x0B01, kCFStringEncodingASCII = 0x0600, kCFStringEncodingUnicode = 0x0100, kCFStringEncodingUTF8 = 0x08000100, kCFStringEncodingNonLossyASCII = 0x0BFF , kCFStringEncodingUTF16 = 0x0100, kCFStringEncodingUTF16BE = 0x10000100, kCFStringEncodingUTF16LE = 0x14000100, kCFStringEncodingUTF32 = 0x0c000100, kCFStringEncodingUTF32BE = 0x18000100, kCFStringEncodingUTF32LE = 0x1c000100 };
-extern CFStringRef CFStringCreateWithCString(CFAllocatorRef alloc, const char *cStr, CFStringEncoding encoding);
-
-//===----------------------------------------------------------------------===//
-// Test cases.
-//===----------------------------------------------------------------------===//
-
-void f1() {
-
- // Create the array.
- CFMutableArrayRef A = CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks);
-
- // Create a string.
- CFStringRef s1 = CFStringCreateWithCString(0, "hello world",
- kCFStringEncodingUTF8);
-
- // Add the string to the array.
- CFArrayAppendValue(A, s1);
-
- // Decrement the reference count.
- CFRelease(s1); // no-warning
-
- // Get the string. We don't own it.
- s1 = (CFStringRef) CFArrayGetValueAtIndex(A, 0);
-
- // Release the array.
- CFRelease(A); // no-warning
-
- // Release the string. This is a bug.
- CFRelease(s1); // expected-warning{{Incorrect decrement of the reference count}}
-}
-
Added: cfe/trunk/test/Analysis/retain-release.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/retain-release.m?rev=62106&view=auto
==============================================================================
--- cfe/trunk/test/Analysis/retain-release.m (added)
+++ cfe/trunk/test/Analysis/retain-release.m Mon Jan 12 15:45:02 2009
@@ -0,0 +1,239 @@
+// RUN: clang -checker-cfref -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 including Foundation.h directly makes this test case both svelte and
+// portable to non-Mac platforms.
+//===----------------------------------------------------------------------===//
+
+typedef unsigned int __darwin_natural_t;
+typedef unsigned long UInt32;
+typedef signed long CFIndex;
+typedef const void * CFTypeRef;
+typedef const struct __CFString * CFStringRef;
+typedef const struct __CFAllocator * CFAllocatorRef;
+extern const CFAllocatorRef kCFAllocatorDefault;
+extern CFTypeRef CFRetain(CFTypeRef cf);
+extern void CFRelease(CFTypeRef cf);
+typedef struct {
+}
+CFArrayCallBacks;
+extern const CFArrayCallBacks kCFTypeArrayCallBacks;
+typedef const struct __CFArray * CFArrayRef;
+typedef struct __CFArray * CFMutableArrayRef;
+extern CFMutableArrayRef CFArrayCreateMutable(CFAllocatorRef allocator, CFIndex capacity, const CFArrayCallBacks *callBacks);
+extern const void *CFArrayGetValueAtIndex(CFArrayRef theArray, CFIndex idx);
+typedef const struct __CFDictionary * CFDictionaryRef;
+typedef UInt32 CFStringEncoding;
+enum {
+kCFStringEncodingMacRoman = 0, kCFStringEncodingWindowsLatin1 = 0x0500, kCFStringEncodingISOLatin1 = 0x0201, kCFStringEncodingNextStepLatin = 0x0B01, kCFStringEncodingASCII = 0x0600, kCFStringEncodingUnicode = 0x0100, kCFStringEncodingUTF8 = 0x08000100, kCFStringEncodingNonLossyASCII = 0x0BFF , kCFStringEncodingUTF16 = 0x0100, kCFStringEncodingUTF16BE = 0x10000100, kCFStringEncodingUTF16LE = 0x14000100, kCFStringEncodingUTF32 = 0x0c000100, kCFStringEncodingUTF32BE = 0x18000100, kCFStringEncodingUTF32LE = 0x1c000100 };
+extern CFStringRef CFStringCreateWithCString(CFAllocatorRef alloc, const char *cStr, CFStringEncoding encoding);
+typedef double CFTimeInterval;
+typedef CFTimeInterval CFAbsoluteTime;
+typedef const struct __CFDate * CFDateRef;
+extern CFDateRef CFDateCreate(CFAllocatorRef allocator, CFAbsoluteTime at);
+extern CFAbsoluteTime CFDateGetAbsoluteTime(CFDateRef theDate);
+typedef __darwin_natural_t natural_t;
+typedef natural_t mach_port_name_t;
+typedef mach_port_name_t mach_port_t;
+typedef signed char BOOL;
+typedef struct _NSZone NSZone;
+ at class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
+ at protocol NSObject - (BOOL)isEqual:(id)object;
+- (id)retain;
+- (oneway void)release;
+ at end @protocol NSCopying - (id)copyWithZone:(NSZone *)zone;
+ at end @protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder;
+ at end @interface NSObject <NSObject> {
+}
+ at end typedef float CGFloat;
+typedef double NSTimeInterval;
+ at interface NSDate : NSObject <NSCopying, NSCoding> - (NSTimeInterval)timeIntervalSinceReferenceDate;
+ at end enum {
+NSObjCNoType = 0, NSObjCVoidType = 'v', NSObjCCharType = 'c', NSObjCShortType = 's', NSObjCLongType = 'l', NSObjCLonglongType = 'q', NSObjCFloatType = 'f', NSObjCDoubleType = 'd', NSObjCBoolType = 'B', NSObjCSelectorType = ':', NSObjCObjectType = '@', NSObjCStructType = '{', NSObjCPointerType = '^', NSObjCStringType = '*', NSObjCArrayType = '[', NSObjCUnionType = '(', NSObjCBitfield = 'b' }
+__attribute__((deprecated));
+typedef int kern_return_t;
+typedef kern_return_t mach_error_t;
+typedef mach_port_t io_object_t;
+typedef io_object_t io_service_t;
+typedef struct __DASession * DASessionRef;
+extern DASessionRef DASessionCreate( CFAllocatorRef allocator );
+typedef struct __DADisk * DADiskRef;
+extern DADiskRef DADiskCreateFromBSDName( CFAllocatorRef allocator, DASessionRef session, const char * name );
+extern DADiskRef DADiskCreateFromIOMedia( CFAllocatorRef allocator, DASessionRef session, io_service_t media );
+extern CFDictionaryRef DADiskCopyDescription( DADiskRef disk );
+extern DADiskRef DADiskCopyWholeDisk( DADiskRef disk );
+ at interface NSAppleEventManager : NSObject {
+}
+ at end enum {
+kDAReturnSuccess = 0, kDAReturnError = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x01, kDAReturnBusy = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x02, kDAReturnBadArgument = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x03, kDAReturnExclusiveAccess = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x04, kDAReturnNoResources = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x05, kDAReturnNotFound = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x06, kDAReturnNotMounted = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x07, kDAReturnNotPermitted = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x08, kDAReturnNotPrivileged = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x09, kDAReturnNotReady = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x0A, kDAReturnNotWritable = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x0B, kDAReturnUnsupported = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x0C };
+typedef mach_error_t DAReturn;
+typedef const struct __DADissenter * DADissenterRef;
+extern DADissenterRef DADissenterCreate( CFAllocatorRef allocator, DAReturn status, CFStringRef string );
+
+//===----------------------------------------------------------------------===//
+// Test cases.
+//===----------------------------------------------------------------------===//
+
+CFAbsoluteTime f1() {
+ CFAbsoluteTime t = CFAbsoluteTimeGetCurrent();
+ CFDateRef date = CFDateCreate(0, t);
+ CFRetain(date);
+ CFRelease(date);
+ CFDateGetAbsoluteTime(date); // no-warning
+ CFRelease(date);
+ t = CFDateGetAbsoluteTime(date); // expected-warning{{Reference-counted object is used after it is released.}}
+ return t;
+}
+
+CFAbsoluteTime f2() {
+ CFAbsoluteTime t = CFAbsoluteTimeGetCurrent();
+ CFDateRef date = CFDateCreate(0, t);
+ [((NSDate*) date) retain];
+ CFRelease(date);
+ CFDateGetAbsoluteTime(date); // no-warning
+ [((NSDate*) date) release];
+ t = CFDateGetAbsoluteTime(date); // expected-warning{{Reference-counted object is used after it is released.}}
+ return t;
+}
+
+
+NSDate* global_x;
+
+// Test to see if we supresss an error when we store the pointer
+// to a global.
+
+CFAbsoluteTime f3() {
+ CFAbsoluteTime t = CFAbsoluteTimeGetCurrent();
+ CFDateRef date = CFDateCreate(0, t);
+ [((NSDate*) date) retain];
+ CFRelease(date);
+ CFDateGetAbsoluteTime(date); // no-warning
+ global_x = (NSDate*) date;
+ [((NSDate*) date) release];
+ t = CFDateGetAbsoluteTime(date); // no-warning
+ return t;
+}
+
+// Test to see if we supresss an error when we store the pointer
+// to a struct.
+
+struct foo {
+ NSDate* f;
+};
+
+CFAbsoluteTime f4() {
+ struct foo x;
+
+ CFAbsoluteTime t = CFAbsoluteTimeGetCurrent();
+ CFDateRef date = CFDateCreate(0, t);
+ [((NSDate*) date) retain];
+ CFRelease(date);
+ CFDateGetAbsoluteTime(date); // no-warning
+ x.f = (NSDate*) date;
+ [((NSDate*) date) release];
+ t = CFDateGetAbsoluteTime(date); // no-warning
+ return t;
+}
+
+// Test a leak.
+
+CFAbsoluteTime f5(int x) {
+ CFAbsoluteTime t = CFAbsoluteTimeGetCurrent();
+ CFDateRef date = CFDateCreate(0, t);
+
+ if (x)
+ CFRelease(date);
+
+ return t; // expected-warning{{leak}}
+}
+
+// Test a leak involving the return.
+
+CFDateRef f6(int x) {
+ CFDateRef date = CFDateCreate(0, CFAbsoluteTimeGetCurrent());
+ CFRetain(date);
+ return date; // expected-warning{{leak}}
+}
+
+// Test a leak involving an overwrite.
+
+CFDateRef f7() {
+ CFDateRef date = CFDateCreate(0, CFAbsoluteTimeGetCurrent());
+ CFRetain(date); //expected-warning{{leak}}
+ date = CFDateCreate(0, CFAbsoluteTimeGetCurrent());
+ return date;
+}
+
+// Generalization of Create rule. MyDateCreate returns a CFXXXTypeRef, and
+// has the word create.
+CFDateRef MyDateCreate();
+
+CFDateRef f8() {
+ CFDateRef date = MyDateCreate();
+ CFRetain(date);
+ return date; // expected-warning{{leak}}
+}
+
+CFDateRef f9() {
+ CFDateRef date = CFDateCreate(0, CFAbsoluteTimeGetCurrent());
+ int *p = 0;
+ // test that the checker assumes that CFDateCreate returns a non-null
+ // pointer
+ if (!date) *p = 1; // no-warning
+ return date;
+}
+
+// Handle DiskArbitration API:
+//
+// http://developer.apple.com/DOCUMENTATION/DARWIN/Reference/DiscArbitrationFramework/
+//
+void f10(io_service_t media, DADiskRef d, CFStringRef s) {
+ DADiskRef disk = DADiskCreateFromBSDName(kCFAllocatorDefault, 0, "hello");
+ if (disk) NSLog(@"ok"); // expected-warning{{leak}}
+
+ disk = DADiskCreateFromIOMedia(kCFAllocatorDefault, 0, media);
+ if (disk) NSLog(@"ok"); // expected-warning{{leak}}
+
+ CFDictionaryRef dict = DADiskCopyDescription(d);
+ if (dict) NSLog(@"ok"); // expected-warning{{leak}}
+
+ disk = DADiskCopyWholeDisk(d);
+ if (disk) NSLog(@"ok"); // expected-warning{{leak}}
+
+ DADissenterRef dissenter = DADissenterCreate(kCFAllocatorDefault,
+ kDAReturnSuccess, s);
+ if (dissenter) NSLog(@"ok"); // expected-warning{{leak}}
+
+ DASessionRef session = DASessionCreate(kCFAllocatorDefault);
+ if (session) NSLog(@"ok"); // expected-warning{{leak}}
+}
+
+// Test retain/release checker with CFString and CFMutableArray.
+void f11() {
+ // Create the array.
+ CFMutableArrayRef A = CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks);
+
+ // Create a string.
+ CFStringRef s1 = CFStringCreateWithCString(0, "hello world",
+ kCFStringEncodingUTF8);
+
+ // Add the string to the array.
+ CFArrayAppendValue(A, s1);
+
+ // Decrement the reference count.
+ CFRelease(s1); // no-warning
+
+ // Get the string. We don't own it.
+ s1 = (CFStringRef) CFArrayGetValueAtIndex(A, 0);
+
+ // Release the array.
+ CFRelease(A); // no-warning
+
+ // Release the string. This is a bug.
+ CFRelease(s1); // expected-warning{{Incorrect decrement of the reference count}}
+}
+
More information about the cfe-commits
mailing list