Home | History | Annotate | Download | only in Checkers
      1 //== BasicObjCFoundationChecks.cpp - Simple Apple-Foundation checks -*- 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 file defines BasicObjCFoundationChecks, a class that encapsulates
     11 //  a set of simple checks to run on Objective-C code using Apple's Foundation
     12 //  classes.
     13 //
     14 //===----------------------------------------------------------------------===//
     15 
     16 #include "ClangSACheckers.h"
     17 #include "clang/AST/ASTContext.h"
     18 #include "clang/AST/DeclObjC.h"
     19 #include "clang/AST/Expr.h"
     20 #include "clang/AST/ExprObjC.h"
     21 #include "clang/AST/StmtObjC.h"
     22 #include "clang/Analysis/DomainSpecific/CocoaConventions.h"
     23 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
     24 #include "clang/StaticAnalyzer/Core/Checker.h"
     25 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
     26 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
     27 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
     28 #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
     29 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
     30 #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
     31 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
     32 #include "llvm/ADT/SmallString.h"
     33 #include "llvm/ADT/StringMap.h"
     34 #include "llvm/Support/raw_ostream.h"
     35 
     36 using namespace clang;
     37 using namespace ento;
     38 
     39 namespace {
     40 class APIMisuse : public BugType {
     41 public:
     42   APIMisuse(const char* name) : BugType(name, "API Misuse (Apple)") {}
     43 };
     44 } // end anonymous namespace
     45 
     46 //===----------------------------------------------------------------------===//
     47 // Utility functions.
     48 //===----------------------------------------------------------------------===//
     49 
     50 static StringRef GetReceiverInterfaceName(const ObjCMethodCall &msg) {
     51   if (const ObjCInterfaceDecl *ID = msg.getReceiverInterface())
     52     return ID->getIdentifier()->getName();
     53   return StringRef();
     54 }
     55 
     56 enum FoundationClass {
     57   FC_None,
     58   FC_NSArray,
     59   FC_NSDictionary,
     60   FC_NSEnumerator,
     61   FC_NSNull,
     62   FC_NSOrderedSet,
     63   FC_NSSet,
     64   FC_NSString
     65 };
     66 
     67 static FoundationClass findKnownClass(const ObjCInterfaceDecl *ID) {
     68   static llvm::StringMap<FoundationClass> Classes;
     69   if (Classes.empty()) {
     70     Classes["NSArray"] = FC_NSArray;
     71     Classes["NSDictionary"] = FC_NSDictionary;
     72     Classes["NSEnumerator"] = FC_NSEnumerator;
     73     Classes["NSNull"] = FC_NSNull;
     74     Classes["NSOrderedSet"] = FC_NSOrderedSet;
     75     Classes["NSSet"] = FC_NSSet;
     76     Classes["NSString"] = FC_NSString;
     77   }
     78 
     79   // FIXME: Should we cache this at all?
     80   FoundationClass result = Classes.lookup(ID->getIdentifier()->getName());
     81   if (result == FC_None)
     82     if (const ObjCInterfaceDecl *Super = ID->getSuperClass())
     83       return findKnownClass(Super);
     84 
     85   return result;
     86 }
     87 
     88 //===----------------------------------------------------------------------===//
     89 // NilArgChecker - Check for prohibited nil arguments to ObjC method calls.
     90 //===----------------------------------------------------------------------===//
     91 
     92 namespace {
     93   class NilArgChecker : public Checker<check::PreObjCMessage,
     94                                        check::PostStmt<ObjCDictionaryLiteral>,
     95                                        check::PostStmt<ObjCArrayLiteral> > {
     96     mutable OwningPtr<APIMisuse> BT;
     97 
     98     void warnIfNilExpr(const Expr *E,
     99                        const char *Msg,
    100                        CheckerContext &C) const;
    101 
    102     void warnIfNilArg(CheckerContext &C,
    103                       const ObjCMethodCall &msg, unsigned Arg,
    104                       FoundationClass Class,
    105                       bool CanBeSubscript = false) const;
    106 
    107     void generateBugReport(ExplodedNode *N,
    108                            StringRef Msg,
    109                            SourceRange Range,
    110                            const Expr *Expr,
    111                            CheckerContext &C) const;
    112 
    113   public:
    114     void checkPreObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
    115     void checkPostStmt(const ObjCDictionaryLiteral *DL,
    116                        CheckerContext &C) const;
    117     void checkPostStmt(const ObjCArrayLiteral *AL,
    118                        CheckerContext &C) const;
    119   };
    120 }
    121 
    122 void NilArgChecker::warnIfNilExpr(const Expr *E,
    123                                   const char *Msg,
    124                                   CheckerContext &C) const {
    125   ProgramStateRef State = C.getState();
    126   if (State->isNull(C.getSVal(E)).isConstrainedTrue()) {
    127 
    128     if (ExplodedNode *N = C.generateSink()) {
    129       generateBugReport(N, Msg, E->getSourceRange(), E, C);
    130     }
    131 
    132   }
    133 }
    134 
    135 void NilArgChecker::warnIfNilArg(CheckerContext &C,
    136                                  const ObjCMethodCall &msg,
    137                                  unsigned int Arg,
    138                                  FoundationClass Class,
    139                                  bool CanBeSubscript) const {
    140   // Check if the argument is nil.
    141   ProgramStateRef State = C.getState();
    142   if (!State->isNull(msg.getArgSVal(Arg)).isConstrainedTrue())
    143       return;
    144 
    145   if (ExplodedNode *N = C.generateSink()) {
    146     SmallString<128> sbuf;
    147     llvm::raw_svector_ostream os(sbuf);
    148 
    149     if (CanBeSubscript && msg.getMessageKind() == OCM_Subscript) {
    150 
    151       if (Class == FC_NSArray) {
    152         os << "Array element cannot be nil";
    153       } else if (Class == FC_NSDictionary) {
    154         if (Arg == 0) {
    155           os << "Value stored into '";
    156           os << GetReceiverInterfaceName(msg) << "' cannot be nil";
    157         } else {
    158           assert(Arg == 1);
    159           os << "'"<< GetReceiverInterfaceName(msg) << "' key cannot be nil";
    160         }
    161       } else
    162         llvm_unreachable("Missing foundation class for the subscript expr");
    163 
    164     } else {
    165       if (Class == FC_NSDictionary) {
    166         if (Arg == 0)
    167           os << "Value argument ";
    168         else {
    169           assert(Arg == 1);
    170           os << "Key argument ";
    171         }
    172         os << "to '" << msg.getSelector().getAsString() << "' cannot be nil";
    173       } else {
    174         os << "Argument to '" << GetReceiverInterfaceName(msg) << "' method '"
    175         << msg.getSelector().getAsString() << "' cannot be nil";
    176       }
    177     }
    178 
    179     generateBugReport(N, os.str(), msg.getArgSourceRange(Arg),
    180                       msg.getArgExpr(Arg), C);
    181   }
    182 }
    183 
    184 void NilArgChecker::generateBugReport(ExplodedNode *N,
    185                                       StringRef Msg,
    186                                       SourceRange Range,
    187                                       const Expr *E,
    188                                       CheckerContext &C) const {
    189   if (!BT)
    190     BT.reset(new APIMisuse("nil argument"));
    191 
    192   BugReport *R = new BugReport(*BT, Msg, N);
    193   R->addRange(Range);
    194   bugreporter::trackNullOrUndefValue(N, E, *R);
    195   C.emitReport(R);
    196 }
    197 
    198 void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
    199                                         CheckerContext &C) const {
    200   const ObjCInterfaceDecl *ID = msg.getReceiverInterface();
    201   if (!ID)
    202     return;
    203 
    204   FoundationClass Class = findKnownClass(ID);
    205 
    206   static const unsigned InvalidArgIndex = UINT_MAX;
    207   unsigned Arg = InvalidArgIndex;
    208   bool CanBeSubscript = false;
    209 
    210   if (Class == FC_NSString) {
    211     Selector S = msg.getSelector();
    212 
    213     if (S.isUnarySelector())
    214       return;
    215 
    216     // FIXME: This is going to be really slow doing these checks with
    217     //  lexical comparisons.
    218 
    219     std::string NameStr = S.getAsString();
    220     StringRef Name(NameStr);
    221     assert(!Name.empty());
    222 
    223     // FIXME: Checking for initWithFormat: will not work in most cases
    224     //  yet because [NSString alloc] returns id, not NSString*.  We will
    225     //  need support for tracking expected-type information in the analyzer
    226     //  to find these errors.
    227     if (Name == "caseInsensitiveCompare:" ||
    228         Name == "compare:" ||
    229         Name == "compare:options:" ||
    230         Name == "compare:options:range:" ||
    231         Name == "compare:options:range:locale:" ||
    232         Name == "componentsSeparatedByCharactersInSet:" ||
    233         Name == "initWithFormat:") {
    234       Arg = 0;
    235     }
    236   } else if (Class == FC_NSArray) {
    237     Selector S = msg.getSelector();
    238 
    239     if (S.isUnarySelector())
    240       return;
    241 
    242     if (S.getNameForSlot(0).equals("addObject")) {
    243       Arg = 0;
    244     } else if (S.getNameForSlot(0).equals("insertObject") &&
    245                S.getNameForSlot(1).equals("atIndex")) {
    246       Arg = 0;
    247     } else if (S.getNameForSlot(0).equals("replaceObjectAtIndex") &&
    248                S.getNameForSlot(1).equals("withObject")) {
    249       Arg = 1;
    250     } else if (S.getNameForSlot(0).equals("setObject") &&
    251                S.getNameForSlot(1).equals("atIndexedSubscript")) {
    252       Arg = 0;
    253       CanBeSubscript = true;
    254     } else if (S.getNameForSlot(0).equals("arrayByAddingObject")) {
    255       Arg = 0;
    256     }
    257   } else if (Class == FC_NSDictionary) {
    258     Selector S = msg.getSelector();
    259 
    260     if (S.isUnarySelector())
    261       return;
    262 
    263     if (S.getNameForSlot(0).equals("dictionaryWithObject") &&
    264         S.getNameForSlot(1).equals("forKey")) {
    265       Arg = 0;
    266       warnIfNilArg(C, msg, /* Arg */1, Class);
    267     } else if (S.getNameForSlot(0).equals("setObject") &&
    268                S.getNameForSlot(1).equals("forKey")) {
    269       Arg = 0;
    270       warnIfNilArg(C, msg, /* Arg */1, Class);
    271     } else if (S.getNameForSlot(0).equals("setObject") &&
    272                S.getNameForSlot(1).equals("forKeyedSubscript")) {
    273       CanBeSubscript = true;
    274       Arg = 0;
    275       warnIfNilArg(C, msg, /* Arg */1, Class, CanBeSubscript);
    276     } else if (S.getNameForSlot(0).equals("removeObjectForKey")) {
    277       Arg = 0;
    278     }
    279   }
    280 
    281   // If argument is '0', report a warning.
    282   if ((Arg != InvalidArgIndex))
    283     warnIfNilArg(C, msg, Arg, Class, CanBeSubscript);
    284 
    285 }
    286 
    287 void NilArgChecker::checkPostStmt(const ObjCArrayLiteral *AL,
    288                                   CheckerContext &C) const {
    289   unsigned NumOfElements = AL->getNumElements();
    290   for (unsigned i = 0; i < NumOfElements; ++i) {
    291     warnIfNilExpr(AL->getElement(i), "Array element cannot be nil", C);
    292   }
    293 }
    294 
    295 void NilArgChecker::checkPostStmt(const ObjCDictionaryLiteral *DL,
    296                                   CheckerContext &C) const {
    297   unsigned NumOfElements = DL->getNumElements();
    298   for (unsigned i = 0; i < NumOfElements; ++i) {
    299     ObjCDictionaryElement Element = DL->getKeyValueElement(i);
    300     warnIfNilExpr(Element.Key, "Dictionary key cannot be nil", C);
    301     warnIfNilExpr(Element.Value, "Dictionary value cannot be nil", C);
    302   }
    303 }
    304 
    305 //===----------------------------------------------------------------------===//
    306 // Error reporting.
    307 //===----------------------------------------------------------------------===//
    308 
    309 namespace {
    310 class CFNumberCreateChecker : public Checker< check::PreStmt<CallExpr> > {
    311   mutable OwningPtr<APIMisuse> BT;
    312   mutable IdentifierInfo* II;
    313 public:
    314   CFNumberCreateChecker() : II(0) {}
    315 
    316   void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
    317 
    318 private:
    319   void EmitError(const TypedRegion* R, const Expr *Ex,
    320                 uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind);
    321 };
    322 } // end anonymous namespace
    323 
    324 enum CFNumberType {
    325   kCFNumberSInt8Type = 1,
    326   kCFNumberSInt16Type = 2,
    327   kCFNumberSInt32Type = 3,
    328   kCFNumberSInt64Type = 4,
    329   kCFNumberFloat32Type = 5,
    330   kCFNumberFloat64Type = 6,
    331   kCFNumberCharType = 7,
    332   kCFNumberShortType = 8,
    333   kCFNumberIntType = 9,
    334   kCFNumberLongType = 10,
    335   kCFNumberLongLongType = 11,
    336   kCFNumberFloatType = 12,
    337   kCFNumberDoubleType = 13,
    338   kCFNumberCFIndexType = 14,
    339   kCFNumberNSIntegerType = 15,
    340   kCFNumberCGFloatType = 16
    341 };
    342 
    343 static Optional<uint64_t> GetCFNumberSize(ASTContext &Ctx, uint64_t i) {
    344   static const unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 };
    345 
    346   if (i < kCFNumberCharType)
    347     return FixedSize[i-1];
    348 
    349   QualType T;
    350 
    351   switch (i) {
    352     case kCFNumberCharType:     T = Ctx.CharTy;     break;
    353     case kCFNumberShortType:    T = Ctx.ShortTy;    break;
    354     case kCFNumberIntType:      T = Ctx.IntTy;      break;
    355     case kCFNumberLongType:     T = Ctx.LongTy;     break;
    356     case kCFNumberLongLongType: T = Ctx.LongLongTy; break;
    357     case kCFNumberFloatType:    T = Ctx.FloatTy;    break;
    358     case kCFNumberDoubleType:   T = Ctx.DoubleTy;   break;
    359     case kCFNumberCFIndexType:
    360     case kCFNumberNSIntegerType:
    361     case kCFNumberCGFloatType:
    362       // FIXME: We need a way to map from names to Type*.
    363     default:
    364       return None;
    365   }
    366 
    367   return Ctx.getTypeSize(T);
    368 }
    369 
    370 #if 0
    371 static const char* GetCFNumberTypeStr(uint64_t i) {
    372   static const char* Names[] = {
    373     "kCFNumberSInt8Type",
    374     "kCFNumberSInt16Type",
    375     "kCFNumberSInt32Type",
    376     "kCFNumberSInt64Type",
    377     "kCFNumberFloat32Type",
    378     "kCFNumberFloat64Type",
    379     "kCFNumberCharType",
    380     "kCFNumberShortType",
    381     "kCFNumberIntType",
    382     "kCFNumberLongType",
    383     "kCFNumberLongLongType",
    384     "kCFNumberFloatType",
    385     "kCFNumberDoubleType",
    386     "kCFNumberCFIndexType",
    387     "kCFNumberNSIntegerType",
    388     "kCFNumberCGFloatType"
    389   };
    390 
    391   return i <= kCFNumberCGFloatType ? Names[i-1] : "Invalid CFNumberType";
    392 }
    393 #endif
    394 
    395 void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE,
    396                                          CheckerContext &C) const {
    397   ProgramStateRef state = C.getState();
    398   const FunctionDecl *FD = C.getCalleeDecl(CE);
    399   if (!FD)
    400     return;
    401 
    402   ASTContext &Ctx = C.getASTContext();
    403   if (!II)
    404     II = &Ctx.Idents.get("CFNumberCreate");
    405 
    406   if (FD->getIdentifier() != II || CE->getNumArgs() != 3)
    407     return;
    408 
    409   // Get the value of the "theType" argument.
    410   const LocationContext *LCtx = C.getLocationContext();
    411   SVal TheTypeVal = state->getSVal(CE->getArg(1), LCtx);
    412 
    413   // FIXME: We really should allow ranges of valid theType values, and
    414   //   bifurcate the state appropriately.
    415   Optional<nonloc::ConcreteInt> V = TheTypeVal.getAs<nonloc::ConcreteInt>();
    416   if (!V)
    417     return;
    418 
    419   uint64_t NumberKind = V->getValue().getLimitedValue();
    420   Optional<uint64_t> OptTargetSize = GetCFNumberSize(Ctx, NumberKind);
    421 
    422   // FIXME: In some cases we can emit an error.
    423   if (!OptTargetSize)
    424     return;
    425 
    426   uint64_t TargetSize = *OptTargetSize;
    427 
    428   // Look at the value of the integer being passed by reference.  Essentially
    429   // we want to catch cases where the value passed in is not equal to the
    430   // size of the type being created.
    431   SVal TheValueExpr = state->getSVal(CE->getArg(2), LCtx);
    432 
    433   // FIXME: Eventually we should handle arbitrary locations.  We can do this
    434   //  by having an enhanced memory model that does low-level typing.
    435   Optional<loc::MemRegionVal> LV = TheValueExpr.getAs<loc::MemRegionVal>();
    436   if (!LV)
    437     return;
    438 
    439   const TypedValueRegion* R = dyn_cast<TypedValueRegion>(LV->stripCasts());
    440   if (!R)
    441     return;
    442 
    443   QualType T = Ctx.getCanonicalType(R->getValueType());
    444 
    445   // FIXME: If the pointee isn't an integer type, should we flag a warning?
    446   //  People can do weird stuff with pointers.
    447 
    448   if (!T->isIntegralOrEnumerationType())
    449     return;
    450 
    451   uint64_t SourceSize = Ctx.getTypeSize(T);
    452 
    453   // CHECK: is SourceSize == TargetSize
    454   if (SourceSize == TargetSize)
    455     return;
    456 
    457   // Generate an error.  Only generate a sink if 'SourceSize < TargetSize';
    458   // otherwise generate a regular node.
    459   //
    460   // FIXME: We can actually create an abstract "CFNumber" object that has
    461   //  the bits initialized to the provided values.
    462   //
    463   if (ExplodedNode *N = SourceSize < TargetSize ? C.generateSink()
    464                                                 : C.addTransition()) {
    465     SmallString<128> sbuf;
    466     llvm::raw_svector_ostream os(sbuf);
    467 
    468     os << (SourceSize == 8 ? "An " : "A ")
    469        << SourceSize << " bit integer is used to initialize a CFNumber "
    470                         "object that represents "
    471        << (TargetSize == 8 ? "an " : "a ")
    472        << TargetSize << " bit integer. ";
    473 
    474     if (SourceSize < TargetSize)
    475       os << (TargetSize - SourceSize)
    476       << " bits of the CFNumber value will be garbage." ;
    477     else
    478       os << (SourceSize - TargetSize)
    479       << " bits of the input integer will be lost.";
    480 
    481     if (!BT)
    482       BT.reset(new APIMisuse("Bad use of CFNumberCreate"));
    483 
    484     BugReport *report = new BugReport(*BT, os.str(), N);
    485     report->addRange(CE->getArg(2)->getSourceRange());
    486     C.emitReport(report);
    487   }
    488 }
    489 
    490 //===----------------------------------------------------------------------===//
    491 // CFRetain/CFRelease/CFMakeCollectable checking for null arguments.
    492 //===----------------------------------------------------------------------===//
    493 
    494 namespace {
    495 class CFRetainReleaseChecker : public Checker< check::PreStmt<CallExpr> > {
    496   mutable OwningPtr<APIMisuse> BT;
    497   mutable IdentifierInfo *Retain, *Release, *MakeCollectable;
    498 public:
    499   CFRetainReleaseChecker(): Retain(0), Release(0), MakeCollectable(0) {}
    500   void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
    501 };
    502 } // end anonymous namespace
    503 
    504 
    505 void CFRetainReleaseChecker::checkPreStmt(const CallExpr *CE,
    506                                           CheckerContext &C) const {
    507   // If the CallExpr doesn't have exactly 1 argument just give up checking.
    508   if (CE->getNumArgs() != 1)
    509     return;
    510 
    511   ProgramStateRef state = C.getState();
    512   const FunctionDecl *FD = C.getCalleeDecl(CE);
    513   if (!FD)
    514     return;
    515 
    516   if (!BT) {
    517     ASTContext &Ctx = C.getASTContext();
    518     Retain = &Ctx.Idents.get("CFRetain");
    519     Release = &Ctx.Idents.get("CFRelease");
    520     MakeCollectable = &Ctx.Idents.get("CFMakeCollectable");
    521     BT.reset(
    522       new APIMisuse("null passed to CFRetain/CFRelease/CFMakeCollectable"));
    523   }
    524 
    525   // Check if we called CFRetain/CFRelease/CFMakeCollectable.
    526   const IdentifierInfo *FuncII = FD->getIdentifier();
    527   if (!(FuncII == Retain || FuncII == Release || FuncII == MakeCollectable))
    528     return;
    529 
    530   // FIXME: The rest of this just checks that the argument is non-null.
    531   // It should probably be refactored and combined with NonNullParamChecker.
    532 
    533   // Get the argument's value.
    534   const Expr *Arg = CE->getArg(0);
    535   SVal ArgVal = state->getSVal(Arg, C.getLocationContext());
    536   Optional<DefinedSVal> DefArgVal = ArgVal.getAs<DefinedSVal>();
    537   if (!DefArgVal)
    538     return;
    539 
    540   // Get a NULL value.
    541   SValBuilder &svalBuilder = C.getSValBuilder();
    542   DefinedSVal zero =
    543       svalBuilder.makeZeroVal(Arg->getType()).castAs<DefinedSVal>();
    544 
    545   // Make an expression asserting that they're equal.
    546   DefinedOrUnknownSVal ArgIsNull = svalBuilder.evalEQ(state, zero, *DefArgVal);
    547 
    548   // Are they equal?
    549   ProgramStateRef stateTrue, stateFalse;
    550   llvm::tie(stateTrue, stateFalse) = state->assume(ArgIsNull);
    551 
    552   if (stateTrue && !stateFalse) {
    553     ExplodedNode *N = C.generateSink(stateTrue);
    554     if (!N)
    555       return;
    556 
    557     const char *description;
    558     if (FuncII == Retain)
    559       description = "Null pointer argument in call to CFRetain";
    560     else if (FuncII == Release)
    561       description = "Null pointer argument in call to CFRelease";
    562     else if (FuncII == MakeCollectable)
    563       description = "Null pointer argument in call to CFMakeCollectable";
    564     else
    565       llvm_unreachable("impossible case");
    566 
    567     BugReport *report = new BugReport(*BT, description, N);
    568     report->addRange(Arg->getSourceRange());
    569     bugreporter::trackNullOrUndefValue(N, Arg, *report);
    570     C.emitReport(report);
    571     return;
    572   }
    573 
    574   // From here on, we know the argument is non-null.
    575   C.addTransition(stateFalse);
    576 }
    577 
    578 //===----------------------------------------------------------------------===//
    579 // Check for sending 'retain', 'release', or 'autorelease' directly to a Class.
    580 //===----------------------------------------------------------------------===//
    581 
    582 namespace {
    583 class ClassReleaseChecker : public Checker<check::PreObjCMessage> {
    584   mutable Selector releaseS;
    585   mutable Selector retainS;
    586   mutable Selector autoreleaseS;
    587   mutable Selector drainS;
    588   mutable OwningPtr<BugType> BT;
    589 
    590 public:
    591   void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
    592 };
    593 }
    594 
    595 void ClassReleaseChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
    596                                               CheckerContext &C) const {
    597 
    598   if (!BT) {
    599     BT.reset(new APIMisuse("message incorrectly sent to class instead of class "
    600                            "instance"));
    601 
    602     ASTContext &Ctx = C.getASTContext();
    603     releaseS = GetNullarySelector("release", Ctx);
    604     retainS = GetNullarySelector("retain", Ctx);
    605     autoreleaseS = GetNullarySelector("autorelease", Ctx);
    606     drainS = GetNullarySelector("drain", Ctx);
    607   }
    608 
    609   if (msg.isInstanceMessage())
    610     return;
    611   const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
    612   assert(Class);
    613 
    614   Selector S = msg.getSelector();
    615   if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
    616     return;
    617 
    618   if (ExplodedNode *N = C.addTransition()) {
    619     SmallString<200> buf;
    620     llvm::raw_svector_ostream os(buf);
    621 
    622     os << "The '" << S.getAsString() << "' message should be sent to instances "
    623           "of class '" << Class->getName()
    624        << "' and not the class directly";
    625 
    626     BugReport *report = new BugReport(*BT, os.str(), N);
    627     report->addRange(msg.getSourceRange());
    628     C.emitReport(report);
    629   }
    630 }
    631 
    632 //===----------------------------------------------------------------------===//
    633 // Check for passing non-Objective-C types to variadic methods that expect
    634 // only Objective-C types.
    635 //===----------------------------------------------------------------------===//
    636 
    637 namespace {
    638 class VariadicMethodTypeChecker : public Checker<check::PreObjCMessage> {
    639   mutable Selector arrayWithObjectsS;
    640   mutable Selector dictionaryWithObjectsAndKeysS;
    641   mutable Selector setWithObjectsS;
    642   mutable Selector orderedSetWithObjectsS;
    643   mutable Selector initWithObjectsS;
    644   mutable Selector initWithObjectsAndKeysS;
    645   mutable OwningPtr<BugType> BT;
    646 
    647   bool isVariadicMessage(const ObjCMethodCall &msg) const;
    648 
    649 public:
    650   void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
    651 };
    652 }
    653 
    654 /// isVariadicMessage - Returns whether the given message is a variadic message,
    655 /// where all arguments must be Objective-C types.
    656 bool
    657 VariadicMethodTypeChecker::isVariadicMessage(const ObjCMethodCall &msg) const {
    658   const ObjCMethodDecl *MD = msg.getDecl();
    659 
    660   if (!MD || !MD->isVariadic() || isa<ObjCProtocolDecl>(MD->getDeclContext()))
    661     return false;
    662 
    663   Selector S = msg.getSelector();
    664 
    665   if (msg.isInstanceMessage()) {
    666     // FIXME: Ideally we'd look at the receiver interface here, but that's not
    667     // useful for init, because alloc returns 'id'. In theory, this could lead
    668     // to false positives, for example if there existed a class that had an
    669     // initWithObjects: implementation that does accept non-Objective-C pointer
    670     // types, but the chance of that happening is pretty small compared to the
    671     // gains that this analysis gives.
    672     const ObjCInterfaceDecl *Class = MD->getClassInterface();
    673 
    674     switch (findKnownClass(Class)) {
    675     case FC_NSArray:
    676     case FC_NSOrderedSet:
    677     case FC_NSSet:
    678       return S == initWithObjectsS;
    679     case FC_NSDictionary:
    680       return S == initWithObjectsAndKeysS;
    681     default:
    682       return false;
    683     }
    684   } else {
    685     const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
    686 
    687     switch (findKnownClass(Class)) {
    688       case FC_NSArray:
    689         return S == arrayWithObjectsS;
    690       case FC_NSOrderedSet:
    691         return S == orderedSetWithObjectsS;
    692       case FC_NSSet:
    693         return S == setWithObjectsS;
    694       case FC_NSDictionary:
    695         return S == dictionaryWithObjectsAndKeysS;
    696       default:
    697         return false;
    698     }
    699   }
    700 }
    701 
    702 void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
    703                                                     CheckerContext &C) const {
    704   if (!BT) {
    705     BT.reset(new APIMisuse("Arguments passed to variadic method aren't all "
    706                            "Objective-C pointer types"));
    707 
    708     ASTContext &Ctx = C.getASTContext();
    709     arrayWithObjectsS = GetUnarySelector("arrayWithObjects", Ctx);
    710     dictionaryWithObjectsAndKeysS =
    711       GetUnarySelector("dictionaryWithObjectsAndKeys", Ctx);
    712     setWithObjectsS = GetUnarySelector("setWithObjects", Ctx);
    713     orderedSetWithObjectsS = GetUnarySelector("orderedSetWithObjects", Ctx);
    714 
    715     initWithObjectsS = GetUnarySelector("initWithObjects", Ctx);
    716     initWithObjectsAndKeysS = GetUnarySelector("initWithObjectsAndKeys", Ctx);
    717   }
    718 
    719   if (!isVariadicMessage(msg))
    720       return;
    721 
    722   // We are not interested in the selector arguments since they have
    723   // well-defined types, so the compiler will issue a warning for them.
    724   unsigned variadicArgsBegin = msg.getSelector().getNumArgs();
    725 
    726   // We're not interested in the last argument since it has to be nil or the
    727   // compiler would have issued a warning for it elsewhere.
    728   unsigned variadicArgsEnd = msg.getNumArgs() - 1;
    729 
    730   if (variadicArgsEnd <= variadicArgsBegin)
    731     return;
    732 
    733   // Verify that all arguments have Objective-C types.
    734   Optional<ExplodedNode*> errorNode;
    735   ProgramStateRef state = C.getState();
    736 
    737   for (unsigned I = variadicArgsBegin; I != variadicArgsEnd; ++I) {
    738     QualType ArgTy = msg.getArgExpr(I)->getType();
    739     if (ArgTy->isObjCObjectPointerType())
    740       continue;
    741 
    742     // Block pointers are treaded as Objective-C pointers.
    743     if (ArgTy->isBlockPointerType())
    744       continue;
    745 
    746     // Ignore pointer constants.
    747     if (msg.getArgSVal(I).getAs<loc::ConcreteInt>())
    748       continue;
    749 
    750     // Ignore pointer types annotated with 'NSObject' attribute.
    751     if (C.getASTContext().isObjCNSObjectType(ArgTy))
    752       continue;
    753 
    754     // Ignore CF references, which can be toll-free bridged.
    755     if (coreFoundation::isCFObjectRef(ArgTy))
    756       continue;
    757 
    758     // Generate only one error node to use for all bug reports.
    759     if (!errorNode.hasValue())
    760       errorNode = C.addTransition();
    761 
    762     if (!errorNode.getValue())
    763       continue;
    764 
    765     SmallString<128> sbuf;
    766     llvm::raw_svector_ostream os(sbuf);
    767 
    768     StringRef TypeName = GetReceiverInterfaceName(msg);
    769     if (!TypeName.empty())
    770       os << "Argument to '" << TypeName << "' method '";
    771     else
    772       os << "Argument to method '";
    773 
    774     os << msg.getSelector().getAsString()
    775        << "' should be an Objective-C pointer type, not '";
    776     ArgTy.print(os, C.getLangOpts());
    777     os << "'";
    778 
    779     BugReport *R = new BugReport(*BT, os.str(), errorNode.getValue());
    780     R->addRange(msg.getArgSourceRange(I));
    781     C.emitReport(R);
    782   }
    783 }
    784 
    785 //===----------------------------------------------------------------------===//
    786 // Improves the modeling of loops over Cocoa collections.
    787 //===----------------------------------------------------------------------===//
    788 
    789 // The map from container symbol to the container count symbol.
    790 // We currently will remember the last countainer count symbol encountered.
    791 REGISTER_MAP_WITH_PROGRAMSTATE(ContainerCountMap, SymbolRef, SymbolRef)
    792 
    793 namespace {
    794 class ObjCLoopChecker
    795   : public Checker<check::PostStmt<ObjCForCollectionStmt>,
    796                    check::PostObjCMessage,
    797                    check::DeadSymbols,
    798                    check::PointerEscape > {
    799   mutable IdentifierInfo *CountSelectorII;
    800 
    801   bool isCollectionCountMethod(const ObjCMethodCall &M,
    802                                CheckerContext &C) const;
    803 
    804 public:
    805   ObjCLoopChecker() : CountSelectorII(0) {}
    806   void checkPostStmt(const ObjCForCollectionStmt *FCS, CheckerContext &C) const;
    807   void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
    808   void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
    809   ProgramStateRef checkPointerEscape(ProgramStateRef State,
    810                                      const InvalidatedSymbols &Escaped,
    811                                      const CallEvent *Call,
    812                                      PointerEscapeKind Kind) const;
    813 };
    814 }
    815 
    816 static bool isKnownNonNilCollectionType(QualType T) {
    817   const ObjCObjectPointerType *PT = T->getAs<ObjCObjectPointerType>();
    818   if (!PT)
    819     return false;
    820 
    821   const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();
    822   if (!ID)
    823     return false;
    824 
    825   switch (findKnownClass(ID)) {
    826   case FC_NSArray:
    827   case FC_NSDictionary:
    828   case FC_NSEnumerator:
    829   case FC_NSOrderedSet:
    830   case FC_NSSet:
    831     return true;
    832   default:
    833     return false;
    834   }
    835 }
    836 
    837 /// Assumes that the collection is non-nil.
    838 ///
    839 /// If the collection is known to be nil, returns NULL to indicate an infeasible
    840 /// path.
    841 static ProgramStateRef checkCollectionNonNil(CheckerContext &C,
    842                                              ProgramStateRef State,
    843                                              const ObjCForCollectionStmt *FCS) {
    844   if (!State)
    845     return NULL;
    846 
    847   SVal CollectionVal = C.getSVal(FCS->getCollection());
    848   Optional<DefinedSVal> KnownCollection = CollectionVal.getAs<DefinedSVal>();
    849   if (!KnownCollection)
    850     return State;
    851 
    852   ProgramStateRef StNonNil, StNil;
    853   llvm::tie(StNonNil, StNil) = State->assume(*KnownCollection);
    854   if (StNil && !StNonNil) {
    855     // The collection is nil. This path is infeasible.
    856     return NULL;
    857   }
    858 
    859   return StNonNil;
    860 }
    861 
    862 /// Assumes that the collection elements are non-nil.
    863 ///
    864 /// This only applies if the collection is one of those known not to contain
    865 /// nil values.
    866 static ProgramStateRef checkElementNonNil(CheckerContext &C,
    867                                           ProgramStateRef State,
    868                                           const ObjCForCollectionStmt *FCS) {
    869   if (!State)
    870     return NULL;
    871 
    872   // See if the collection is one where we /know/ the elements are non-nil.
    873   if (!isKnownNonNilCollectionType(FCS->getCollection()->getType()))
    874     return State;
    875 
    876   const LocationContext *LCtx = C.getLocationContext();
    877   const Stmt *Element = FCS->getElement();
    878 
    879   // FIXME: Copied from ExprEngineObjC.
    880   Optional<Loc> ElementLoc;
    881   if (const DeclStmt *DS = dyn_cast<DeclStmt>(Element)) {
    882     const VarDecl *ElemDecl = cast<VarDecl>(DS->getSingleDecl());
    883     assert(ElemDecl->getInit() == 0);
    884     ElementLoc = State->getLValue(ElemDecl, LCtx);
    885   } else {
    886     ElementLoc = State->getSVal(Element, LCtx).getAs<Loc>();
    887   }
    888 
    889   if (!ElementLoc)
    890     return State;
    891 
    892   // Go ahead and assume the value is non-nil.
    893   SVal Val = State->getSVal(*ElementLoc);
    894   return State->assume(Val.castAs<DefinedOrUnknownSVal>(), true);
    895 }
    896 
    897 /// Returns NULL state if the collection is known to contain elements
    898 /// (or is known not to contain elements if the Assumption parameter is false.)
    899 static ProgramStateRef assumeCollectionNonEmpty(CheckerContext &C,
    900                                             ProgramStateRef State,
    901                                             const ObjCForCollectionStmt *FCS,
    902                                             bool Assumption = false) {
    903   if (!State)
    904     return NULL;
    905 
    906   SymbolRef CollectionS = C.getSVal(FCS->getCollection()).getAsSymbol();
    907   if (!CollectionS)
    908     return State;
    909   const SymbolRef *CountS = State->get<ContainerCountMap>(CollectionS);
    910   if (!CountS)
    911     return State;
    912 
    913   SValBuilder &SvalBuilder = C.getSValBuilder();
    914   SVal CountGreaterThanZeroVal =
    915     SvalBuilder.evalBinOp(State, BO_GT,
    916                           nonloc::SymbolVal(*CountS),
    917                           SvalBuilder.makeIntVal(0, (*CountS)->getType()),
    918                           SvalBuilder.getConditionType());
    919   Optional<DefinedSVal> CountGreaterThanZero =
    920     CountGreaterThanZeroVal.getAs<DefinedSVal>();
    921   if (!CountGreaterThanZero) {
    922     // The SValBuilder cannot construct a valid SVal for this condition.
    923     // This means we cannot properly reason about it.
    924     return State;
    925   }
    926 
    927   return State->assume(*CountGreaterThanZero, Assumption);
    928 }
    929 
    930 /// If the fist block edge is a back edge, we are reentering the loop.
    931 static bool alreadyExecutedAtLeastOneLoopIteration(const ExplodedNode *N,
    932                                              const ObjCForCollectionStmt *FCS) {
    933   if (!N)
    934     return false;
    935 
    936   ProgramPoint P = N->getLocation();
    937   if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) {
    938     if (BE->getSrc()->getLoopTarget() == FCS)
    939       return true;
    940     return false;
    941   }
    942 
    943   // Keep looking for a block edge.
    944   for (ExplodedNode::const_pred_iterator I = N->pred_begin(),
    945                                          E = N->pred_end(); I != E; ++I) {
    946     if (alreadyExecutedAtLeastOneLoopIteration(*I, FCS))
    947       return true;
    948   }
    949 
    950   return false;
    951 }
    952 
    953 void ObjCLoopChecker::checkPostStmt(const ObjCForCollectionStmt *FCS,
    954                                     CheckerContext &C) const {
    955   ProgramStateRef State = C.getState();
    956 
    957   // Check if this is the branch for the end of the loop.
    958   SVal CollectionSentinel = C.getSVal(FCS);
    959   if (CollectionSentinel.isZeroConstant()) {
    960     if (!alreadyExecutedAtLeastOneLoopIteration(C.getPredecessor(), FCS))
    961       State = assumeCollectionNonEmpty(C, State, FCS, /*Assumption*/false);
    962 
    963   // Otherwise, this is a branch that goes through the loop body.
    964   } else {
    965     State = checkCollectionNonNil(C, State, FCS);
    966     State = checkElementNonNil(C, State, FCS);
    967     State = assumeCollectionNonEmpty(C, State, FCS, /*Assumption*/true);
    968   }
    969 
    970   if (!State)
    971     C.generateSink();
    972   else if (State != C.getState())
    973     C.addTransition(State);
    974 }
    975 
    976 bool ObjCLoopChecker::isCollectionCountMethod(const ObjCMethodCall &M,
    977                                               CheckerContext &C) const {
    978   Selector S = M.getSelector();
    979   // Initialize the identifiers on first use.
    980   if (!CountSelectorII)
    981     CountSelectorII = &C.getASTContext().Idents.get("count");
    982 
    983   // If the method returns collection count, record the value.
    984   if (S.isUnarySelector() &&
    985       (S.getIdentifierInfoForSlot(0) == CountSelectorII))
    986     return true;
    987 
    988   return false;
    989 }
    990 
    991 void ObjCLoopChecker::checkPostObjCMessage(const ObjCMethodCall &M,
    992                                            CheckerContext &C) const {
    993   if (!M.isInstanceMessage())
    994     return;
    995 
    996   const ObjCInterfaceDecl *ClassID = M.getReceiverInterface();
    997   if (!ClassID)
    998     return;
    999 
   1000   FoundationClass Class = findKnownClass(ClassID);
   1001   if (Class != FC_NSDictionary &&
   1002       Class != FC_NSArray &&
   1003       Class != FC_NSSet)
   1004     return;
   1005 
   1006   SymbolRef ContainerS = M.getReceiverSVal().getAsSymbol();
   1007   if (!ContainerS)
   1008     return;
   1009 
   1010   // If we are processing a call to "count", get the symbolic value returned by
   1011   // a call to "count" and add it to the map.
   1012   if (!isCollectionCountMethod(M, C))
   1013     return;
   1014 
   1015   const Expr *MsgExpr = M.getOriginExpr();
   1016   SymbolRef CountS = C.getSVal(MsgExpr).getAsSymbol();
   1017   if (CountS) {
   1018     ProgramStateRef State = C.getState();
   1019     C.getSymbolManager().addSymbolDependency(ContainerS, CountS);
   1020     State = State->set<ContainerCountMap>(ContainerS, CountS);
   1021     C.addTransition(State);
   1022   }
   1023   return;
   1024 }
   1025 
   1026 ProgramStateRef
   1027 ObjCLoopChecker::checkPointerEscape(ProgramStateRef State,
   1028                                     const InvalidatedSymbols &Escaped,
   1029                                     const CallEvent *Call,
   1030                                     PointerEscapeKind Kind) const {
   1031   // TODO: If we know that the call cannot change the collection count, there
   1032   // is nothing to do, just return.
   1033 
   1034   // Remove the invalidated symbols form the collection count map.
   1035   for (InvalidatedSymbols::const_iterator I = Escaped.begin(),
   1036        E = Escaped.end();
   1037        I != E; ++I) {
   1038     SymbolRef Sym = *I;
   1039 
   1040     // The symbol escaped. Pessimistically, assume that the count could have
   1041     // changed.
   1042     State = State->remove<ContainerCountMap>(Sym);
   1043   }
   1044   return State;
   1045 }
   1046 
   1047 void ObjCLoopChecker::checkDeadSymbols(SymbolReaper &SymReaper,
   1048                                        CheckerContext &C) const {
   1049   ProgramStateRef State = C.getState();
   1050 
   1051   // Remove the dead symbols from the collection count map.
   1052   ContainerCountMapTy Tracked = State->get<ContainerCountMap>();
   1053   for (ContainerCountMapTy::iterator I = Tracked.begin(),
   1054                                      E = Tracked.end(); I != E; ++I) {
   1055     SymbolRef Sym = I->first;
   1056     if (SymReaper.isDead(Sym))
   1057       State = State->remove<ContainerCountMap>(Sym);
   1058   }
   1059 
   1060   C.addTransition(State);
   1061 }
   1062 
   1063 namespace {
   1064 /// \class ObjCNonNilReturnValueChecker
   1065 /// \brief The checker restricts the return values of APIs known to
   1066 /// never (or almost never) return 'nil'.
   1067 class ObjCNonNilReturnValueChecker
   1068   : public Checker<check::PostObjCMessage> {
   1069     mutable bool Initialized;
   1070     mutable Selector ObjectAtIndex;
   1071     mutable Selector ObjectAtIndexedSubscript;
   1072     mutable Selector NullSelector;
   1073 
   1074 public:
   1075   ObjCNonNilReturnValueChecker() : Initialized(false) {}
   1076   void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
   1077 };
   1078 }
   1079 
   1080 static ProgramStateRef assumeExprIsNonNull(const Expr *NonNullExpr,
   1081                                            ProgramStateRef State,
   1082                                            CheckerContext &C) {
   1083   SVal Val = State->getSVal(NonNullExpr, C.getLocationContext());
   1084   if (Optional<DefinedOrUnknownSVal> DV = Val.getAs<DefinedOrUnknownSVal>())
   1085     return State->assume(*DV, true);
   1086   return State;
   1087 }
   1088 
   1089 void ObjCNonNilReturnValueChecker::checkPostObjCMessage(const ObjCMethodCall &M,
   1090                                                         CheckerContext &C)
   1091                                                         const {
   1092   ProgramStateRef State = C.getState();
   1093 
   1094   if (!Initialized) {
   1095     ASTContext &Ctx = C.getASTContext();
   1096     ObjectAtIndex = GetUnarySelector("objectAtIndex", Ctx);
   1097     ObjectAtIndexedSubscript = GetUnarySelector("objectAtIndexedSubscript", Ctx);
   1098     NullSelector = GetNullarySelector("null", Ctx);
   1099   }
   1100 
   1101   // Check the receiver type.
   1102   if (const ObjCInterfaceDecl *Interface = M.getReceiverInterface()) {
   1103 
   1104     // Assume that object returned from '[self init]' or '[super init]' is not
   1105     // 'nil' if we are processing an inlined function/method.
   1106     //
   1107     // A defensive callee will (and should) check if the object returned by
   1108     // '[super init]' is 'nil' before doing it's own initialization. However,
   1109     // since 'nil' is rarely returned in practice, we should not warn when the
   1110     // caller to the defensive constructor uses the object in contexts where
   1111     // 'nil' is not accepted.
   1112     if (!C.inTopFrame() && M.getDecl() &&
   1113         M.getDecl()->getMethodFamily() == OMF_init &&
   1114         M.isReceiverSelfOrSuper()) {
   1115       State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
   1116     }
   1117 
   1118     FoundationClass Cl = findKnownClass(Interface);
   1119 
   1120     // Objects returned from
   1121     // [NSArray|NSOrderedSet]::[ObjectAtIndex|ObjectAtIndexedSubscript]
   1122     // are never 'nil'.
   1123     if (Cl == FC_NSArray || Cl == FC_NSOrderedSet) {
   1124       Selector Sel = M.getSelector();
   1125       if (Sel == ObjectAtIndex || Sel == ObjectAtIndexedSubscript) {
   1126         // Go ahead and assume the value is non-nil.
   1127         State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
   1128       }
   1129     }
   1130 
   1131     // Objects returned from [NSNull null] are not nil.
   1132     if (Cl == FC_NSNull) {
   1133       if (M.getSelector() == NullSelector) {
   1134         // Go ahead and assume the value is non-nil.
   1135         State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
   1136       }
   1137     }
   1138   }
   1139   C.addTransition(State);
   1140 }
   1141 
   1142 //===----------------------------------------------------------------------===//
   1143 // Check registration.
   1144 //===----------------------------------------------------------------------===//
   1145 
   1146 void ento::registerNilArgChecker(CheckerManager &mgr) {
   1147   mgr.registerChecker<NilArgChecker>();
   1148 }
   1149 
   1150 void ento::registerCFNumberCreateChecker(CheckerManager &mgr) {
   1151   mgr.registerChecker<CFNumberCreateChecker>();
   1152 }
   1153 
   1154 void ento::registerCFRetainReleaseChecker(CheckerManager &mgr) {
   1155   mgr.registerChecker<CFRetainReleaseChecker>();
   1156 }
   1157 
   1158 void ento::registerClassReleaseChecker(CheckerManager &mgr) {
   1159   mgr.registerChecker<ClassReleaseChecker>();
   1160 }
   1161 
   1162 void ento::registerVariadicMethodTypeChecker(CheckerManager &mgr) {
   1163   mgr.registerChecker<VariadicMethodTypeChecker>();
   1164 }
   1165 
   1166 void ento::registerObjCLoopChecker(CheckerManager &mgr) {
   1167   mgr.registerChecker<ObjCLoopChecker>();
   1168 }
   1169 
   1170 void ento::registerObjCNonNilReturnValueChecker(CheckerManager &mgr) {
   1171   mgr.registerChecker<ObjCNonNilReturnValueChecker>();
   1172 }
   1173