From a883355a6fe8d72b8899efb65a7d7645a51afc3b Mon Sep 17 00:00:00 2001 From: Ted Kremenek Date: Wed, 29 Apr 2009 23:03:22 +0000 Subject: [PATCH] retain/release checker: When determining whether an analyzed method can return an owned object, consult its summary instead of inspecting the selector. This picks up annotations, and is just more general. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@70429 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Analysis/CFRefCount.cpp | 75 ++++++++++++++++++++-------------- test/Analysis/retain-release.m | 5 ++- 2 files changed, 49 insertions(+), 31 deletions(-) diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp index 81017211a6..f5d29fd73e 100644 --- a/lib/Analysis/CFRefCount.cpp +++ b/lib/Analysis/CFRefCount.cpp @@ -149,9 +149,14 @@ static bool followsFundamentalRule(const char* s) { return deriveNamingConvention(s) == CreateRule; } -static bool followsReturnRule(const char* s) { - NamingConvention C = deriveNamingConvention(s); - return C == CreateRule || C == InitRule; +static const ObjCMethodDecl* +ResolveToInterfaceMethodDecl(const ObjCMethodDecl *MD, ASTContext &Context) { + ObjCInterfaceDecl *ID = + const_cast(MD->getClassInterface()); + + return MD->isInstanceMethod() + ? ID->lookupInstanceMethod(Context, MD->getSelector()) + : ID->lookupClassMethod(Context, MD->getSelector()); } //===----------------------------------------------------------------------===// @@ -269,6 +274,10 @@ public: return index; } + bool isOwned() const { + return K == OwnedSymbol || K == OwnedAllocatedSymbol; + } + static RetEffect MakeAlias(unsigned Idx) { return RetEffect(Alias, Idx); } @@ -399,7 +408,7 @@ public: ObjCSummaryKey(IdentifierInfo* ii, Selector s) : II(ii), S(s) {} - ObjCSummaryKey(ObjCInterfaceDecl* d, Selector s) + ObjCSummaryKey(const ObjCInterfaceDecl* d, Selector s) : II(d ? d->getIdentifier() : 0), S(s) {} ObjCSummaryKey(Selector s) @@ -452,14 +461,14 @@ public: typedef MapTy::iterator iterator; - iterator find(ObjCInterfaceDecl* D, IdentifierInfo *ClsName, Selector S) { + iterator find(const ObjCInterfaceDecl* D, IdentifierInfo *ClsName, + Selector S) { // Lookup the method using the decl for the class @interface. If we // have no decl, lookup using the class name. return D ? find(D, S) : find(ClsName, S); } - iterator find(ObjCInterfaceDecl* D, Selector S) { - + iterator find(const ObjCInterfaceDecl* D, Selector S) { // Do a lookup with the (D,S) pair. If we find a match return // the iterator. ObjCSummaryKey K(D, S); @@ -730,18 +739,21 @@ public: RetainSummary* getSummary(FunctionDecl* FD); - RetainSummary* getInstanceMethodSummary(ObjCMessageExpr* ME, ObjCInterfaceDecl* ID) { + RetainSummary* getInstanceMethodSummary(ObjCMessageExpr* ME, + const ObjCInterfaceDecl* ID) { return getInstanceMethodSummary(ME->getSelector(), ME->getClassName(), ID, ME->getMethodDecl(), ME->getType()); } RetainSummary* getInstanceMethodSummary(Selector S, IdentifierInfo *ClsName, - ObjCInterfaceDecl* ID, - ObjCMethodDecl *MD, QualType RetTy); + const ObjCInterfaceDecl* ID, + const ObjCMethodDecl *MD, + QualType RetTy); RetainSummary *getClassMethodSummary(Selector S, IdentifierInfo *ClsName, - ObjCInterfaceDecl *ID, - ObjCMethodDecl *MD, QualType RetTy); + const ObjCInterfaceDecl *ID, + const ObjCMethodDecl *MD, + QualType RetTy); RetainSummary *getClassMethodSummary(ObjCMessageExpr *ME) { return getClassMethodSummary(ME->getSelector(), ME->getClassName(), @@ -751,9 +763,12 @@ public: /// getMethodSummary - This version of getMethodSummary is used to query /// the summary for the current method being analyzed. - RetainSummary *getMethodSummary(ObjCMethodDecl *MD) { + RetainSummary *getMethodSummary(const ObjCMethodDecl *MD) { + // FIXME: Eventually this should be unneeded. + MD = ResolveToInterfaceMethodDecl(MD, Ctx); + Selector S = MD->getSelector(); - ObjCInterfaceDecl *ID = MD->getClassInterface(); + const ObjCInterfaceDecl *ID = MD->getClassInterface(); IdentifierInfo *ClsName = ID->getIdentifier(); QualType ResultTy = MD->getResultType(); @@ -763,9 +778,10 @@ public: return getClassMethodSummary(S, ClsName, ID, MD, ResultTy); } - RetainSummary* getCommonMethodSummary(ObjCMethodDecl* MD, Selector S, - QualType RetTy); - RetainSummary* getMethodSummaryFromAnnotations(ObjCMethodDecl *MD); + RetainSummary* getCommonMethodSummary(const ObjCMethodDecl* MD, + Selector S, QualType RetTy); + + RetainSummary* getMethodSummaryFromAnnotations(const ObjCMethodDecl *MD); bool isGCEnabled() const { return GCEnabled; } }; @@ -1113,7 +1129,7 @@ RetainSummaryManager::getInitMethodSummary(QualType RetTy) { } RetainSummary* -RetainSummaryManager::getMethodSummaryFromAnnotations(ObjCMethodDecl *MD) { +RetainSummaryManager::getMethodSummaryFromAnnotations(const ObjCMethodDecl *MD){ if (!MD) return 0; @@ -1169,8 +1185,8 @@ RetainSummaryManager::getMethodSummaryFromAnnotations(ObjCMethodDecl *MD) { } RetainSummary* -RetainSummaryManager::getCommonMethodSummary(ObjCMethodDecl* MD, Selector S, - QualType RetTy) { +RetainSummaryManager::getCommonMethodSummary(const ObjCMethodDecl* MD, + Selector S, QualType RetTy) { if (MD) { // Scan the method decl for 'void*' arguments. These should be treated @@ -1224,8 +1240,8 @@ RetainSummaryManager::getCommonMethodSummary(ObjCMethodDecl* MD, Selector S, RetainSummary* RetainSummaryManager::getInstanceMethodSummary(Selector S, IdentifierInfo *ClsName, - ObjCInterfaceDecl* ID, - ObjCMethodDecl *MD, + const ObjCInterfaceDecl* ID, + const ObjCMethodDecl *MD, QualType RetTy) { // Look up a summary in our summary cache. @@ -1255,8 +1271,9 @@ RetainSummaryManager::getInstanceMethodSummary(Selector S, RetainSummary* RetainSummaryManager::getClassMethodSummary(Selector S, IdentifierInfo *ClsName, - ObjCInterfaceDecl *ID, - ObjCMethodDecl *MD, QualType RetTy){ + const ObjCInterfaceDecl *ID, + const ObjCMethodDecl *MD, + QualType RetTy) { assert(ClsName && "Class name must be specified."); ObjCMethodSummariesTy::iterator I = @@ -2448,7 +2465,7 @@ CFRefLeakReport::getEndPath(BugReporter& br, const ExplodedNode* EndN){ // to the caller for NS objects. ObjCMethodDecl& MD = cast(BR.getGraph().getCodeDecl()); os << " is returned from a method whose name ('" - << MD.getSelector().getAsString() + << MD.getSelector().getAsString() << "') does not contain 'copy' or otherwise starts with" " 'new' or 'alloc'. This violates the naming convention rules given" " in the Memory Management Guide for Cocoa (object leaked)"; @@ -2992,13 +3009,11 @@ void CFRefCount::EvalReturn(ExplodedNodeSet& Dst, if (X.isReturnedOwned() && X.getCount() == 0) { const Decl *CD = &Eng.getStateManager().getCodeDecl(); - if (const ObjCMethodDecl* MD = dyn_cast(CD)) { - std::string s = MD->getSelector().getAsString(); - // FIXME: Use method summary. - if (!followsReturnRule(s.c_str())) { + if (const ObjCMethodDecl* MD = dyn_cast(CD)) { + RetainSummary *Summ = Summaries.getMethodSummary(MD); + if (!GetRetEffect(Summ).isOwned()) { static int ReturnOwnLeakTag = 0; state = state.set(Sym, X ^ RefVal::ErrorLeakReturned); - // Generate an error node. ExplodedNode *N = Builder.generateNode(PostStmt(S, &ReturnOwnLeakTag), state, Pred); diff --git a/test/Analysis/retain-release.m b/test/Analysis/retain-release.m index dfaba6fae9..5413debd81 100644 --- a/test/Analysis/retain-release.m +++ b/test/Analysis/retain-release.m @@ -440,13 +440,16 @@ void rdar6704930(unsigned char *s, unsigned int length) { @interface TestAttrHelper : NSObject - (NSString*) createString:(TestOwnershipAttr*)X; +- (NSString*) createStringAttr:(TestOwnershipAttr*)X __attribute__((objc_ownership_returns)); @end @implementation TestAttrHelper - (NSString*) createString:(TestOwnershipAttr*)X { return [X returnsAnOwnedString]; // expected-warning{{leak}} } - +- (NSString*) createStringAttr:(TestOwnershipAttr*)X { + return [X returnsAnOwnedString]; // no-warning +} @end void test_attr_1(TestOwnershipAttr *X) { -- 2.40.0