1 //== ObjCSelfInitChecker.cpp - Checker for 'self' initialization -*- C++ -*--=// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This defines ObjCSelfInitChecker, a builtin check that checks for uses of 11 // 'self' before proper initialization. 12 // 13 //===----------------------------------------------------------------------===// 14 15 // This checks initialization methods to verify that they assign 'self' to the 16 // result of an initialization call (e.g. [super init], or [self initWith..]) 17 // before using 'self' or any instance variable. 18 // 19 // To perform the required checking, values are tagged wih flags that indicate 20 // 1) if the object is the one pointed to by 'self', and 2) if the object 21 // is the result of an initializer (e.g. [super init]). 22 // 23 // Uses of an object that is true for 1) but not 2) trigger a diagnostic. 24 // The uses that are currently checked are: 25 // - Using instance variables. 26 // - Returning the object. 27 // 28 // Note that we don't check for an invalid 'self' that is the receiver of an 29 // obj-c message expression to cut down false positives where logging functions 30 // get information from self (like its class) or doing "invalidation" on self 31 // when the initialization fails. 32 // 33 // Because the object that 'self' points to gets invalidated when a call 34 // receives a reference to 'self', the checker keeps track and passes the flags 35 // for 1) and 2) to the new object that 'self' points to after the call. 36 // 37 // FIXME (rdar://7937506): In the case of: 38 // [super init]; 39 // return self; 40 // Have an extra PathDiagnosticPiece in the path that says "called [super init], 41 // but didn't assign the result to self." 42 43 //===----------------------------------------------------------------------===// 44 45 // FIXME: Somehow stick the link to Apple's documentation about initializing 46 // objects in the diagnostics. 47 // http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Articles/ocAllocInit.html 48 49 #include "ClangSACheckers.h" 50 #include "clang/StaticAnalyzer/Core/CheckerManager.h" 51 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h" 52 #include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h" 53 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 54 #include "clang/Analysis/DomainSpecific/CocoaConventions.h" 55 #include "clang/AST/ParentMap.h" 56 57 using namespace clang; 58 using namespace ento; 59 60 static bool shouldRunOnFunctionOrMethod(const NamedDecl *ND); 61 static bool isInitializationMethod(const ObjCMethodDecl *MD); 62 static bool isInitMessage(const ObjCMessage &msg); 63 static bool isSelfVar(SVal location, CheckerContext &C); 64 65 namespace { 66 enum SelfFlagEnum { 67 /// \brief No flag set. 68 SelfFlag_None = 0x0, 69 /// \brief Value came from 'self'. 70 SelfFlag_Self = 0x1, 71 /// \brief Value came from the result of an initializer (e.g. [super init]). 72 SelfFlag_InitRes = 0x2 73 }; 74 } 75 76 namespace { 77 class ObjCSelfInitChecker : public CheckerVisitor<ObjCSelfInitChecker> { 78 /// \brief A call receiving a reference to 'self' invalidates the object that 79 /// 'self' contains. This field keeps the "self flags" assigned to the 'self' 80 /// object before the call and assign them to the new object that 'self' 81 /// points to after the call. 82 SelfFlagEnum preCallSelfFlags; 83 84 public: 85 static void *getTag() { static int tag = 0; return &tag; } 86 void postVisitObjCMessage(CheckerContext &C, ObjCMessage msg); 87 void PostVisitObjCIvarRefExpr(CheckerContext &C, const ObjCIvarRefExpr *E); 88 void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S); 89 void PreVisitGenericCall(CheckerContext &C, const CallExpr *CE); 90 void PostVisitGenericCall(CheckerContext &C, const CallExpr *CE); 91 virtual void visitLocation(CheckerContext &C, const Stmt *S, SVal location, 92 bool isLoad); 93 }; 94 } // end anonymous namespace 95 96 static void RegisterObjCSelfInitChecker(ExprEngine &Eng) { 97 if (Eng.getContext().getLangOptions().ObjC1) 98 Eng.registerCheck(new ObjCSelfInitChecker()); 99 } 100 101 void ento::registerObjCSelfInitChecker(CheckerManager &mgr) { 102 mgr.addCheckerRegisterFunction(RegisterObjCSelfInitChecker); 103 } 104 105 namespace { 106 107 class InitSelfBug : public BugType { 108 const std::string desc; 109 public: 110 InitSelfBug() : BugType("missing \"self = [(super or self) init...]\"", 111 "missing \"self = [(super or self) init...]\"") {} 112 }; 113 114 } // end anonymous namespace 115 116 typedef llvm::ImmutableMap<SymbolRef, unsigned> SelfFlag; 117 namespace { struct CalledInit {}; } 118 119 namespace clang { 120 namespace ento { 121 template<> 122 struct GRStateTrait<SelfFlag> : public GRStatePartialTrait<SelfFlag> { 123 static void* GDMIndex() { 124 static int index = 0; 125 return &index; 126 } 127 }; 128 template <> 129 struct GRStateTrait<CalledInit> : public GRStatePartialTrait<bool> { 130 static void *GDMIndex() { static int index = 0; return &index; } 131 }; 132 } 133 } 134 135 static SelfFlagEnum getSelfFlags(SVal val, const GRState *state) { 136 if (SymbolRef sym = val.getAsSymbol()) 137 if (const unsigned *attachedFlags = state->get<SelfFlag>(sym)) 138 return (SelfFlagEnum)*attachedFlags; 139 return SelfFlag_None; 140 } 141 142 static SelfFlagEnum getSelfFlags(SVal val, CheckerContext &C) { 143 return getSelfFlags(val, C.getState()); 144 } 145 146 static void addSelfFlag(const GRState *state, SVal val, 147 SelfFlagEnum flag, CheckerContext &C) { 148 // We tag the symbol that the SVal wraps. 149 if (SymbolRef sym = val.getAsSymbol()) 150 C.addTransition(state->set<SelfFlag>(sym, getSelfFlags(val, C) | flag)); 151 } 152 153 static bool hasSelfFlag(SVal val, SelfFlagEnum flag, CheckerContext &C) { 154 return getSelfFlags(val, C) & flag; 155 } 156 157 /// \brief Returns true of the value of the expression is the object that 'self' 158 /// points to and is an object that did not come from the result of calling 159 /// an initializer. 160 static bool isInvalidSelf(const Expr *E, CheckerContext &C) { 161 SVal exprVal = C.getState()->getSVal(E); 162 if (!hasSelfFlag(exprVal, SelfFlag_Self, C)) 163 return false; // value did not come from 'self'. 164 if (hasSelfFlag(exprVal, SelfFlag_InitRes, C)) 165 return false; // 'self' is properly initialized. 166 167 return true; 168 } 169 170 static void checkForInvalidSelf(const Expr *E, CheckerContext &C, 171 const char *errorStr) { 172 if (!E) 173 return; 174 175 if (!C.getState()->get<CalledInit>()) 176 return; 177 178 if (!isInvalidSelf(E, C)) 179 return; 180 181 // Generate an error node. 182 ExplodedNode *N = C.generateSink(); 183 if (!N) 184 return; 185 186 EnhancedBugReport *report = 187 new EnhancedBugReport(*new InitSelfBug(), errorStr, N); 188 C.EmitReport(report); 189 } 190 191 void ObjCSelfInitChecker::postVisitObjCMessage(CheckerContext &C, 192 ObjCMessage msg) { 193 // When encountering a message that does initialization (init rule), 194 // tag the return value so that we know later on that if self has this value 195 // then it is properly initialized. 196 197 // FIXME: A callback should disable checkers at the start of functions. 198 if (!shouldRunOnFunctionOrMethod(dyn_cast<NamedDecl>( 199 C.getCurrentAnalysisContext()->getDecl()))) 200 return; 201 202 if (isInitMessage(msg)) { 203 // Tag the return value as the result of an initializer. 204 const GRState *state = C.getState(); 205 206 // FIXME this really should be context sensitive, where we record 207 // the current stack frame (for IPA). Also, we need to clean this 208 // value out when we return from this method. 209 state = state->set<CalledInit>(true); 210 211 SVal V = state->getSVal(msg.getOriginExpr()); 212 addSelfFlag(state, V, SelfFlag_InitRes, C); 213 return; 214 } 215 216 // We don't check for an invalid 'self' in an obj-c message expression to cut 217 // down false positives where logging functions get information from self 218 // (like its class) or doing "invalidation" on self when the initialization 219 // fails. 220 } 221 222 void ObjCSelfInitChecker::PostVisitObjCIvarRefExpr(CheckerContext &C, 223 const ObjCIvarRefExpr *E) { 224 // FIXME: A callback should disable checkers at the start of functions. 225 if (!shouldRunOnFunctionOrMethod(dyn_cast<NamedDecl>( 226 C.getCurrentAnalysisContext()->getDecl()))) 227 return; 228 229 checkForInvalidSelf(E->getBase(), C, 230 "Instance variable used while 'self' is not set to the result of " 231 "'[(super or self) init...]'"); 232 } 233 234 void ObjCSelfInitChecker::PreVisitReturnStmt(CheckerContext &C, 235 const ReturnStmt *S) { 236 // FIXME: A callback should disable checkers at the start of functions. 237 if (!shouldRunOnFunctionOrMethod(dyn_cast<NamedDecl>( 238 C.getCurrentAnalysisContext()->getDecl()))) 239 return; 240 241 checkForInvalidSelf(S->getRetValue(), C, 242 "Returning 'self' while it is not set to the result of " 243 "'[(super or self) init...]'"); 244 } 245 246 // When a call receives a reference to 'self', [Pre/Post]VisitGenericCall pass 247 // the SelfFlags from the object 'self' point to before the call, to the new 248 // object after the call. This is to avoid invalidation of 'self' by logging 249 // functions. 250 // Another common pattern in classes with multiple initializers is to put the 251 // subclass's common initialization bits into a static function that receives 252 // the value of 'self', e.g: 253 // @code 254 // if (!(self = [super init])) 255 // return nil; 256 // if (!(self = _commonInit(self))) 257 // return nil; 258 // @endcode 259 // Until we can use inter-procedural analysis, in such a call, transfer the 260 // SelfFlags to the result of the call. 261 262 void ObjCSelfInitChecker::PreVisitGenericCall(CheckerContext &C, 263 const CallExpr *CE) { 264 const GRState *state = C.getState(); 265 for (CallExpr::const_arg_iterator 266 I = CE->arg_begin(), E = CE->arg_end(); I != E; ++I) { 267 SVal argV = state->getSVal(*I); 268 if (isSelfVar(argV, C)) { 269 preCallSelfFlags = getSelfFlags(state->getSVal(cast<Loc>(argV)), C); 270 return; 271 } else if (hasSelfFlag(argV, SelfFlag_Self, C)) { 272 preCallSelfFlags = getSelfFlags(argV, C); 273 return; 274 } 275 } 276 } 277 278 void ObjCSelfInitChecker::PostVisitGenericCall(CheckerContext &C, 279 const CallExpr *CE) { 280 const GRState *state = C.getState(); 281 for (CallExpr::const_arg_iterator 282 I = CE->arg_begin(), E = CE->arg_end(); I != E; ++I) { 283 SVal argV = state->getSVal(*I); 284 if (isSelfVar(argV, C)) { 285 addSelfFlag(state, state->getSVal(cast<Loc>(argV)), preCallSelfFlags, C); 286 return; 287 } else if (hasSelfFlag(argV, SelfFlag_Self, C)) { 288 addSelfFlag(state, state->getSVal(CE), preCallSelfFlags, C); 289 return; 290 } 291 } 292 } 293 294 void ObjCSelfInitChecker::visitLocation(CheckerContext &C, const Stmt *S, 295 SVal location, bool isLoad) { 296 // Tag the result of a load from 'self' so that we can easily know that the 297 // value is the object that 'self' points to. 298 const GRState *state = C.getState(); 299 if (isSelfVar(location, C)) 300 addSelfFlag(state, state->getSVal(cast<Loc>(location)), SelfFlag_Self, C); 301 } 302 303 // FIXME: A callback should disable checkers at the start of functions. 304 static bool shouldRunOnFunctionOrMethod(const NamedDecl *ND) { 305 if (!ND) 306 return false; 307 308 const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(ND); 309 if (!MD) 310 return false; 311 if (!isInitializationMethod(MD)) 312 return false; 313 314 // self = [super init] applies only to NSObject subclasses. 315 // For instance, NSProxy doesn't implement -init. 316 ASTContext& Ctx = MD->getASTContext(); 317 IdentifierInfo* NSObjectII = &Ctx.Idents.get("NSObject"); 318 ObjCInterfaceDecl* ID = MD->getClassInterface()->getSuperClass(); 319 for ( ; ID ; ID = ID->getSuperClass()) { 320 IdentifierInfo *II = ID->getIdentifier(); 321 322 if (II == NSObjectII) 323 break; 324 } 325 if (!ID) 326 return false; 327 328 return true; 329 } 330 331 /// \brief Returns true if the location is 'self'. 332 static bool isSelfVar(SVal location, CheckerContext &C) { 333 AnalysisContext *analCtx = C.getCurrentAnalysisContext(); 334 if (!analCtx->getSelfDecl()) 335 return false; 336 if (!isa<loc::MemRegionVal>(location)) 337 return false; 338 339 loc::MemRegionVal MRV = cast<loc::MemRegionVal>(location); 340 if (const DeclRegion *DR = dyn_cast<DeclRegion>(MRV.getRegion())) 341 return (DR->getDecl() == analCtx->getSelfDecl()); 342 343 return false; 344 } 345 346 static bool isInitializationMethod(const ObjCMethodDecl *MD) { 347 // Init methods with prefix like '-(id)_init' are private and the requirements 348 // are less strict so we don't check those. 349 return MD->isInstanceMethod() && 350 cocoa::deriveNamingConvention(MD->getSelector(), 351 /*ignorePrefix=*/false) == cocoa::InitRule; 352 } 353 354 static bool isInitMessage(const ObjCMessage &msg) { 355 return cocoa::deriveNamingConvention(msg.getSelector()) == cocoa::InitRule; 356 } 357