r231553 - [analyzer] RetainCountChecker: CF properties are always manually retain-counted.

Jordan Rose jordan_rose at apple.com
Fri Mar 6 21:47:25 PST 2015


Author: jrose
Date: Fri Mar  6 23:47:24 2015
New Revision: 231553

URL: http://llvm.org/viewvc/llvm-project?rev=231553&view=rev
Log:
[analyzer] RetainCountChecker: CF properties are always manually retain-counted.

In theory we could assume a CF property is stored at +0 if there's not a custom
setter, but that's not really worth the complexity. What we do know is that a
CF property can't have ownership attributes, and so we shouldn't assume anything
about the ownership of the ivar.

rdar://problem/20076963

Modified:
    cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
    cfe/trunk/test/Analysis/properties.m

Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp?rev=231553&r1=231552&r2=231553&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp Fri Mar  6 23:47:24 2015
@@ -2882,9 +2882,10 @@ void RetainCountChecker::checkPostStmt(c
 
     // Also don't do anything if the ivar is unretained. If so, we know that
     // there's no outstanding retain count for the value.
-    if (const ObjCPropertyDecl *Prop = findPropForIvar(IRE->getDecl()))
-      if (!Prop->isRetaining())
-        return;
+    if (Kind == RetEffect::ObjC)
+      if (const ObjCPropertyDecl *Prop = findPropForIvar(IRE->getDecl()))
+        if (!Prop->isRetaining())
+          return;
 
     // Note that this value has been loaded from an ivar.
     C.addTransition(setRefBinding(State, Sym, RV->withIvarAccess()));
@@ -2900,12 +2901,16 @@ void RetainCountChecker::checkPostStmt(c
   }
 
   // Try to find the property associated with this ivar.
-  const ObjCPropertyDecl *Prop = findPropForIvar(IRE->getDecl());
-
-  if (Prop && !Prop->isRetaining())
-    State = setRefBinding(State, Sym, PlusZero);
-  else
+  if (Kind != RetEffect::ObjC) {
     State = setRefBinding(State, Sym, PlusZero.withIvarAccess());
+  } else {
+    const ObjCPropertyDecl *Prop = findPropForIvar(IRE->getDecl());
+
+    if (Prop && !Prop->isRetaining())
+      State = setRefBinding(State, Sym, PlusZero);
+    else
+      State = setRefBinding(State, Sym, PlusZero.withIvarAccess());
+  }
 
   C.addTransition(State);
 }

Modified: cfe/trunk/test/Analysis/properties.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/properties.m?rev=231553&r1=231552&r2=231553&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/properties.m (original)
+++ cfe/trunk/test/Analysis/properties.m Fri Mar  6 23:47:24 2015
@@ -3,6 +3,10 @@
 
 void clang_analyzer_eval(int);
 
+typedef const void * CFTypeRef;
+extern CFTypeRef CFRetain(CFTypeRef cf);
+void CFRelease(CFTypeRef cf);
+
 typedef signed char BOOL;
 typedef unsigned int NSUInteger;
 typedef struct _NSZone NSZone;
@@ -352,6 +356,7 @@ void testOpaqueConsistency(OpaqueIntWrap
 @property (strong) id ownedProp;
 @property (unsafe_unretained) id unownedProp;
 @property (nonatomic, strong) id manualProp;
+ at property CFTypeRef cfProp;
 @end
 
 @implementation RetainCountTesting {
@@ -382,6 +387,13 @@ void testOpaqueConsistency(OpaqueIntWrap
   [_ivarOnly release]; // expected-warning{{used after it is released}}
 }
 
+- (void)testOverreleaseCF {
+  CFRetain(_cfProp);
+  CFRelease(_cfProp);
+  CFRelease(_cfProp);
+  CFRelease(_cfProp); // expected-warning{{used after it is released}}
+}
+
 - (void)testOverreleaseOwnedIvarUse {
   [_ownedProp retain];
   [_ownedProp release];
@@ -396,6 +408,15 @@ void testOpaqueConsistency(OpaqueIntWrap
   [_ivarOnly myMethod]; // expected-warning{{used after it is released}}
 }
 
+- (void)testOverreleaseCFUse {
+  CFRetain(_cfProp);
+  CFRelease(_cfProp);
+  CFRelease(_cfProp);
+
+  extern void CFUse(CFTypeRef);
+  CFUse(_cfProp); // expected-warning{{used after it is released}}
+}
+
 - (void)testOverreleaseOwnedIvarAutoreleaseOkay {
   [_ownedProp retain];
   [_ownedProp release];
@@ -465,6 +486,21 @@ void testOpaqueConsistency(OpaqueIntWrap
   [fromIvar release]; // no-warning
 }
 
+- (void)testPropertyAccessThenReleaseCF {
+  CFTypeRef owned = CFRetain(self.cfProp);
+  CFRelease(owned);
+  CFRelease(_cfProp); // no-warning
+  clang_analyzer_eval(owned == _cfProp); // expected-warning{{TRUE}}
+}
+
+- (void)testPropertyAccessThenReleaseCF2 {
+  CFTypeRef fromIvar = _cfProp;
+  CFTypeRef owned = CFRetain(self.cfProp);
+  CFRelease(owned);
+  CFRelease(fromIvar);
+  clang_analyzer_eval(owned == fromIvar); // expected-warning{{TRUE}}
+}
+
 - (id)getUnownedFromProperty {
   [_ownedProp retain];
   [_ownedProp autorelease];
@@ -498,6 +534,11 @@ void testOpaqueConsistency(OpaqueIntWrap
   [_ivarOnly release]; // FIXME: no-warning{{not owned}}
 }
 
+- (void)testAssignCF:(CFTypeRef)newValue {
+  _cfProp = newValue;
+  CFRelease(_cfProp); // FIXME: no-warning{{not owned}}
+}
+
 - (void)testAssignOwnedOkay:(id)newValue {
   _ownedProp = [newValue retain];
   [_ownedProp release]; // no-warning
@@ -513,6 +554,11 @@ void testOpaqueConsistency(OpaqueIntWrap
   [_ivarOnly release]; // no-warning
 }
 
+- (void)testAssignCFOkay:(CFTypeRef)newValue {
+  _cfProp = CFRetain(newValue);
+  CFRelease(_cfProp); // no-warning
+}
+
 // rdar://problem/19862648
 - (void)establishIvarIsNilDuringLoops {
   extern id getRandomObject();





More information about the cfe-commits mailing list