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