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/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
16#include "clang/AST/ASTContext.h"
17#include "clang/AST/DeclObjC.h"
18#include "clang/AST/Expr.h"
19#include "clang/AST/ExprObjC.h"
20#include "clang/AST/StmtObjC.h"
21#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
22#include "clang/Analysis/SelectorExtras.h"
23#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
24#include "clang/StaticAnalyzer/Core/Checker.h"
25#include "clang/StaticAnalyzer/Core/CheckerManager.h"
26#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
27#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
28#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
29#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
30#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
31#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
32#include "llvm/ADT/SmallString.h"
33#include "llvm/ADT/StringMap.h"
34#include "llvm/Support/raw_ostream.h"
35
36using namespace clang;
37using namespace ento;
38using namespace llvm;
39
40namespace {
41class APIMisuse : public BugType {
42public:
43  APIMisuse(const CheckerBase *checker, const char *name)
44      : BugType(checker, name, "API Misuse (Apple)") {}
45};
46} // end anonymous namespace
47
48//===----------------------------------------------------------------------===//
49// Utility functions.
50//===----------------------------------------------------------------------===//
51
52static StringRef GetReceiverInterfaceName(const ObjCMethodCall &msg) {
53  if (const ObjCInterfaceDecl *ID = msg.getReceiverInterface())
54    return ID->getIdentifier()->getName();
55  return StringRef();
56}
57
58enum FoundationClass {
59  FC_None,
60  FC_NSArray,
61  FC_NSDictionary,
62  FC_NSEnumerator,
63  FC_NSNull,
64  FC_NSOrderedSet,
65  FC_NSSet,
66  FC_NSString
67};
68
69static FoundationClass findKnownClass(const ObjCInterfaceDecl *ID,
70                                      bool IncludeSuperclasses = true) {
71  static llvm::StringMap<FoundationClass> Classes;
72  if (Classes.empty()) {
73    Classes["NSArray"] = FC_NSArray;
74    Classes["NSDictionary"] = FC_NSDictionary;
75    Classes["NSEnumerator"] = FC_NSEnumerator;
76    Classes["NSNull"] = FC_NSNull;
77    Classes["NSOrderedSet"] = FC_NSOrderedSet;
78    Classes["NSSet"] = FC_NSSet;
79    Classes["NSString"] = FC_NSString;
80  }
81
82  // FIXME: Should we cache this at all?
83  FoundationClass result = Classes.lookup(ID->getIdentifier()->getName());
84  if (result == FC_None && IncludeSuperclasses)
85    if (const ObjCInterfaceDecl *Super = ID->getSuperClass())
86      return findKnownClass(Super);
87
88  return result;
89}
90
91//===----------------------------------------------------------------------===//
92// NilArgChecker - Check for prohibited nil arguments to ObjC method calls.
93//===----------------------------------------------------------------------===//
94
95namespace {
96  class NilArgChecker : public Checker<check::PreObjCMessage,
97                                       check::PostStmt<ObjCDictionaryLiteral>,
98                                       check::PostStmt<ObjCArrayLiteral> > {
99    mutable std::unique_ptr<APIMisuse> BT;
100
101    mutable llvm::SmallDenseMap<Selector, unsigned, 16> StringSelectors;
102    mutable Selector ArrayWithObjectSel;
103    mutable Selector AddObjectSel;
104    mutable Selector InsertObjectAtIndexSel;
105    mutable Selector ReplaceObjectAtIndexWithObjectSel;
106    mutable Selector SetObjectAtIndexedSubscriptSel;
107    mutable Selector ArrayByAddingObjectSel;
108    mutable Selector DictionaryWithObjectForKeySel;
109    mutable Selector SetObjectForKeySel;
110    mutable Selector SetObjectForKeyedSubscriptSel;
111    mutable Selector RemoveObjectForKeySel;
112
113    void warnIfNilExpr(const Expr *E,
114                       const char *Msg,
115                       CheckerContext &C) const;
116
117    void warnIfNilArg(CheckerContext &C,
118                      const ObjCMethodCall &msg, unsigned Arg,
119                      FoundationClass Class,
120                      bool CanBeSubscript = false) const;
121
122    void generateBugReport(ExplodedNode *N,
123                           StringRef Msg,
124                           SourceRange Range,
125                           const Expr *Expr,
126                           CheckerContext &C) const;
127
128  public:
129    void checkPreObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
130    void checkPostStmt(const ObjCDictionaryLiteral *DL,
131                       CheckerContext &C) const;
132    void checkPostStmt(const ObjCArrayLiteral *AL,
133                       CheckerContext &C) const;
134  };
135} // end anonymous namespace
136
137void NilArgChecker::warnIfNilExpr(const Expr *E,
138                                  const char *Msg,
139                                  CheckerContext &C) const {
140  ProgramStateRef State = C.getState();
141  if (State->isNull(C.getSVal(E)).isConstrainedTrue()) {
142
143    if (ExplodedNode *N = C.generateErrorNode()) {
144      generateBugReport(N, Msg, E->getSourceRange(), E, C);
145    }
146  }
147}
148
149void NilArgChecker::warnIfNilArg(CheckerContext &C,
150                                 const ObjCMethodCall &msg,
151                                 unsigned int Arg,
152                                 FoundationClass Class,
153                                 bool CanBeSubscript) const {
154  // Check if the argument is nil.
155  ProgramStateRef State = C.getState();
156  if (!State->isNull(msg.getArgSVal(Arg)).isConstrainedTrue())
157      return;
158
159  // NOTE: We cannot throw non-fatal errors from warnIfNilExpr,
160  // because it's called multiple times from some callers, so it'd cause
161  // an unwanted state split if two or more non-fatal errors are thrown
162  // within the same checker callback. For now we don't want to, but
163  // it'll need to be fixed if we ever want to.
164  if (ExplodedNode *N = C.generateErrorNode()) {
165    SmallString<128> sbuf;
166    llvm::raw_svector_ostream os(sbuf);
167
168    if (CanBeSubscript && msg.getMessageKind() == OCM_Subscript) {
169
170      if (Class == FC_NSArray) {
171        os << "Array element cannot be nil";
172      } else if (Class == FC_NSDictionary) {
173        if (Arg == 0) {
174          os << "Value stored into '";
175          os << GetReceiverInterfaceName(msg) << "' cannot be nil";
176        } else {
177          assert(Arg == 1);
178          os << "'"<< GetReceiverInterfaceName(msg) << "' key cannot be nil";
179        }
180      } else
181        llvm_unreachable("Missing foundation class for the subscript expr");
182
183    } else {
184      if (Class == FC_NSDictionary) {
185        if (Arg == 0)
186          os << "Value argument ";
187        else {
188          assert(Arg == 1);
189          os << "Key argument ";
190        }
191        os << "to '";
192        msg.getSelector().print(os);
193        os << "' cannot be nil";
194      } else {
195        os << "Argument to '" << GetReceiverInterfaceName(msg) << "' method '";
196        msg.getSelector().print(os);
197        os << "' cannot be nil";
198      }
199    }
200
201    generateBugReport(N, os.str(), msg.getArgSourceRange(Arg),
202                      msg.getArgExpr(Arg), C);
203  }
204}
205
206void NilArgChecker::generateBugReport(ExplodedNode *N,
207                                      StringRef Msg,
208                                      SourceRange Range,
209                                      const Expr *E,
210                                      CheckerContext &C) const {
211  if (!BT)
212    BT.reset(new APIMisuse(this, "nil argument"));
213
214  auto R = std::make_unique<PathSensitiveBugReport>(*BT, Msg, N);
215  R->addRange(Range);
216  bugreporter::trackExpressionValue(N, E, *R);
217  C.emitReport(std::move(R));
218}
219
220void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
221                                        CheckerContext &C) const {
222  const ObjCInterfaceDecl *ID = msg.getReceiverInterface();
223  if (!ID)
224    return;
225
226  FoundationClass Class = findKnownClass(ID);
227
228  static const unsigned InvalidArgIndex = UINT_MAX;
229  unsigned Arg = InvalidArgIndex;
230  bool CanBeSubscript = false;
231
232  if (Class == FC_NSString) {
233    Selector S = msg.getSelector();
234
235    if (S.isUnarySelector())
236      return;
237
238    if (StringSelectors.empty()) {
239      ASTContext &Ctx = C.getASTContext();
240      Selector Sels[] = {
241          getKeywordSelector(Ctx, "caseInsensitiveCompare"),
242          getKeywordSelector(Ctx, "compare"),
243          getKeywordSelector(Ctx, "compare", "options"),
244          getKeywordSelector(Ctx, "compare", "options", "range"),
245          getKeywordSelector(Ctx, "compare", "options", "range", "locale"),
246          getKeywordSelector(Ctx, "componentsSeparatedByCharactersInSet"),
247          getKeywordSelector(Ctx, "initWithFormat"),
248          getKeywordSelector(Ctx, "localizedCaseInsensitiveCompare"),
249          getKeywordSelector(Ctx, "localizedCompare"),
250          getKeywordSelector(Ctx, "localizedStandardCompare"),
251      };
252      for (Selector KnownSel : Sels)
253        StringSelectors[KnownSel] = 0;
254    }
255    auto I = StringSelectors.find(S);
256    if (I == StringSelectors.end())
257      return;
258    Arg = I->second;
259  } else if (Class == FC_NSArray) {
260    Selector S = msg.getSelector();
261
262    if (S.isUnarySelector())
263      return;
264
265    if (ArrayWithObjectSel.isNull()) {
266      ASTContext &Ctx = C.getASTContext();
267      ArrayWithObjectSel = getKeywordSelector(Ctx, "arrayWithObject");
268      AddObjectSel = getKeywordSelector(Ctx, "addObject");
269      InsertObjectAtIndexSel =
270          getKeywordSelector(Ctx, "insertObject", "atIndex");
271      ReplaceObjectAtIndexWithObjectSel =
272          getKeywordSelector(Ctx, "replaceObjectAtIndex", "withObject");
273      SetObjectAtIndexedSubscriptSel =
274          getKeywordSelector(Ctx, "setObject", "atIndexedSubscript");
275      ArrayByAddingObjectSel = getKeywordSelector(Ctx, "arrayByAddingObject");
276    }
277
278    if (S == ArrayWithObjectSel || S == AddObjectSel ||
279        S == InsertObjectAtIndexSel || S == ArrayByAddingObjectSel) {
280      Arg = 0;
281    } else if (S == SetObjectAtIndexedSubscriptSel) {
282      Arg = 0;
283      CanBeSubscript = true;
284    } else if (S == ReplaceObjectAtIndexWithObjectSel) {
285      Arg = 1;
286    }
287  } else if (Class == FC_NSDictionary) {
288    Selector S = msg.getSelector();
289
290    if (S.isUnarySelector())
291      return;
292
293    if (DictionaryWithObjectForKeySel.isNull()) {
294      ASTContext &Ctx = C.getASTContext();
295      DictionaryWithObjectForKeySel =
296          getKeywordSelector(Ctx, "dictionaryWithObject", "forKey");
297      SetObjectForKeySel = getKeywordSelector(Ctx, "setObject", "forKey");
298      SetObjectForKeyedSubscriptSel =
299          getKeywordSelector(Ctx, "setObject", "forKeyedSubscript");
300      RemoveObjectForKeySel = getKeywordSelector(Ctx, "removeObjectForKey");
301    }
302
303    if (S == DictionaryWithObjectForKeySel || S == SetObjectForKeySel) {
304      Arg = 0;
305      warnIfNilArg(C, msg, /* Arg */1, Class);
306    } else if (S == SetObjectForKeyedSubscriptSel) {
307      CanBeSubscript = true;
308      Arg = 1;
309    } else if (S == RemoveObjectForKeySel) {
310      Arg = 0;
311    }
312  }
313
314  // If argument is '0', report a warning.
315  if ((Arg != InvalidArgIndex))
316    warnIfNilArg(C, msg, Arg, Class, CanBeSubscript);
317}
318
319void NilArgChecker::checkPostStmt(const ObjCArrayLiteral *AL,
320                                  CheckerContext &C) const {
321  unsigned NumOfElements = AL->getNumElements();
322  for (unsigned i = 0; i < NumOfElements; ++i) {
323    warnIfNilExpr(AL->getElement(i), "Array element cannot be nil", C);
324  }
325}
326
327void NilArgChecker::checkPostStmt(const ObjCDictionaryLiteral *DL,
328                                  CheckerContext &C) const {
329  unsigned NumOfElements = DL->getNumElements();
330  for (unsigned i = 0; i < NumOfElements; ++i) {
331    ObjCDictionaryElement Element = DL->getKeyValueElement(i);
332    warnIfNilExpr(Element.Key, "Dictionary key cannot be nil", C);
333    warnIfNilExpr(Element.Value, "Dictionary value cannot be nil", C);
334  }
335}
336
337//===----------------------------------------------------------------------===//
338// Checking for mismatched types passed to CFNumberCreate/CFNumberGetValue.
339//===----------------------------------------------------------------------===//
340
341namespace {
342class CFNumberChecker : public Checker< check::PreStmt<CallExpr> > {
343  mutable std::unique_ptr<APIMisuse> BT;
344  mutable IdentifierInfo *ICreate, *IGetValue;
345public:
346  CFNumberChecker() : ICreate(nullptr), IGetValue(nullptr) {}
347
348  void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
349
350private:
351  void EmitError(const TypedRegion* R, const Expr *Ex,
352                uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind);
353};
354} // end anonymous namespace
355
356enum CFNumberType {
357  kCFNumberSInt8Type = 1,
358  kCFNumberSInt16Type = 2,
359  kCFNumberSInt32Type = 3,
360  kCFNumberSInt64Type = 4,
361  kCFNumberFloat32Type = 5,
362  kCFNumberFloat64Type = 6,
363  kCFNumberCharType = 7,
364  kCFNumberShortType = 8,
365  kCFNumberIntType = 9,
366  kCFNumberLongType = 10,
367  kCFNumberLongLongType = 11,
368  kCFNumberFloatType = 12,
369  kCFNumberDoubleType = 13,
370  kCFNumberCFIndexType = 14,
371  kCFNumberNSIntegerType = 15,
372  kCFNumberCGFloatType = 16
373};
374
375static Optional<uint64_t> GetCFNumberSize(ASTContext &Ctx, uint64_t i) {
376  static const unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 };
377
378  if (i < kCFNumberCharType)
379    return FixedSize[i-1];
380
381  QualType T;
382
383  switch (i) {
384    case kCFNumberCharType:     T = Ctx.CharTy;     break;
385    case kCFNumberShortType:    T = Ctx.ShortTy;    break;
386    case kCFNumberIntType:      T = Ctx.IntTy;      break;
387    case kCFNumberLongType:     T = Ctx.LongTy;     break;
388    case kCFNumberLongLongType: T = Ctx.LongLongTy; break;
389    case kCFNumberFloatType:    T = Ctx.FloatTy;    break;
390    case kCFNumberDoubleType:   T = Ctx.DoubleTy;   break;
391    case kCFNumberCFIndexType:
392    case kCFNumberNSIntegerType:
393    case kCFNumberCGFloatType:
394      // FIXME: We need a way to map from names to Type*.
395    default:
396      return None;
397  }
398
399  return Ctx.getTypeSize(T);
400}
401
402#if 0
403static const char* GetCFNumberTypeStr(uint64_t i) {
404  static const char* Names[] = {
405    "kCFNumberSInt8Type",
406    "kCFNumberSInt16Type",
407    "kCFNumberSInt32Type",
408    "kCFNumberSInt64Type",
409    "kCFNumberFloat32Type",
410    "kCFNumberFloat64Type",
411    "kCFNumberCharType",
412    "kCFNumberShortType",
413    "kCFNumberIntType",
414    "kCFNumberLongType",
415    "kCFNumberLongLongType",
416    "kCFNumberFloatType",
417    "kCFNumberDoubleType",
418    "kCFNumberCFIndexType",
419    "kCFNumberNSIntegerType",
420    "kCFNumberCGFloatType"
421  };
422
423  return i <= kCFNumberCGFloatType ? Names[i-1] : "Invalid CFNumberType";
424}
425#endif
426
427void CFNumberChecker::checkPreStmt(const CallExpr *CE,
428                                         CheckerContext &C) const {
429  ProgramStateRef state = C.getState();
430  const FunctionDecl *FD = C.getCalleeDecl(CE);
431  if (!FD)
432    return;
433
434  ASTContext &Ctx = C.getASTContext();
435  if (!ICreate) {
436    ICreate = &Ctx.Idents.get("CFNumberCreate");
437    IGetValue = &Ctx.Idents.get("CFNumberGetValue");
438  }
439  if (!(FD->getIdentifier() == ICreate || FD->getIdentifier() == IGetValue) ||
440      CE->getNumArgs() != 3)
441    return;
442
443  // Get the value of the "theType" argument.
444  SVal TheTypeVal = C.getSVal(CE->getArg(1));
445
446  // FIXME: We really should allow ranges of valid theType values, and
447  //   bifurcate the state appropriately.
448  Optional<nonloc::ConcreteInt> V = TheTypeVal.getAs<nonloc::ConcreteInt>();
449  if (!V)
450    return;
451
452  uint64_t NumberKind = V->getValue().getLimitedValue();
453  Optional<uint64_t> OptCFNumberSize = GetCFNumberSize(Ctx, NumberKind);
454
455  // FIXME: In some cases we can emit an error.
456  if (!OptCFNumberSize)
457    return;
458
459  uint64_t CFNumberSize = *OptCFNumberSize;
460
461  // Look at the value of the integer being passed by reference.  Essentially
462  // we want to catch cases where the value passed in is not equal to the
463  // size of the type being created.
464  SVal TheValueExpr = C.getSVal(CE->getArg(2));
465
466  // FIXME: Eventually we should handle arbitrary locations.  We can do this
467  //  by having an enhanced memory model that does low-level typing.
468  Optional<loc::MemRegionVal> LV = TheValueExpr.getAs<loc::MemRegionVal>();
469  if (!LV)
470    return;
471
472  const TypedValueRegion* R = dyn_cast<TypedValueRegion>(LV->stripCasts());
473  if (!R)
474    return;
475
476  QualType T = Ctx.getCanonicalType(R->getValueType());
477
478  // FIXME: If the pointee isn't an integer type, should we flag a warning?
479  //  People can do weird stuff with pointers.
480
481  if (!T->isIntegralOrEnumerationType())
482    return;
483
484  uint64_t PrimitiveTypeSize = Ctx.getTypeSize(T);
485
486  if (PrimitiveTypeSize == CFNumberSize)
487    return;
488
489  // FIXME: We can actually create an abstract "CFNumber" object that has
490  //  the bits initialized to the provided values.
491  ExplodedNode *N = C.generateNonFatalErrorNode();
492  if (N) {
493    SmallString<128> sbuf;
494    llvm::raw_svector_ostream os(sbuf);
495    bool isCreate = (FD->getIdentifier() == ICreate);
496
497    if (isCreate) {
498      os << (PrimitiveTypeSize == 8 ? "An " : "A ")
499         << PrimitiveTypeSize << "-bit integer is used to initialize a "
500         << "CFNumber object that represents "
501         << (CFNumberSize == 8 ? "an " : "a ")
502         << CFNumberSize << "-bit integer; ";
503    } else {
504      os << "A CFNumber object that represents "
505         << (CFNumberSize == 8 ? "an " : "a ")
506         << CFNumberSize << "-bit integer is used to initialize "
507         << (PrimitiveTypeSize == 8 ? "an " : "a ")
508         << PrimitiveTypeSize << "-bit integer; ";
509    }
510
511    if (PrimitiveTypeSize < CFNumberSize)
512      os << (CFNumberSize - PrimitiveTypeSize)
513      << " bits of the CFNumber value will "
514      << (isCreate ? "be garbage." : "overwrite adjacent storage.");
515    else
516      os << (PrimitiveTypeSize - CFNumberSize)
517      << " bits of the integer value will be "
518      << (isCreate ? "lost." : "garbage.");
519
520    if (!BT)
521      BT.reset(new APIMisuse(this, "Bad use of CFNumber APIs"));
522
523    auto report = std::make_unique<PathSensitiveBugReport>(*BT, os.str(), N);
524    report->addRange(CE->getArg(2)->getSourceRange());
525    C.emitReport(std::move(report));
526  }
527}
528
529//===----------------------------------------------------------------------===//
530// CFRetain/CFRelease/CFMakeCollectable/CFAutorelease checking for null arguments.
531//===----------------------------------------------------------------------===//
532
533namespace {
534class CFRetainReleaseChecker : public Checker<check::PreCall> {
535  mutable APIMisuse BT{this, "null passed to CF memory management function"};
536  CallDescription CFRetain{"CFRetain", 1},
537                  CFRelease{"CFRelease", 1},
538                  CFMakeCollectable{"CFMakeCollectable", 1},
539                  CFAutorelease{"CFAutorelease", 1};
540
541public:
542  void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
543};
544} // end anonymous namespace
545
546void CFRetainReleaseChecker::checkPreCall(const CallEvent &Call,
547                                          CheckerContext &C) const {
548  // TODO: Make this check part of CallDescription.
549  if (!Call.isGlobalCFunction())
550    return;
551
552  // Check if we called CFRetain/CFRelease/CFMakeCollectable/CFAutorelease.
553  if (!(Call.isCalled(CFRetain) || Call.isCalled(CFRelease) ||
554        Call.isCalled(CFMakeCollectable) || Call.isCalled(CFAutorelease)))
555    return;
556
557  // Get the argument's value.
558  SVal ArgVal = Call.getArgSVal(0);
559  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
593namespace {
594class 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
601public:
602  void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
603};
604} // end anonymous namespace
605
606void 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
649namespace {
650class 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
661public:
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.
668bool
669VariadicMethodTypeChecker::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
714void 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  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 (msg.getArgSVal(I).getAs<loc::ConcreteInt>())
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.hasValue())
772      errorNode = C.generateNonFatalErrorNode();
773
774    if (!errorNode.getValue())
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 = std::make_unique<PathSensitiveBugReport>(*BT, os.str(),
792                                                      errorNode.getValue());
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.
804REGISTER_MAP_WITH_PROGRAMSTATE(ContainerCountMap, SymbolRef, SymbolRef)
805REGISTER_MAP_WITH_PROGRAMSTATE(ContainerNonEmptyMap, SymbolRef, bool)
806
807namespace {
808class 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
818public:
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
830static 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.
855static 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  Optional<DefinedSVal> KnownCollection = CollectionVal.getAs<DefinedSVal>();
863  if (!KnownCollection)
864    return State;
865
866  ProgramStateRef StNonNil, StNil;
867  std::tie(StNonNil, StNil) = State->assume(*KnownCollection);
868  if (StNil && !StNonNil) {
869    // The collection is nil. This path is infeasible.
870    return nullptr;
871  }
872
873  return StNonNil;
874}
875
876/// Assumes that the collection elements are non-nil.
877///
878/// This only applies if the collection is one of those known not to contain
879/// nil values.
880static ProgramStateRef checkElementNonNil(CheckerContext &C,
881                                          ProgramStateRef State,
882                                          const ObjCForCollectionStmt *FCS) {
883  if (!State)
884    return nullptr;
885
886  // See if the collection is one where we /know/ the elements are non-nil.
887  if (!isKnownNonNilCollectionType(FCS->getCollection()->getType()))
888    return State;
889
890  const LocationContext *LCtx = C.getLocationContext();
891  const Stmt *Element = FCS->getElement();
892
893  // FIXME: Copied from ExprEngineObjC.
894  Optional<Loc> ElementLoc;
895  if (const DeclStmt *DS = dyn_cast<DeclStmt>(Element)) {
896    const VarDecl *ElemDecl = cast<VarDecl>(DS->getSingleDecl());
897    assert(ElemDecl->getInit() == nullptr);
898    ElementLoc = State->getLValue(ElemDecl, LCtx);
899  } else {
900    ElementLoc = State->getSVal(Element, LCtx).getAs<Loc>();
901  }
902
903  if (!ElementLoc)
904    return State;
905
906  // Go ahead and assume the value is non-nil.
907  SVal Val = State->getSVal(*ElementLoc);
908  return State->assume(Val.castAs<DefinedOrUnknownSVal>(), true);
909}
910
911/// Returns NULL state if the collection is known to contain elements
912/// (or is known not to contain elements if the Assumption parameter is false.)
913static ProgramStateRef
914assumeCollectionNonEmpty(CheckerContext &C, ProgramStateRef State,
915                         SymbolRef CollectionS, bool Assumption) {
916  if (!State || !CollectionS)
917    return State;
918
919  const SymbolRef *CountS = State->get<ContainerCountMap>(CollectionS);
920  if (!CountS) {
921    const bool *KnownNonEmpty = State->get<ContainerNonEmptyMap>(CollectionS);
922    if (!KnownNonEmpty)
923      return State->set<ContainerNonEmptyMap>(CollectionS, Assumption);
924    return (Assumption == *KnownNonEmpty) ? State : nullptr;
925  }
926
927  SValBuilder &SvalBuilder = C.getSValBuilder();
928  SVal CountGreaterThanZeroVal =
929    SvalBuilder.evalBinOp(State, BO_GT,
930                          nonloc::SymbolVal(*CountS),
931                          SvalBuilder.makeIntVal(0, (*CountS)->getType()),
932                          SvalBuilder.getConditionType());
933  Optional<DefinedSVal> CountGreaterThanZero =
934    CountGreaterThanZeroVal.getAs<DefinedSVal>();
935  if (!CountGreaterThanZero) {
936    // The SValBuilder cannot construct a valid SVal for this condition.
937    // This means we cannot properly reason about it.
938    return State;
939  }
940
941  return State->assume(*CountGreaterThanZero, Assumption);
942}
943
944static ProgramStateRef
945assumeCollectionNonEmpty(CheckerContext &C, ProgramStateRef State,
946                         const ObjCForCollectionStmt *FCS,
947                         bool Assumption) {
948  if (!State)
949    return nullptr;
950
951  SymbolRef CollectionS = C.getSVal(FCS->getCollection()).getAsSymbol();
952  return assumeCollectionNonEmpty(C, State, CollectionS, Assumption);
953}
954
955/// If the fist block edge is a back edge, we are reentering the loop.
956static bool alreadyExecutedAtLeastOneLoopIteration(const ExplodedNode *N,
957                                             const ObjCForCollectionStmt *FCS) {
958  if (!N)
959    return false;
960
961  ProgramPoint P = N->getLocation();
962  if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) {
963    return BE->getSrc()->getLoopTarget() == FCS;
964  }
965
966  // Keep looking for a block edge.
967  for (ExplodedNode::const_pred_iterator I = N->pred_begin(),
968                                         E = N->pred_end(); I != E; ++I) {
969    if (alreadyExecutedAtLeastOneLoopIteration(*I, FCS))
970      return true;
971  }
972
973  return false;
974}
975
976void ObjCLoopChecker::checkPostStmt(const ObjCForCollectionStmt *FCS,
977                                    CheckerContext &C) const {
978  ProgramStateRef State = C.getState();
979
980  // Check if this is the branch for the end of the loop.
981  if (!ExprEngine::hasMoreIteration(State, FCS, C.getLocationContext())) {
982    if (!alreadyExecutedAtLeastOneLoopIteration(C.getPredecessor(), FCS))
983      State = assumeCollectionNonEmpty(C, State, FCS, /*Assumption*/false);
984
985  // Otherwise, this is a branch that goes through the loop body.
986  } else {
987    State = checkCollectionNonNil(C, State, FCS);
988    State = checkElementNonNil(C, State, FCS);
989    State = assumeCollectionNonEmpty(C, State, FCS, /*Assumption*/true);
990  }
991
992  if (!State)
993    C.generateSink(C.getState(), C.getPredecessor());
994  else if (State != C.getState())
995    C.addTransition(State);
996}
997
998bool ObjCLoopChecker::isCollectionCountMethod(const ObjCMethodCall &M,
999                                              CheckerContext &C) const {
1000  Selector S = M.getSelector();
1001  // Initialize the identifiers on first use.
1002  if (!CountSelectorII)
1003    CountSelectorII = &C.getASTContext().Idents.get("count");
1004
1005  // If the method returns collection count, record the value.
1006  return S.isUnarySelector() &&
1007         (S.getIdentifierInfoForSlot(0) == CountSelectorII);
1008}
1009
1010void ObjCLoopChecker::checkPostObjCMessage(const ObjCMethodCall &M,
1011                                           CheckerContext &C) const {
1012  if (!M.isInstanceMessage())
1013    return;
1014
1015  const ObjCInterfaceDecl *ClassID = M.getReceiverInterface();
1016  if (!ClassID)
1017    return;
1018
1019  FoundationClass Class = findKnownClass(ClassID);
1020  if (Class != FC_NSDictionary &&
1021      Class != FC_NSArray &&
1022      Class != FC_NSSet &&
1023      Class != FC_NSOrderedSet)
1024    return;
1025
1026  SymbolRef ContainerS = M.getReceiverSVal().getAsSymbol();
1027  if (!ContainerS)
1028    return;
1029
1030  // If we are processing a call to "count", get the symbolic value returned by
1031  // a call to "count" and add it to the map.
1032  if (!isCollectionCountMethod(M, C))
1033    return;
1034
1035  const Expr *MsgExpr = M.getOriginExpr();
1036  SymbolRef CountS = C.getSVal(MsgExpr).getAsSymbol();
1037  if (CountS) {
1038    ProgramStateRef State = C.getState();
1039
1040    C.getSymbolManager().addSymbolDependency(ContainerS, CountS);
1041    State = State->set<ContainerCountMap>(ContainerS, CountS);
1042
1043    if (const bool *NonEmpty = State->get<ContainerNonEmptyMap>(ContainerS)) {
1044      State = State->remove<ContainerNonEmptyMap>(ContainerS);
1045      State = assumeCollectionNonEmpty(C, State, ContainerS, *NonEmpty);
1046    }
1047
1048    C.addTransition(State);
1049  }
1050}
1051
1052static SymbolRef getMethodReceiverIfKnownImmutable(const CallEvent *Call) {
1053  const ObjCMethodCall *Message = dyn_cast_or_null<ObjCMethodCall>(Call);
1054  if (!Message)
1055    return nullptr;
1056
1057  const ObjCMethodDecl *MD = Message->getDecl();
1058  if (!MD)
1059    return nullptr;
1060
1061  const ObjCInterfaceDecl *StaticClass;
1062  if (isa<ObjCProtocolDecl>(MD->getDeclContext())) {
1063    // We can't find out where the method was declared without doing more work.
1064    // Instead, see if the receiver is statically typed as a known immutable
1065    // collection.
1066    StaticClass = Message->getOriginExpr()->getReceiverInterface();
1067  } else {
1068    StaticClass = MD->getClassInterface();
1069  }
1070
1071  if (!StaticClass)
1072    return nullptr;
1073
1074  switch (findKnownClass(StaticClass, /*IncludeSuper=*/false)) {
1075  case FC_None:
1076    return nullptr;
1077  case FC_NSArray:
1078  case FC_NSDictionary:
1079  case FC_NSEnumerator:
1080  case FC_NSNull:
1081  case FC_NSOrderedSet:
1082  case FC_NSSet:
1083  case FC_NSString:
1084    break;
1085  }
1086
1087  return Message->getReceiverSVal().getAsSymbol();
1088}
1089
1090ProgramStateRef
1091ObjCLoopChecker::checkPointerEscape(ProgramStateRef State,
1092                                    const InvalidatedSymbols &Escaped,
1093                                    const CallEvent *Call,
1094                                    PointerEscapeKind Kind) const {
1095  SymbolRef ImmutableReceiver = getMethodReceiverIfKnownImmutable(Call);
1096
1097  // Remove the invalidated symbols form the collection count map.
1098  for (InvalidatedSymbols::const_iterator I = Escaped.begin(),
1099       E = Escaped.end();
1100       I != E; ++I) {
1101    SymbolRef Sym = *I;
1102
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
1118void 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 (ContainerCountMapTy::iterator I = Tracked.begin(),
1125                                     E = Tracked.end(); I != E; ++I) {
1126    SymbolRef Sym = I->first;
1127    if (SymReaper.isDead(Sym)) {
1128      State = State->remove<ContainerCountMap>(Sym);
1129      State = State->remove<ContainerNonEmptyMap>(Sym);
1130    }
1131  }
1132
1133  C.addTransition(State);
1134}
1135
1136namespace {
1137/// \class ObjCNonNilReturnValueChecker
1138/// The checker restricts the return values of APIs known to
1139/// never (or almost never) return 'nil'.
1140class ObjCNonNilReturnValueChecker
1141  : public Checker<check::PostObjCMessage,
1142                   check::PostStmt<ObjCArrayLiteral>,
1143                   check::PostStmt<ObjCDictionaryLiteral>,
1144                   check::PostStmt<ObjCBoxedExpr> > {
1145    mutable bool Initialized;
1146    mutable Selector ObjectAtIndex;
1147    mutable Selector ObjectAtIndexedSubscript;
1148    mutable Selector NullSelector;
1149
1150public:
1151  ObjCNonNilReturnValueChecker() : Initialized(false) {}
1152
1153  ProgramStateRef assumeExprIsNonNull(const Expr *NonNullExpr,
1154                                      ProgramStateRef State,
1155                                      CheckerContext &C) const;
1156  void assumeExprIsNonNull(const Expr *E, CheckerContext &C) const {
1157    C.addTransition(assumeExprIsNonNull(E, C.getState(), C));
1158  }
1159
1160  void checkPostStmt(const ObjCArrayLiteral *E, CheckerContext &C) const {
1161    assumeExprIsNonNull(E, C);
1162  }
1163  void checkPostStmt(const ObjCDictionaryLiteral *E, CheckerContext &C) const {
1164    assumeExprIsNonNull(E, C);
1165  }
1166  void checkPostStmt(const ObjCBoxedExpr *E, CheckerContext &C) const {
1167    assumeExprIsNonNull(E, C);
1168  }
1169
1170  void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
1171};
1172} // end anonymous namespace
1173
1174ProgramStateRef
1175ObjCNonNilReturnValueChecker::assumeExprIsNonNull(const Expr *NonNullExpr,
1176                                                  ProgramStateRef State,
1177                                                  CheckerContext &C) const {
1178  SVal Val = C.getSVal(NonNullExpr);
1179  if (Optional<DefinedOrUnknownSVal> DV = Val.getAs<DefinedOrUnknownSVal>())
1180    return State->assume(*DV, true);
1181  return State;
1182}
1183
1184void ObjCNonNilReturnValueChecker::checkPostObjCMessage(const ObjCMethodCall &M,
1185                                                        CheckerContext &C)
1186                                                        const {
1187  ProgramStateRef State = C.getState();
1188
1189  if (!Initialized) {
1190    ASTContext &Ctx = C.getASTContext();
1191    ObjectAtIndex = GetUnarySelector("objectAtIndex", Ctx);
1192    ObjectAtIndexedSubscript = GetUnarySelector("objectAtIndexedSubscript", Ctx);
1193    NullSelector = GetNullarySelector("null", Ctx);
1194  }
1195
1196  // Check the receiver type.
1197  if (const ObjCInterfaceDecl *Interface = M.getReceiverInterface()) {
1198
1199    // Assume that object returned from '[self init]' or '[super init]' is not
1200    // 'nil' if we are processing an inlined function/method.
1201    //
1202    // A defensive callee will (and should) check if the object returned by
1203    // '[super init]' is 'nil' before doing it's own initialization. However,
1204    // since 'nil' is rarely returned in practice, we should not warn when the
1205    // caller to the defensive constructor uses the object in contexts where
1206    // 'nil' is not accepted.
1207    if (!C.inTopFrame() && M.getDecl() &&
1208        M.getDecl()->getMethodFamily() == OMF_init &&
1209        M.isReceiverSelfOrSuper()) {
1210      State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
1211    }
1212
1213    FoundationClass Cl = findKnownClass(Interface);
1214
1215    // Objects returned from
1216    // [NSArray|NSOrderedSet]::[ObjectAtIndex|ObjectAtIndexedSubscript]
1217    // are never 'nil'.
1218    if (Cl == FC_NSArray || Cl == FC_NSOrderedSet) {
1219      Selector Sel = M.getSelector();
1220      if (Sel == ObjectAtIndex || Sel == ObjectAtIndexedSubscript) {
1221        // Go ahead and assume the value is non-nil.
1222        State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
1223      }
1224    }
1225
1226    // Objects returned from [NSNull null] are not nil.
1227    if (Cl == FC_NSNull) {
1228      if (M.getSelector() == NullSelector) {
1229        // Go ahead and assume the value is non-nil.
1230        State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
1231      }
1232    }
1233  }
1234  C.addTransition(State);
1235}
1236
1237//===----------------------------------------------------------------------===//
1238// Check registration.
1239//===----------------------------------------------------------------------===//
1240
1241void ento::registerNilArgChecker(CheckerManager &mgr) {
1242  mgr.registerChecker<NilArgChecker>();
1243}
1244
1245bool ento::shouldRegisterNilArgChecker(const CheckerManager &mgr) {
1246  return true;
1247}
1248
1249void ento::registerCFNumberChecker(CheckerManager &mgr) {
1250  mgr.registerChecker<CFNumberChecker>();
1251}
1252
1253bool ento::shouldRegisterCFNumberChecker(const CheckerManager &mgr) {
1254  return true;
1255}
1256
1257void ento::registerCFRetainReleaseChecker(CheckerManager &mgr) {
1258  mgr.registerChecker<CFRetainReleaseChecker>();
1259}
1260
1261bool ento::shouldRegisterCFRetainReleaseChecker(const CheckerManager &mgr) {
1262  return true;
1263}
1264
1265void ento::registerClassReleaseChecker(CheckerManager &mgr) {
1266  mgr.registerChecker<ClassReleaseChecker>();
1267}
1268
1269bool ento::shouldRegisterClassReleaseChecker(const CheckerManager &mgr) {
1270  return true;
1271}
1272
1273void ento::registerVariadicMethodTypeChecker(CheckerManager &mgr) {
1274  mgr.registerChecker<VariadicMethodTypeChecker>();
1275}
1276
1277bool ento::shouldRegisterVariadicMethodTypeChecker(const CheckerManager &mgr) {
1278  return true;
1279}
1280
1281void ento::registerObjCLoopChecker(CheckerManager &mgr) {
1282  mgr.registerChecker<ObjCLoopChecker>();
1283}
1284
1285bool ento::shouldRegisterObjCLoopChecker(const CheckerManager &mgr) {
1286  return true;
1287}
1288
1289void ento::registerObjCNonNilReturnValueChecker(CheckerManager &mgr) {
1290  mgr.registerChecker<ObjCNonNilReturnValueChecker>();
1291}
1292
1293bool ento::shouldRegisterObjCNonNilReturnValueChecker(const CheckerManager &mgr) {
1294  return true;
1295}
1296