[cfe-commits] r134449 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td include/clang/Basic/IdentifierTable.h lib/AST/DeclObjC.cpp lib/Basic/IdentifierTable.cpp lib/Sema/SemaDeclObjC.cpp lib/Sema/SemaExprObjC.cpp test/SemaObjC/arc-peformselector.m
Fariborz Jahanian
fjahanian at apple.com
Tue Jul 5 15:38:59 PDT 2011
Author: fjahanian
Date: Tue Jul 5 17:38:59 2011
New Revision: 134449
URL: http://llvm.org/viewvc/llvm-project?rev=134449&view=rev
Log:
objc-arc: enforce performSelector rules in rejecting retaining selectors
passed to it, and unknown selectors causing potential leak.
// rdar://9659270
Added:
cfe/trunk/test/SemaObjC/arc-peformselector.m
Modified:
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/include/clang/Basic/IdentifierTable.h
cfe/trunk/lib/AST/DeclObjC.cpp
cfe/trunk/lib/Basic/IdentifierTable.cpp
cfe/trunk/lib/Sema/SemaDeclObjC.cpp
cfe/trunk/lib/Sema/SemaExprObjC.cpp
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=134449&r1=134448&r2=134449&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Jul 5 17:38:59 2011
@@ -484,6 +484,10 @@
" ivar or must explicitly name an ivar">;
def error_synthesize_weak_non_arc_or_gc : Error<
"@synthesize of 'weak' property is only allowed in ARC or GC mode">;
+def err_arc_perform_selector_retains : Error<
+ "performSelector names a selector which retains the object">;
+def warn_arc_perform_selector_leaks : Warning<
+ "performSelector may cause a leak because its selector is unknown">;
def error_synthesized_ivar_yet_not_supported : Error<
"instance variable synthesis not yet supported"
Modified: cfe/trunk/include/clang/Basic/IdentifierTable.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/IdentifierTable.h?rev=134449&r1=134448&r2=134449&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/IdentifierTable.h (original)
+++ cfe/trunk/include/clang/Basic/IdentifierTable.h Tue Jul 5 17:38:59 2011
@@ -488,7 +488,10 @@
OMF_release,
OMF_retain,
OMF_retainCount,
- OMF_self
+ OMF_self,
+
+ // performSelector families
+ OMF_performSelector
};
/// Enough bits to store any enumerator in ObjCMethodFamily or
Modified: cfe/trunk/lib/AST/DeclObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclObjC.cpp?rev=134449&r1=134448&r2=134449&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclObjC.cpp (original)
+++ cfe/trunk/lib/AST/DeclObjC.cpp Tue Jul 5 17:38:59 2011
@@ -452,6 +452,34 @@
if (!isInstanceMethod())
family = OMF_None;
break;
+
+ case OMF_performSelector:
+ if (!isInstanceMethod() ||
+ !getResultType()->isObjCIdType())
+ family = OMF_None;
+ else {
+ unsigned noParams = param_size();
+ if (noParams < 1 || noParams > 3)
+ family = OMF_None;
+ else {
+ ObjCMethodDecl::arg_type_iterator it = arg_type_begin();
+ QualType ArgT = (*it);
+ if (!ArgT->isObjCSelType()) {
+ family = OMF_None;
+ break;
+ }
+ while (--noParams) {
+ it++;
+ ArgT = (*it);
+ if (!ArgT->isObjCIdType()) {
+ family = OMF_None;
+ break;
+ }
+ }
+ }
+ }
+ break;
+
}
// Cache the result.
Modified: cfe/trunk/lib/Basic/IdentifierTable.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/IdentifierTable.cpp?rev=134449&r1=134448&r2=134449&view=diff
==============================================================================
--- cfe/trunk/lib/Basic/IdentifierTable.cpp (original)
+++ cfe/trunk/lib/Basic/IdentifierTable.cpp Tue Jul 5 17:38:59 2011
@@ -397,6 +397,8 @@
if (name == "retainCount") return OMF_retainCount;
if (name == "self") return OMF_self;
}
+
+ if (name == "performSelector") return OMF_performSelector;
// The other method families may begin with a prefix of underscores.
while (!name.empty() && name.front() == '_')
Modified: cfe/trunk/lib/Sema/SemaDeclObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclObjC.cpp?rev=134449&r1=134448&r2=134449&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclObjC.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclObjC.cpp Tue Jul 5 17:38:59 2011
@@ -286,6 +286,11 @@
method->hasAttr<NSReturnsAutoreleasedAttr>())
return false;
break;
+
+ case OMF_performSelector:
+ // we don't annotate performSelector's
+ return true;
+
}
method->addAttr(new (S.Context) NSReturnsRetainedAttr(SourceLocation(),
@@ -366,6 +371,7 @@
case OMF_copy:
case OMF_new:
case OMF_self:
+ case OMF_performSelector:
break;
}
}
@@ -1298,6 +1304,7 @@
case OMF_dealloc:
case OMF_retainCount:
case OMF_self:
+ case OMF_performSelector:
// Mismatches for these methods don't change ownership
// conventions, so we don't care.
return false;
@@ -2467,6 +2474,7 @@
case OMF_mutableCopy:
case OMF_release:
case OMF_retainCount:
+ case OMF_performSelector:
break;
case OMF_alloc:
Modified: cfe/trunk/lib/Sema/SemaExprObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprObjC.cpp?rev=134449&r1=134448&r2=134449&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprObjC.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprObjC.cpp Tue Jul 5 17:38:59 2011
@@ -204,6 +204,7 @@
case OMF_mutableCopy:
case OMF_new:
case OMF_self:
+ case OMF_performSelector:
break;
}
}
@@ -1417,6 +1418,53 @@
Diag(Loc, diag::err_arc_illegal_explicit_message)
<< Sel << SelectorLoc;
break;
+
+ case OMF_performSelector:
+ if (Method && NumArgs >= 1) {
+ if (ObjCSelectorExpr *SelExp = dyn_cast<ObjCSelectorExpr>(Args[0])) {
+ Selector ArgSel = SelExp->getSelector();
+ ObjCMethodDecl *SelMethod =
+ LookupInstanceMethodInGlobalPool(ArgSel,
+ SelExp->getSourceRange());
+ if (!SelMethod)
+ SelMethod =
+ LookupFactoryMethodInGlobalPool(ArgSel,
+ SelExp->getSourceRange());
+ if (SelMethod) {
+ ObjCMethodFamily SelFamily = SelMethod->getMethodFamily();
+ switch (SelFamily) {
+ case OMF_alloc:
+ case OMF_copy:
+ case OMF_mutableCopy:
+ case OMF_new:
+ case OMF_self:
+ case OMF_init:
+ // Issue error, unless ns_returns_not_retained.
+ if (!SelMethod->hasAttr<NSReturnsNotRetainedAttr>()) {
+ // selector names a +1 method
+ Diag(SelectorLoc,
+ diag::err_arc_perform_selector_retains);
+ Diag(SelMethod->getLocation(), diag::note_method_declared_at);
+ }
+ break;
+ default:
+ // +0 call. OK. unless ns_returns_retained.
+ if (SelMethod->hasAttr<NSReturnsRetainedAttr>()) {
+ // selector names a +1 method
+ Diag(SelectorLoc,
+ diag::err_arc_perform_selector_retains);
+ Diag(SelMethod->getLocation(), diag::note_method_declared_at);
+ }
+ break;
+ }
+ }
+ } else {
+ // error (may leak).
+ Diag(SelectorLoc, diag::warn_arc_perform_selector_leaks);
+ Diag(Args[0]->getExprLoc(), diag::note_used_here);
+ }
+ }
+ break;
}
}
Added: cfe/trunk/test/SemaObjC/arc-peformselector.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/arc-peformselector.m?rev=134449&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjC/arc-peformselector.m (added)
+++ cfe/trunk/test/SemaObjC/arc-peformselector.m Tue Jul 5 17:38:59 2011
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -verify %s
+// rdar://9659270
+
+ at interface NSObject
+- (id)copy; // expected-note {{method declared here}}
+- (id) test __attribute__((ns_returns_retained)); // expected-note {{method declared here}}
++ (id) new ; // expected-note {{method declared here}}
+- (id) init __attribute__((ns_returns_not_retained));
+- (id)PlusZero;
+- (id)PlusOne __attribute__((ns_returns_retained)); // expected-note {{method declared here}}
+ at end
+
+ at interface I : NSObject
+{
+ SEL sel1;
+}
+- (id)performSelector:(SEL)aSelector;
+- (id)performSelector:(SEL)aSelector withObject:(id)object;
+- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;
+ at end
+
+ at implementation I
+- (id) Meth {
+ return [self performSelector : @selector(copy)]; // expected-error {{performSelector names a selector which retains the object}}
+ return [self performSelector : @selector(test)]; // expected-error {{performSelector names a selector which retains the object}}
+ return [self performSelector : @selector(new)]; // expected-error {{performSelector names a selector which retains the object}}
+ return [self performSelector : @selector(init)];
+ return [self performSelector : sel1]; // expected-warning {{performSelector may cause a leak because its selector is unknown}} \
+ // expected-note {{used here}}
+
+ return [self performSelector : @selector(PlusZero)];
+ return [self performSelector : @selector(PlusOne)]; // expected-error {{performSelector names a selector which retains the object}}
+}
+
+- (id)performSelector:(SEL)aSelector { return 0; }
+- (id)performSelector:(SEL)aSelector withObject:(id)object { return 0; }
+- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2 { return 0; }
+ at end
More information about the cfe-commits
mailing list