]> granicus.if.org Git - clang/commitdiff
retain/release checker: When generating summaries for CF/CG functions, allow argument...
authorTed Kremenek <kremenek@apple.com>
Thu, 29 Jan 2009 22:45:13 +0000 (22:45 +0000)
committerTed Kremenek <kremenek@apple.com>
Thu, 29 Jan 2009 22:45:13 +0000 (22:45 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@63341 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Analysis/CFRefCount.cpp
test/Analysis/rdar-6539791.c [new file with mode: 0644]

index 35b7ee7b805ac829c60826bdb923c3a9cf62967e..ab9d409dd21d1add34037b5409fef2e04f58644a 100644 (file)
@@ -809,12 +809,27 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) {
       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);
+        assert (ScratchArgs.empty());
+        // Remaining CoreFoundation and CoreGraphics functions.
+        // 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);
       }
     }
   }
diff --git a/test/Analysis/rdar-6539791.c b/test/Analysis/rdar-6539791.c
new file mode 100644 (file)
index 0000000..0d0b675
--- /dev/null
@@ -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
+  }
+}