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