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