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