From: Anna Zaks Date: Mon, 5 Mar 2012 18:58:25 +0000 (+0000) Subject: [analyzer] False positive in SelfInit - teach the checker about method X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f420fe35dc3a7b7b53809b615fb28379e5694c22;p=clang [analyzer] False positive in SelfInit - teach the checker about method calls with self as a parameter. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@152039 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp index 165dff5b10..9d77ad4daa 100644 --- a/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp @@ -54,7 +54,7 @@ static bool isInitMessage(const ObjCMessage &msg); static bool isSelfVar(SVal location, CheckerContext &C); namespace { -class ObjCSelfInitChecker : public Checker< +class ObjCSelfInitChecker : public Checker< check::PreObjCMessage, check::PostObjCMessage, check::PostStmt, check::PreStmt, @@ -62,6 +62,7 @@ class ObjCSelfInitChecker : public Checker< check::PostStmt, check::Location > { public: + void checkPreObjCMessage(ObjCMessage msg, CheckerContext &C) const; void checkPostObjCMessage(ObjCMessage msg, CheckerContext &C) const; void checkPostStmt(const ObjCIvarRefExpr *E, CheckerContext &C) const; void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const; @@ -69,6 +70,10 @@ public: void checkPostStmt(const CallExpr *CE, CheckerContext &C) const; void checkLocation(SVal location, bool isLoad, const Stmt *S, CheckerContext &C) const; + + void checkPreStmt(const CallOrObjCMessage &CE, CheckerContext &C) const; + void checkPostStmt(const CallOrObjCMessage &CE, CheckerContext &C) const; + }; } // end anonymous namespace @@ -178,6 +183,9 @@ static void checkForInvalidSelf(const Expr *E, CheckerContext &C, void ObjCSelfInitChecker::checkPostObjCMessage(ObjCMessage msg, CheckerContext &C) const { + CallOrObjCMessage MsgWrapper(msg, C.getState(), C.getLocationContext()); + checkPostStmt(MsgWrapper, C); + // When encountering a message that does initialization (init rule), // tag the return value so that we know later on that if self has this value // then it is properly initialized. @@ -249,10 +257,28 @@ void ObjCSelfInitChecker::checkPreStmt(const ReturnStmt *S, void ObjCSelfInitChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const { + CallOrObjCMessage CEWrapper(CE, C.getState(), C.getLocationContext()); + checkPreStmt(CEWrapper, C); +} + +void ObjCSelfInitChecker::checkPostStmt(const CallExpr *CE, + CheckerContext &C) const { + CallOrObjCMessage CEWrapper(CE, C.getState(), C.getLocationContext()); + checkPostStmt(CEWrapper, C); +} + +void ObjCSelfInitChecker::checkPreObjCMessage(ObjCMessage Msg, + CheckerContext &C) const { + CallOrObjCMessage MsgWrapper(Msg, C.getState(), C.getLocationContext()); + checkPreStmt(MsgWrapper, C); +} + +void ObjCSelfInitChecker::checkPreStmt(const CallOrObjCMessage &CE, + CheckerContext &C) const { ProgramStateRef state = C.getState(); - for (CallExpr::const_arg_iterator - I = CE->arg_begin(), E = CE->arg_end(); I != E; ++I) { - SVal argV = state->getSVal(*I, C.getLocationContext()); + unsigned NumArgs = CE.getNumArgs(); + for (unsigned i = 0; i < NumArgs; ++i) { + SVal argV = CE.getArgSVal(i); if (isSelfVar(argV, C)) { unsigned selfFlags = getSelfFlags(state->getSVal(cast(argV)), C); C.addTransition(state->set(selfFlags)); @@ -265,13 +291,12 @@ void ObjCSelfInitChecker::checkPreStmt(const CallExpr *CE, } } -void ObjCSelfInitChecker::checkPostStmt(const CallExpr *CE, +void ObjCSelfInitChecker::checkPostStmt(const CallOrObjCMessage &CE, CheckerContext &C) const { ProgramStateRef state = C.getState(); - const LocationContext *LCtx = C.getLocationContext(); - for (CallExpr::const_arg_iterator - I = CE->arg_begin(), E = CE->arg_end(); I != E; ++I) { - SVal argV = state->getSVal(*I, LCtx); + unsigned NumArgs = CE.getNumArgs(); + for (unsigned i = 0; i < NumArgs; ++i) { + SVal argV = CE.getArgSVal(i); if (isSelfVar(argV, C)) { SelfFlagEnum prevFlags = (SelfFlagEnum)state->get(); state = state->remove(); @@ -280,7 +305,7 @@ void ObjCSelfInitChecker::checkPostStmt(const CallExpr *CE, } else if (hasSelfFlag(argV, SelfFlag_Self, C)) { SelfFlagEnum prevFlags = (SelfFlagEnum)state->get(); state = state->remove(); - addSelfFlag(state, state->getSVal(CE, LCtx), prevFlags, C); + addSelfFlag(state, state->getSVal(cast(argV)), prevFlags, C); return; } } diff --git a/test/Analysis/self-init.m b/test/Analysis/self-init.m index eaa8fd46f1..3db42e9cf5 100644 --- a/test/Analysis/self-init.m +++ b/test/Analysis/self-init.m @@ -1,8 +1,8 @@ // RUN: %clang_cc1 -analyze -analyzer-checker=osx.cocoa.SelfInit %s -verify @class NSZone, NSCoder; -@protocol NSObject -@end +@protocol NSObject- (id)self; +@end @protocol NSCopying - (id)copyWithZone:(NSZone *)zone; @end @protocol NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone; @@ -22,9 +22,14 @@ //#import "Foundation/NSObject.h" typedef unsigned NSUInteger; -typedef int NSInteger; +typedef long NSInteger; + +@interface NSInvocation : NSObject {} +- (void)getArgument:(void *)argumentLocation atIndex:(NSInteger)idx; +- (void)setArgument:(void *)argumentLocation atIndex:(NSInteger)idx; +@end -@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator; +@class NSMethodSignature, NSCoder, NSString, NSEnumerator; @interface NSString : NSObject - (NSUInteger)length; + (id)stringWithUTF8String:(const char *)nullTerminatedCString; @@ -180,3 +185,19 @@ static id _commonInit(MyObj *self) { - (id)init { return self; } @end + + +// Test for radar://10973514 : self should not be invalidated by a method call. +@interface Test : NSObject { + NSInvocation *invocation_; +} +@end +@implementation Test +-(id) initWithTarget:(id) rec selector:(SEL) cb { + if (self=[super init]) { + [invocation_ setArgument:&self atIndex:2]; + } + return self; +} +@end +