• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "SelectorExtras.h"
18 #include "clang/AST/ASTContext.h"
19 #include "clang/AST/DeclObjC.h"
20 #include "clang/AST/Expr.h"
21 #include "clang/AST/ExprObjC.h"
22 #include "clang/AST/StmtObjC.h"
23 #include "clang/Analysis/DomainSpecific/CocoaConventions.h"
24 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
25 #include "clang/StaticAnalyzer/Core/Checker.h"
26 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
27 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
28 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
29 #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
30 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
31 #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
32 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
33 #include "llvm/ADT/SmallString.h"
34 #include "llvm/ADT/StringMap.h"
35 #include "llvm/Support/raw_ostream.h"
36 
37 using namespace clang;
38 using namespace ento;
39 
40 namespace {
41 class APIMisuse : public BugType {
42 public:
APIMisuse(const CheckerBase * checker,const char * name)43   APIMisuse(const CheckerBase *checker, const char *name)
44       : BugType(checker, name, "API Misuse (Apple)") {}
45 };
46 } // end anonymous namespace
47 
48 //===----------------------------------------------------------------------===//
49 // Utility functions.
50 //===----------------------------------------------------------------------===//
51 
GetReceiverInterfaceName(const ObjCMethodCall & msg)52 static StringRef GetReceiverInterfaceName(const ObjCMethodCall &msg) {
53   if (const ObjCInterfaceDecl *ID = msg.getReceiverInterface())
54     return ID->getIdentifier()->getName();
55   return StringRef();
56 }
57 
58 enum FoundationClass {
59   FC_None,
60   FC_NSArray,
61   FC_NSDictionary,
62   FC_NSEnumerator,
63   FC_NSNull,
64   FC_NSOrderedSet,
65   FC_NSSet,
66   FC_NSString
67 };
68 
findKnownClass(const ObjCInterfaceDecl * ID,bool IncludeSuperclasses=true)69 static FoundationClass findKnownClass(const ObjCInterfaceDecl *ID,
70                                       bool IncludeSuperclasses = true) {
71   static llvm::StringMap<FoundationClass> Classes;
72   if (Classes.empty()) {
73     Classes["NSArray"] = FC_NSArray;
74     Classes["NSDictionary"] = FC_NSDictionary;
75     Classes["NSEnumerator"] = FC_NSEnumerator;
76     Classes["NSNull"] = FC_NSNull;
77     Classes["NSOrderedSet"] = FC_NSOrderedSet;
78     Classes["NSSet"] = FC_NSSet;
79     Classes["NSString"] = FC_NSString;
80   }
81 
82   // FIXME: Should we cache this at all?
83   FoundationClass result = Classes.lookup(ID->getIdentifier()->getName());
84   if (result == FC_None && IncludeSuperclasses)
85     if (const ObjCInterfaceDecl *Super = ID->getSuperClass())
86       return findKnownClass(Super);
87 
88   return result;
89 }
90 
91 //===----------------------------------------------------------------------===//
92 // NilArgChecker - Check for prohibited nil arguments to ObjC method calls.
93 //===----------------------------------------------------------------------===//
94 
95 namespace {
96   class NilArgChecker : public Checker<check::PreObjCMessage,
97                                        check::PostStmt<ObjCDictionaryLiteral>,
98                                        check::PostStmt<ObjCArrayLiteral> > {
99     mutable std::unique_ptr<APIMisuse> BT;
100 
101     mutable llvm::SmallDenseMap<Selector, unsigned, 16> StringSelectors;
102     mutable Selector ArrayWithObjectSel;
103     mutable Selector AddObjectSel;
104     mutable Selector InsertObjectAtIndexSel;
105     mutable Selector ReplaceObjectAtIndexWithObjectSel;
106     mutable Selector SetObjectAtIndexedSubscriptSel;
107     mutable Selector ArrayByAddingObjectSel;
108     mutable Selector DictionaryWithObjectForKeySel;
109     mutable Selector SetObjectForKeySel;
110     mutable Selector SetObjectForKeyedSubscriptSel;
111     mutable Selector RemoveObjectForKeySel;
112 
113     void warnIfNilExpr(const Expr *E,
114                        const char *Msg,
115                        CheckerContext &C) const;
116 
117     void warnIfNilArg(CheckerContext &C,
118                       const ObjCMethodCall &msg, unsigned Arg,
119                       FoundationClass Class,
120                       bool CanBeSubscript = false) const;
121 
122     void generateBugReport(ExplodedNode *N,
123                            StringRef Msg,
124                            SourceRange Range,
125                            const Expr *Expr,
126                            CheckerContext &C) const;
127 
128   public:
129     void checkPreObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
130     void checkPostStmt(const ObjCDictionaryLiteral *DL,
131                        CheckerContext &C) const;
132     void checkPostStmt(const ObjCArrayLiteral *AL,
133                        CheckerContext &C) const;
134   };
135 }
136 
warnIfNilExpr(const Expr * E,const char * Msg,CheckerContext & C) const137 void NilArgChecker::warnIfNilExpr(const Expr *E,
138                                   const char *Msg,
139                                   CheckerContext &C) const {
140   ProgramStateRef State = C.getState();
141   if (State->isNull(C.getSVal(E)).isConstrainedTrue()) {
142 
143     if (ExplodedNode *N = C.generateSink()) {
144       generateBugReport(N, Msg, E->getSourceRange(), E, C);
145     }
146 
147   }
148 }
149 
warnIfNilArg(CheckerContext & C,const ObjCMethodCall & msg,unsigned int Arg,FoundationClass Class,bool CanBeSubscript) const150 void NilArgChecker::warnIfNilArg(CheckerContext &C,
151                                  const ObjCMethodCall &msg,
152                                  unsigned int Arg,
153                                  FoundationClass Class,
154                                  bool CanBeSubscript) const {
155   // Check if the argument is nil.
156   ProgramStateRef State = C.getState();
157   if (!State->isNull(msg.getArgSVal(Arg)).isConstrainedTrue())
158       return;
159 
160   if (ExplodedNode *N = C.generateSink()) {
161     SmallString<128> sbuf;
162     llvm::raw_svector_ostream os(sbuf);
163 
164     if (CanBeSubscript && msg.getMessageKind() == OCM_Subscript) {
165 
166       if (Class == FC_NSArray) {
167         os << "Array element cannot be nil";
168       } else if (Class == FC_NSDictionary) {
169         if (Arg == 0) {
170           os << "Value stored into '";
171           os << GetReceiverInterfaceName(msg) << "' cannot be nil";
172         } else {
173           assert(Arg == 1);
174           os << "'"<< GetReceiverInterfaceName(msg) << "' key cannot be nil";
175         }
176       } else
177         llvm_unreachable("Missing foundation class for the subscript expr");
178 
179     } else {
180       if (Class == FC_NSDictionary) {
181         if (Arg == 0)
182           os << "Value argument ";
183         else {
184           assert(Arg == 1);
185           os << "Key argument ";
186         }
187         os << "to '";
188         msg.getSelector().print(os);
189         os << "' cannot be nil";
190       } else {
191         os << "Argument to '" << GetReceiverInterfaceName(msg) << "' method '";
192         msg.getSelector().print(os);
193         os << "' cannot be nil";
194       }
195     }
196 
197     generateBugReport(N, os.str(), msg.getArgSourceRange(Arg),
198                       msg.getArgExpr(Arg), C);
199   }
200 }
201 
generateBugReport(ExplodedNode * N,StringRef Msg,SourceRange Range,const Expr * E,CheckerContext & C) const202 void NilArgChecker::generateBugReport(ExplodedNode *N,
203                                       StringRef Msg,
204                                       SourceRange Range,
205                                       const Expr *E,
206                                       CheckerContext &C) const {
207   if (!BT)
208     BT.reset(new APIMisuse(this, "nil argument"));
209 
210   BugReport *R = new BugReport(*BT, Msg, N);
211   R->addRange(Range);
212   bugreporter::trackNullOrUndefValue(N, E, *R);
213   C.emitReport(R);
214 }
215 
checkPreObjCMessage(const ObjCMethodCall & msg,CheckerContext & C) const216 void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
217                                         CheckerContext &C) const {
218   const ObjCInterfaceDecl *ID = msg.getReceiverInterface();
219   if (!ID)
220     return;
221 
222   FoundationClass Class = findKnownClass(ID);
223 
224   static const unsigned InvalidArgIndex = UINT_MAX;
225   unsigned Arg = InvalidArgIndex;
226   bool CanBeSubscript = false;
227 
228   if (Class == FC_NSString) {
229     Selector S = msg.getSelector();
230 
231     if (S.isUnarySelector())
232       return;
233 
234     if (StringSelectors.empty()) {
235       ASTContext &Ctx = C.getASTContext();
236       Selector Sels[] = {
237         getKeywordSelector(Ctx, "caseInsensitiveCompare", nullptr),
238         getKeywordSelector(Ctx, "compare", nullptr),
239         getKeywordSelector(Ctx, "compare", "options", nullptr),
240         getKeywordSelector(Ctx, "compare", "options", "range", nullptr),
241         getKeywordSelector(Ctx, "compare", "options", "range", "locale",
242                            nullptr),
243         getKeywordSelector(Ctx, "componentsSeparatedByCharactersInSet",
244                            nullptr),
245         getKeywordSelector(Ctx, "initWithFormat",
246                            nullptr),
247         getKeywordSelector(Ctx, "localizedCaseInsensitiveCompare", nullptr),
248         getKeywordSelector(Ctx, "localizedCompare", nullptr),
249         getKeywordSelector(Ctx, "localizedStandardCompare", nullptr),
250       };
251       for (Selector KnownSel : Sels)
252         StringSelectors[KnownSel] = 0;
253     }
254     auto I = StringSelectors.find(S);
255     if (I == StringSelectors.end())
256       return;
257     Arg = I->second;
258   } else if (Class == FC_NSArray) {
259     Selector S = msg.getSelector();
260 
261     if (S.isUnarySelector())
262       return;
263 
264     if (ArrayWithObjectSel.isNull()) {
265       ASTContext &Ctx = C.getASTContext();
266       ArrayWithObjectSel = getKeywordSelector(Ctx, "arrayWithObject", nullptr);
267       AddObjectSel = getKeywordSelector(Ctx, "addObject", nullptr);
268       InsertObjectAtIndexSel =
269         getKeywordSelector(Ctx, "insertObject", "atIndex", nullptr);
270       ReplaceObjectAtIndexWithObjectSel =
271         getKeywordSelector(Ctx, "replaceObjectAtIndex", "withObject", nullptr);
272       SetObjectAtIndexedSubscriptSel =
273         getKeywordSelector(Ctx, "setObject", "atIndexedSubscript", nullptr);
274       ArrayByAddingObjectSel =
275         getKeywordSelector(Ctx, "arrayByAddingObject", nullptr);
276     }
277 
278     if (S == ArrayWithObjectSel || S == AddObjectSel ||
279         S == InsertObjectAtIndexSel || S == ArrayByAddingObjectSel) {
280       Arg = 0;
281     } else if (S == SetObjectAtIndexedSubscriptSel) {
282       Arg = 0;
283       CanBeSubscript = true;
284     } else if (S == ReplaceObjectAtIndexWithObjectSel) {
285       Arg = 1;
286     }
287   } else if (Class == FC_NSDictionary) {
288     Selector S = msg.getSelector();
289 
290     if (S.isUnarySelector())
291       return;
292 
293     if (DictionaryWithObjectForKeySel.isNull()) {
294       ASTContext &Ctx = C.getASTContext();
295       DictionaryWithObjectForKeySel =
296         getKeywordSelector(Ctx, "dictionaryWithObject", "forKey", nullptr);
297       SetObjectForKeySel =
298         getKeywordSelector(Ctx, "setObject", "forKey", nullptr);
299       SetObjectForKeyedSubscriptSel =
300         getKeywordSelector(Ctx, "setObject", "forKeyedSubscript", nullptr);
301       RemoveObjectForKeySel =
302         getKeywordSelector(Ctx, "removeObjectForKey", nullptr);
303     }
304 
305     if (S == DictionaryWithObjectForKeySel || S == SetObjectForKeySel) {
306       Arg = 0;
307       warnIfNilArg(C, msg, /* Arg */1, Class);
308     } else if (S == SetObjectForKeyedSubscriptSel) {
309       CanBeSubscript = true;
310       Arg = 0;
311       warnIfNilArg(C, msg, /* Arg */1, Class, CanBeSubscript);
312     } else if (S == RemoveObjectForKeySel) {
313       Arg = 0;
314     }
315   }
316 
317   // If argument is '0', report a warning.
318   if ((Arg != InvalidArgIndex))
319     warnIfNilArg(C, msg, Arg, Class, CanBeSubscript);
320 }
321 
checkPostStmt(const ObjCArrayLiteral * AL,CheckerContext & C) const322 void NilArgChecker::checkPostStmt(const ObjCArrayLiteral *AL,
323                                   CheckerContext &C) const {
324   unsigned NumOfElements = AL->getNumElements();
325   for (unsigned i = 0; i < NumOfElements; ++i) {
326     warnIfNilExpr(AL->getElement(i), "Array element cannot be nil", C);
327   }
328 }
329 
checkPostStmt(const ObjCDictionaryLiteral * DL,CheckerContext & C) const330 void NilArgChecker::checkPostStmt(const ObjCDictionaryLiteral *DL,
331                                   CheckerContext &C) const {
332   unsigned NumOfElements = DL->getNumElements();
333   for (unsigned i = 0; i < NumOfElements; ++i) {
334     ObjCDictionaryElement Element = DL->getKeyValueElement(i);
335     warnIfNilExpr(Element.Key, "Dictionary key cannot be nil", C);
336     warnIfNilExpr(Element.Value, "Dictionary value cannot be nil", C);
337   }
338 }
339 
340 //===----------------------------------------------------------------------===//
341 // Error reporting.
342 //===----------------------------------------------------------------------===//
343 
344 namespace {
345 class CFNumberCreateChecker : public Checker< check::PreStmt<CallExpr> > {
346   mutable std::unique_ptr<APIMisuse> BT;
347   mutable IdentifierInfo* II;
348 public:
CFNumberCreateChecker()349   CFNumberCreateChecker() : II(nullptr) {}
350 
351   void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
352 
353 private:
354   void EmitError(const TypedRegion* R, const Expr *Ex,
355                 uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind);
356 };
357 } // end anonymous namespace
358 
359 enum CFNumberType {
360   kCFNumberSInt8Type = 1,
361   kCFNumberSInt16Type = 2,
362   kCFNumberSInt32Type = 3,
363   kCFNumberSInt64Type = 4,
364   kCFNumberFloat32Type = 5,
365   kCFNumberFloat64Type = 6,
366   kCFNumberCharType = 7,
367   kCFNumberShortType = 8,
368   kCFNumberIntType = 9,
369   kCFNumberLongType = 10,
370   kCFNumberLongLongType = 11,
371   kCFNumberFloatType = 12,
372   kCFNumberDoubleType = 13,
373   kCFNumberCFIndexType = 14,
374   kCFNumberNSIntegerType = 15,
375   kCFNumberCGFloatType = 16
376 };
377 
GetCFNumberSize(ASTContext & Ctx,uint64_t i)378 static Optional<uint64_t> GetCFNumberSize(ASTContext &Ctx, uint64_t i) {
379   static const unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 };
380 
381   if (i < kCFNumberCharType)
382     return FixedSize[i-1];
383 
384   QualType T;
385 
386   switch (i) {
387     case kCFNumberCharType:     T = Ctx.CharTy;     break;
388     case kCFNumberShortType:    T = Ctx.ShortTy;    break;
389     case kCFNumberIntType:      T = Ctx.IntTy;      break;
390     case kCFNumberLongType:     T = Ctx.LongTy;     break;
391     case kCFNumberLongLongType: T = Ctx.LongLongTy; break;
392     case kCFNumberFloatType:    T = Ctx.FloatTy;    break;
393     case kCFNumberDoubleType:   T = Ctx.DoubleTy;   break;
394     case kCFNumberCFIndexType:
395     case kCFNumberNSIntegerType:
396     case kCFNumberCGFloatType:
397       // FIXME: We need a way to map from names to Type*.
398     default:
399       return None;
400   }
401 
402   return Ctx.getTypeSize(T);
403 }
404 
405 #if 0
406 static const char* GetCFNumberTypeStr(uint64_t i) {
407   static const char* Names[] = {
408     "kCFNumberSInt8Type",
409     "kCFNumberSInt16Type",
410     "kCFNumberSInt32Type",
411     "kCFNumberSInt64Type",
412     "kCFNumberFloat32Type",
413     "kCFNumberFloat64Type",
414     "kCFNumberCharType",
415     "kCFNumberShortType",
416     "kCFNumberIntType",
417     "kCFNumberLongType",
418     "kCFNumberLongLongType",
419     "kCFNumberFloatType",
420     "kCFNumberDoubleType",
421     "kCFNumberCFIndexType",
422     "kCFNumberNSIntegerType",
423     "kCFNumberCGFloatType"
424   };
425 
426   return i <= kCFNumberCGFloatType ? Names[i-1] : "Invalid CFNumberType";
427 }
428 #endif
429 
checkPreStmt(const CallExpr * CE,CheckerContext & C) const430 void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE,
431                                          CheckerContext &C) const {
432   ProgramStateRef state = C.getState();
433   const FunctionDecl *FD = C.getCalleeDecl(CE);
434   if (!FD)
435     return;
436 
437   ASTContext &Ctx = C.getASTContext();
438   if (!II)
439     II = &Ctx.Idents.get("CFNumberCreate");
440 
441   if (FD->getIdentifier() != II || CE->getNumArgs() != 3)
442     return;
443 
444   // Get the value of the "theType" argument.
445   const LocationContext *LCtx = C.getLocationContext();
446   SVal TheTypeVal = state->getSVal(CE->getArg(1), LCtx);
447 
448   // FIXME: We really should allow ranges of valid theType values, and
449   //   bifurcate the state appropriately.
450   Optional<nonloc::ConcreteInt> V = TheTypeVal.getAs<nonloc::ConcreteInt>();
451   if (!V)
452     return;
453 
454   uint64_t NumberKind = V->getValue().getLimitedValue();
455   Optional<uint64_t> OptTargetSize = GetCFNumberSize(Ctx, NumberKind);
456 
457   // FIXME: In some cases we can emit an error.
458   if (!OptTargetSize)
459     return;
460 
461   uint64_t TargetSize = *OptTargetSize;
462 
463   // Look at the value of the integer being passed by reference.  Essentially
464   // we want to catch cases where the value passed in is not equal to the
465   // size of the type being created.
466   SVal TheValueExpr = state->getSVal(CE->getArg(2), LCtx);
467 
468   // FIXME: Eventually we should handle arbitrary locations.  We can do this
469   //  by having an enhanced memory model that does low-level typing.
470   Optional<loc::MemRegionVal> LV = TheValueExpr.getAs<loc::MemRegionVal>();
471   if (!LV)
472     return;
473 
474   const TypedValueRegion* R = dyn_cast<TypedValueRegion>(LV->stripCasts());
475   if (!R)
476     return;
477 
478   QualType T = Ctx.getCanonicalType(R->getValueType());
479 
480   // FIXME: If the pointee isn't an integer type, should we flag a warning?
481   //  People can do weird stuff with pointers.
482 
483   if (!T->isIntegralOrEnumerationType())
484     return;
485 
486   uint64_t SourceSize = Ctx.getTypeSize(T);
487 
488   // CHECK: is SourceSize == TargetSize
489   if (SourceSize == TargetSize)
490     return;
491 
492   // Generate an error.  Only generate a sink if 'SourceSize < TargetSize';
493   // otherwise generate a regular node.
494   //
495   // FIXME: We can actually create an abstract "CFNumber" object that has
496   //  the bits initialized to the provided values.
497   //
498   if (ExplodedNode *N = SourceSize < TargetSize ? C.generateSink()
499                                                 : C.addTransition()) {
500     SmallString<128> sbuf;
501     llvm::raw_svector_ostream os(sbuf);
502 
503     os << (SourceSize == 8 ? "An " : "A ")
504        << SourceSize << " bit integer is used to initialize a CFNumber "
505                         "object that represents "
506        << (TargetSize == 8 ? "an " : "a ")
507        << TargetSize << " bit integer. ";
508 
509     if (SourceSize < TargetSize)
510       os << (TargetSize - SourceSize)
511       << " bits of the CFNumber value will be garbage." ;
512     else
513       os << (SourceSize - TargetSize)
514       << " bits of the input integer will be lost.";
515 
516     if (!BT)
517       BT.reset(new APIMisuse(this, "Bad use of CFNumberCreate"));
518 
519     BugReport *report = new BugReport(*BT, os.str(), N);
520     report->addRange(CE->getArg(2)->getSourceRange());
521     C.emitReport(report);
522   }
523 }
524 
525 //===----------------------------------------------------------------------===//
526 // CFRetain/CFRelease/CFMakeCollectable/CFAutorelease checking for null arguments.
527 //===----------------------------------------------------------------------===//
528 
529 namespace {
530 class CFRetainReleaseChecker : public Checker< check::PreStmt<CallExpr> > {
531   mutable std::unique_ptr<APIMisuse> BT;
532   mutable IdentifierInfo *Retain, *Release, *MakeCollectable, *Autorelease;
533 public:
CFRetainReleaseChecker()534   CFRetainReleaseChecker()
535       : Retain(nullptr), Release(nullptr), MakeCollectable(nullptr),
536         Autorelease(nullptr) {}
537   void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
538 };
539 } // end anonymous namespace
540 
541 
checkPreStmt(const CallExpr * CE,CheckerContext & C) const542 void CFRetainReleaseChecker::checkPreStmt(const CallExpr *CE,
543                                           CheckerContext &C) const {
544   // If the CallExpr doesn't have exactly 1 argument just give up checking.
545   if (CE->getNumArgs() != 1)
546     return;
547 
548   ProgramStateRef state = C.getState();
549   const FunctionDecl *FD = C.getCalleeDecl(CE);
550   if (!FD)
551     return;
552 
553   if (!BT) {
554     ASTContext &Ctx = C.getASTContext();
555     Retain = &Ctx.Idents.get("CFRetain");
556     Release = &Ctx.Idents.get("CFRelease");
557     MakeCollectable = &Ctx.Idents.get("CFMakeCollectable");
558     Autorelease = &Ctx.Idents.get("CFAutorelease");
559     BT.reset(new APIMisuse(
560         this, "null passed to CF memory management function"));
561   }
562 
563   // Check if we called CFRetain/CFRelease/CFMakeCollectable/CFAutorelease.
564   const IdentifierInfo *FuncII = FD->getIdentifier();
565   if (!(FuncII == Retain || FuncII == Release || FuncII == MakeCollectable ||
566         FuncII == Autorelease))
567     return;
568 
569   // FIXME: The rest of this just checks that the argument is non-null.
570   // It should probably be refactored and combined with NonNullParamChecker.
571 
572   // Get the argument's value.
573   const Expr *Arg = CE->getArg(0);
574   SVal ArgVal = state->getSVal(Arg, C.getLocationContext());
575   Optional<DefinedSVal> DefArgVal = ArgVal.getAs<DefinedSVal>();
576   if (!DefArgVal)
577     return;
578 
579   // Get a NULL value.
580   SValBuilder &svalBuilder = C.getSValBuilder();
581   DefinedSVal zero =
582       svalBuilder.makeZeroVal(Arg->getType()).castAs<DefinedSVal>();
583 
584   // Make an expression asserting that they're equal.
585   DefinedOrUnknownSVal ArgIsNull = svalBuilder.evalEQ(state, zero, *DefArgVal);
586 
587   // Are they equal?
588   ProgramStateRef stateTrue, stateFalse;
589   std::tie(stateTrue, stateFalse) = state->assume(ArgIsNull);
590 
591   if (stateTrue && !stateFalse) {
592     ExplodedNode *N = C.generateSink(stateTrue);
593     if (!N)
594       return;
595 
596     const char *description;
597     if (FuncII == Retain)
598       description = "Null pointer argument in call to CFRetain";
599     else if (FuncII == Release)
600       description = "Null pointer argument in call to CFRelease";
601     else if (FuncII == MakeCollectable)
602       description = "Null pointer argument in call to CFMakeCollectable";
603     else if (FuncII == Autorelease)
604       description = "Null pointer argument in call to CFAutorelease";
605     else
606       llvm_unreachable("impossible case");
607 
608     BugReport *report = new BugReport(*BT, description, N);
609     report->addRange(Arg->getSourceRange());
610     bugreporter::trackNullOrUndefValue(N, Arg, *report);
611     C.emitReport(report);
612     return;
613   }
614 
615   // From here on, we know the argument is non-null.
616   C.addTransition(stateFalse);
617 }
618 
619 //===----------------------------------------------------------------------===//
620 // Check for sending 'retain', 'release', or 'autorelease' directly to a Class.
621 //===----------------------------------------------------------------------===//
622 
623 namespace {
624 class ClassReleaseChecker : public Checker<check::PreObjCMessage> {
625   mutable Selector releaseS;
626   mutable Selector retainS;
627   mutable Selector autoreleaseS;
628   mutable Selector drainS;
629   mutable std::unique_ptr<BugType> BT;
630 
631 public:
632   void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
633 };
634 }
635 
checkPreObjCMessage(const ObjCMethodCall & msg,CheckerContext & C) const636 void ClassReleaseChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
637                                               CheckerContext &C) const {
638 
639   if (!BT) {
640     BT.reset(new APIMisuse(
641         this, "message incorrectly sent to class instead of class instance"));
642 
643     ASTContext &Ctx = C.getASTContext();
644     releaseS = GetNullarySelector("release", Ctx);
645     retainS = GetNullarySelector("retain", Ctx);
646     autoreleaseS = GetNullarySelector("autorelease", Ctx);
647     drainS = GetNullarySelector("drain", Ctx);
648   }
649 
650   if (msg.isInstanceMessage())
651     return;
652   const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
653   assert(Class);
654 
655   Selector S = msg.getSelector();
656   if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
657     return;
658 
659   if (ExplodedNode *N = C.addTransition()) {
660     SmallString<200> buf;
661     llvm::raw_svector_ostream os(buf);
662 
663     os << "The '";
664     S.print(os);
665     os << "' message should be sent to instances "
666           "of class '" << Class->getName()
667        << "' and not the class directly";
668 
669     BugReport *report = new BugReport(*BT, os.str(), N);
670     report->addRange(msg.getSourceRange());
671     C.emitReport(report);
672   }
673 }
674 
675 //===----------------------------------------------------------------------===//
676 // Check for passing non-Objective-C types to variadic methods that expect
677 // only Objective-C types.
678 //===----------------------------------------------------------------------===//
679 
680 namespace {
681 class VariadicMethodTypeChecker : public Checker<check::PreObjCMessage> {
682   mutable Selector arrayWithObjectsS;
683   mutable Selector dictionaryWithObjectsAndKeysS;
684   mutable Selector setWithObjectsS;
685   mutable Selector orderedSetWithObjectsS;
686   mutable Selector initWithObjectsS;
687   mutable Selector initWithObjectsAndKeysS;
688   mutable std::unique_ptr<BugType> BT;
689 
690   bool isVariadicMessage(const ObjCMethodCall &msg) const;
691 
692 public:
693   void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
694 };
695 }
696 
697 /// isVariadicMessage - Returns whether the given message is a variadic message,
698 /// where all arguments must be Objective-C types.
699 bool
isVariadicMessage(const ObjCMethodCall & msg) const700 VariadicMethodTypeChecker::isVariadicMessage(const ObjCMethodCall &msg) const {
701   const ObjCMethodDecl *MD = msg.getDecl();
702 
703   if (!MD || !MD->isVariadic() || isa<ObjCProtocolDecl>(MD->getDeclContext()))
704     return false;
705 
706   Selector S = msg.getSelector();
707 
708   if (msg.isInstanceMessage()) {
709     // FIXME: Ideally we'd look at the receiver interface here, but that's not
710     // useful for init, because alloc returns 'id'. In theory, this could lead
711     // to false positives, for example if there existed a class that had an
712     // initWithObjects: implementation that does accept non-Objective-C pointer
713     // types, but the chance of that happening is pretty small compared to the
714     // gains that this analysis gives.
715     const ObjCInterfaceDecl *Class = MD->getClassInterface();
716 
717     switch (findKnownClass(Class)) {
718     case FC_NSArray:
719     case FC_NSOrderedSet:
720     case FC_NSSet:
721       return S == initWithObjectsS;
722     case FC_NSDictionary:
723       return S == initWithObjectsAndKeysS;
724     default:
725       return false;
726     }
727   } else {
728     const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
729 
730     switch (findKnownClass(Class)) {
731       case FC_NSArray:
732         return S == arrayWithObjectsS;
733       case FC_NSOrderedSet:
734         return S == orderedSetWithObjectsS;
735       case FC_NSSet:
736         return S == setWithObjectsS;
737       case FC_NSDictionary:
738         return S == dictionaryWithObjectsAndKeysS;
739       default:
740         return false;
741     }
742   }
743 }
744 
checkPreObjCMessage(const ObjCMethodCall & msg,CheckerContext & C) const745 void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
746                                                     CheckerContext &C) const {
747   if (!BT) {
748     BT.reset(new APIMisuse(this,
749                            "Arguments passed to variadic method aren't all "
750                            "Objective-C pointer types"));
751 
752     ASTContext &Ctx = C.getASTContext();
753     arrayWithObjectsS = GetUnarySelector("arrayWithObjects", Ctx);
754     dictionaryWithObjectsAndKeysS =
755       GetUnarySelector("dictionaryWithObjectsAndKeys", Ctx);
756     setWithObjectsS = GetUnarySelector("setWithObjects", Ctx);
757     orderedSetWithObjectsS = GetUnarySelector("orderedSetWithObjects", Ctx);
758 
759     initWithObjectsS = GetUnarySelector("initWithObjects", Ctx);
760     initWithObjectsAndKeysS = GetUnarySelector("initWithObjectsAndKeys", Ctx);
761   }
762 
763   if (!isVariadicMessage(msg))
764       return;
765 
766   // We are not interested in the selector arguments since they have
767   // well-defined types, so the compiler will issue a warning for them.
768   unsigned variadicArgsBegin = msg.getSelector().getNumArgs();
769 
770   // We're not interested in the last argument since it has to be nil or the
771   // compiler would have issued a warning for it elsewhere.
772   unsigned variadicArgsEnd = msg.getNumArgs() - 1;
773 
774   if (variadicArgsEnd <= variadicArgsBegin)
775     return;
776 
777   // Verify that all arguments have Objective-C types.
778   Optional<ExplodedNode*> errorNode;
779 
780   for (unsigned I = variadicArgsBegin; I != variadicArgsEnd; ++I) {
781     QualType ArgTy = msg.getArgExpr(I)->getType();
782     if (ArgTy->isObjCObjectPointerType())
783       continue;
784 
785     // Block pointers are treaded as Objective-C pointers.
786     if (ArgTy->isBlockPointerType())
787       continue;
788 
789     // Ignore pointer constants.
790     if (msg.getArgSVal(I).getAs<loc::ConcreteInt>())
791       continue;
792 
793     // Ignore pointer types annotated with 'NSObject' attribute.
794     if (C.getASTContext().isObjCNSObjectType(ArgTy))
795       continue;
796 
797     // Ignore CF references, which can be toll-free bridged.
798     if (coreFoundation::isCFObjectRef(ArgTy))
799       continue;
800 
801     // Generate only one error node to use for all bug reports.
802     if (!errorNode.hasValue())
803       errorNode = C.addTransition();
804 
805     if (!errorNode.getValue())
806       continue;
807 
808     SmallString<128> sbuf;
809     llvm::raw_svector_ostream os(sbuf);
810 
811     StringRef TypeName = GetReceiverInterfaceName(msg);
812     if (!TypeName.empty())
813       os << "Argument to '" << TypeName << "' method '";
814     else
815       os << "Argument to method '";
816 
817     msg.getSelector().print(os);
818     os << "' should be an Objective-C pointer type, not '";
819     ArgTy.print(os, C.getLangOpts());
820     os << "'";
821 
822     BugReport *R = new BugReport(*BT, os.str(), errorNode.getValue());
823     R->addRange(msg.getArgSourceRange(I));
824     C.emitReport(R);
825   }
826 }
827 
828 //===----------------------------------------------------------------------===//
829 // Improves the modeling of loops over Cocoa collections.
830 //===----------------------------------------------------------------------===//
831 
832 // The map from container symbol to the container count symbol.
833 // We currently will remember the last countainer count symbol encountered.
834 REGISTER_MAP_WITH_PROGRAMSTATE(ContainerCountMap, SymbolRef, SymbolRef)
835 REGISTER_MAP_WITH_PROGRAMSTATE(ContainerNonEmptyMap, SymbolRef, bool)
836 
837 namespace {
838 class ObjCLoopChecker
839   : public Checker<check::PostStmt<ObjCForCollectionStmt>,
840                    check::PostObjCMessage,
841                    check::DeadSymbols,
842                    check::PointerEscape > {
843   mutable IdentifierInfo *CountSelectorII;
844 
845   bool isCollectionCountMethod(const ObjCMethodCall &M,
846                                CheckerContext &C) const;
847 
848 public:
ObjCLoopChecker()849   ObjCLoopChecker() : CountSelectorII(nullptr) {}
850   void checkPostStmt(const ObjCForCollectionStmt *FCS, CheckerContext &C) const;
851   void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
852   void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
853   ProgramStateRef checkPointerEscape(ProgramStateRef State,
854                                      const InvalidatedSymbols &Escaped,
855                                      const CallEvent *Call,
856                                      PointerEscapeKind Kind) const;
857 };
858 }
859 
isKnownNonNilCollectionType(QualType T)860 static bool isKnownNonNilCollectionType(QualType T) {
861   const ObjCObjectPointerType *PT = T->getAs<ObjCObjectPointerType>();
862   if (!PT)
863     return false;
864 
865   const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();
866   if (!ID)
867     return false;
868 
869   switch (findKnownClass(ID)) {
870   case FC_NSArray:
871   case FC_NSDictionary:
872   case FC_NSEnumerator:
873   case FC_NSOrderedSet:
874   case FC_NSSet:
875     return true;
876   default:
877     return false;
878   }
879 }
880 
881 /// Assumes that the collection is non-nil.
882 ///
883 /// If the collection is known to be nil, returns NULL to indicate an infeasible
884 /// path.
checkCollectionNonNil(CheckerContext & C,ProgramStateRef State,const ObjCForCollectionStmt * FCS)885 static ProgramStateRef checkCollectionNonNil(CheckerContext &C,
886                                              ProgramStateRef State,
887                                              const ObjCForCollectionStmt *FCS) {
888   if (!State)
889     return nullptr;
890 
891   SVal CollectionVal = C.getSVal(FCS->getCollection());
892   Optional<DefinedSVal> KnownCollection = CollectionVal.getAs<DefinedSVal>();
893   if (!KnownCollection)
894     return State;
895 
896   ProgramStateRef StNonNil, StNil;
897   std::tie(StNonNil, StNil) = State->assume(*KnownCollection);
898   if (StNil && !StNonNil) {
899     // The collection is nil. This path is infeasible.
900     return nullptr;
901   }
902 
903   return StNonNil;
904 }
905 
906 /// Assumes that the collection elements are non-nil.
907 ///
908 /// This only applies if the collection is one of those known not to contain
909 /// nil values.
checkElementNonNil(CheckerContext & C,ProgramStateRef State,const ObjCForCollectionStmt * FCS)910 static ProgramStateRef checkElementNonNil(CheckerContext &C,
911                                           ProgramStateRef State,
912                                           const ObjCForCollectionStmt *FCS) {
913   if (!State)
914     return nullptr;
915 
916   // See if the collection is one where we /know/ the elements are non-nil.
917   if (!isKnownNonNilCollectionType(FCS->getCollection()->getType()))
918     return State;
919 
920   const LocationContext *LCtx = C.getLocationContext();
921   const Stmt *Element = FCS->getElement();
922 
923   // FIXME: Copied from ExprEngineObjC.
924   Optional<Loc> ElementLoc;
925   if (const DeclStmt *DS = dyn_cast<DeclStmt>(Element)) {
926     const VarDecl *ElemDecl = cast<VarDecl>(DS->getSingleDecl());
927     assert(ElemDecl->getInit() == nullptr);
928     ElementLoc = State->getLValue(ElemDecl, LCtx);
929   } else {
930     ElementLoc = State->getSVal(Element, LCtx).getAs<Loc>();
931   }
932 
933   if (!ElementLoc)
934     return State;
935 
936   // Go ahead and assume the value is non-nil.
937   SVal Val = State->getSVal(*ElementLoc);
938   return State->assume(Val.castAs<DefinedOrUnknownSVal>(), true);
939 }
940 
941 /// Returns NULL state if the collection is known to contain elements
942 /// (or is known not to contain elements if the Assumption parameter is false.)
943 static ProgramStateRef
assumeCollectionNonEmpty(CheckerContext & C,ProgramStateRef State,SymbolRef CollectionS,bool Assumption)944 assumeCollectionNonEmpty(CheckerContext &C, ProgramStateRef State,
945                          SymbolRef CollectionS, bool Assumption) {
946   if (!State || !CollectionS)
947     return State;
948 
949   const SymbolRef *CountS = State->get<ContainerCountMap>(CollectionS);
950   if (!CountS) {
951     const bool *KnownNonEmpty = State->get<ContainerNonEmptyMap>(CollectionS);
952     if (!KnownNonEmpty)
953       return State->set<ContainerNonEmptyMap>(CollectionS, Assumption);
954     return (Assumption == *KnownNonEmpty) ? State : nullptr;
955   }
956 
957   SValBuilder &SvalBuilder = C.getSValBuilder();
958   SVal CountGreaterThanZeroVal =
959     SvalBuilder.evalBinOp(State, BO_GT,
960                           nonloc::SymbolVal(*CountS),
961                           SvalBuilder.makeIntVal(0, (*CountS)->getType()),
962                           SvalBuilder.getConditionType());
963   Optional<DefinedSVal> CountGreaterThanZero =
964     CountGreaterThanZeroVal.getAs<DefinedSVal>();
965   if (!CountGreaterThanZero) {
966     // The SValBuilder cannot construct a valid SVal for this condition.
967     // This means we cannot properly reason about it.
968     return State;
969   }
970 
971   return State->assume(*CountGreaterThanZero, Assumption);
972 }
973 
974 static ProgramStateRef
assumeCollectionNonEmpty(CheckerContext & C,ProgramStateRef State,const ObjCForCollectionStmt * FCS,bool Assumption)975 assumeCollectionNonEmpty(CheckerContext &C, ProgramStateRef State,
976                          const ObjCForCollectionStmt *FCS,
977                          bool Assumption) {
978   if (!State)
979     return nullptr;
980 
981   SymbolRef CollectionS =
982     State->getSVal(FCS->getCollection(), C.getLocationContext()).getAsSymbol();
983   return assumeCollectionNonEmpty(C, State, CollectionS, Assumption);
984 }
985 
986 
987 /// If the fist block edge is a back edge, we are reentering the loop.
alreadyExecutedAtLeastOneLoopIteration(const ExplodedNode * N,const ObjCForCollectionStmt * FCS)988 static bool alreadyExecutedAtLeastOneLoopIteration(const ExplodedNode *N,
989                                              const ObjCForCollectionStmt *FCS) {
990   if (!N)
991     return false;
992 
993   ProgramPoint P = N->getLocation();
994   if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) {
995     if (BE->getSrc()->getLoopTarget() == FCS)
996       return true;
997     return false;
998   }
999 
1000   // Keep looking for a block edge.
1001   for (ExplodedNode::const_pred_iterator I = N->pred_begin(),
1002                                          E = N->pred_end(); I != E; ++I) {
1003     if (alreadyExecutedAtLeastOneLoopIteration(*I, FCS))
1004       return true;
1005   }
1006 
1007   return false;
1008 }
1009 
checkPostStmt(const ObjCForCollectionStmt * FCS,CheckerContext & C) const1010 void ObjCLoopChecker::checkPostStmt(const ObjCForCollectionStmt *FCS,
1011                                     CheckerContext &C) const {
1012   ProgramStateRef State = C.getState();
1013 
1014   // Check if this is the branch for the end of the loop.
1015   SVal CollectionSentinel = C.getSVal(FCS);
1016   if (CollectionSentinel.isZeroConstant()) {
1017     if (!alreadyExecutedAtLeastOneLoopIteration(C.getPredecessor(), FCS))
1018       State = assumeCollectionNonEmpty(C, State, FCS, /*Assumption*/false);
1019 
1020   // Otherwise, this is a branch that goes through the loop body.
1021   } else {
1022     State = checkCollectionNonNil(C, State, FCS);
1023     State = checkElementNonNil(C, State, FCS);
1024     State = assumeCollectionNonEmpty(C, State, FCS, /*Assumption*/true);
1025   }
1026 
1027   if (!State)
1028     C.generateSink();
1029   else if (State != C.getState())
1030     C.addTransition(State);
1031 }
1032 
isCollectionCountMethod(const ObjCMethodCall & M,CheckerContext & C) const1033 bool ObjCLoopChecker::isCollectionCountMethod(const ObjCMethodCall &M,
1034                                               CheckerContext &C) const {
1035   Selector S = M.getSelector();
1036   // Initialize the identifiers on first use.
1037   if (!CountSelectorII)
1038     CountSelectorII = &C.getASTContext().Idents.get("count");
1039 
1040   // If the method returns collection count, record the value.
1041   if (S.isUnarySelector() &&
1042       (S.getIdentifierInfoForSlot(0) == CountSelectorII))
1043     return true;
1044 
1045   return false;
1046 }
1047 
checkPostObjCMessage(const ObjCMethodCall & M,CheckerContext & C) const1048 void ObjCLoopChecker::checkPostObjCMessage(const ObjCMethodCall &M,
1049                                            CheckerContext &C) const {
1050   if (!M.isInstanceMessage())
1051     return;
1052 
1053   const ObjCInterfaceDecl *ClassID = M.getReceiverInterface();
1054   if (!ClassID)
1055     return;
1056 
1057   FoundationClass Class = findKnownClass(ClassID);
1058   if (Class != FC_NSDictionary &&
1059       Class != FC_NSArray &&
1060       Class != FC_NSSet &&
1061       Class != FC_NSOrderedSet)
1062     return;
1063 
1064   SymbolRef ContainerS = M.getReceiverSVal().getAsSymbol();
1065   if (!ContainerS)
1066     return;
1067 
1068   // If we are processing a call to "count", get the symbolic value returned by
1069   // a call to "count" and add it to the map.
1070   if (!isCollectionCountMethod(M, C))
1071     return;
1072 
1073   const Expr *MsgExpr = M.getOriginExpr();
1074   SymbolRef CountS = C.getSVal(MsgExpr).getAsSymbol();
1075   if (CountS) {
1076     ProgramStateRef State = C.getState();
1077 
1078     C.getSymbolManager().addSymbolDependency(ContainerS, CountS);
1079     State = State->set<ContainerCountMap>(ContainerS, CountS);
1080 
1081     if (const bool *NonEmpty = State->get<ContainerNonEmptyMap>(ContainerS)) {
1082       State = State->remove<ContainerNonEmptyMap>(ContainerS);
1083       State = assumeCollectionNonEmpty(C, State, ContainerS, *NonEmpty);
1084     }
1085 
1086     C.addTransition(State);
1087   }
1088   return;
1089 }
1090 
getMethodReceiverIfKnownImmutable(const CallEvent * Call)1091 static SymbolRef getMethodReceiverIfKnownImmutable(const CallEvent *Call) {
1092   const ObjCMethodCall *Message = dyn_cast_or_null<ObjCMethodCall>(Call);
1093   if (!Message)
1094     return nullptr;
1095 
1096   const ObjCMethodDecl *MD = Message->getDecl();
1097   if (!MD)
1098     return nullptr;
1099 
1100   const ObjCInterfaceDecl *StaticClass;
1101   if (isa<ObjCProtocolDecl>(MD->getDeclContext())) {
1102     // We can't find out where the method was declared without doing more work.
1103     // Instead, see if the receiver is statically typed as a known immutable
1104     // collection.
1105     StaticClass = Message->getOriginExpr()->getReceiverInterface();
1106   } else {
1107     StaticClass = MD->getClassInterface();
1108   }
1109 
1110   if (!StaticClass)
1111     return nullptr;
1112 
1113   switch (findKnownClass(StaticClass, /*IncludeSuper=*/false)) {
1114   case FC_None:
1115     return nullptr;
1116   case FC_NSArray:
1117   case FC_NSDictionary:
1118   case FC_NSEnumerator:
1119   case FC_NSNull:
1120   case FC_NSOrderedSet:
1121   case FC_NSSet:
1122   case FC_NSString:
1123     break;
1124   }
1125 
1126   return Message->getReceiverSVal().getAsSymbol();
1127 }
1128 
1129 ProgramStateRef
checkPointerEscape(ProgramStateRef State,const InvalidatedSymbols & Escaped,const CallEvent * Call,PointerEscapeKind Kind) const1130 ObjCLoopChecker::checkPointerEscape(ProgramStateRef State,
1131                                     const InvalidatedSymbols &Escaped,
1132                                     const CallEvent *Call,
1133                                     PointerEscapeKind Kind) const {
1134   SymbolRef ImmutableReceiver = getMethodReceiverIfKnownImmutable(Call);
1135 
1136   // Remove the invalidated symbols form the collection count map.
1137   for (InvalidatedSymbols::const_iterator I = Escaped.begin(),
1138        E = Escaped.end();
1139        I != E; ++I) {
1140     SymbolRef Sym = *I;
1141 
1142     // Don't invalidate this symbol's count if we know the method being called
1143     // is declared on an immutable class. This isn't completely correct if the
1144     // receiver is also passed as an argument, but in most uses of NSArray,
1145     // NSDictionary, etc. this isn't likely to happen in a dangerous way.
1146     if (Sym == ImmutableReceiver)
1147       continue;
1148 
1149     // The symbol escaped. Pessimistically, assume that the count could have
1150     // changed.
1151     State = State->remove<ContainerCountMap>(Sym);
1152     State = State->remove<ContainerNonEmptyMap>(Sym);
1153   }
1154   return State;
1155 }
1156 
checkDeadSymbols(SymbolReaper & SymReaper,CheckerContext & C) const1157 void ObjCLoopChecker::checkDeadSymbols(SymbolReaper &SymReaper,
1158                                        CheckerContext &C) const {
1159   ProgramStateRef State = C.getState();
1160 
1161   // Remove the dead symbols from the collection count map.
1162   ContainerCountMapTy Tracked = State->get<ContainerCountMap>();
1163   for (ContainerCountMapTy::iterator I = Tracked.begin(),
1164                                      E = Tracked.end(); I != E; ++I) {
1165     SymbolRef Sym = I->first;
1166     if (SymReaper.isDead(Sym)) {
1167       State = State->remove<ContainerCountMap>(Sym);
1168       State = State->remove<ContainerNonEmptyMap>(Sym);
1169     }
1170   }
1171 
1172   C.addTransition(State);
1173 }
1174 
1175 namespace {
1176 /// \class ObjCNonNilReturnValueChecker
1177 /// \brief The checker restricts the return values of APIs known to
1178 /// never (or almost never) return 'nil'.
1179 class ObjCNonNilReturnValueChecker
1180   : public Checker<check::PostObjCMessage,
1181                    check::PostStmt<ObjCArrayLiteral>,
1182                    check::PostStmt<ObjCDictionaryLiteral>,
1183                    check::PostStmt<ObjCBoxedExpr> > {
1184     mutable bool Initialized;
1185     mutable Selector ObjectAtIndex;
1186     mutable Selector ObjectAtIndexedSubscript;
1187     mutable Selector NullSelector;
1188 
1189 public:
ObjCNonNilReturnValueChecker()1190   ObjCNonNilReturnValueChecker() : Initialized(false) {}
1191 
1192   ProgramStateRef assumeExprIsNonNull(const Expr *NonNullExpr,
1193                                       ProgramStateRef State,
1194                                       CheckerContext &C) const;
assumeExprIsNonNull(const Expr * E,CheckerContext & C) const1195   void assumeExprIsNonNull(const Expr *E, CheckerContext &C) const {
1196     C.addTransition(assumeExprIsNonNull(E, C.getState(), C));
1197   }
1198 
checkPostStmt(const ObjCArrayLiteral * E,CheckerContext & C) const1199   void checkPostStmt(const ObjCArrayLiteral *E, CheckerContext &C) const {
1200     assumeExprIsNonNull(E, C);
1201   }
checkPostStmt(const ObjCDictionaryLiteral * E,CheckerContext & C) const1202   void checkPostStmt(const ObjCDictionaryLiteral *E, CheckerContext &C) const {
1203     assumeExprIsNonNull(E, C);
1204   }
checkPostStmt(const ObjCBoxedExpr * E,CheckerContext & C) const1205   void checkPostStmt(const ObjCBoxedExpr *E, CheckerContext &C) const {
1206     assumeExprIsNonNull(E, C);
1207   }
1208 
1209   void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
1210 };
1211 }
1212 
1213 ProgramStateRef
assumeExprIsNonNull(const Expr * NonNullExpr,ProgramStateRef State,CheckerContext & C) const1214 ObjCNonNilReturnValueChecker::assumeExprIsNonNull(const Expr *NonNullExpr,
1215                                                   ProgramStateRef State,
1216                                                   CheckerContext &C) const {
1217   SVal Val = State->getSVal(NonNullExpr, C.getLocationContext());
1218   if (Optional<DefinedOrUnknownSVal> DV = Val.getAs<DefinedOrUnknownSVal>())
1219     return State->assume(*DV, true);
1220   return State;
1221 }
1222 
checkPostObjCMessage(const ObjCMethodCall & M,CheckerContext & C) const1223 void ObjCNonNilReturnValueChecker::checkPostObjCMessage(const ObjCMethodCall &M,
1224                                                         CheckerContext &C)
1225                                                         const {
1226   ProgramStateRef State = C.getState();
1227 
1228   if (!Initialized) {
1229     ASTContext &Ctx = C.getASTContext();
1230     ObjectAtIndex = GetUnarySelector("objectAtIndex", Ctx);
1231     ObjectAtIndexedSubscript = GetUnarySelector("objectAtIndexedSubscript", Ctx);
1232     NullSelector = GetNullarySelector("null", Ctx);
1233   }
1234 
1235   // Check the receiver type.
1236   if (const ObjCInterfaceDecl *Interface = M.getReceiverInterface()) {
1237 
1238     // Assume that object returned from '[self init]' or '[super init]' is not
1239     // 'nil' if we are processing an inlined function/method.
1240     //
1241     // A defensive callee will (and should) check if the object returned by
1242     // '[super init]' is 'nil' before doing it's own initialization. However,
1243     // since 'nil' is rarely returned in practice, we should not warn when the
1244     // caller to the defensive constructor uses the object in contexts where
1245     // 'nil' is not accepted.
1246     if (!C.inTopFrame() && M.getDecl() &&
1247         M.getDecl()->getMethodFamily() == OMF_init &&
1248         M.isReceiverSelfOrSuper()) {
1249       State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
1250     }
1251 
1252     FoundationClass Cl = findKnownClass(Interface);
1253 
1254     // Objects returned from
1255     // [NSArray|NSOrderedSet]::[ObjectAtIndex|ObjectAtIndexedSubscript]
1256     // are never 'nil'.
1257     if (Cl == FC_NSArray || Cl == FC_NSOrderedSet) {
1258       Selector Sel = M.getSelector();
1259       if (Sel == ObjectAtIndex || Sel == ObjectAtIndexedSubscript) {
1260         // Go ahead and assume the value is non-nil.
1261         State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
1262       }
1263     }
1264 
1265     // Objects returned from [NSNull null] are not nil.
1266     if (Cl == FC_NSNull) {
1267       if (M.getSelector() == NullSelector) {
1268         // Go ahead and assume the value is non-nil.
1269         State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
1270       }
1271     }
1272   }
1273   C.addTransition(State);
1274 }
1275 
1276 //===----------------------------------------------------------------------===//
1277 // Check registration.
1278 //===----------------------------------------------------------------------===//
1279 
registerNilArgChecker(CheckerManager & mgr)1280 void ento::registerNilArgChecker(CheckerManager &mgr) {
1281   mgr.registerChecker<NilArgChecker>();
1282 }
1283 
registerCFNumberCreateChecker(CheckerManager & mgr)1284 void ento::registerCFNumberCreateChecker(CheckerManager &mgr) {
1285   mgr.registerChecker<CFNumberCreateChecker>();
1286 }
1287 
registerCFRetainReleaseChecker(CheckerManager & mgr)1288 void ento::registerCFRetainReleaseChecker(CheckerManager &mgr) {
1289   mgr.registerChecker<CFRetainReleaseChecker>();
1290 }
1291 
registerClassReleaseChecker(CheckerManager & mgr)1292 void ento::registerClassReleaseChecker(CheckerManager &mgr) {
1293   mgr.registerChecker<ClassReleaseChecker>();
1294 }
1295 
registerVariadicMethodTypeChecker(CheckerManager & mgr)1296 void ento::registerVariadicMethodTypeChecker(CheckerManager &mgr) {
1297   mgr.registerChecker<VariadicMethodTypeChecker>();
1298 }
1299 
registerObjCLoopChecker(CheckerManager & mgr)1300 void ento::registerObjCLoopChecker(CheckerManager &mgr) {
1301   mgr.registerChecker<ObjCLoopChecker>();
1302 }
1303 
1304 void
registerObjCNonNilReturnValueChecker(CheckerManager & mgr)1305 ento::registerObjCNonNilReturnValueChecker(CheckerManager &mgr) {
1306   mgr.registerChecker<ObjCNonNilReturnValueChecker>();
1307 }
1308