ObjCSelfInitChecker.cpp revision 6a2a1865f8bfaedff312b043f1e875a43e95b259
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 with 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//===----------------------------------------------------------------------===// 38 39#include "ClangSACheckers.h" 40#include "clang/StaticAnalyzer/Core/Checker.h" 41#include "clang/StaticAnalyzer/Core/CheckerManager.h" 42#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 43#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" 44#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h" 45#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 46#include "clang/AST/ParentMap.h" 47 48using namespace clang; 49using namespace ento; 50 51static bool shouldRunOnFunctionOrMethod(const NamedDecl *ND); 52static bool isInitializationMethod(const ObjCMethodDecl *MD); 53static bool isInitMessage(const ObjCMessage &msg); 54static bool isSelfVar(SVal location, CheckerContext &C); 55 56namespace { 57class ObjCSelfInitChecker : public Checker< check::PreObjCMessage, 58 check::PostObjCMessage, 59 check::PostStmt<ObjCIvarRefExpr>, 60 check::PreStmt<ReturnStmt>, 61 check::PreStmt<CallExpr>, 62 check::PostStmt<CallExpr>, 63 check::Location, 64 check::Bind > { 65public: 66 void checkPreObjCMessage(ObjCMessage msg, CheckerContext &C) const; 67 void checkPostObjCMessage(ObjCMessage msg, CheckerContext &C) const; 68 void checkPostStmt(const ObjCIvarRefExpr *E, CheckerContext &C) const; 69 void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const; 70 void checkPreStmt(const CallExpr *CE, CheckerContext &C) const; 71 void checkPostStmt(const CallExpr *CE, CheckerContext &C) const; 72 void checkLocation(SVal location, bool isLoad, const Stmt *S, 73 CheckerContext &C) const; 74 void checkBind(SVal loc, SVal val, const Stmt *S, CheckerContext &C) const; 75 76 void checkPreStmt(const CallOrObjCMessage &CE, CheckerContext &C) const; 77 void checkPostStmt(const CallOrObjCMessage &CE, CheckerContext &C) const; 78 79}; 80} // end anonymous namespace 81 82namespace { 83 84class InitSelfBug : public BugType { 85 const std::string desc; 86public: 87 InitSelfBug() : BugType("Missing \"self = [(super or self) init...]\"", 88 categories::CoreFoundationObjectiveC) {} 89}; 90 91} // end anonymous namespace 92 93namespace { 94enum SelfFlagEnum { 95 /// \brief No flag set. 96 SelfFlag_None = 0x0, 97 /// \brief Value came from 'self'. 98 SelfFlag_Self = 0x1, 99 /// \brief Value came from the result of an initializer (e.g. [super init]). 100 SelfFlag_InitRes = 0x2 101}; 102} 103 104typedef llvm::ImmutableMap<SymbolRef, unsigned> SelfFlag; 105namespace { struct CalledInit {}; } 106namespace { struct PreCallSelfFlags {}; } 107 108namespace clang { 109namespace ento { 110 template<> 111 struct ProgramStateTrait<SelfFlag> : public ProgramStatePartialTrait<SelfFlag> { 112 static void *GDMIndex() { static int index = 0; return &index; } 113 }; 114 template <> 115 struct ProgramStateTrait<CalledInit> : public ProgramStatePartialTrait<bool> { 116 static void *GDMIndex() { static int index = 0; return &index; } 117 }; 118 119 /// \brief A call receiving a reference to 'self' invalidates the object that 120 /// 'self' contains. This keeps the "self flags" assigned to the 'self' 121 /// object before the call so we can assign them to the new object that 'self' 122 /// points to after the call. 123 template <> 124 struct ProgramStateTrait<PreCallSelfFlags> : public ProgramStatePartialTrait<unsigned> { 125 static void *GDMIndex() { static int index = 0; return &index; } 126 }; 127} 128} 129 130static SelfFlagEnum getSelfFlags(SVal val, ProgramStateRef state) { 131 if (SymbolRef sym = val.getAsSymbol()) 132 if (const unsigned *attachedFlags = state->get<SelfFlag>(sym)) 133 return (SelfFlagEnum)*attachedFlags; 134 return SelfFlag_None; 135} 136 137static SelfFlagEnum getSelfFlags(SVal val, CheckerContext &C) { 138 return getSelfFlags(val, C.getState()); 139} 140 141static void addSelfFlag(ProgramStateRef state, SVal val, 142 SelfFlagEnum flag, CheckerContext &C) { 143 // We tag the symbol that the SVal wraps. 144 if (SymbolRef sym = val.getAsSymbol()) 145 C.addTransition(state->set<SelfFlag>(sym, getSelfFlags(val, C) | flag)); 146} 147 148static bool hasSelfFlag(SVal val, SelfFlagEnum flag, CheckerContext &C) { 149 return getSelfFlags(val, C) & flag; 150} 151 152/// \brief Returns true of the value of the expression is the object that 'self' 153/// points to and is an object that did not come from the result of calling 154/// an initializer. 155static bool isInvalidSelf(const Expr *E, CheckerContext &C) { 156 SVal exprVal = C.getState()->getSVal(E, C.getLocationContext()); 157 if (!hasSelfFlag(exprVal, SelfFlag_Self, C)) 158 return false; // value did not come from 'self'. 159 if (hasSelfFlag(exprVal, SelfFlag_InitRes, C)) 160 return false; // 'self' is properly initialized. 161 162 return true; 163} 164 165static void checkForInvalidSelf(const Expr *E, CheckerContext &C, 166 const char *errorStr) { 167 if (!E) 168 return; 169 170 if (!C.getState()->get<CalledInit>()) 171 return; 172 173 if (!isInvalidSelf(E, C)) 174 return; 175 176 // Generate an error node. 177 ExplodedNode *N = C.generateSink(); 178 if (!N) 179 return; 180 181 BugReport *report = 182 new BugReport(*new InitSelfBug(), errorStr, N); 183 C.EmitReport(report); 184} 185 186void ObjCSelfInitChecker::checkPostObjCMessage(ObjCMessage msg, 187 CheckerContext &C) const { 188 // When encountering a message that does initialization (init rule), 189 // tag the return value so that we know later on that if self has this value 190 // then it is properly initialized. 191 192 // FIXME: A callback should disable checkers at the start of functions. 193 if (!shouldRunOnFunctionOrMethod(dyn_cast<NamedDecl>( 194 C.getCurrentAnalysisDeclContext()->getDecl()))) 195 return; 196 197 if (isInitMessage(msg)) { 198 // Tag the return value as the result of an initializer. 199 ProgramStateRef state = C.getState(); 200 201 // FIXME this really should be context sensitive, where we record 202 // the current stack frame (for IPA). Also, we need to clean this 203 // value out when we return from this method. 204 state = state->set<CalledInit>(true); 205 206 SVal V = state->getSVal(msg.getMessageExpr(), C.getLocationContext()); 207 addSelfFlag(state, V, SelfFlag_InitRes, C); 208 return; 209 } 210 211 CallOrObjCMessage MsgWrapper(msg, C.getState(), C.getLocationContext()); 212 checkPostStmt(MsgWrapper, C); 213 214 // We don't check for an invalid 'self' in an obj-c message expression to cut 215 // down false positives where logging functions get information from self 216 // (like its class) or doing "invalidation" on self when the initialization 217 // fails. 218} 219 220void ObjCSelfInitChecker::checkPostStmt(const ObjCIvarRefExpr *E, 221 CheckerContext &C) const { 222 // FIXME: A callback should disable checkers at the start of functions. 223 if (!shouldRunOnFunctionOrMethod(dyn_cast<NamedDecl>( 224 C.getCurrentAnalysisDeclContext()->getDecl()))) 225 return; 226 227 checkForInvalidSelf(E->getBase(), C, 228 "Instance variable used while 'self' is not set to the result of " 229 "'[(super or self) init...]'"); 230} 231 232void ObjCSelfInitChecker::checkPreStmt(const ReturnStmt *S, 233 CheckerContext &C) const { 234 // FIXME: A callback should disable checkers at the start of functions. 235 if (!shouldRunOnFunctionOrMethod(dyn_cast<NamedDecl>( 236 C.getCurrentAnalysisDeclContext()->getDecl()))) 237 return; 238 239 checkForInvalidSelf(S->getRetValue(), C, 240 "Returning 'self' while it is not set to the result of " 241 "'[(super or self) init...]'"); 242} 243 244// When a call receives a reference to 'self', [Pre/Post]VisitGenericCall pass 245// the SelfFlags from the object 'self' point to before the call, to the new 246// object after the call. This is to avoid invalidation of 'self' by logging 247// functions. 248// Another common pattern in classes with multiple initializers is to put the 249// subclass's common initialization bits into a static function that receives 250// the value of 'self', e.g: 251// @code 252// if (!(self = [super init])) 253// return nil; 254// if (!(self = _commonInit(self))) 255// return nil; 256// @endcode 257// Until we can use inter-procedural analysis, in such a call, transfer the 258// SelfFlags to the result of the call. 259 260void ObjCSelfInitChecker::checkPreStmt(const CallExpr *CE, 261 CheckerContext &C) const { 262 CallOrObjCMessage CEWrapper(CE, C.getState(), C.getLocationContext()); 263 checkPreStmt(CEWrapper, C); 264} 265 266void ObjCSelfInitChecker::checkPostStmt(const CallExpr *CE, 267 CheckerContext &C) const { 268 CallOrObjCMessage CEWrapper(CE, C.getState(), C.getLocationContext()); 269 checkPostStmt(CEWrapper, C); 270} 271 272void ObjCSelfInitChecker::checkPreObjCMessage(ObjCMessage Msg, 273 CheckerContext &C) const { 274 CallOrObjCMessage MsgWrapper(Msg, C.getState(), C.getLocationContext()); 275 checkPreStmt(MsgWrapper, C); 276} 277 278void ObjCSelfInitChecker::checkPreStmt(const CallOrObjCMessage &CE, 279 CheckerContext &C) const { 280 ProgramStateRef state = C.getState(); 281 unsigned NumArgs = CE.getNumArgs(); 282 // If we passed 'self' as and argument to the call, record it in the state 283 // to be propagated after the call. 284 // Note, we could have just given up, but try to be more optimistic here and 285 // assume that the functions are going to continue initialization or will not 286 // modify self. 287 for (unsigned i = 0; i < NumArgs; ++i) { 288 SVal argV = CE.getArgSVal(i); 289 if (isSelfVar(argV, C)) { 290 unsigned selfFlags = getSelfFlags(state->getSVal(cast<Loc>(argV)), C); 291 C.addTransition(state->set<PreCallSelfFlags>(selfFlags)); 292 return; 293 } else if (hasSelfFlag(argV, SelfFlag_Self, C)) { 294 unsigned selfFlags = getSelfFlags(argV, C); 295 C.addTransition(state->set<PreCallSelfFlags>(selfFlags)); 296 return; 297 } 298 } 299} 300 301void ObjCSelfInitChecker::checkPostStmt(const CallOrObjCMessage &CE, 302 CheckerContext &C) const { 303 ProgramStateRef state = C.getState(); 304 unsigned NumArgs = CE.getNumArgs(); 305 for (unsigned i = 0; i < NumArgs; ++i) { 306 SVal argV = CE.getArgSVal(i); 307 if (isSelfVar(argV, C)) { 308 // If the address of 'self' is being passed to the call, assume that the 309 // 'self' after the call will have the same flags. 310 // EX: log(&self) 311 SelfFlagEnum prevFlags = (SelfFlagEnum)state->get<PreCallSelfFlags>(); 312 state = state->remove<PreCallSelfFlags>(); 313 addSelfFlag(state, state->getSVal(cast<Loc>(argV)), prevFlags, C); 314 return; 315 } else if (hasSelfFlag(argV, SelfFlag_Self, C)) { 316 // If 'self' is passed to the call by value, assume that the function 317 // returns 'self'. So assign the flags, which were set on 'self' to the 318 // return value. 319 // EX: self = performMoreInitialization(self) 320 SelfFlagEnum prevFlags = (SelfFlagEnum)state->get<PreCallSelfFlags>(); 321 state = state->remove<PreCallSelfFlags>(); 322 const Expr *CallExpr = CE.getOriginExpr(); 323 if (CallExpr) 324 addSelfFlag(state, state->getSVal(CallExpr, C.getLocationContext()), 325 prevFlags, C); 326 return; 327 } 328 } 329} 330 331void ObjCSelfInitChecker::checkLocation(SVal location, bool isLoad, 332 const Stmt *S, 333 CheckerContext &C) const { 334 // Tag the result of a load from 'self' so that we can easily know that the 335 // value is the object that 'self' points to. 336 ProgramStateRef state = C.getState(); 337 if (isSelfVar(location, C)) 338 addSelfFlag(state, state->getSVal(cast<Loc>(location)), SelfFlag_Self, C); 339} 340 341 342void ObjCSelfInitChecker::checkBind(SVal loc, SVal val, const Stmt *S, 343 CheckerContext &C) const { 344 // Allow assignment of anything to self. Self is a local variable in the 345 // initializer, so it is legal to assign anything to it, like results of 346 // static functions/method calls. After self is assigned something we cannot 347 // reason about, stop enforcing the rules. 348 // (Only continue checking if the assigned value should be treated as self.) 349 if ((isSelfVar(loc, C)) && 350 !hasSelfFlag(val, SelfFlag_InitRes, C) && 351 !hasSelfFlag(val, SelfFlag_Self, C) && 352 !isSelfVar(val, C)) { 353 354 // Stop tracking the checker-specific state in the state. 355 ProgramStateRef State = C.getState(); 356 State = State->remove<CalledInit>(); 357 if (SymbolRef sym = loc.getAsSymbol()) 358 State = State->remove<SelfFlag>(sym); 359 C.addTransition(State); 360 } 361} 362 363// FIXME: A callback should disable checkers at the start of functions. 364static bool shouldRunOnFunctionOrMethod(const NamedDecl *ND) { 365 if (!ND) 366 return false; 367 368 const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(ND); 369 if (!MD) 370 return false; 371 if (!isInitializationMethod(MD)) 372 return false; 373 374 // self = [super init] applies only to NSObject subclasses. 375 // For instance, NSProxy doesn't implement -init. 376 ASTContext &Ctx = MD->getASTContext(); 377 IdentifierInfo* NSObjectII = &Ctx.Idents.get("NSObject"); 378 ObjCInterfaceDecl *ID = MD->getClassInterface()->getSuperClass(); 379 for ( ; ID ; ID = ID->getSuperClass()) { 380 IdentifierInfo *II = ID->getIdentifier(); 381 382 if (II == NSObjectII) 383 break; 384 } 385 if (!ID) 386 return false; 387 388 return true; 389} 390 391/// \brief Returns true if the location is 'self'. 392static bool isSelfVar(SVal location, CheckerContext &C) { 393 AnalysisDeclContext *analCtx = C.getCurrentAnalysisDeclContext(); 394 if (!analCtx->getSelfDecl()) 395 return false; 396 if (!isa<loc::MemRegionVal>(location)) 397 return false; 398 399 loc::MemRegionVal MRV = cast<loc::MemRegionVal>(location); 400 if (const DeclRegion *DR = dyn_cast<DeclRegion>(MRV.stripCasts())) 401 return (DR->getDecl() == analCtx->getSelfDecl()); 402 403 return false; 404} 405 406static bool isInitializationMethod(const ObjCMethodDecl *MD) { 407 return MD->getMethodFamily() == OMF_init; 408} 409 410static bool isInitMessage(const ObjCMessage &msg) { 411 return msg.getMethodFamily() == OMF_init; 412} 413 414//===----------------------------------------------------------------------===// 415// Registration. 416//===----------------------------------------------------------------------===// 417 418void ento::registerObjCSelfInitChecker(CheckerManager &mgr) { 419 mgr.registerChecker<ObjCSelfInitChecker>(); 420} 421