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