]> granicus.if.org Git - clang/commitdiff
Fix: <rdar://problem/6850275> CF objects returned from methods with "new" or "copy...
authorTed Kremenek <kremenek@apple.com>
Sun, 3 May 2009 06:08:32 +0000 (06:08 +0000)
committerTed Kremenek <kremenek@apple.com>
Sun, 3 May 2009 06:08:32 +0000 (06:08 +0000)
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

lib/Analysis/CFRefCount.cpp
test/Analysis/NSString.m

index b9c9bb5923dd254967c62d00abd966dc31504612..58f581aff83ce7a581df25efb980ec5e4f8c2e36 100644 (file)
@@ -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*
index 2f6d5912cf8a7da882a85f7ea738e09a98f13563..702551bbda3e6d8312610336e1868086eb3e8b13 100644 (file)
@@ -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'