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