forked from OSchip/llvm-project
[analyzer] RetainCountChecker: add support for CFAutorelease.
<rdar://problems/13710586&13710643> llvm-svn: 192113
This commit is contained in:
parent
027dfade54
commit
7741132f47
|
@ -550,7 +550,7 @@ class RetainSummaryManager {
|
|||
/// data in ScratchArgs.
|
||||
ArgEffects getArgEffects();
|
||||
|
||||
enum UnaryFuncKind { cfretain, cfrelease, cfmakecollectable };
|
||||
enum UnaryFuncKind { cfretain, cfrelease, cfautorelease, cfmakecollectable };
|
||||
|
||||
const RetainSummary *getUnarySummary(const FunctionType* FT,
|
||||
UnaryFuncKind func);
|
||||
|
@ -804,6 +804,10 @@ static bool isRelease(const FunctionDecl *FD, StringRef FName) {
|
|||
return FName.endswith("Release");
|
||||
}
|
||||
|
||||
static bool isAutorelease(const FunctionDecl *FD, StringRef FName) {
|
||||
return FName.endswith("Autorelease");
|
||||
}
|
||||
|
||||
static bool isMakeCollectable(const FunctionDecl *FD, StringRef FName) {
|
||||
// FIXME: Remove FunctionDecl parameter.
|
||||
// FIXME: Is it really okay if MakeCollectable isn't a suffix?
|
||||
|
@ -1063,12 +1067,19 @@ RetainSummaryManager::getFunctionSummary(const FunctionDecl *FD) {
|
|||
if (RetTy->isPointerType()) {
|
||||
// For CoreFoundation ('CF') types.
|
||||
if (cocoa::isRefType(RetTy, "CF", FName)) {
|
||||
if (isRetain(FD, FName))
|
||||
if (isRetain(FD, FName)) {
|
||||
S = getUnarySummary(FT, cfretain);
|
||||
else if (isMakeCollectable(FD, FName))
|
||||
} else if (isAutorelease(FD, FName)) {
|
||||
S = getUnarySummary(FT, cfautorelease);
|
||||
// The headers use cf_consumed, but we can fully model CFAutorelease
|
||||
// ourselves.
|
||||
AllowAnnotations = false;
|
||||
} else if (isMakeCollectable(FD, FName)) {
|
||||
S = getUnarySummary(FT, cfmakecollectable);
|
||||
else
|
||||
AllowAnnotations = false;
|
||||
} else {
|
||||
S = getCFCreateGetRuleSummary(FD);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -1171,9 +1182,10 @@ RetainSummaryManager::getUnarySummary(const FunctionType* FT,
|
|||
|
||||
ArgEffect Effect;
|
||||
switch (func) {
|
||||
case cfretain: Effect = IncRef; break;
|
||||
case cfrelease: Effect = DecRef; break;
|
||||
case cfmakecollectable: Effect = MakeCollectable; break;
|
||||
case cfretain: Effect = IncRef; break;
|
||||
case cfrelease: Effect = DecRef; break;
|
||||
case cfautorelease: Effect = Autorelease; break;
|
||||
case cfmakecollectable: Effect = MakeCollectable; break;
|
||||
}
|
||||
|
||||
ScratchArgs = AF.add(ScratchArgs, 0, Effect);
|
||||
|
@ -3104,11 +3116,13 @@ bool RetainCountChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
|
|||
canEval = II->isStr("NSMakeCollectable");
|
||||
} else if (ResultTy->isPointerType()) {
|
||||
// Handle: (CF|CG)Retain
|
||||
// CFAutorelease
|
||||
// CFMakeCollectable
|
||||
// It's okay to be a little sloppy here (CGMakeCollectable doesn't exist).
|
||||
if (cocoa::isRefType(ResultTy, "CF", FName) ||
|
||||
cocoa::isRefType(ResultTy, "CG", FName)) {
|
||||
canEval = isRetain(FD, FName) || isMakeCollectable(FD, FName);
|
||||
canEval = isRetain(FD, FName) || isAutorelease(FD, FName) ||
|
||||
isMakeCollectable(FD, FName);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -63,9 +63,12 @@ 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);
|
||||
extern CFTypeRef CFMakeCollectable(CFTypeRef cf);
|
||||
extern CFTypeRef CFAutorelease(CFTypeRef CF_CONSUMED cf);
|
||||
|
||||
typedef struct {
|
||||
}
|
||||
CFArrayCallBacks;
|
||||
|
@ -2004,6 +2007,87 @@ static int Cond;
|
|||
}
|
||||
@end
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// CFAutorelease
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
CFTypeRef getAutoreleasedCFType() {
|
||||
extern CFTypeRef CFCreateSomething();
|
||||
return CFAutorelease(CFCreateSomething()); // no-warning
|
||||
}
|
||||
|
||||
CFTypeRef getIncorrectlyAutoreleasedCFType() {
|
||||
extern CFTypeRef CFGetSomething();
|
||||
return CFAutorelease(CFGetSomething()); // expected-warning{{Object autoreleased too many times}}
|
||||
}
|
||||
|
||||
CFTypeRef createIncorrectlyAutoreleasedCFType() {
|
||||
extern CFTypeRef CFCreateSomething();
|
||||
return CFAutorelease(CFCreateSomething()); // expected-warning{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}}
|
||||
}
|
||||
|
||||
void useAfterAutorelease() {
|
||||
extern CFTypeRef CFCreateSomething();
|
||||
CFTypeRef obj = CFCreateSomething();
|
||||
CFAutorelease(obj);
|
||||
|
||||
extern void useCF(CFTypeRef);
|
||||
useCF(obj); // no-warning
|
||||
}
|
||||
|
||||
void useAfterRelease() {
|
||||
// Sanity check that the previous example would have warned with CFRelease.
|
||||
extern CFTypeRef CFCreateSomething();
|
||||
CFTypeRef obj = CFCreateSomething();
|
||||
CFRelease(obj);
|
||||
|
||||
extern void useCF(CFTypeRef);
|
||||
useCF(obj); // expected-warning{{Reference-counted object is used after it is released}}
|
||||
}
|
||||
|
||||
void testAutoreleaseReturnsInput() {
|
||||
extern CFTypeRef CFCreateSomething();
|
||||
CFTypeRef obj = CFCreateSomething(); // expected-warning{{Potential leak of an object stored into 'obj'}}
|
||||
CFTypeRef second = CFAutorelease(obj);
|
||||
CFRetain(second);
|
||||
}
|
||||
|
||||
CFTypeRef testAutoreleaseReturnsInputSilent() {
|
||||
extern CFTypeRef CFCreateSomething();
|
||||
CFTypeRef obj = CFCreateSomething();
|
||||
CFTypeRef alias = CFAutorelease(obj);
|
||||
CFRetain(alias);
|
||||
CFRelease(obj);
|
||||
return obj; // no-warning
|
||||
}
|
||||
|
||||
void autoreleaseTypedObject() {
|
||||
CFArrayRef arr = CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks);
|
||||
CFAutorelease((CFTypeRef)arr); // no-warning
|
||||
}
|
||||
|
||||
void autoreleaseReturningTypedObject() {
|
||||
CFArrayRef arr = CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // expected-warning{{Potential leak of an object stored into 'arr'}}
|
||||
CFArrayRef alias = (CFArrayRef)CFAutorelease((CFTypeRef)arr);
|
||||
CFRetain(alias);
|
||||
}
|
||||
|
||||
CFArrayRef autoreleaseReturningTypedObjectSilent() {
|
||||
CFArrayRef arr = CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks);
|
||||
CFArrayRef alias = (CFArrayRef)CFAutorelease((CFTypeRef)arr);
|
||||
CFRetain(alias);
|
||||
CFRelease(arr);
|
||||
return alias; // no-warning
|
||||
}
|
||||
|
||||
void autoreleaseObjC() {
|
||||
id obj = [@1 retain];
|
||||
CFAutorelease(obj); // no-warning
|
||||
|
||||
id anotherObj = @1;
|
||||
CFAutorelease(anotherObj);
|
||||
} // expected-warning{{Object autoreleased too many times}}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// <rdar://problem/13783514> xpc_connection_set_finalizer_f
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
Loading…
Reference in New Issue