Skip to content

Commit

Permalink
[analyzer] RetainCount: Suppress retain detection heuristic on some C…
Browse files Browse the repository at this point in the history
…M methods.

If it ends with "Retain" like CFRetain and returns a CFTypeRef like CFRetain,
then it is not necessarily a CFRetain. But it is indeed true that these two
return something retained.

Differential Revision: https://reviews.llvm.org/D55907

rdar://problem/39390714

llvm-svn: 349862
  • Loading branch information
haoNoQ committed Dec 21, 2018
1 parent 33c46ca commit 212bbfa
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 2 deletions.
11 changes: 11 additions & 0 deletions clang/lib/StaticAnalyzer/Core/RetainSummaryManager.cpp
Expand Up @@ -204,6 +204,11 @@ const RetainSummary *RetainSummaryManager::getSummaryForObjCOrCFObject(
AllowAnnotations = false;
return RetTy->isObjCIdType() ? getUnarySummary(FT, cfmakecollectable)
: getPersistentStopSummary();
} else if (FName == "CMBufferQueueDequeueAndRetain" ||
FName == "CMBufferQueueDequeueIfDataReadyAndRetain") {
// Part of: <rdar://problem/39390714>.
return getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF), DoNothing,
DoNothing);
} else if (FName == "CFPlugInInstanceCreate") {
return getPersistentSummary(RetEffect::MakeNoRet());
} else if (FName == "IORegistryEntrySearchCFProperty" ||
Expand Down Expand Up @@ -591,6 +596,12 @@ RetainSummaryManager::canEval(const CallExpr *CE, const FunctionDecl *FD,
// Handle: (CF|CG|CV)Retain
// CFAutorelease
// It's okay to be a little sloppy here.
if (FName == "CMBufferQueueDequeueAndRetain" ||
FName == "CMBufferQueueDequeueIfDataReadyAndRetain") {
// Part of: <rdar://problem/39390714>.
// These are not retain. They just return something and retain it.
return None;
}
if (cocoa::isRefType(ResultTy, "CF", FName) ||
cocoa::isRefType(ResultTy, "CG", FName) ||
cocoa::isRefType(ResultTy, "CV", FName))
Expand Down
30 changes: 28 additions & 2 deletions clang/test/Analysis/retain-release.m
@@ -1,9 +1,20 @@
// RUN: rm -f %t.objc.plist %t.objcpp.plist
// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -fblocks -verify -Wno-objc-root-class %s -analyzer-output=plist -o %t.objc.plist
// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -fblocks -verify -x objective-c++ -std=gnu++98 -Wno-objc-root-class %s -analyzer-output=plist -o %t.objcpp.plist
// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10\
// RUN: -analyzer-checker=core,osx.coreFoundation.CFRetainRelease\
// RUN: -analyzer-checker=osx.cocoa.ClassRelease,osx.cocoa.RetainCount\
// RUN: -analyzer-checker=debug.ExprInspection -fblocks -verify %s\
// RUN: -Wno-objc-root-class -analyzer-output=plist -o %t.objcpp.plist
// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10\
// RUN: -analyzer-checker=core,osx.coreFoundation.CFRetainRelease\
// RUN: -analyzer-checker=osx.cocoa.ClassRelease,osx.cocoa.RetainCount\
// RUN: -analyzer-checker=debug.ExprInspection -fblocks -verify %s\
// RUN: -Wno-objc-root-class -analyzer-output=plist -o %t.objcpp.plist\
// RUN: -x objective-c++ -std=gnu++98
// FIXLATER: cat %t.objc.plist ; FileCheck --input-file=%t.objc.plist %s
// FIXLATER: cat %t.objcpp.plist ; FileCheck --input-file=%t.objcpp.plist %s

void clang_analyzer_eval(int);

#if __has_feature(attribute_ns_returns_retained)
#define NS_RETURNS_RETAINED __attribute__((ns_returns_retained))
#endif
Expand Down Expand Up @@ -495,6 +506,21 @@ void testLeakWithReturnsRetainedOutParameter() {
// status is returned.
}

typedef CFTypeRef CMBufferRef;

typedef CFTypeRef *CMBufferQueueRef;

CMBufferRef CMBufferQueueDequeueAndRetain(CMBufferQueueRef);

void testCMBufferQueueDequeueAndRetain(CMBufferQueueRef queue) {
CMBufferRef buffer = CMBufferQueueDequeueAndRetain(queue); // expected-warning{{Potential leak of an object stored into 'buffer'}}
// There's a state split due to the eagerly-assume behavior.
// The point here is that we don't treat CMBufferQueueDequeueAndRetain
// as some sort of CFRetain() that returns its argument.
clang_analyzer_eval((CMFooRef)buffer == (CMFooRef)queue); // expected-warning{{TRUE}}
// expected-warning@-1{{FALSE}}
}

// Test retain/release checker with CFString and CFMutableArray.
void f11() {
// Create the array.
Expand Down

0 comments on commit 212bbfa

Please sign in to comment.