retain/release checker: When generating summaries for CF/CG functions, allow arguments to "escape" if they are passed to a function containing the terms "InsertValue", "SetValue", or "AddValue". This fixes <rdar://problem/6539791>.
llvm-svn: 63341
This commit is contained in:
parent
ad89c410e6
commit
ed90de4caa
|
|
@ -809,12 +809,27 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) {
|
||||||
if (isRelease(FD, FName+2))
|
if (isRelease(FD, FName+2))
|
||||||
S = getUnarySummary(FT, cfrelease);
|
S = getUnarySummary(FT, cfrelease);
|
||||||
else {
|
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());
|
assert (ScratchArgs.empty());
|
||||||
S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing,
|
// Remaining CoreFoundation and CoreGraphics functions.
|
||||||
DoNothing);
|
// We use to assume that they all strictly followed the ownership idiom
|
||||||
|
// and that ownership cannot be transferred. While this is technically
|
||||||
|
// correct, many methods allow a tracked object to escape. For example:
|
||||||
|
//
|
||||||
|
// CFMutableDictionaryRef x = CFDictionaryCreateMutable(...);
|
||||||
|
// CFDictionaryAddValue(y, key, x);
|
||||||
|
// CFRelease(x);
|
||||||
|
// ... it is okay to use 'x' since 'y' has a reference to it
|
||||||
|
//
|
||||||
|
// We handle this and similar cases with the follow heuristic. If the
|
||||||
|
// function name contains "InsertValue", "SetValue" or "AddValue" then
|
||||||
|
// we assume that arguments may "escape."
|
||||||
|
//
|
||||||
|
ArgEffect E = (CStrInCStrNoCase(FName, "InsertValue") ||
|
||||||
|
CStrInCStrNoCase(FName, "AddValue") ||
|
||||||
|
CStrInCStrNoCase(FName, "SetValue"))
|
||||||
|
? MayEscape : DoNothing;
|
||||||
|
|
||||||
|
S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, E);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
// RUN: clang -analyze -checker-cfref -analyzer-store-basic -verify %s &&
|
||||||
|
// RUN: clang -analyze -checker-cfref -analyzer-store-region -verify %s
|
||||||
|
|
||||||
|
typedef const struct __CFAllocator * CFAllocatorRef;
|
||||||
|
typedef struct __CFDictionary * CFMutableDictionaryRef;
|
||||||
|
typedef signed long CFIndex;
|
||||||
|
typedef CFIndex CFNumberType;
|
||||||
|
typedef const void * CFTypeRef;
|
||||||
|
typedef struct {} CFDictionaryKeyCallBacks, CFDictionaryValueCallBacks;
|
||||||
|
typedef const struct __CFNumber * CFNumberRef;
|
||||||
|
extern const CFAllocatorRef kCFAllocatorDefault;
|
||||||
|
extern const CFDictionaryKeyCallBacks kCFTypeDictionaryKeyCallBacks;
|
||||||
|
extern const CFDictionaryValueCallBacks kCFTypeDictionaryValueCallBacks;
|
||||||
|
enum { kCFNumberSInt32Type = 3 };
|
||||||
|
CFMutableDictionaryRef CFDictionaryCreateMutable(CFAllocatorRef allocator, CFIndex capacity, const CFDictionaryKeyCallBacks *keyCallBacks, const CFDictionaryValueCallBacks *valueCallBacks);
|
||||||
|
void CFDictionaryAddValue(CFMutableDictionaryRef theDict, const void *key, const void *value);
|
||||||
|
void CFRelease(CFTypeRef cf);
|
||||||
|
extern CFNumberRef CFNumberCreate(CFAllocatorRef allocator, CFNumberType theType, const void *valuePtr);
|
||||||
|
|
||||||
|
void f(CFMutableDictionaryRef y, void* key, void* val_key) {
|
||||||
|
CFMutableDictionaryRef x = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
||||||
|
CFDictionaryAddValue(y, key, x);
|
||||||
|
CFRelease(x); // the dictionary keeps a reference, so the object isn't deallocated yet
|
||||||
|
signed z = 1;
|
||||||
|
CFNumberRef value = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &z);
|
||||||
|
if (value) {
|
||||||
|
CFDictionaryAddValue(x, val_key, value); // no-warning
|
||||||
|
CFRelease(value);
|
||||||
|
CFDictionaryAddValue(y, val_key, value); // no-warning
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue