From: Devin Coughlin Date: Sat, 25 Nov 2017 14:57:42 +0000 (+0000) Subject: [analyzer] Teach RetainCountChecker about CoreMedia APIs X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=486042e6fec16778a862e16b75cc526d6d9d5606;p=clang [analyzer] Teach RetainCountChecker about CoreMedia APIs 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 --- diff --git a/lib/Analysis/CocoaConventions.cpp b/lib/Analysis/CocoaConventions.cpp index be1262dc99..4d57623e21 100644 --- a/lib/Analysis/CocoaConventions.cpp +++ b/lib/Analysis/CocoaConventions.cpp @@ -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); } diff --git a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp index 4db83af17f..e47494a3e9 100644 --- a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp @@ -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; } diff --git a/test/Analysis/retain-release.m b/test/Analysis/retain-release.m index a1cc62cb35..4add50eb5d 100644 --- a/test/Analysis/retain-release.m +++ b/test/Analysis/retain-release.m @@ -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.