From: Ted Kremenek Date: Sun, 3 May 2009 06:08:32 +0000 (+0000) Subject: Fix: CF objects returned from methods with "new" or "copy... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=92511433cc78021dca5f340136be1bbd72388191;p=clang Fix: CF objects returned from methods with "new" or "copy" in their name should be treated as owned For methods that follow the "fundamental rule" and return Core Foundation objects, treat those objects as owned by the caller. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@70665 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp index b9c9bb5923..58f581aff8 100644 --- a/lib/Analysis/CFRefCount.cpp +++ b/lib/Analysis/CFRefCount.cpp @@ -621,6 +621,7 @@ public: void InitializeMethodSummaries(); bool isTrackedObjCObjectType(QualType T); + bool isTrackedCFObjectType(QualType T); private: @@ -834,6 +835,14 @@ bool RetainSummaryManager::isTrackedObjCObjectType(QualType Ty) { return false; } +bool RetainSummaryManager::isTrackedCFObjectType(QualType T) { + return isRefType(T, "CF") || // Core Foundation. + isRefType(T, "CG") || // Core Graphics. + isRefType(T, "DADisk") || // Disk Arbitration API. + isRefType(T, "DADissenter") || + isRefType(T, "DASessionRef"); +} + //===----------------------------------------------------------------------===// // Summary creation for functions (largely uses of Core Foundation). //===----------------------------------------------------------------------===// @@ -1170,26 +1179,37 @@ RetainSummaryManager::getCommonMethodSummary(const ObjCMethodDecl* MD, assert(!str.empty()); if (CStrInCStrNoCase(&str[0], "delegate:")) ReceiverEff = StopTracking; } + // Look for methods that return an owned object. - if (!isTrackedObjCObjectType(RetTy)) { - if (ScratchArgs.isEmpty() && ReceiverEff == DoNothing) - return 0; + if (isTrackedObjCObjectType(RetTy)) { + // EXPERIMENTAL: Assume the Cocoa conventions for all objects returned + // by instance methods. + + RetEffect E = + followsFundamentalRule(S.getIdentifierInfoForSlot(0)->getName()) + ? (isGCEnabled() ? RetEffect::MakeGCNotOwned() + : RetEffect::MakeOwned(RetEffect::ObjC, true)) + : RetEffect::MakeNotOwned(RetEffect::ObjC); - return getPersistentSummary(RetEffect::MakeNoRet(), ReceiverEff, - MayEscape); + return getPersistentSummary(E, ReceiverEff, MayEscape); } - // EXPERIMENTAL: Assume the Cocoa conventions for all objects returned - // by instance methods. + // Look for methods that return an owned core foundation object. + if (isTrackedCFObjectType(RetTy)) { + RetEffect E = + followsFundamentalRule(S.getIdentifierInfoForSlot(0)->getName()) + ? RetEffect::MakeOwned(RetEffect::CF, true) + : RetEffect::MakeNotOwned(RetEffect::CF); + + return getPersistentSummary(E, ReceiverEff, MayEscape); + } - RetEffect E = - followsFundamentalRule(S.getIdentifierInfoForSlot(0)->getName()) - ? (isGCEnabled() ? RetEffect::MakeGCNotOwned() - : RetEffect::MakeOwned(RetEffect::ObjC, true)) - : RetEffect::MakeNotOwned(RetEffect::ObjC); + if (ScratchArgs.isEmpty() && ReceiverEff == DoNothing) + return 0; - return getPersistentSummary(E, ReceiverEff, MayEscape); + return getPersistentSummary(RetEffect::MakeNoRet(), ReceiverEff, + MayEscape); } RetainSummary* diff --git a/test/Analysis/NSString.m b/test/Analysis/NSString.m index 2f6d5912cf..702551bbda 100644 --- a/test/Analysis/NSString.m +++ b/test/Analysis/NSString.m @@ -262,7 +262,7 @@ void test_stringWithFormat() { [string release]; // expected-warning{{Incorrect decrement of the reference count}} } -// Test isTrackedObjectType() +// Test isTrackedObjectType(). typedef NSString* WonkyTypedef; @interface TestIsTracked + (WonkyTypedef)newString; @@ -272,6 +272,22 @@ void test_isTrackedObjectType(void) { NSString *str = [TestIsTracked newString]; // expected-warning{{Potential leak}} } +// Test isTrackedCFObjectType(). +@interface TestIsCFTracked ++ (CFStringRef) badNewCFString; ++ (CFStringRef) newCFString; +@end + +@implementation TestIsCFTracked ++ (CFStringRef) newCFString { + return CFStringCreateWithFormat(kCFAllocatorDefault, ((void*)0), ((CFStringRef) __builtin___CFStringMakeConstantString ("" "%d" "")), 100); // no-warning +} ++ (CFStringRef) badNewCFString { + return CFStringCreateWithFormat(kCFAllocatorDefault, ((void*)0), ((CFStringRef) __builtin___CFStringMakeConstantString ("" "%d" "")), 100); // expected-warning{{leak}} +} + + + // Test @synchronized void test_synchronized(id x) { @synchronized(x) { @@ -279,3 +295,4 @@ void test_synchronized(id x) { } } +// Test return from method starting with 'new' or 'copy'