[cfe-commits] r124386 - in /cfe/trunk: lib/Lex/PPMacroExpansion.cpp lib/StaticAnalyzer/CFRefCount.cpp test/Analysis/retain-release.m www/analyzer/annotations.html

Ted Kremenek kremenek at apple.com
Thu Jan 27 10:43:03 PST 2011


Author: kremenek
Date: Thu Jan 27 12:43:03 2011
New Revision: 124386

URL: http://llvm.org/viewvc/llvm-project?rev=124386&view=rev
Log:
Wire up attributes 'ns_consumed' and 'cf_consumed' in the static analyzer's ObjC retain/release checker.

Modified:
    cfe/trunk/lib/Lex/PPMacroExpansion.cpp
    cfe/trunk/lib/StaticAnalyzer/CFRefCount.cpp
    cfe/trunk/test/Analysis/retain-release.m
    cfe/trunk/www/analyzer/annotations.html

Modified: cfe/trunk/lib/Lex/PPMacroExpansion.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PPMacroExpansion.cpp?rev=124386&r1=124385&r2=124386&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/PPMacroExpansion.cpp (original)
+++ cfe/trunk/lib/Lex/PPMacroExpansion.cpp Thu Jan 27 12:43:03 2011
@@ -537,6 +537,8 @@
            .Case("attribute_ns_returns_not_retained", true)
            .Case("attribute_ns_returns_retained", true)
            .Case("attribute_ns_consumes_self", true)
+           .Case("attribute_ns_consumed", true)
+           .Case("attribute_cf_consumed", true)
            .Case("attribute_objc_ivar_unused", true)
            .Case("attribute_overloadable", true)
            .Case("attribute_unavailable_with_message", true)

Modified: cfe/trunk/lib/StaticAnalyzer/CFRefCount.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/CFRefCount.cpp?rev=124386&r1=124385&r2=124386&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/CFRefCount.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/CFRefCount.cpp Thu Jan 27 12:43:03 2011
@@ -451,6 +451,10 @@
 
     return DefaultArgEffect;
   }
+  
+  void addArg(ArgEffects::Factory &af, unsigned idx, ArgEffect e) {
+    Args = af.add(Args, idx, e);
+  }
 
   /// setDefaultArgEffect - Set the default argument effect.
   void setDefaultArgEffect(ArgEffect E) {
@@ -1191,6 +1195,20 @@
   if (!FD)
     return;
 
+  // Effects on the parameters.
+  unsigned parm_idx = 0;
+  for (FunctionDecl::param_const_iterator pi = FD->param_begin(), 
+       pe = FD->param_end(); pi != pe; ++pi) {
+    const ParmVarDecl *pd = *pi;
+    if (pd->getAttr<NSConsumedAttr>()) {
+      if (!GCEnabled)
+        Summ.addArg(AF, parm_idx, DecRef);      
+    }
+    else if(pd->getAttr<CFConsumedAttr>()) {
+      Summ.addArg(AF, parm_idx, DecRef);      
+    }   
+  }
+  
   QualType RetTy = FD->getResultType();
 
   // Determine if there is a special return effect for this method.
@@ -1225,7 +1243,22 @@
 
   // Effects on the receiver.
   if (MD->getAttr<NSConsumesSelfAttr>()) {
-    Summ.setReceiverEffect(DecRefMsg);      
+    if (!GCEnabled)
+      Summ.setReceiverEffect(DecRefMsg);      
+  }
+  
+  // Effects on the parameters.
+  unsigned parm_idx = 0;
+  for (ObjCMethodDecl::param_iterator pi=MD->param_begin(), pe=MD->param_end();
+       pi != pe; ++pi, ++parm_idx) {
+    const ParmVarDecl *pd = *pi;
+    if (pd->getAttr<NSConsumedAttr>()) {
+      if (!GCEnabled)
+        Summ.addArg(AF, parm_idx, DecRef);      
+    }
+    else if(pd->getAttr<CFConsumedAttr>()) {
+      Summ.addArg(AF, parm_idx, DecRef);      
+    }   
   }
   
   // Determine if there is a special return effect for this method.

Modified: cfe/trunk/test/Analysis/retain-release.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/retain-release.m?rev=124386&r1=124385&r2=124386&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/retain-release.m (original)
+++ cfe/trunk/test/Analysis/retain-release.m Thu Jan 27 12:43:03 2011
@@ -16,6 +16,12 @@
 #if __has_feature(attribute_ns_consumes_self)
 #define NS_CONSUMES_SELF __attribute__((ns_consumes_self))
 #endif
+#if __has_feature(attribute_ns_consumed)
+#define NS_CONSUMED __attribute__((ns_consumed))
+#endif
+#if __has_feature(attribute_cf_consumed)
+#define CF_CONSUMED __attribute__((cf_consumed))
+#endif
 
 //===----------------------------------------------------------------------===//
 // The following code is reduced using delta-debugging from Mac OS X headers:
@@ -1215,6 +1221,8 @@
 - (NSString*) newStringNoAttr;
 - (int) returnsAnOwnedInt NS_RETURNS_RETAINED; // expected-warning{{'ns_returns_retained' attribute only applies to methods that return an Objective-C object}}
 - (id) pseudoInit NS_CONSUMES_SELF NS_RETURNS_RETAINED;
++ (void) consume:(id) NS_CONSUMED x;
++ (void) consume2:(id) CF_CONSUMED x;
 @end
 
 static int ownership_attribute_doesnt_go_here NS_RETURNS_RETAINED; // expected-warning{{'ns_returns_retained' attribute only applies to functions and methods}}
@@ -1245,6 +1253,24 @@
   [x release];
 }
 
