]> granicus.if.org Git - clang/commitdiff
[analyzer] False positive in SelfInit - teach the checker about method
authorAnna Zaks <ganna@apple.com>
Mon, 5 Mar 2012 18:58:25 +0000 (18:58 +0000)
committerAnna Zaks <ganna@apple.com>
Mon, 5 Mar 2012 18:58:25 +0000 (18:58 +0000)
calls with self as a parameter.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@152039 91177308-0d34-0410-b5e6-96231b3b80d8

lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
test/Analysis/self-init.m

index 165dff5b107f5ffaa917cb9e1acb33f830fb0b69..9d77ad4daaacac6fbb0fed19d257d10801f74574 100644 (file)
@@ -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<ObjCIvarRefExpr>,
                                              check::PreStmt<ReturnStmt>,
@@ -62,6 +62,7 @@ class ObjCSelfInitChecker : public Checker<
                                              check::PostStmt<CallExpr>,
                                              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<Loc>(argV)), C);
       C.addTransition(state->set<PreCallSelfFlags>(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<PreCallSelfFlags>();
       state = state->remove<PreCallSelfFlags>();
@@ -280,7 +305,7 @@ void ObjCSelfInitChecker::checkPostStmt(const CallExpr *CE,
     } else if (hasSelfFlag(argV, SelfFlag_Self, C)) {
       SelfFlagEnum prevFlags = (SelfFlagEnum)state->get<PreCallSelfFlags>();
       state = state->remove<PreCallSelfFlags>();
-      addSelfFlag(state, state->getSVal(CE, LCtx), prevFlags, C);
+      addSelfFlag(state, state->getSVal(cast<Loc>(argV)), prevFlags, C);
       return;
     }
   }
index eaa8fd46f19c94106fcc50e0beadecc5d9fe5800..3db42e9cf5acf298dc052b9750aae3a850801813 100644 (file)
@@ -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;
 
 //#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 <NSCopying, NSMutableCopying, NSCoding>
 - (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
+