clang API Documentation

BasicObjCFoundationChecks.cpp
Go to the documentation of this file.
00001 //== BasicObjCFoundationChecks.cpp - Simple Apple-Foundation checks -*- C++ -*--
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 //  This file defines BasicObjCFoundationChecks, a class that encapsulates
00011 //  a set of simple checks to run on Objective-C code using Apple's Foundation
00012 //  classes.
00013 //
00014 //===----------------------------------------------------------------------===//
00015 
00016 #include "ClangSACheckers.h"
00017 #include "SelectorExtras.h"
00018 #include "clang/AST/ASTContext.h"
00019 #include "clang/AST/DeclObjC.h"
00020 #include "clang/AST/Expr.h"
00021 #include "clang/AST/ExprObjC.h"
00022 #include "clang/AST/StmtObjC.h"
00023 #include "clang/Analysis/DomainSpecific/CocoaConventions.h"
00024 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
00025 #include "clang/StaticAnalyzer/Core/Checker.h"
00026 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
00027 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
00028 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
00029 #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
00030 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
00031 #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
00032 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
00033 #include "llvm/ADT/SmallString.h"
00034 #include "llvm/ADT/StringMap.h"
00035 #include "llvm/Support/raw_ostream.h"
00036 
00037 using namespace clang;
00038 using namespace ento;
00039 
00040 namespace {
00041 class APIMisuse : public BugType {
00042 public:
00043   APIMisuse(const CheckerBase *checker, const char *name)
00044       : BugType(checker, name, "API Misuse (Apple)") {}
00045 };
00046 } // end anonymous namespace
00047 
00048 //===----------------------------------------------------------------------===//
00049 // Utility functions.
00050 //===----------------------------------------------------------------------===//
00051 
00052 static StringRef GetReceiverInterfaceName(const ObjCMethodCall &msg) {
00053   if (const ObjCInterfaceDecl *ID = msg.getReceiverInterface())
00054     return ID->getIdentifier()->getName();
00055   return StringRef();
00056 }
00057 
00058 enum FoundationClass {
00059   FC_None,
00060   FC_NSArray,
00061   FC_NSDictionary,
00062   FC_NSEnumerator,
00063   FC_NSNull,
00064   FC_NSOrderedSet,
00065   FC_NSSet,
00066   FC_NSString
00067 };
00068 
00069 static FoundationClass findKnownClass(const ObjCInterfaceDecl *ID,
00070                                       bool IncludeSuperclasses = true) {
00071   static llvm::StringMap<FoundationClass> Classes;
00072   if (Classes.empty()) {
00073     Classes["NSArray"] = FC_NSArray;
00074     Classes["NSDictionary"] = FC_NSDictionary;
00075     Classes["NSEnumerator"] = FC_NSEnumerator;
00076     Classes["NSNull"] = FC_NSNull;
00077     Classes["NSOrderedSet"] = FC_NSOrderedSet;
00078     Classes["NSSet"] = FC_NSSet;
00079     Classes["NSString"] = FC_NSString;
00080   }
00081 
00082   // FIXME: Should we cache this at all?
00083   FoundationClass result = Classes.lookup(ID->getIdentifier()->getName());
00084   if (result == FC_None && IncludeSuperclasses)
00085     if (const ObjCInterfaceDecl *Super = ID->getSuperClass())
00086       return findKnownClass(Super);
00087 
00088   return result;
00089 }
00090 
00091 //===----------------------------------------------------------------------===//
00092 // NilArgChecker - Check for prohibited nil arguments to ObjC method calls.
00093 //===----------------------------------------------------------------------===//
00094 
00095 namespace {
00096   class NilArgChecker : public Checker<check::PreObjCMessage,
00097                                        check::PostStmt<ObjCDictionaryLiteral>,
00098                                        check::PostStmt<ObjCArrayLiteral> > {
00099     mutable std::unique_ptr<APIMisuse> BT;
00100 
00101     mutable llvm::SmallDenseMap<Selector, unsigned, 16> StringSelectors;
00102     mutable Selector ArrayWithObjectSel;
00103     mutable Selector AddObjectSel;
00104     mutable Selector InsertObjectAtIndexSel;
00105     mutable Selector ReplaceObjectAtIndexWithObjectSel;
00106     mutable Selector SetObjectAtIndexedSubscriptSel;
00107     mutable Selector ArrayByAddingObjectSel;
00108     mutable Selector DictionaryWithObjectForKeySel;
00109     mutable Selector SetObjectForKeySel;
00110     mutable Selector SetObjectForKeyedSubscriptSel;
00111     mutable Selector RemoveObjectForKeySel;
00112 
00113     void warnIfNilExpr(const Expr *E,
00114                        const char *Msg,
00115                        CheckerContext &C) const;
00116 
00117     void warnIfNilArg(CheckerContext &C,
00118                       const ObjCMethodCall &msg, unsigned Arg,
00119                       FoundationClass Class,
00120                       bool CanBeSubscript = false) const;
00121 
00122     void generateBugReport(ExplodedNode *N,
00123                            StringRef Msg,
00124                            SourceRange Range,
00125                            const Expr *Expr,
00126                            CheckerContext &C) const;
00127 
00128   public:
00129     void checkPreObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
00130     void checkPostStmt(const ObjCDictionaryLiteral *DL,
00131                        CheckerContext &C) const;
00132     void checkPostStmt(const ObjCArrayLiteral *AL,
00133                        CheckerContext &C) const;
00134   };
00135 }
00136 
00137 void NilArgChecker::warnIfNilExpr(const Expr *E,
00138                                   const char *Msg,
00139                                   CheckerContext &C) const {
00140   ProgramStateRef State = C.getState();
00141   if (State->isNull(C.getSVal(E)).isConstrainedTrue()) {
00142 
00143     if (ExplodedNode *N = C.generateSink()) {
00144       generateBugReport(N, Msg, E->getSourceRange(), E, C);
00145     }
00146     
00147   }
00148 }
00149 
00150 void NilArgChecker::warnIfNilArg(CheckerContext &C,
00151                                  const ObjCMethodCall &msg,
00152                                  unsigned int Arg,
00153                                  FoundationClass Class,
00154                                  bool CanBeSubscript) const {
00155   // Check if the argument is nil.
00156   ProgramStateRef State = C.getState();
00157   if (!State->isNull(msg.getArgSVal(Arg)).isConstrainedTrue())
00158       return;
00159       
00160   if (ExplodedNode *N = C.generateSink()) {
00161     SmallString<128> sbuf;
00162     llvm::raw_svector_ostream os(sbuf);
00163 
00164     if (CanBeSubscript && msg.getMessageKind() == OCM_Subscript) {
00165 
00166       if (Class == FC_NSArray) {
00167         os << "Array element cannot be nil";
00168       } else if (Class == FC_NSDictionary) {
00169         if (Arg == 0) {
00170           os << "Value stored into '";
00171           os << GetReceiverInterfaceName(msg) << "' cannot be nil";
00172         } else {
00173           assert(Arg == 1);
00174           os << "'"<< GetReceiverInterfaceName(msg) << "' key cannot be nil";
00175         }
00176       } else
00177         llvm_unreachable("Missing foundation class for the subscript expr");
00178 
00179     } else {
00180       if (Class == FC_NSDictionary) {
00181         if (Arg == 0)
00182           os << "Value argument ";
00183         else {
00184           assert(Arg == 1);
00185           os << "Key argument ";
00186         }
00187         os << "to '";
00188         msg.getSelector().print(os);
00189         os << "' cannot be nil";
00190       } else {
00191         os << "Argument to '" << GetReceiverInterfaceName(msg) << "' method '";
00192         msg.getSelector().print(os);
00193         os << "' cannot be nil";
00194       }
00195     }
00196     
00197     generateBugReport(N, os.str(), msg.getArgSourceRange(Arg),
00198                       msg.getArgExpr(Arg), C);
00199   }
00200 }
00201 
00202 void NilArgChecker::generateBugReport(ExplodedNode *N,
00203                                       StringRef Msg,
00204                                       SourceRange Range,
00205                                       const Expr *E,
00206                                       CheckerContext &C) const {
00207   if (!BT)
00208     BT.reset(new APIMisuse(this, "nil argument"));
00209 
00210   BugReport *R = new BugReport(*BT, Msg, N);
00211   R->addRange(Range);
00212   bugreporter::trackNullOrUndefValue(N, E, *R);
00213   C.emitReport(R);
00214 }
00215 
00216 void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
00217                                         CheckerContext &C) const {
00218   const ObjCInterfaceDecl *ID = msg.getReceiverInterface();
00219   if (!ID)
00220     return;
00221 
00222   FoundationClass Class = findKnownClass(ID);
00223 
00224   static const unsigned InvalidArgIndex = UINT_MAX;
00225   unsigned Arg = InvalidArgIndex;
00226   bool CanBeSubscript = false;
00227   
00228   if (Class == FC_NSString) {
00229     Selector S = msg.getSelector();
00230 
00231     if (S.isUnarySelector())
00232       return;
00233 
00234     if (StringSelectors.empty()) {
00235       ASTContext &Ctx = C.getASTContext();
00236       Selector Sels[] = {
00237         getKeywordSelector(Ctx, "caseInsensitiveCompare", nullptr),
00238         getKeywordSelector(Ctx, "compare", nullptr),
00239         getKeywordSelector(Ctx, "compare", "options", nullptr),
00240         getKeywordSelector(Ctx, "compare", "options", "range", nullptr),
00241         getKeywordSelector(Ctx, "compare", "options", "range", "locale",
00242                            nullptr),
00243         getKeywordSelector(Ctx, "componentsSeparatedByCharactersInSet",
00244                            nullptr),
00245         getKeywordSelector(Ctx, "initWithFormat",
00246                            nullptr),
00247         getKeywordSelector(Ctx, "localizedCaseInsensitiveCompare", nullptr),
00248         getKeywordSelector(Ctx, "localizedCompare", nullptr),
00249         getKeywordSelector(Ctx, "localizedStandardCompare", nullptr),
00250       };
00251       for (Selector KnownSel : Sels)
00252         StringSelectors[KnownSel] = 0;
00253     }
00254     auto I = StringSelectors.find(S);
00255     if (I == StringSelectors.end())
00256       return;
00257     Arg = I->second;
00258   } else if (Class == FC_NSArray) {
00259     Selector S = msg.getSelector();
00260 
00261     if (S.isUnarySelector())
00262       return;
00263 
00264     if (ArrayWithObjectSel.isNull()) {
00265       ASTContext &Ctx = C.getASTContext();
00266       ArrayWithObjectSel = getKeywordSelector(Ctx, "arrayWithObject", nullptr);
00267       AddObjectSel = getKeywordSelector(Ctx, "addObject", nullptr);
00268       InsertObjectAtIndexSel =
00269         getKeywordSelector(Ctx, "insertObject", "atIndex", nullptr);
00270       ReplaceObjectAtIndexWithObjectSel =
00271         getKeywordSelector(Ctx, "replaceObjectAtIndex", "withObject", nullptr);
00272       SetObjectAtIndexedSubscriptSel =
00273         getKeywordSelector(Ctx, "setObject", "atIndexedSubscript", nullptr);
00274       ArrayByAddingObjectSel =
00275         getKeywordSelector(Ctx, "arrayByAddingObject", nullptr);
00276     }
00277 
00278     if (S == ArrayWithObjectSel || S == AddObjectSel ||
00279         S == InsertObjectAtIndexSel || S == ArrayByAddingObjectSel) {
00280       Arg = 0;
00281     } else if (S == SetObjectAtIndexedSubscriptSel) {
00282       Arg = 0;
00283       CanBeSubscript = true;
00284     } else if (S == ReplaceObjectAtIndexWithObjectSel) {
00285       Arg = 1;
00286     }
00287   } else if (Class == FC_NSDictionary) {
00288     Selector S = msg.getSelector();
00289 
00290     if (S.isUnarySelector())
00291       return;
00292 
00293     if (DictionaryWithObjectForKeySel.isNull()) {
00294       ASTContext &Ctx = C.getASTContext();
00295       DictionaryWithObjectForKeySel =
00296         getKeywordSelector(Ctx, "dictionaryWithObject", "forKey", nullptr);
00297       SetObjectForKeySel =
00298         getKeywordSelector(Ctx, "setObject", "forKey", nullptr);
00299       SetObjectForKeyedSubscriptSel =
00300         getKeywordSelector(Ctx, "setObject", "forKeyedSubscript", nullptr);
00301       RemoveObjectForKeySel =
00302         getKeywordSelector(Ctx, "removeObjectForKey", nullptr);
00303     }
00304 
00305     if (S == DictionaryWithObjectForKeySel || S == SetObjectForKeySel) {
00306       Arg = 0;
00307       warnIfNilArg(C, msg, /* Arg */1, Class);
00308     } else if (S == SetObjectForKeyedSubscriptSel) {
00309       CanBeSubscript = true;
00310       Arg = 0;
00311       warnIfNilArg(C, msg, /* Arg */1, Class, CanBeSubscript);
00312     } else if (S == RemoveObjectForKeySel) {
00313       Arg = 0;
00314     }
00315   }
00316 
00317   // If argument is '0', report a warning.
00318   if ((Arg != InvalidArgIndex))
00319     warnIfNilArg(C, msg, Arg, Class, CanBeSubscript);
00320 }
00321 
00322 void NilArgChecker::checkPostStmt(const ObjCArrayLiteral *AL,
00323                                   CheckerContext &C) const {
00324   unsigned NumOfElements = AL->getNumElements();
00325   for (unsigned i = 0; i < NumOfElements; ++i) {
00326     warnIfNilExpr(AL->getElement(i), "Array element cannot be nil", C);
00327   }
00328 }
00329 
00330 void NilArgChecker::checkPostStmt(const ObjCDictionaryLiteral *DL,
00331                                   CheckerContext &C) const {
00332   unsigned NumOfElements = DL->getNumElements();
00333   for (unsigned i = 0; i < NumOfElements; ++i) {
00334     ObjCDictionaryElement Element = DL->getKeyValueElement(i);
00335     warnIfNilExpr(Element.Key, "Dictionary key cannot be nil", C);
00336     warnIfNilExpr(Element.Value, "Dictionary value cannot be nil", C);
00337   }
00338 }
00339 
00340 //===----------------------------------------------------------------------===//
00341 // Error reporting.
00342 //===----------------------------------------------------------------------===//
00343 
00344 namespace {
00345 class CFNumberCreateChecker : public Checker< check::PreStmt<CallExpr> > {
00346   mutable std::unique_ptr<APIMisuse> BT;
00347   mutable IdentifierInfo* II;
00348 public:
00349   CFNumberCreateChecker() : II(nullptr) {}
00350 
00351   void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
00352 
00353 private:
00354   void EmitError(const TypedRegion* R, const Expr *Ex,
00355                 uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind);
00356 };
00357 } // end anonymous namespace
00358 
00359 enum CFNumberType {
00360   kCFNumberSInt8Type = 1,
00361   kCFNumberSInt16Type = 2,
00362   kCFNumberSInt32Type = 3,
00363   kCFNumberSInt64Type = 4,
00364   kCFNumberFloat32Type = 5,
00365   kCFNumberFloat64Type = 6,
00366   kCFNumberCharType = 7,
00367   kCFNumberShortType = 8,
00368   kCFNumberIntType = 9,
00369   kCFNumberLongType = 10,
00370   kCFNumberLongLongType = 11,
00371   kCFNumberFloatType = 12,
00372   kCFNumberDoubleType = 13,
00373   kCFNumberCFIndexType = 14,
00374   kCFNumberNSIntegerType = 15,
00375   kCFNumberCGFloatType = 16
00376 };
00377 
00378 static Optional<uint64_t> GetCFNumberSize(ASTContext &Ctx, uint64_t i) {
00379   static const unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 };
00380 
00381   if (i < kCFNumberCharType)
00382     return FixedSize[i-1];
00383 
00384   QualType T;
00385 
00386   switch (i) {
00387     case kCFNumberCharType:     T = Ctx.CharTy;     break;
00388     case kCFNumberShortType:    T = Ctx.ShortTy;    break;
00389     case kCFNumberIntType:      T = Ctx.IntTy;      break;
00390     case kCFNumberLongType:     T = Ctx.LongTy;     break;
00391     case kCFNumberLongLongType: T = Ctx.LongLongTy; break;
00392     case kCFNumberFloatType:    T = Ctx.FloatTy;    break;
00393     case kCFNumberDoubleType:   T = Ctx.DoubleTy;   break;
00394     case kCFNumberCFIndexType:
00395     case kCFNumberNSIntegerType:
00396     case kCFNumberCGFloatType:
00397       // FIXME: We need a way to map from names to Type*.
00398     default:
00399       return None;
00400   }
00401 
00402   return Ctx.getTypeSize(T);
00403 }
00404 
00405 #if 0
00406 static const char* GetCFNumberTypeStr(uint64_t i) {
00407   static const char* Names[] = {
00408     "kCFNumberSInt8Type",
00409     "kCFNumberSInt16Type",
00410     "kCFNumberSInt32Type",
00411     "kCFNumberSInt64Type",
00412     "kCFNumberFloat32Type",
00413     "kCFNumberFloat64Type",
00414     "kCFNumberCharType",
00415     "kCFNumberShortType",
00416     "kCFNumberIntType",
00417     "kCFNumberLongType",
00418     "kCFNumberLongLongType",
00419     "kCFNumberFloatType",
00420     "kCFNumberDoubleType",
00421     "kCFNumberCFIndexType",
00422     "kCFNumberNSIntegerType",
00423     "kCFNumberCGFloatType"
00424   };
00425 
00426   return i <= kCFNumberCGFloatType ? Names[i-1] : "Invalid CFNumberType";
00427 }
00428 #endif
00429 
00430 void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE,
00431                                          CheckerContext &C) const {
00432   ProgramStateRef state = C.getState();
00433   const FunctionDecl *FD = C.getCalleeDecl(CE);
00434   if (!FD)
00435     return;
00436   
00437   ASTContext &Ctx = C.getASTContext();
00438   if (!II)
00439     II = &Ctx.Idents.get("CFNumberCreate");
00440 
00441   if (FD->getIdentifier() != II || CE->getNumArgs() != 3)
00442     return;
00443 
00444   // Get the value of the "theType" argument.
00445   const LocationContext *LCtx = C.getLocationContext();
00446   SVal TheTypeVal = state->getSVal(CE->getArg(1), LCtx);
00447 
00448   // FIXME: We really should allow ranges of valid theType values, and
00449   //   bifurcate the state appropriately.
00450   Optional<nonloc::ConcreteInt> V = TheTypeVal.getAs<nonloc::ConcreteInt>();
00451   if (!V)
00452     return;
00453 
00454   uint64_t NumberKind = V->getValue().getLimitedValue();
00455   Optional<uint64_t> OptTargetSize = GetCFNumberSize(Ctx, NumberKind);
00456 
00457   // FIXME: In some cases we can emit an error.
00458   if (!OptTargetSize)
00459     return;
00460 
00461   uint64_t TargetSize = *OptTargetSize;
00462 
00463   // Look at the value of the integer being passed by reference.  Essentially
00464   // we want to catch cases where the value passed in is not equal to the
00465   // size of the type being created.
00466   SVal TheValueExpr = state->getSVal(CE->getArg(2), LCtx);
00467 
00468   // FIXME: Eventually we should handle arbitrary locations.  We can do this
00469   //  by having an enhanced memory model that does low-level typing.
00470   Optional<loc::MemRegionVal> LV = TheValueExpr.getAs<loc::MemRegionVal>();
00471   if (!LV)
00472     return;
00473 
00474   const TypedValueRegion* R = dyn_cast<TypedValueRegion>(LV->stripCasts());
00475   if (!R)
00476     return;
00477 
00478   QualType T = Ctx.getCanonicalType(R->getValueType());
00479 
00480   // FIXME: If the pointee isn't an integer type, should we flag a warning?
00481   //  People can do weird stuff with pointers.
00482 
00483   if (!T->isIntegralOrEnumerationType())
00484     return;
00485 
00486   uint64_t SourceSize = Ctx.getTypeSize(T);
00487 
00488   // CHECK: is SourceSize == TargetSize
00489   if (SourceSize == TargetSize)
00490     return;
00491 
00492   // Generate an error.  Only generate a sink if 'SourceSize < TargetSize';
00493   // otherwise generate a regular node.
00494   //
00495   // FIXME: We can actually create an abstract "CFNumber" object that has
00496   //  the bits initialized to the provided values.
00497   //
00498   if (ExplodedNode *N = SourceSize < TargetSize ? C.generateSink() 
00499                                                 : C.addTransition()) {
00500     SmallString<128> sbuf;
00501     llvm::raw_svector_ostream os(sbuf);
00502     
00503     os << (SourceSize == 8 ? "An " : "A ")
00504        << SourceSize << " bit integer is used to initialize a CFNumber "
00505                         "object that represents "
00506        << (TargetSize == 8 ? "an " : "a ")
00507        << TargetSize << " bit integer. ";
00508     
00509     if (SourceSize < TargetSize)
00510       os << (TargetSize - SourceSize)
00511       << " bits of the CFNumber value will be garbage." ;
00512     else
00513       os << (SourceSize - TargetSize)
00514       << " bits of the input integer will be lost.";
00515 
00516     if (!BT)
00517       BT.reset(new APIMisuse(this, "Bad use of CFNumberCreate"));
00518 
00519     BugReport *report = new BugReport(*BT, os.str(), N);
00520     report->addRange(CE->getArg(2)->getSourceRange());
00521     C.emitReport(report);
00522   }
00523 }
00524 
00525 //===----------------------------------------------------------------------===//
00526 // CFRetain/CFRelease/CFMakeCollectable/CFAutorelease checking for null arguments.
00527 //===----------------------------------------------------------------------===//
00528 
00529 namespace {
00530 class CFRetainReleaseChecker : public Checker< check::PreStmt<CallExpr> > {
00531   mutable std::unique_ptr<APIMisuse> BT;
00532   mutable IdentifierInfo *Retain, *Release, *MakeCollectable, *Autorelease;
00533 public:
00534   CFRetainReleaseChecker()
00535       : Retain(nullptr), Release(nullptr), MakeCollectable(nullptr),
00536         Autorelease(nullptr) {}
00537   void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
00538 };
00539 } // end anonymous namespace
00540 
00541 
00542 void CFRetainReleaseChecker::checkPreStmt(const CallExpr *CE,
00543                                           CheckerContext &C) const {
00544   // If the CallExpr doesn't have exactly 1 argument just give up checking.
00545   if (CE->getNumArgs() != 1)
00546     return;
00547 
00548   ProgramStateRef state = C.getState();
00549   const FunctionDecl *FD = C.getCalleeDecl(CE);
00550   if (!FD)
00551     return;
00552   
00553   if (!BT) {
00554     ASTContext &Ctx = C.getASTContext();
00555     Retain = &Ctx.Idents.get("CFRetain");
00556     Release = &Ctx.Idents.get("CFRelease");
00557     MakeCollectable = &Ctx.Idents.get("CFMakeCollectable");
00558     Autorelease = &Ctx.Idents.get("CFAutorelease");
00559     BT.reset(new APIMisuse(
00560         this, "null passed to CF memory management function"));
00561   }
00562 
00563   // Check if we called CFRetain/CFRelease/CFMakeCollectable/CFAutorelease.
00564   const IdentifierInfo *FuncII = FD->getIdentifier();
00565   if (!(FuncII == Retain || FuncII == Release || FuncII == MakeCollectable ||
00566         FuncII == Autorelease))
00567     return;
00568 
00569   // FIXME: The rest of this just checks that the argument is non-null.
00570   // It should probably be refactored and combined with NonNullParamChecker.
00571 
00572   // Get the argument's value.
00573   const Expr *Arg = CE->getArg(0);
00574   SVal ArgVal = state->getSVal(Arg, C.getLocationContext());
00575   Optional<DefinedSVal> DefArgVal = ArgVal.getAs<DefinedSVal>();
00576   if (!DefArgVal)
00577     return;
00578 
00579   // Get a NULL value.
00580   SValBuilder &svalBuilder = C.getSValBuilder();
00581   DefinedSVal zero =
00582       svalBuilder.makeZeroVal(Arg->getType()).castAs<DefinedSVal>();
00583 
00584   // Make an expression asserting that they're equal.
00585   DefinedOrUnknownSVal ArgIsNull = svalBuilder.evalEQ(state, zero, *DefArgVal);
00586 
00587   // Are they equal?
00588   ProgramStateRef stateTrue, stateFalse;
00589   std::tie(stateTrue, stateFalse) = state->assume(ArgIsNull);
00590 
00591   if (stateTrue && !stateFalse) {
00592     ExplodedNode *N = C.generateSink(stateTrue);
00593     if (!N)
00594       return;
00595 
00596     const char *description;
00597     if (FuncII == Retain)
00598       description = "Null pointer argument in call to CFRetain";
00599     else if (FuncII == Release)
00600       description = "Null pointer argument in call to CFRelease";
00601     else if (FuncII == MakeCollectable)
00602       description = "Null pointer argument in call to CFMakeCollectable";
00603     else if (FuncII == Autorelease)
00604       description = "Null pointer argument in call to CFAutorelease";
00605     else
00606       llvm_unreachable("impossible case");
00607 
00608     BugReport *report = new BugReport(*BT, description, N);
00609     report->addRange(Arg->getSourceRange());
00610     bugreporter::trackNullOrUndefValue(N, Arg, *report);
00611     C.emitReport(report);
00612     return;
00613   }
00614 
00615   // From here on, we know the argument is non-null.
00616   C.addTransition(stateFalse);
00617 }
00618 
00619 //===----------------------------------------------------------------------===//
00620 // Check for sending 'retain', 'release', or 'autorelease' directly to a Class.
00621 //===----------------------------------------------------------------------===//
00622 
00623 namespace {
00624 class ClassReleaseChecker : public Checker<check::PreObjCMessage> {
00625   mutable Selector releaseS;
00626   mutable Selector retainS;
00627   mutable Selector autoreleaseS;
00628   mutable Selector drainS;
00629   mutable std::unique_ptr<BugType> BT;
00630 
00631 public:
00632   void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
00633 };
00634 }
00635 
00636 void ClassReleaseChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
00637                                               CheckerContext &C) const {
00638   
00639   if (!BT) {
00640     BT.reset(new APIMisuse(
00641         this, "message incorrectly sent to class instead of class instance"));
00642 
00643     ASTContext &Ctx = C.getASTContext();
00644     releaseS = GetNullarySelector("release", Ctx);
00645     retainS = GetNullarySelector("retain", Ctx);
00646     autoreleaseS = GetNullarySelector("autorelease", Ctx);
00647     drainS = GetNullarySelector("drain", Ctx);
00648   }
00649   
00650   if (msg.isInstanceMessage())
00651     return;
00652   const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
00653   assert(Class);
00654 
00655   Selector S = msg.getSelector();
00656   if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
00657     return;
00658   
00659   if (ExplodedNode *N = C.addTransition()) {
00660     SmallString<200> buf;
00661     llvm::raw_svector_ostream os(buf);
00662 
00663     os << "The '";
00664     S.print(os);
00665     os << "' message should be sent to instances "
00666           "of class '" << Class->getName()
00667        << "' and not the class directly";
00668   
00669     BugReport *report = new BugReport(*BT, os.str(), N);
00670     report->addRange(msg.getSourceRange());
00671     C.emitReport(report);
00672   }
00673 }
00674 
00675 //===----------------------------------------------------------------------===//
00676 // Check for passing non-Objective-C types to variadic methods that expect
00677 // only Objective-C types.
00678 //===----------------------------------------------------------------------===//
00679 
00680 namespace {
00681 class VariadicMethodTypeChecker : public Checker<check::PreObjCMessage> {
00682   mutable Selector arrayWithObjectsS;
00683   mutable Selector dictionaryWithObjectsAndKeysS;
00684   mutable Selector setWithObjectsS;
00685   mutable Selector orderedSetWithObjectsS;
00686   mutable Selector initWithObjectsS;
00687   mutable Selector initWithObjectsAndKeysS;
00688   mutable std::unique_ptr<BugType> BT;
00689 
00690   bool isVariadicMessage(const ObjCMethodCall &msg) const;
00691 
00692 public:
00693   void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
00694 };
00695 }
00696 
00697 /// isVariadicMessage - Returns whether the given message is a variadic message,
00698 /// where all arguments must be Objective-C types.
00699 bool
00700 VariadicMethodTypeChecker::isVariadicMessage(const ObjCMethodCall &msg) const {
00701   const ObjCMethodDecl *MD = msg.getDecl();
00702   
00703   if (!MD || !MD->isVariadic() || isa<ObjCProtocolDecl>(MD->getDeclContext()))
00704     return false;
00705   
00706   Selector S = msg.getSelector();
00707   
00708   if (msg.isInstanceMessage()) {
00709     // FIXME: Ideally we'd look at the receiver interface here, but that's not
00710     // useful for init, because alloc returns 'id'. In theory, this could lead
00711     // to false positives, for example if there existed a class that had an
00712     // initWithObjects: implementation that does accept non-Objective-C pointer
00713     // types, but the chance of that happening is pretty small compared to the
00714     // gains that this analysis gives.
00715     const ObjCInterfaceDecl *Class = MD->getClassInterface();
00716 
00717     switch (findKnownClass(Class)) {
00718     case FC_NSArray:
00719     case FC_NSOrderedSet:
00720     case FC_NSSet:
00721       return S == initWithObjectsS;
00722     case FC_NSDictionary:
00723       return S == initWithObjectsAndKeysS;
00724     default:
00725       return false;
00726     }
00727   } else {
00728     const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
00729 
00730     switch (findKnownClass(Class)) {
00731       case FC_NSArray:
00732         return S == arrayWithObjectsS;
00733       case FC_NSOrderedSet:
00734         return S == orderedSetWithObjectsS;
00735       case FC_NSSet:
00736         return S == setWithObjectsS;
00737       case FC_NSDictionary:
00738         return S == dictionaryWithObjectsAndKeysS;
00739       default:
00740         return false;
00741     }
00742   }
00743 }
00744 
00745 void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
00746                                                     CheckerContext &C) const {
00747   if (!BT) {
00748     BT.reset(new APIMisuse(this,
00749                            "Arguments passed to variadic method aren't all "
00750                            "Objective-C pointer types"));
00751 
00752     ASTContext &Ctx = C.getASTContext();
00753     arrayWithObjectsS = GetUnarySelector("arrayWithObjects", Ctx);
00754     dictionaryWithObjectsAndKeysS = 
00755       GetUnarySelector("dictionaryWithObjectsAndKeys", Ctx);
00756     setWithObjectsS = GetUnarySelector("setWithObjects", Ctx);
00757     orderedSetWithObjectsS = GetUnarySelector("orderedSetWithObjects", Ctx);
00758 
00759     initWithObjectsS = GetUnarySelector("initWithObjects", Ctx);
00760     initWithObjectsAndKeysS = GetUnarySelector("initWithObjectsAndKeys", Ctx);
00761   }
00762 
00763   if (!isVariadicMessage(msg))
00764       return;
00765 
00766   // We are not interested in the selector arguments since they have
00767   // well-defined types, so the compiler will issue a warning for them.
00768   unsigned variadicArgsBegin = msg.getSelector().getNumArgs();
00769 
00770   // We're not interested in the last argument since it has to be nil or the
00771   // compiler would have issued a warning for it elsewhere.
00772   unsigned variadicArgsEnd = msg.getNumArgs() - 1;
00773 
00774   if (variadicArgsEnd <= variadicArgsBegin)
00775     return;
00776 
00777   // Verify that all arguments have Objective-C types.
00778   Optional<ExplodedNode*> errorNode;
00779 
00780   for (unsigned I = variadicArgsBegin; I != variadicArgsEnd; ++I) {
00781     QualType ArgTy = msg.getArgExpr(I)->getType();
00782     if (ArgTy->isObjCObjectPointerType())
00783       continue;
00784 
00785     // Block pointers are treaded as Objective-C pointers.
00786     if (ArgTy->isBlockPointerType())
00787       continue;
00788 
00789     // Ignore pointer constants.
00790     if (msg.getArgSVal(I).getAs<loc::ConcreteInt>())
00791       continue;
00792     
00793     // Ignore pointer types annotated with 'NSObject' attribute.
00794     if (C.getASTContext().isObjCNSObjectType(ArgTy))
00795       continue;
00796     
00797     // Ignore CF references, which can be toll-free bridged.
00798     if (coreFoundation::isCFObjectRef(ArgTy))
00799       continue;
00800 
00801     // Generate only one error node to use for all bug reports.
00802     if (!errorNode.hasValue())
00803       errorNode = C.addTransition();
00804 
00805     if (!errorNode.getValue())
00806       continue;
00807 
00808     SmallString<128> sbuf;
00809     llvm::raw_svector_ostream os(sbuf);
00810 
00811     StringRef TypeName = GetReceiverInterfaceName(msg);
00812     if (!TypeName.empty())
00813       os << "Argument to '" << TypeName << "' method '";
00814     else
00815       os << "Argument to method '";
00816 
00817     msg.getSelector().print(os);
00818     os << "' should be an Objective-C pointer type, not '";
00819     ArgTy.print(os, C.getLangOpts());
00820     os << "'";
00821 
00822     BugReport *R = new BugReport(*BT, os.str(), errorNode.getValue());
00823     R->addRange(msg.getArgSourceRange(I));
00824     C.emitReport(R);
00825   }
00826 }
00827 
00828 //===----------------------------------------------------------------------===//
00829 // Improves the modeling of loops over Cocoa collections.
00830 //===----------------------------------------------------------------------===//
00831 
00832 // The map from container symbol to the container count symbol.
00833 // We currently will remember the last countainer count symbol encountered.
00834 REGISTER_MAP_WITH_PROGRAMSTATE(ContainerCountMap, SymbolRef, SymbolRef)
00835 REGISTER_MAP_WITH_PROGRAMSTATE(ContainerNonEmptyMap, SymbolRef, bool)
00836 
00837 namespace {
00838 class ObjCLoopChecker
00839   : public Checker<check::PostStmt<ObjCForCollectionStmt>,
00840                    check::PostObjCMessage,
00841                    check::DeadSymbols,
00842                    check::PointerEscape > {
00843   mutable IdentifierInfo *CountSelectorII;
00844 
00845   bool isCollectionCountMethod(const ObjCMethodCall &M,
00846                                CheckerContext &C) const;
00847 
00848 public:
00849   ObjCLoopChecker() : CountSelectorII(nullptr) {}
00850   void checkPostStmt(const ObjCForCollectionStmt *FCS, CheckerContext &C) const;
00851   void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
00852   void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
00853   ProgramStateRef checkPointerEscape(ProgramStateRef State,
00854                                      const InvalidatedSymbols &Escaped,
00855                                      const CallEvent *Call,
00856                                      PointerEscapeKind Kind) const;
00857 };
00858 }
00859 
00860 static bool isKnownNonNilCollectionType(QualType T) {
00861   const ObjCObjectPointerType *PT = T->getAs<ObjCObjectPointerType>();
00862   if (!PT)
00863     return false;
00864   
00865   const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();
00866   if (!ID)
00867     return false;
00868 
00869   switch (findKnownClass(ID)) {
00870   case FC_NSArray:
00871   case FC_NSDictionary:
00872   case FC_NSEnumerator:
00873   case FC_NSOrderedSet:
00874   case FC_NSSet:
00875     return true;
00876   default:
00877     return false;
00878   }
00879 }
00880 
00881 /// Assumes that the collection is non-nil.
00882 ///
00883 /// If the collection is known to be nil, returns NULL to indicate an infeasible
00884 /// path.
00885 static ProgramStateRef checkCollectionNonNil(CheckerContext &C,
00886                                              ProgramStateRef State,
00887                                              const ObjCForCollectionStmt *FCS) {
00888   if (!State)
00889     return nullptr;
00890 
00891   SVal CollectionVal = C.getSVal(FCS->getCollection());
00892   Optional<DefinedSVal> KnownCollection = CollectionVal.getAs<DefinedSVal>();
00893   if (!KnownCollection)
00894     return State;
00895 
00896   ProgramStateRef StNonNil, StNil;
00897   std::tie(StNonNil, StNil) = State->assume(*KnownCollection);
00898   if (StNil && !StNonNil) {
00899     // The collection is nil. This path is infeasible.
00900     return nullptr;
00901   }
00902 
00903   return StNonNil;
00904 }
00905 
00906 /// Assumes that the collection elements are non-nil.
00907 ///
00908 /// This only applies if the collection is one of those known not to contain
00909 /// nil values.
00910 static ProgramStateRef checkElementNonNil(CheckerContext &C,
00911                                           ProgramStateRef State,
00912                                           const ObjCForCollectionStmt *FCS) {
00913   if (!State)
00914     return nullptr;
00915 
00916   // See if the collection is one where we /know/ the elements are non-nil.
00917   if (!isKnownNonNilCollectionType(FCS->getCollection()->getType()))
00918     return State;
00919 
00920   const LocationContext *LCtx = C.getLocationContext();
00921   const Stmt *Element = FCS->getElement();
00922 
00923   // FIXME: Copied from ExprEngineObjC.
00924   Optional<Loc> ElementLoc;
00925   if (const DeclStmt *DS = dyn_cast<DeclStmt>(Element)) {
00926     const VarDecl *ElemDecl = cast<VarDecl>(DS->getSingleDecl());
00927     assert(ElemDecl->getInit() == nullptr);
00928     ElementLoc = State->getLValue(ElemDecl, LCtx);
00929   } else {
00930     ElementLoc = State->getSVal(Element, LCtx).getAs<Loc>();
00931   }
00932 
00933   if (!ElementLoc)
00934     return State;
00935 
00936   // Go ahead and assume the value is non-nil.
00937   SVal Val = State->getSVal(*ElementLoc);
00938   return State->assume(Val.castAs<DefinedOrUnknownSVal>(), true);
00939 }
00940 
00941 /// Returns NULL state if the collection is known to contain elements
00942 /// (or is known not to contain elements if the Assumption parameter is false.)
00943 static ProgramStateRef
00944 assumeCollectionNonEmpty(CheckerContext &C, ProgramStateRef State,
00945                          SymbolRef CollectionS, bool Assumption) {
00946   if (!State || !CollectionS)
00947     return State;
00948 
00949   const SymbolRef *CountS = State->get<ContainerCountMap>(CollectionS);
00950   if (!CountS) {
00951     const bool *KnownNonEmpty = State->get<ContainerNonEmptyMap>(CollectionS);
00952     if (!KnownNonEmpty)
00953       return State->set<ContainerNonEmptyMap>(CollectionS, Assumption);
00954     return (Assumption == *KnownNonEmpty) ? State : nullptr;
00955   }
00956 
00957   SValBuilder &SvalBuilder = C.getSValBuilder();
00958   SVal CountGreaterThanZeroVal =
00959     SvalBuilder.evalBinOp(State, BO_GT,
00960                           nonloc::SymbolVal(*CountS),
00961                           SvalBuilder.makeIntVal(0, (*CountS)->getType()),
00962                           SvalBuilder.getConditionType());
00963   Optional<DefinedSVal> CountGreaterThanZero =
00964     CountGreaterThanZeroVal.getAs<DefinedSVal>();
00965   if (!CountGreaterThanZero) {
00966     // The SValBuilder cannot construct a valid SVal for this condition.
00967     // This means we cannot properly reason about it.
00968     return State;
00969   }
00970 
00971   return State->assume(*CountGreaterThanZero, Assumption);
00972 }
00973 
00974 static ProgramStateRef
00975 assumeCollectionNonEmpty(CheckerContext &C, ProgramStateRef State,
00976                          const ObjCForCollectionStmt *FCS,
00977                          bool Assumption) {
00978   if (!State)
00979     return nullptr;
00980 
00981   SymbolRef CollectionS =
00982     State->getSVal(FCS->getCollection(), C.getLocationContext()).getAsSymbol();
00983   return assumeCollectionNonEmpty(C, State, CollectionS, Assumption);
00984 }
00985 
00986 
00987 /// If the fist block edge is a back edge, we are reentering the loop.
00988 static bool alreadyExecutedAtLeastOneLoopIteration(const ExplodedNode *N,
00989                                              const ObjCForCollectionStmt *FCS) {
00990   if (!N)
00991     return false;
00992 
00993   ProgramPoint P = N->getLocation();
00994   if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) {
00995     if (BE->getSrc()->getLoopTarget() == FCS)
00996       return true;
00997     return false;
00998   }
00999 
01000   // Keep looking for a block edge.
01001   for (ExplodedNode::const_pred_iterator I = N->pred_begin(),
01002                                          E = N->pred_end(); I != E; ++I) {
01003     if (alreadyExecutedAtLeastOneLoopIteration(*I, FCS))
01004       return true;
01005   }
01006 
01007   return false;
01008 }
01009 
01010 void ObjCLoopChecker::checkPostStmt(const ObjCForCollectionStmt *FCS,
01011                                     CheckerContext &C) const {
01012   ProgramStateRef State = C.getState();
01013 
01014   // Check if this is the branch for the end of the loop.
01015   SVal CollectionSentinel = C.getSVal(FCS);
01016   if (CollectionSentinel.isZeroConstant()) {
01017     if (!alreadyExecutedAtLeastOneLoopIteration(C.getPredecessor(), FCS))
01018       State = assumeCollectionNonEmpty(C, State, FCS, /*Assumption*/false);
01019 
01020   // Otherwise, this is a branch that goes through the loop body.
01021   } else {
01022     State = checkCollectionNonNil(C, State, FCS);
01023     State = checkElementNonNil(C, State, FCS);
01024     State = assumeCollectionNonEmpty(C, State, FCS, /*Assumption*/true);
01025   }
01026   
01027   if (!State)
01028     C.generateSink();
01029   else if (State != C.getState())
01030     C.addTransition(State);
01031 }
01032 
01033 bool ObjCLoopChecker::isCollectionCountMethod(const ObjCMethodCall &M,
01034                                               CheckerContext &C) const {
01035   Selector S = M.getSelector();
01036   // Initialize the identifiers on first use.
01037   if (!CountSelectorII)
01038     CountSelectorII = &C.getASTContext().Idents.get("count");
01039 
01040   // If the method returns collection count, record the value.
01041   if (S.isUnarySelector() &&
01042       (S.getIdentifierInfoForSlot(0) == CountSelectorII))
01043     return true;
01044   
01045   return false;
01046 }
01047 
01048 void ObjCLoopChecker::checkPostObjCMessage(const ObjCMethodCall &M,
01049                                            CheckerContext &C) const {
01050   if (!M.isInstanceMessage())
01051     return;
01052 
01053   const ObjCInterfaceDecl *ClassID = M.getReceiverInterface();
01054   if (!ClassID)
01055     return;
01056 
01057   FoundationClass Class = findKnownClass(ClassID);
01058   if (Class != FC_NSDictionary &&
01059       Class != FC_NSArray &&
01060       Class != FC_NSSet &&
01061       Class != FC_NSOrderedSet)
01062     return;
01063 
01064   SymbolRef ContainerS = M.getReceiverSVal().getAsSymbol();
01065   if (!ContainerS)
01066     return;
01067 
01068   // If we are processing a call to "count", get the symbolic value returned by
01069   // a call to "count" and add it to the map.
01070   if (!isCollectionCountMethod(M, C))
01071     return;
01072   
01073   const Expr *MsgExpr = M.getOriginExpr();
01074   SymbolRef CountS = C.getSVal(MsgExpr).getAsSymbol();
01075   if (CountS) {
01076     ProgramStateRef State = C.getState();
01077 
01078     C.getSymbolManager().addSymbolDependency(ContainerS, CountS);
01079     State = State->set<ContainerCountMap>(ContainerS, CountS);
01080 
01081     if (const bool *NonEmpty = State->get<ContainerNonEmptyMap>(ContainerS)) {
01082       State = State->remove<ContainerNonEmptyMap>(ContainerS);
01083       State = assumeCollectionNonEmpty(C, State, ContainerS, *NonEmpty);
01084     }
01085 
01086     C.addTransition(State);
01087   }
01088   return;
01089 }
01090 
01091 static SymbolRef getMethodReceiverIfKnownImmutable(const CallEvent *Call) {
01092   const ObjCMethodCall *Message = dyn_cast_or_null<ObjCMethodCall>(Call);
01093   if (!Message)
01094     return nullptr;
01095 
01096   const ObjCMethodDecl *MD = Message->getDecl();
01097   if (!MD)
01098     return nullptr;
01099 
01100   const ObjCInterfaceDecl *StaticClass;
01101   if (isa<ObjCProtocolDecl>(MD->getDeclContext())) {
01102     // We can't find out where the method was declared without doing more work.
01103     // Instead, see if the receiver is statically typed as a known immutable
01104     // collection.
01105     StaticClass = Message->getOriginExpr()->getReceiverInterface();
01106   } else {
01107     StaticClass = MD->getClassInterface();
01108   }
01109 
01110   if (!StaticClass)
01111     return nullptr;
01112 
01113   switch (findKnownClass(StaticClass, /*IncludeSuper=*/false)) {
01114   case FC_None:
01115     return nullptr;
01116   case FC_NSArray:
01117   case FC_NSDictionary:
01118   case FC_NSEnumerator:
01119   case FC_NSNull:
01120   case FC_NSOrderedSet:
01121   case FC_NSSet:
01122   case FC_NSString:
01123     break;
01124   }
01125 
01126   return Message->getReceiverSVal().getAsSymbol();
01127 }
01128 
01129 ProgramStateRef
01130 ObjCLoopChecker::checkPointerEscape(ProgramStateRef State,
01131                                     const InvalidatedSymbols &Escaped,
01132                                     const CallEvent *Call,
01133                                     PointerEscapeKind Kind) const {
01134   SymbolRef ImmutableReceiver = getMethodReceiverIfKnownImmutable(Call);
01135 
01136   // Remove the invalidated symbols form the collection count map.
01137   for (InvalidatedSymbols::const_iterator I = Escaped.begin(),
01138        E = Escaped.end();
01139        I != E; ++I) {
01140     SymbolRef Sym = *I;
01141 
01142     // Don't invalidate this symbol's count if we know the method being called
01143     // is declared on an immutable class. This isn't completely correct if the
01144     // receiver is also passed as an argument, but in most uses of NSArray,
01145     // NSDictionary, etc. this isn't likely to happen in a dangerous way.
01146     if (Sym == ImmutableReceiver)
01147       continue;
01148 
01149     // The symbol escaped. Pessimistically, assume that the count could have
01150     // changed.
01151     State = State->remove<ContainerCountMap>(Sym);
01152     State = State->remove<ContainerNonEmptyMap>(Sym);
01153   }
01154   return State;
01155 }
01156 
01157 void ObjCLoopChecker::checkDeadSymbols(SymbolReaper &SymReaper,
01158                                        CheckerContext &C) const {
01159   ProgramStateRef State = C.getState();
01160 
01161   // Remove the dead symbols from the collection count map.
01162   ContainerCountMapTy Tracked = State->get<ContainerCountMap>();
01163   for (ContainerCountMapTy::iterator I = Tracked.begin(),
01164                                      E = Tracked.end(); I != E; ++I) {
01165     SymbolRef Sym = I->first;
01166     if (SymReaper.isDead(Sym)) {
01167       State = State->remove<ContainerCountMap>(Sym);
01168       State = State->remove<ContainerNonEmptyMap>(Sym);
01169     }
01170   }
01171 
01172   C.addTransition(State);
01173 }
01174 
01175 namespace {
01176 /// \class ObjCNonNilReturnValueChecker
01177 /// \brief The checker restricts the return values of APIs known to
01178 /// never (or almost never) return 'nil'.
01179 class ObjCNonNilReturnValueChecker
01180   : public Checker<check::PostObjCMessage,
01181                    check::PostStmt<ObjCArrayLiteral>,
01182                    check::PostStmt<ObjCDictionaryLiteral>,
01183                    check::PostStmt<ObjCBoxedExpr> > {
01184     mutable bool Initialized;
01185     mutable Selector ObjectAtIndex;
01186     mutable Selector ObjectAtIndexedSubscript;
01187     mutable Selector NullSelector;
01188 
01189 public:
01190   ObjCNonNilReturnValueChecker() : Initialized(false) {}
01191 
01192   ProgramStateRef assumeExprIsNonNull(const Expr *NonNullExpr,
01193                                       ProgramStateRef State,
01194                                       CheckerContext &C) const;
01195   void assumeExprIsNonNull(const Expr *E, CheckerContext &C) const {
01196     C.addTransition(assumeExprIsNonNull(E, C.getState(), C));
01197   }
01198 
01199   void checkPostStmt(const ObjCArrayLiteral *E, CheckerContext &C) const {
01200     assumeExprIsNonNull(E, C);
01201   }
01202   void checkPostStmt(const ObjCDictionaryLiteral *E, CheckerContext &C) const {
01203     assumeExprIsNonNull(E, C);
01204   }
01205   void checkPostStmt(const ObjCBoxedExpr *E, CheckerContext &C) const {
01206     assumeExprIsNonNull(E, C);
01207   }
01208 
01209   void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
01210 };
01211 }
01212 
01213 ProgramStateRef
01214 ObjCNonNilReturnValueChecker::assumeExprIsNonNull(const Expr *NonNullExpr,
01215                                                   ProgramStateRef State,
01216                                                   CheckerContext &C) const {
01217   SVal Val = State->getSVal(NonNullExpr, C.getLocationContext());
01218   if (Optional<DefinedOrUnknownSVal> DV = Val.getAs<DefinedOrUnknownSVal>())
01219     return State->assume(*DV, true);
01220   return State;
01221 }
01222 
01223 void ObjCNonNilReturnValueChecker::checkPostObjCMessage(const ObjCMethodCall &M,
01224                                                         CheckerContext &C)
01225                                                         const {
01226   ProgramStateRef State = C.getState();
01227 
01228   if (!Initialized) {
01229     ASTContext &Ctx = C.getASTContext();
01230     ObjectAtIndex = GetUnarySelector("objectAtIndex", Ctx);
01231     ObjectAtIndexedSubscript = GetUnarySelector("objectAtIndexedSubscript", Ctx);
01232     NullSelector = GetNullarySelector("null", Ctx);
01233   }
01234 
01235   // Check the receiver type.
01236   if (const ObjCInterfaceDecl *Interface = M.getReceiverInterface()) {
01237 
01238     // Assume that object returned from '[self init]' or '[super init]' is not
01239     // 'nil' if we are processing an inlined function/method.
01240     //
01241     // A defensive callee will (and should) check if the object returned by
01242     // '[super init]' is 'nil' before doing it's own initialization. However,
01243     // since 'nil' is rarely returned in practice, we should not warn when the
01244     // caller to the defensive constructor uses the object in contexts where
01245     // 'nil' is not accepted.
01246     if (!C.inTopFrame() && M.getDecl() &&
01247         M.getDecl()->getMethodFamily() == OMF_init &&
01248         M.isReceiverSelfOrSuper()) {
01249       State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
01250     }
01251 
01252     FoundationClass Cl = findKnownClass(Interface);
01253 
01254     // Objects returned from
01255     // [NSArray|NSOrderedSet]::[ObjectAtIndex|ObjectAtIndexedSubscript]
01256     // are never 'nil'.
01257     if (Cl == FC_NSArray || Cl == FC_NSOrderedSet) {
01258       Selector Sel = M.getSelector();
01259       if (Sel == ObjectAtIndex || Sel == ObjectAtIndexedSubscript) {
01260         // Go ahead and assume the value is non-nil.
01261         State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
01262       }
01263     }
01264 
01265     // Objects returned from [NSNull null] are not nil.
01266     if (Cl == FC_NSNull) {
01267       if (M.getSelector() == NullSelector) {
01268         // Go ahead and assume the value is non-nil.
01269         State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
01270       }
01271     }
01272   }
01273   C.addTransition(State);
01274 }
01275 
01276 //===----------------------------------------------------------------------===//
01277 // Check registration.
01278 //===----------------------------------------------------------------------===//
01279 
01280 void ento::registerNilArgChecker(CheckerManager &mgr) {
01281   mgr.registerChecker<NilArgChecker>();
01282 }
01283 
01284 void ento::registerCFNumberCreateChecker(CheckerManager &mgr) {
01285   mgr.registerChecker<CFNumberCreateChecker>();
01286 }
01287 
01288 void ento::registerCFRetainReleaseChecker(CheckerManager &mgr) {
01289   mgr.registerChecker<CFRetainReleaseChecker>();
01290 }
01291 
01292 void ento::registerClassReleaseChecker(CheckerManager &mgr) {
01293   mgr.registerChecker<ClassReleaseChecker>();
01294 }
01295 
01296 void ento::registerVariadicMethodTypeChecker(CheckerManager &mgr) {
01297   mgr.registerChecker<VariadicMethodTypeChecker>();
01298 }
01299 
01300 void ento::registerObjCLoopChecker(CheckerManager &mgr) {
01301   mgr.registerChecker<ObjCLoopChecker>();
01302 }
01303 
01304 void
01305 ento::registerObjCNonNilReturnValueChecker(CheckerManager &mgr) {
01306   mgr.registerChecker<ObjCNonNilReturnValueChecker>();
01307 }