+void testattr3() {
+  TestOwnershipAttr *x = [TestOwnershipAttr alloc]; // no-warning
+  [TestOwnershipAttr consume:x];
+  TestOwnershipAttr *y = [TestOwnershipAttr alloc]; // no-warning
+  [TestOwnershipAttr consume2:y];
+}
+
+void consume_ns(id NS_CONSUMED x);
+void consume_cf(id CF_CONSUMED x);
+
+void testattr4() {
+  TestOwnershipAttr *x = [TestOwnershipAttr alloc]; // no-warning
+  consume_ns(x);
+  TestOwnershipAttr *y = [TestOwnershipAttr alloc]; // no-warning
+  consume_cf(y);
+}
+
+
 @interface MyClassTestCFAttr : NSObject {}
 - (NSDate*) returnsCFRetained CF_RETURNS_RETAINED;
 - (CFDateRef) returnsCFRetainedAsCF CF_RETURNS_RETAINED;
@@ -1418,7 +1444,7 @@
     while (error_to_dump != ((void*)0)) {
         CFDictionaryRef info;
 
-        info = CFErrorCopyUserInfo(error_to_dump); // expected-warning{{Potential leak of an object allocated on line 1421 and stored into 'info'}}
+        info = CFErrorCopyUserInfo(error_to_dump); // expected-warning{{Potential leak of an object allocated on line 1447 and stored into 'info'}}
 
         if (info != ((void*)0)) {
         }

Modified: cfe/trunk/www/analyzer/annotations.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/analyzer/annotations.html?rev=124386&r1=124385&r2=124386&view=diff
==============================================================================
--- cfe/trunk/www/analyzer/annotations.html (original)
+++ cfe/trunk/www/analyzer/annotations.html Thu Jan 27 12:43:03 2011
@@ -6,7 +6,6 @@
   <link type="text/css" rel="stylesheet" href="menu.css" />
   <link type="text/css" rel="stylesheet" href="content.css" />
   <script type="text/javascript" src="scripts/menu.js"></script>
-  <script type="text/javascript" src="scripts/dbtree.js"></script>
 </head>
 <body>
 
@@ -38,7 +37,7 @@
 
 <h4>Specific Topics</h4>
 
-<ul id="collapsetree" class="dbtree onclick multiple">
+<ul>
 <li><a href="#generic">Annotations to Enhance Generic Checks</a>
   <ul>
     <li><a href="#null_checking"><span>Null Pointer Checking</span></a>
@@ -56,6 +55,8 @@
       <li><a href="#attr_ns_returns_not_retained">Attribute 'ns_returns_not_retained'</a></li>
       <li><a href="#attr_cf_returns_retained">Attribute 'cf_returns_retained'</a></li>
       <li><a href="#attr_cf_returns_not_retained">Attribute 'cf_returns_not_retained'</a></li>
+      <li><a href="#attr_ns_consumed">Attribute 'ns_consumed'</a></li>
+      <li><a href="#attr_cf_consumed">Attribute 'cf_consumed'</a></li>
       <li><a href="#attr_ns_consumes_self">Attribute 'ns_consumes_self'</a></li>
     </ul>
     </li>
@@ -295,15 +296,15 @@
 
 @implementation MyClass
 - (NSDate*) returnsCFRetained {
-  return (NSDate*) returnsRetainedCFDate(); // No leak.
+  return (NSDate*) returnsRetainedCFDate(); <b><i>// No leak.</i></b>
 }
 
 - (NSDate*) alsoReturnsRetained {
-  return (NSDate*) returnsRetainedCFDate(); // Always report a leak.
+  return (NSDate*) returnsRetainedCFDate(); <b><i>// Always report a leak.</i></b>
 }
 
 - (NSDate*) returnsNSRetained {
-  return (NSDate*) returnsRetainedCFDate(); // Report a leak when using GC.  
+  return (NSDate*) returnsRetainedCFDate(); <b><i>// Report a leak when using GC.</i></b>
 }
 @end
 </pre>
@@ -351,6 +352,112 @@
 #endif
 </pre>
 
+<h4 id="attr_ns_consumed">Attribute 'ns_consumed'
+(Clang-specific)</h4>
+
+<p>The 'ns_consumed' attribute can be placed on a specific parameter in either the declaration of a function or an Objective-C method.
+  It indicates to the static analyzer that a <tt>release</tt> message is implicitly sent to the parameter upon
+  completion of the call to the given function or method.
+  
+<p><b>Important note when using Garbage Collection</b>: Note that the analyzer
+essentially ignores this attribute when code is compiled to use Objective-C
+garbage collection.  This is because the <tt>release</tt> message does nothing
+when using GC.  If the underlying function/method uses something like
+<tt>CFRelease</tt> to decrement the reference count, consider using
+the <a href="#attr_cf_consumed">cf_consumed</a> attribute instead.</p>
+
+<p><b>Example</b></p>
+
+<pre class="code_example">
+<span class="command">$ cat test.m</span>
+#ifndef __has_feature      // Optional.
+#define __has_feature(x) 0 // Compatibility with non-clang compilers.
+#endif
+
+#ifndef NS_CONSUMED
+#if __has_feature(attribute_ns_consumed)
+<span class="code_highlight">#define NS_CONSUMED __attribute__((NS_CONSUMED))</span>
+#else
+#define NS_CONSUMED
+#endif
+#endif
+
+void consume_ns(id <span class="code_highlight">NS_CONSUMED</span> x);
+
+void test() {
+  id x = [[NSObject alloc] init];
+  consume_ns(x); <b><i>// No leak!</i></b>
+}
+
+ at interface Foo : NSObject
++ (void) releaseArg:(id) <span class="code_highlight">NS_CONSUMED</span> x;
++ (void) releaseSecondArg:(id)x second:(id) <span class="code_highlight">NS_CONSUMED</span> y;
+ at end
+
+void test_method() {
+  id x = [[NSObject alloc] init];
+  [Foo releaseArg:x]; <b><i>// No leak!</i></b>
+}
+
+void test_method2() {
+  id a = [[NSObject alloc] init];
+  id b = [[NSObject alloc] init];
+  [Foo releaseSecondArg:a second:b]; <b><i>// 'a' is leaked, but 'b' is released.</i></b>
+}
+</pre>
+
+<h4 id="attr_cf_consumed">Attribute 'cf_consumed'
+(Clang-specific)</h4>
+
+<p>The 'cf_consumed' attribute is practically identical to <a href="#attr_ns_consumed">ns_consumed</a>.
+The attribute can be placed on a specific parameter in either the declaration of a function or an Objective-C method.
+It indicates to the static analyzer that the object reference is implicitly passed to a call to <tt>CFRelease</tt> upon
+completion of the call to the given function or method.</p>
+    
+<p>Operationally this attribute is nearly identical to ns_consumed
+with the main difference that the reference count decrement still occurs when using Objective-C garbage
+collection (which is import for Core Foundation types, which are not automatically garbage collected).</p>
+
+<p><b>Example</b></p>
+
+<pre class="code_example">
+<span class="command">$ cat test.m</span>
+#ifndef __has_feature      // Optional.
+#define __has_feature(x) 0 // Compatibility with non-clang compilers.
+#endif
+
+#ifndef CF_CONSUMED
+#if __has_feature(attribute_cf_consumed)
+<span class="code_highlight">#define CF_CONSUMED __attribute__((CF_CONSUMED))</span>
+#else
+#define CF_CONSUMED
+#endif
+#endif
+
+void consume_cf(id <span class="code_highlight">CF_CONSUMED</span> x);
+void consume_CFDate(CFDateRef <span class="code_highlight">CF_CONSUMED</span> x);
+
+void test() {
+  id x = [[NSObject alloc] init];
+  consume_cf(x); <b><i>// No leak!</i></b>
+}
+
+void test2() {
+  CFDateRef date = CFDateCreate(0, CFAbsoluteTimeGetCurrent());
+  consume_CFDate(date); <b><i>// No leak, including under GC!</i></b>
+  
+}
+
+ at interface Foo : NSObject
++ (void) releaseArg:(CFDateRef) <span class="code_highlight">CF_CONSUMED</span> x;
+ at end
+
+void test_method() {
+  CFDateRef date = CFDateCreate(0, CFAbsoluteTimeGetCurrent());
+  [Foo releaseArg:date]; <b><i>// No leak!</i></b>
+}
+</pre>
+
 <h4 id="attr_ns_consumes_self">Attribute 'ns_consumes_self'
 (Clang-specific)</h4>
 
@@ -360,7 +467,9 @@
 </p>
 
 <p>One use of this attribute is declare your own init-like methods that do not follow the
-  standard Cocoa naming conventions.  For example:</p>
+  standard Cocoa naming conventions.</p>
+
+<p><b>Example</b></p>
   
 <pre class="code_example">
 #ifndef __has_feature





More information about the cfe-commits mailing list