[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