]> granicus.if.org Git - clang/commitdiff
[analyzer] Teach RetainCountChecker about CoreMedia APIs
authorDevin Coughlin <dcoughlin@apple.com>
Sat, 25 Nov 2017 14:57:42 +0000 (14:57 +0000)
committerDevin Coughlin <dcoughlin@apple.com>
Sat, 25 Nov 2017 14:57:42 +0000 (14:57 +0000)
Teach the retain-count checker that CoreMedia reference types use
CoreFoundation-style reference counting. This enables the checker
to catch leaks and over releases of those types.

rdar://problem/33599757

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@318979 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Analysis/CocoaConventions.cpp
lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
test/Analysis/retain-release.m

index be1262dc99108a911e73c542a4c356a4720fa38e..4d57623e216114ae2129ace3ae68d0a6e97e079a 100644 (file)
@@ -47,12 +47,19 @@ bool cocoa::isRefType(QualType RetTy, StringRef Prefix,
   return Name.startswith(Prefix);
 }
 
+/// Returns true when the passed-in type is a CF-style reference-counted
+/// type from the DiskArbitration framework.
+static bool isDiskArbitrationAPIRefType(QualType T) {
+  return cocoa::isRefType(T, "DADisk") ||
+      cocoa::isRefType(T, "DADissenter") ||
+      cocoa::isRefType(T, "DASessionRef");
+}
+
 bool coreFoundation::isCFObjectRef(QualType T) {
   return cocoa::isRefType(T, "CF") || // Core Foundation.
          cocoa::isRefType(T, "CG") || // Core Graphics.
-         cocoa::isRefType(T, "DADisk") || // Disk Arbitration API.
-         cocoa::isRefType(T, "DADissenter") ||
-         cocoa::isRefType(T, "DASessionRef");
+         cocoa::isRefType(T, "CM") || // Core Media.
+         isDiskArbitrationAPIRefType(T);
 }
 
 
index 4db83af17f3fa0aa7c63e55e597035ad33237b14..e47494a3e90b343a185f3122e842c755d2079285 100644 (file)
@@ -1201,10 +1201,10 @@ RetainSummaryManager::getFunctionSummary(const FunctionDecl *FD) {
         break;
       }
 
-      // For the Disk Arbitration API (DiskArbitration/DADisk.h)
-      if (cocoa::isRefType(RetTy, "DADisk") ||
-          cocoa::isRefType(RetTy, "DADissenter") ||
-          cocoa::isRefType(RetTy, "DASessionRef")) {
+      // For all other CF-style types, use the Create/Get
+      // rule for summaries but don't support Retain functions
+      // with framework-specific prefixes.
+      if (coreFoundation::isCFObjectRef(RetTy)) {
         S = getCFCreateGetRuleSummary(FD);
         break;
       }
index a1cc62cb3593f85a22863d6accd5ab8685d9a1d0..4add50eb5d0d5eb60d2022e87a396c1ff1805618 100644 (file)
@@ -450,6 +450,51 @@ void f10(io_service_t media, DADiskRef d, CFStringRef s) {
   if (session) NSLog(@"ok");
 }
 
+
+// Handle CoreMedia API
+
+struct CMFoo;
+typedef struct CMFoo *CMFooRef;
+
+CMFooRef CMCreateFooRef();
+CMFooRef CMGetFooRef();
+
+typedef signed long SInt32;
+typedef SInt32  OSStatus;
+OSStatus CMCreateFooAndReturnViaOutParameter(CMFooRef * CF_RETURNS_RETAINED fooOut);
+
+void testLeakCoreMediaReferenceType() {
+  CMFooRef f = CMCreateFooRef(); // expected-warning{{leak}}
+}
+
+void testOverReleaseMediaReferenceType() {
+  CMFooRef f = CMGetFooRef();
+  CFRelease(f); // expected-warning{{Incorrect decrement of the reference count}}
+}
+
+void testOkToReleaseReturnsRetainedOutParameter() {
+  CMFooRef foo = 0;
+  OSStatus status = CMCreateFooAndReturnViaOutParameter(&foo);
+
+  if (status != 0)
+    return;
+
+  CFRelease(foo); // no-warning
+}
+
+void testLeakWithReturnsRetainedOutParameter() {
+  CMFooRef foo = 0;
+  OSStatus status = CMCreateFooAndReturnViaOutParameter(&foo);
+
+  if (status != 0)
+    return;
+
+  // FIXME: Ideally we would report a leak here since it is the caller's
+  // responsibility to release 'foo'. However, we don't currently have
+  // a mechanism in this checker to only require a release when a successful
+  // status is returned.
+}
+
 // Test retain/release checker with CFString and CFMutableArray.
 void f11() {
   // Create the array.