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_NSOrderedSet,
     62   FC_NSSet,
     63   FC_NSString
     64 };
     65 
     66 static FoundationClass findKnownClass(const ObjCInterfaceDecl *ID) {
     67   static llvm::StringMap<FoundationClass> Classes;
     68   if (Classes.empty()) {
     69     Classes["NSArray"] = FC_NSArray;
     70     Classes["NSDictionary"] = FC_NSDictionary;
     71     Classes["NSEnumerator"] = FC_NSEnumerator;
     72     Classes["NSOrderedSet"] = FC_NSOrderedSet;
     73     Classes["NSSet"] = FC_NSSet;
     74     Classes["NSString"] = FC_NSString;
     75   }
     76 
     77   // FIXME: Should we cache this at all?
     78   FoundationClass result = Classes.lookup(ID->getIdentifier()->getName());
     79   if (result == FC_None)
     80     if (const ObjCInterfaceDecl *Super = ID->getSuperClass())
     81       return findKnownClass(Super);
     82 
     83   return result;
     84 }
     85 
     86 static inline bool isNil(SVal X) {
     87   return X.getAs<loc::ConcreteInt>().hasValue();
     88 }
     89 
     90 //===----------------------------------------------------------------------===//
     91 // NilArgChecker - Check for prohibited nil arguments to ObjC method calls.
     92 //===----------------------------------------------------------------------===//
     93 
     94 namespace {
     95   class NilArgChecker : public Checker<check::PreObjCMessage> {
     96     mutable OwningPtr<APIMisuse> BT;
     97 
     98     void WarnNilArg(CheckerContext &C,
     99                     const ObjCMethodCall &msg, unsigned Arg) const;
    100 
    101   public:
    102     void checkPreObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
    103   };
    104 }
    105 
    106 void NilArgChecker::WarnNilArg(CheckerContext &C,
    107                                const ObjCMethodCall &msg,
    108                                unsigned int Arg) const
    109 {
    110   if (!BT)
    111     BT.reset(new APIMisuse("nil argument"));
    112 
    113   if (ExplodedNode *N = C.generateSink()) {
    114     SmallString<128> sbuf;
    115     llvm::raw_svector_ostream os(sbuf);
    116     os << "Argument to '" << GetReceiverInterfaceName(msg) << "' method '"
    117        << msg.getSelector().getAsString() << "' cannot be nil";
    118 
    119     BugReport *R = new BugReport(*BT, os.str(), N);
    120     R->addRange(msg.getArgSourceRange(Arg));
    121     C.emitReport(R);
    122   }
    123 }
    124 
    125 void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
    126                                         CheckerContext &C) const {
    127   const ObjCInterfaceDecl *ID = msg.getReceiverInterface();
    128   if (!ID)
    129     return;
    130 
    131   FoundationClass Class = findKnownClass(ID);
    132 
    133   static const unsigned InvalidArgIndex = UINT_MAX;
    134   unsigned Arg = InvalidArgIndex;
    135 
    136   if (Class == FC_NSString) {
    137     Selector S = msg.getSelector();
    138 
    139     if (S.isUnarySelector())
    140       return;
    141 
    142     // FIXME: This is going to be really slow doing these checks with
    143     //  lexical comparisons.
    144 
    145     std::string NameStr = S.getAsString();
    146     StringRef Name(NameStr);
    147     assert(!Name.empty());
    148 
    149     // FIXME: Checking for initWithFormat: will not work in most cases
    150     //  yet because [NSString alloc] returns id, not NSString*.  We will
    151     //  need support for tracking expected-type information in the analyzer
    152     //  to find these errors.
    153     if (Name == "caseInsensitiveCompare:" ||
    154         Name == "compare:" ||
    155         Name == "compare:options:" ||
    156         Name == "compare:options:range:" ||
    157         Name == "compare:options:range:locale:" ||
    158         Name == "componentsSeparatedByCharactersInSet:" ||
    159         Name == "initWithFormat:") {
    160       Arg = 0;
    161     }
    162   } else if (Class == FC_NSArray) {
    163     Selector S = msg.getSelector();
    164 
    165     if (S.isUnarySelector())
    166       return;
    167 
    168     if (S.getNameForSlot(0).equals("addObject")) {
    169       Arg = 0;
    170     } else if (S.getNameForSlot(0).equals("insertObject") &&
    171                S.getNameForSlot(1).equals("atIndex")) {
    172       Arg = 0;
    173     } else if (S.getNameForSlot(0).equals("replaceObjectAtIndex") &&
    174                S.getNameForSlot(1).equals("withObject")) {
    175       Arg = 1;
    176     } else if (S.getNameForSlot(0).equals("setObject") &&
    177                S.getNameForSlot(1).equals("atIndexedSubscript")) {
    178       Arg = 0;
    179     } else if (S.getNameForSlot(0).equals("arrayByAddingObject")) {
    180       Arg = 0;
    181     }
    182   }
    183 
    184   // If argument is '0', report a warning.
    185   if ((Arg != InvalidArgIndex) && isNil(msg.getArgSVal(Arg)))
    186     WarnNilArg(C, msg, Arg);
    187 
    188 }
    189 
    190 //===----------------------------------------------------------------------===//
    191 // Error reporting.
    192 //===----------------------------------------------------------------------===//
    193 
    194 namespace {
    195 class CFNumberCreateChecker : public Checker< check::PreStmt<CallExpr> > {
    196   mutable OwningPtr<APIMisuse> BT;
    197   mutable IdentifierInfo* II;
    198 public:
    199   CFNumberCreateChecker() : II(0) {}
    200 
    201   void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
    202 
    203 private:
    204   void EmitError(const TypedRegion* R, const Expr *Ex,
    205                 uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind);
    206 };
    207 } // end anonymous namespace
    208 
    209 enum CFNumberType {
    210   kCFNumberSInt8Type = 1,
    211   kCFNumberSInt16Type = 2,
    212   kCFNumberSInt32Type = 3,
    213   kCFNumberSInt64Type = 4,
    214   kCFNumberFloat32Type = 5,
    215   kCFNumberFloat64Type = 6,
    216   kCFNumberCharType = 7,
    217   kCFNumberShortType = 8,
    218   kCFNumberIntType = 9,
    219   kCFNumberLongType = 10,
    220   kCFNumberLongLongType = 11,
    221   kCFNumberFloatType = 12,
    222   kCFNumberDoubleType = 13,
    223   kCFNumberCFIndexType = 14,
    224   kCFNumberNSIntegerType = 15,
    225   kCFNumberCGFloatType = 16
    226 };
    227 
    228 static Optional<uint64_t> GetCFNumberSize(ASTContext &Ctx, uint64_t i) {
    229   static const unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 };
    230 
    231   if (i < kCFNumberCharType)
    232     return FixedSize[i-1];
    233 
    234   QualType T;
    235 
    236   switch (i) {
    237     case kCFNumberCharType:     T = Ctx.CharTy;     break;
    238     case kCFNumberShortType:    T = Ctx.ShortTy;    break;
    239     case kCFNumberIntType:      T = Ctx.IntTy;      break;
    240     case kCFNumberLongType:     T = Ctx.LongTy;     break;
    241     case kCFNumberLongLongType: T = Ctx.LongLongTy; break;
    242     case kCFNumberFloatType:    T = Ctx.FloatTy;    break;
    243     case kCFNumberDoubleType:   T = Ctx.DoubleTy;   break;
    244     case kCFNumberCFIndexType:
    245     case kCFNumberNSIntegerType:
    246     case kCFNumberCGFloatType:
    247       // FIXME: We need a way to map from names to Type*.
    248     default:
    249       return None;
    250   }
    251 
    252   return Ctx.getTypeSize(T);
    253 }
    254 
    255 #if 0
    256 static const char* GetCFNumberTypeStr(uint64_t i) {
    257   static const char* Names[] = {
    258     "kCFNumberSInt8Type",
    259     "kCFNumberSInt16Type",
    260     "kCFNumberSInt32Type",
    261     "kCFNumberSInt64Type",
    262     "kCFNumberFloat32Type",
    263     "kCFNumberFloat64Type",
    264     "kCFNumberCharType",
    265     "kCFNumberShortType",
    266     "kCFNumberIntType",
    267     "kCFNumberLongType",
    268     "kCFNumberLongLongType",
    269     "kCFNumberFloatType",
    270     "kCFNumberDoubleType",
    271     "kCFNumberCFIndexType",
    272     "kCFNumberNSIntegerType",
    273     "kCFNumberCGFloatType"
    274   };
    275 
    276   return i <= kCFNumberCGFloatType ? Names[i-1] : "Invalid CFNumberType";
    277 }
    278 #endif
    279 
    280 void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE,
    281                                          CheckerContext &C) const {
    282   ProgramStateRef state = C.getState();
    283   const FunctionDecl *FD = C.getCalleeDecl(CE);
    284   if (!FD)
    285     return;
    286 
    287   ASTContext &Ctx = C.getASTContext();
    288   if (!II)
    289     II = &Ctx.Idents.get("CFNumberCreate");
    290 
    291   if (FD->getIdentifier() != II || CE->getNumArgs() != 3)
    292     return;
    293 
    294   // Get the value of the "theType" argument.
    295   const LocationContext *LCtx = C.getLocationContext();
    296   SVal TheTypeVal = state->getSVal(CE->getArg(1), LCtx);
    297 
    298   // FIXME: We really should allow ranges of valid theType values, and
    299   //   bifurcate the state appropriately.
    300   Optional<nonloc::ConcreteInt> V = TheTypeVal.getAs<nonloc::ConcreteInt>();
    301   if (!V)
    302     return;
    303 
    304   uint64_t NumberKind = V->getValue().getLimitedValue();
    305   Optional<uint64_t> OptTargetSize = GetCFNumberSize(Ctx, NumberKind);
    306 
    307   // FIXME: In some cases we can emit an error.
    308   if (!OptTargetSize)
    309     return;
    310 
    311   uint64_t TargetSize = *OptTargetSize;
    312 
    313   // Look at the value of the integer being passed by reference.  Essentially
    314   // we want to catch cases where the value passed in is not equal to the
    315   // size of the type being created.
    316   SVal TheValueExpr = state->getSVal(CE->getArg(2), LCtx);
    317 
    318   // FIXME: Eventually we should handle arbitrary locations.  We can do this
    319   //  by having an enhanced memory model that does low-level typing.
    320   Optional<loc::MemRegionVal> LV = TheValueExpr.getAs<loc::MemRegionVal>();
    321   if (!LV)
    322     return;
    323 
    324   const TypedValueRegion* R = dyn_cast<TypedValueRegion>(LV->stripCasts());
    325   if (!R)
    326     return;
    327 
    328   QualType T = Ctx.getCanonicalType(R->getValueType());
    329 
    330   // FIXME: If the pointee isn't an integer type, should we flag a warning?
    331   //  People can do weird stuff with pointers.
    332 
    333   if (!T->isIntegerType())
    334     return;
    335 
    336   uint64_t SourceSize = Ctx.getTypeSize(T);
    337 
    338   // CHECK: is SourceSize == TargetSize
    339   if (SourceSize == TargetSize)
    340     return;
    341 
    342   // Generate an error.  Only generate a sink if 'SourceSize < TargetSize';
    343   // otherwise generate a regular node.
    344   //
    345   // FIXME: We can actually create an abstract "CFNumber" object that has
    346   //  the bits initialized to the provided values.
    347   //
    348   if (ExplodedNode *N = SourceSize < TargetSize ? C.generateSink()
    349                                                 : C.addTransition()) {
    350     SmallString<128> sbuf;
    351     llvm::raw_svector_ostream os(sbuf);
    352 
    353     os << (SourceSize == 8 ? "An " : "A ")
    354        << SourceSize << " bit integer is used to initialize a CFNumber "
    355                         "object that represents "
    356        << (TargetSize == 8 ? "an " : "a ")
    357        << TargetSize << " bit integer. ";
    358 
    359     if (SourceSize < TargetSize)
    360       os << (TargetSize - SourceSize)
    361       << " bits of the CFNumber value will be garbage." ;
    362     else
    363       os << (SourceSize - TargetSize)
    364       << " bits of the input integer will be lost.";
    365 
    366     if (!BT)
    367       BT.reset(new APIMisuse("Bad use of CFNumberCreate"));
    368 
    369     BugReport *report = new BugReport(*BT, os.str(), N);
    370     report->addRange(CE->getArg(2)->getSourceRange());
    371     C.emitReport(report);
    372   }
    373 }
    374 
    375 //===----------------------------------------------------------------------===//
    376 // CFRetain/CFRelease/CFMakeCollectable checking for null arguments.
    377 //===----------------------------------------------------------------------===//
    378 
    379 namespace {
    380 class CFRetainReleaseChecker : public Checker< check::PreStmt<CallExpr> > {
    381   mutable OwningPtr<APIMisuse> BT;
    382   mutable IdentifierInfo *Retain, *Release, *MakeCollectable;
    383 public:
    384   CFRetainReleaseChecker(): Retain(0), Release(0), MakeCollectable(0) {}
    385   void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
    386 };
    387 } // end anonymous namespace
    388 
    389 
    390 void CFRetainReleaseChecker::checkPreStmt(const CallExpr *CE,
    391                                           CheckerContext &C) const {
    392   // If the CallExpr doesn't have exactly 1 argument just give up checking.
    393   if (CE->getNumArgs() != 1)
    394     return;
    395 
    396   ProgramStateRef state = C.getState();
    397   const FunctionDecl *FD = C.getCalleeDecl(CE);
    398   if (!FD)
    399     return;
    400 
    401   if (!BT) {
    402     ASTContext &Ctx = C.getASTContext();
    403     Retain = &Ctx.Idents.get("CFRetain");
    404     Release = &Ctx.Idents.get("CFRelease");
    405     MakeCollectable = &Ctx.Idents.get("CFMakeCollectable");
    406     BT.reset(
    407       new APIMisuse("null passed to CFRetain/CFRelease/CFMakeCollectable"));
    408   }
    409 
    410   // Check if we called CFRetain/CFRelease/CFMakeCollectable.
    411   const IdentifierInfo *FuncII = FD->getIdentifier();
    412   if (!(FuncII == Retain || FuncII == Release || FuncII == MakeCollectable))
    413     return;
    414 
    415   // FIXME: The rest of this just checks that the argument is non-null.
    416   // It should probably be refactored and combined with NonNullParamChecker.
    417 
    418   // Get the argument's value.
    419   const Expr *Arg = CE->getArg(0);
    420   SVal ArgVal = state->getSVal(Arg, C.getLocationContext());
    421   Optional<DefinedSVal> DefArgVal = ArgVal.getAs<DefinedSVal>();
    422   if (!DefArgVal)
    423     return;
    424 
    425   // Get a NULL value.
    426   SValBuilder &svalBuilder = C.getSValBuilder();
    427   DefinedSVal zero =
    428       svalBuilder.makeZeroVal(Arg->getType()).castAs<DefinedSVal>();
    429 
    430   // Make an expression asserting that they're equal.
    431   DefinedOrUnknownSVal ArgIsNull = svalBuilder.evalEQ(state, zero, *DefArgVal);
    432 
    433   // Are they equal?
    434   ProgramStateRef stateTrue, stateFalse;
    435   llvm::tie(stateTrue, stateFalse) = state->assume(ArgIsNull);
    436 
    437   if (stateTrue && !stateFalse) {
    438     ExplodedNode *N = C.generateSink(stateTrue);
    439     if (!N)
    440       return;
    441 
    442     const char *description;
    443     if (FuncII == Retain)
    444       description = "Null pointer argument in call to CFRetain";
    445     else if (FuncII == Release)
    446       description = "Null pointer argument in call to CFRelease";
    447     else if (FuncII == MakeCollectable)
    448       description = "Null pointer argument in call to CFMakeCollectable";
    449     else
    450       llvm_unreachable("impossible case");
    451 
    452     BugReport *report = new BugReport(*BT, description, N);
    453     report->addRange(Arg->getSourceRange());
    454     bugreporter::trackNullOrUndefValue(N, Arg, *report);
    455     C.emitReport(report);
    456     return;
    457   }
    458 
    459   // From here on, we know the argument is non-null.
    460   C.addTransition(stateFalse);
    461 }
    462 
    463 //===----------------------------------------------------------------------===//
    464 // Check for sending 'retain', 'release', or 'autorelease' directly to a Class.
    465 //===----------------------------------------------------------------------===//
    466 
    467 namespace {
    468 class ClassReleaseChecker : public Checker<check::PreObjCMessage> {
    469   mutable Selector releaseS;
    470   mutable Selector retainS;
    471   mutable Selector autoreleaseS;
    472   mutable Selector drainS;
    473   mutable OwningPtr<BugType> BT;
    474 
    475 public:
    476   void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
    477 };
    478 }
    479 
    480 void ClassReleaseChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
    481                                               CheckerContext &C) const {
    482 
    483   if (!BT) {
    484     BT.reset(new APIMisuse("message incorrectly sent to class instead of class "
    485                            "instance"));
    486 
    487     ASTContext &Ctx = C.getASTContext();
    488     releaseS = GetNullarySelector("release", Ctx);
    489     retainS = GetNullarySelector("retain", Ctx);
    490     autoreleaseS = GetNullarySelector("autorelease", Ctx);
    491     drainS = GetNullarySelector("drain", Ctx);
    492   }
    493 
    494   if (msg.isInstanceMessage())
    495     return;
    496   const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
    497   assert(Class);
    498 
    499   Selector S = msg.getSelector();
    500   if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
    501     return;
    502 
    503   if (ExplodedNode *N = C.addTransition()) {
    504     SmallString<200> buf;
    505     llvm::raw_svector_ostream os(buf);
    506 
    507     os << "The '" << S.getAsString() << "' message should be sent to instances "
    508           "of class '" << Class->getName()
    509        << "' and not the class directly";
    510 
    511     BugReport *report = new BugReport(*BT, os.str(), N);
    512     report->addRange(msg.getSourceRange());
    513     C.emitReport(report);
    514   }
    515 }
    516 
    517 //===----------------------------------------------------------------------===//
    518 // Check for passing non-Objective-C types to variadic methods that expect
    519 // only Objective-C types.
    520 //===----------------------------------------------------------------------===//
    521 
    522 namespace {
    523 class VariadicMethodTypeChecker : public Checker<check::PreObjCMessage> {
    524   mutable Selector arrayWithObjectsS;
    525   mutable Selector dictionaryWithObjectsAndKeysS;
    526   mutable Selector setWithObjectsS;
    527   mutable Selector orderedSetWithObjectsS;
    528   mutable Selector initWithObjectsS;
    529   mutable Selector initWithObjectsAndKeysS;
    530   mutable OwningPtr<BugType> BT;
    531 
    532   bool isVariadicMessage(const ObjCMethodCall &msg) const;
    533 
    534 public:
    535   void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
    536 };
    537 }
    538 
    539 /// isVariadicMessage - Returns whether the given message is a variadic message,
    540 /// where all arguments must be Objective-C types.
    541 bool
    542 VariadicMethodTypeChecker::isVariadicMessage(const ObjCMethodCall &msg) const {
    543   const ObjCMethodDecl *MD = msg.getDecl();
    544 
    545   if (!MD || !MD->isVariadic() || isa<ObjCProtocolDecl>(MD->getDeclContext()))
    546     return false;
    547 
    548   Selector S = msg.getSelector();
    549 
    550   if (msg.isInstanceMessage()) {
    551     // FIXME: Ideally we'd look at the receiver interface here, but that's not
    552     // useful for init, because alloc returns 'id'. In theory, this could lead
    553     // to false positives, for example if there existed a class that had an
    554     // initWithObjects: implementation that does accept non-Objective-C pointer
    555     // types, but the chance of that happening is pretty small compared to the
    556     // gains that this analysis gives.
    557     const ObjCInterfaceDecl *Class = MD->getClassInterface();
    558 
    559     switch (findKnownClass(Class)) {
    560     case FC_NSArray:
    561     case FC_NSOrderedSet:
    562     case FC_NSSet:
    563       return S == initWithObjectsS;
    564     case FC_NSDictionary:
    565       return S == initWithObjectsAndKeysS;
    566     default:
    567       return false;
    568     }
    569   } else {
    570     const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
    571 
    572     switch (findKnownClass(Class)) {
    573       case FC_NSArray:
    574         return S == arrayWithObjectsS;
    575       case FC_NSOrderedSet:
    576         return S == orderedSetWithObjectsS;
    577       case FC_NSSet:
    578         return S == setWithObjectsS;
    579       case FC_NSDictionary:
    580         return S == dictionaryWithObjectsAndKeysS;
    581       default:
    582         return false;
    583     }
    584   }
    585 }
    586 
    587 void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
    588                                                     CheckerContext &C) const {
    589   if (!BT) {
    590     BT.reset(new APIMisuse("Arguments passed to variadic method aren't all "
    591                            "Objective-C pointer types"));
    592 
    593     ASTContext &Ctx = C.getASTContext();
    594     arrayWithObjectsS = GetUnarySelector("arrayWithObjects", Ctx);
    595     dictionaryWithObjectsAndKeysS =
    596       GetUnarySelector("dictionaryWithObjectsAndKeys", Ctx);
    597     setWithObjectsS = GetUnarySelector("setWithObjects", Ctx);
    598     orderedSetWithObjectsS = GetUnarySelector("orderedSetWithObjects", Ctx);
    599 
    600     initWithObjectsS = GetUnarySelector("initWithObjects", Ctx);
    601     initWithObjectsAndKeysS = GetUnarySelector("initWithObjectsAndKeys", Ctx);
    602   }
    603 
    604   if (!isVariadicMessage(msg))
    605       return;
    606 
    607   // We are not interested in the selector arguments since they have
    608   // well-defined types, so the compiler will issue a warning for them.
    609   unsigned variadicArgsBegin = msg.getSelector().getNumArgs();
    610 
    611   // We're not interested in the last argument since it has to be nil or the
    612   // compiler would have issued a warning for it elsewhere.
    613   unsigned variadicArgsEnd = msg.getNumArgs() - 1;
    614 
    615   if (variadicArgsEnd <= variadicArgsBegin)
    616     return;
    617 
    618   // Verify that all arguments have Objective-C types.
    619   Optional<ExplodedNode*> errorNode;
    620   ProgramStateRef state = C.getState();
    621 
    622   for (unsigned I = variadicArgsBegin; I != variadicArgsEnd; ++I) {
    623     QualType ArgTy = msg.getArgExpr(I)->getType();
    624     if (ArgTy->isObjCObjectPointerType())
    625       continue;
    626 
    627     // Block pointers are treaded as Objective-C pointers.
    628     if (ArgTy->isBlockPointerType())
    629       continue;
    630 
    631     // Ignore pointer constants.
    632     if (msg.getArgSVal(I).getAs<loc::ConcreteInt>())
    633       continue;
    634 
    635     // Ignore pointer types annotated with 'NSObject' attribute.
    636     if (C.getASTContext().isObjCNSObjectType(ArgTy))
    637       continue;
    638 
    639     // Ignore CF references, which can be toll-free bridged.
    640     if (coreFoundation::isCFObjectRef(ArgTy))
    641       continue;
    642 
    643     // Generate only one error node to use for all bug reports.
    644     if (!errorNode.hasValue())
    645       errorNode = C.addTransition();
    646 
    647     if (!errorNode.getValue())
    648       continue;
    649 
    650     SmallString<128> sbuf;
    651     llvm::raw_svector_ostream os(sbuf);
    652 
    653     StringRef TypeName = GetReceiverInterfaceName(msg);
    654     if (!TypeName.empty())
    655       os << "Argument to '" << TypeName << "' method '";
    656     else
    657       os << "Argument to method '";
    658 
    659     os << msg.getSelector().getAsString()
    660        << "' should be an Objective-C pointer type, not '";
    661     ArgTy.print(os, C.getLangOpts());
    662     os << "'";
    663 
    664     BugReport *R = new BugReport(*BT, os.str(), errorNode.getValue());
    665     R->addRange(msg.getArgSourceRange(I));
    666     C.emitReport(R);
    667   }
    668 }
    669 
    670 //===----------------------------------------------------------------------===//
    671 // Improves the modeling of loops over Cocoa collections.
    672 //===----------------------------------------------------------------------===//
    673 
    674 namespace {
    675 class ObjCLoopChecker
    676   : public Checker<check::PostStmt<ObjCForCollectionStmt> > {
    677 
    678 public:
    679   void checkPostStmt(const ObjCForCollectionStmt *FCS, CheckerContext &C) const;
    680 };
    681 }
    682 
    683 static bool isKnownNonNilCollectionType(QualType T) {
    684   const ObjCObjectPointerType *PT = T->getAs<ObjCObjectPointerType>();
    685   if (!PT)
    686     return false;
    687 
    688   const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();
    689   if (!ID)
    690     return false;
    691 
    692   switch (findKnownClass(ID)) {
    693   case FC_NSArray:
    694   case FC_NSDictionary:
    695   case FC_NSEnumerator:
    696   case FC_NSOrderedSet:
    697   case FC_NSSet:
    698     return true;
    699   default:
    700     return false;
    701   }
    702 }
    703 
    704 void ObjCLoopChecker::checkPostStmt(const ObjCForCollectionStmt *FCS,
    705                                     CheckerContext &C) const {
    706   ProgramStateRef State = C.getState();
    707 
    708   // Check if this is the branch for the end of the loop.
    709   SVal CollectionSentinel = State->getSVal(FCS, C.getLocationContext());
    710   if (CollectionSentinel.isZeroConstant())
    711     return;
    712 
    713   // See if the collection is one where we /know/ the elements are non-nil.
    714   const Expr *Collection = FCS->getCollection();
    715   if (!isKnownNonNilCollectionType(Collection->getType()))
    716     return;
    717 
    718   // FIXME: Copied from ExprEngineObjC.
    719   const Stmt *Element = FCS->getElement();
    720   SVal ElementVar;
    721   if (const DeclStmt *DS = dyn_cast<DeclStmt>(Element)) {
    722     const VarDecl *ElemDecl = cast<VarDecl>(DS->getSingleDecl());
    723     assert(ElemDecl->getInit() == 0);
    724     ElementVar = State->getLValue(ElemDecl, C.getLocationContext());
    725   } else {
    726     ElementVar = State->getSVal(Element, C.getLocationContext());
    727   }
    728 
    729   if (!ElementVar.getAs<Loc>())
    730     return;
    731 
    732   // Go ahead and assume the value is non-nil.
    733   SVal Val = State->getSVal(ElementVar.castAs<Loc>());
    734   State = State->assume(Val.castAs<DefinedOrUnknownSVal>(), true);
    735   C.addTransition(State);
    736 }
    737 
    738 namespace {
    739 /// \class ObjCNonNilReturnValueChecker
    740 /// \brief The checker restricts the return values of APIs known to
    741 /// never (or almost never) return 'nil'.
    742 class ObjCNonNilReturnValueChecker
    743   : public Checker<check::PostObjCMessage> {
    744     mutable bool Initialized;
    745     mutable Selector ObjectAtIndex;
    746     mutable Selector ObjectAtIndexedSubscript;
    747 
    748 public:
    749   ObjCNonNilReturnValueChecker() : Initialized(false) {}
    750   void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
    751 };
    752 }
    753 
    754 static ProgramStateRef assumeExprIsNonNull(const Expr *NonNullExpr,
    755                                            ProgramStateRef State,
    756                                            CheckerContext &C) {
    757   SVal Val = State->getSVal(NonNullExpr, C.getLocationContext());
    758   if (Optional<DefinedOrUnknownSVal> DV = Val.getAs<DefinedOrUnknownSVal>())
    759     return State->assume(*DV, true);
    760   return State;
    761 }
    762 
    763 void ObjCNonNilReturnValueChecker::checkPostObjCMessage(const ObjCMethodCall &M,
    764                                                         CheckerContext &C)
    765                                                         const {
    766   ProgramStateRef State = C.getState();
    767 
    768   if (!Initialized) {
    769     ASTContext &Ctx = C.getASTContext();
    770     ObjectAtIndex = GetUnarySelector("objectAtIndex", Ctx);
    771     ObjectAtIndexedSubscript = GetUnarySelector("objectAtIndexedSubscript", Ctx);
    772   }
    773 
    774   // Check the receiver type.
    775   if (const ObjCInterfaceDecl *Interface = M.getReceiverInterface()) {
    776 
    777     // Assume that object returned from '[self init]' or '[super init]' is not
    778     // 'nil' if we are processing an inlined function/method.
    779     //
    780     // A defensive callee will (and should) check if the object returned by
    781     // '[super init]' is 'nil' before doing it's own initialization. However,
    782     // since 'nil' is rarely returned in practice, we should not warn when the
    783     // caller to the defensive constructor uses the object in contexts where
    784     // 'nil' is not accepted.
    785     if (!C.inTopFrame() && M.getDecl() &&
    786         M.getDecl()->getMethodFamily() == OMF_init &&
    787         M.isReceiverSelfOrSuper()) {
    788       State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
    789     }
    790 
    791     // Objects returned from
    792     // [NSArray|NSOrderedSet]::[ObjectAtIndex|ObjectAtIndexedSubscript]
    793     // are never 'nil'.
    794     FoundationClass Cl = findKnownClass(Interface);
    795     if (Cl == FC_NSArray || Cl == FC_NSOrderedSet) {
    796       Selector Sel = M.getSelector();
    797       if (Sel == ObjectAtIndex || Sel == ObjectAtIndexedSubscript) {
    798         // Go ahead and assume the value is non-nil.
    799         State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
    800       }
    801     }
    802   }
    803   C.addTransition(State);
    804 }
    805 
    806 //===----------------------------------------------------------------------===//
    807 // Check registration.
    808 //===----------------------------------------------------------------------===//
    809 
    810 void ento::registerNilArgChecker(CheckerManager &mgr) {
    811   mgr.registerChecker<NilArgChecker>();
    812 }
    813 
    814 void ento::registerCFNumberCreateChecker(CheckerManager &mgr) {
    815   mgr.registerChecker<CFNumberCreateChecker>();
    816 }
    817 
    818 void ento::registerCFRetainReleaseChecker(CheckerManager &mgr) {
    819   mgr.registerChecker<CFRetainReleaseChecker>();
    820 }
    821 
    822 void ento::registerClassReleaseChecker(CheckerManager &mgr) {
    823   mgr.registerChecker<ClassReleaseChecker>();
    824 }
    825 
    826 void ento::registerVariadicMethodTypeChecker(CheckerManager &mgr) {
    827   mgr.registerChecker<VariadicMethodTypeChecker>();
    828 }
    829 
    830 void ento::registerObjCLoopChecker(CheckerManager &mgr) {
    831   mgr.registerChecker<ObjCLoopChecker>();
    832 }
    833 
    834 void ento::registerObjCNonNilReturnValueChecker(CheckerManager &mgr) {
    835   mgr.registerChecker<ObjCNonNilReturnValueChecker>();
    836 }
    837