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