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