BasicObjCFoundationChecks.cpp revision 1533833e21ae5b3f5f39b168b3fbac109ee77008
1//== BasicObjCFoundationChecks.cpp - Simple Apple-Foundation checks -*- C++ -*--
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10//  This file defines BasicObjCFoundationChecks, a class that encapsulates
11//  a set of simple checks to run on Objective-C code using Apple's Foundation
12//  classes.
13//
14//===----------------------------------------------------------------------===//
15
16#include "ClangSACheckers.h"
17#include "clang/AST/ASTContext.h"
18#include "clang/AST/DeclObjC.h"
19#include "clang/AST/Expr.h"
20#include "clang/AST/ExprObjC.h"
21#include "clang/AST/StmtObjC.h"
22#include "clang/Analysis/DomainSpecific/CocoaConventions.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;
38
39namespace {
40class APIMisuse : public BugType {
41public:
42  APIMisuse(const char* name) : BugType(name, "API Misuse (Apple)") {}
43};
44} // end anonymous namespace
45
46//===----------------------------------------------------------------------===//
47// Utility functions.
48//===----------------------------------------------------------------------===//
49
50static StringRef GetReceiverInterfaceName(const ObjCMethodCall &msg) {
51  if (const ObjCInterfaceDecl *ID = msg.getReceiverInterface())
52    return ID->getIdentifier()->getName();
53  return StringRef();
54}
55
56enum FoundationClass {
57  FC_None,
58  FC_NSArray,
59  FC_NSDictionary,
60  FC_NSEnumerator,
61  FC_NSOrderedSet,
62  FC_NSSet,
63  FC_NSString
64};
65
66static FoundationClass findKnownClass(const ObjCInterfaceDecl *ID) {
67  static llvm::StringMap<FoundationClass> Classes;
68  if (Classes.empty()) {
69    Classes["NSArray"] = FC_NSArray;
70    Classes["NSDictionary"] = FC_NSDictionary;
71    Classes["NSEnumerator"] = FC_NSEnumerator;
72    Classes["NSOrderedSet"] = FC_NSOrderedSet;
73    Classes["NSSet"] = FC_NSSet;
74    Classes["NSString"] = FC_NSString;
75  }
76
77  // FIXME: Should we cache this at all?
78  FoundationClass result = Classes.lookup(ID->getIdentifier()->getName());
79  if (result == FC_None)
80    if (const ObjCInterfaceDecl *Super = ID->getSuperClass())
81      return findKnownClass(Super);
82
83  return result;
84}
85
86//===----------------------------------------------------------------------===//
87// NilArgChecker - Check for prohibited nil arguments to ObjC method calls.
88//===----------------------------------------------------------------------===//
89
90namespace {
91  class NilArgChecker : public Checker<check::PreObjCMessage> {
92    mutable OwningPtr<APIMisuse> BT;
93
94    void WarnIfNilArg(CheckerContext &C,
95                    const ObjCMethodCall &msg, unsigned Arg,
96                    FoundationClass Class,
97                    bool CanBeSubscript = false) const;
98
99  public:
100    void checkPreObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
101  };
102}
103
104void NilArgChecker::WarnIfNilArg(CheckerContext &C,
105                                 const ObjCMethodCall &msg,
106                                 unsigned int Arg,
107                                 FoundationClass Class,
108                                 bool CanBeSubscript) const {
109  // Check if the argument is nil.
110  ProgramStateRef State = C.getState();
111  if (!State->isNull(msg.getArgSVal(Arg)).isConstrainedTrue())
112      return;
113
114  if (!BT)
115    BT.reset(new APIMisuse("nil argument"));
116
117  if (ExplodedNode *N = C.generateSink()) {
118    SmallString<128> sbuf;
119    llvm::raw_svector_ostream os(sbuf);
120
121    if (CanBeSubscript && msg.getMessageKind() == OCM_Subscript) {
122
123      if (Class == FC_NSArray) {
124        os << "Array element cannot be nil";
125      } else if (Class == FC_NSDictionary) {
126        if (Arg == 0)
127          os << "Dictionary object cannot be nil";
128        else {
129          assert(Arg == 1);
130          os << "Dictionary key cannot be nil";
131        }
132      } else
133        llvm_unreachable("Missing foundation class for the subscript expr");
134
135    } else {
136      os << "Argument to '" << GetReceiverInterfaceName(msg) << "' method '"
137      << msg.getSelector().getAsString() << "' cannot be nil";
138    }
139
140    BugReport *R = new BugReport(*BT, os.str(), N);
141    R->addRange(msg.getArgSourceRange(Arg));
142    bugreporter::trackNullOrUndefValue(N, msg.getArgExpr(Arg), *R);
143    C.emitReport(R);
144  }
145}
146
147void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
148                                        CheckerContext &C) const {
149  const ObjCInterfaceDecl *ID = msg.getReceiverInterface();
150  if (!ID)
151    return;
152
153  FoundationClass Class = findKnownClass(ID);
154
155  static const unsigned InvalidArgIndex = UINT_MAX;
156  unsigned Arg = InvalidArgIndex;
157  bool CanBeSubscript = false;
158
159  if (Class == FC_NSString) {
160    Selector S = msg.getSelector();
161
162    if (S.isUnarySelector())
163      return;
164
165    // FIXME: This is going to be really slow doing these checks with
166    //  lexical comparisons.
167
168    std::string NameStr = S.getAsString();
169    StringRef Name(NameStr);
170    assert(!Name.empty());
171
172    // FIXME: Checking for initWithFormat: will not work in most cases
173    //  yet because [NSString alloc] returns id, not NSString*.  We will
174    //  need support for tracking expected-type information in the analyzer
175    //  to find these errors.
176    if (Name == "caseInsensitiveCompare:" ||
177        Name == "compare:" ||
178        Name == "compare:options:" ||
179        Name == "compare:options:range:" ||
180        Name == "compare:options:range:locale:" ||
181        Name == "componentsSeparatedByCharactersInSet:" ||
182        Name == "initWithFormat:") {
183      Arg = 0;
184    }
185  } else if (Class == FC_NSArray) {
186    Selector S = msg.getSelector();
187
188    if (S.isUnarySelector())
189      return;
190
191    if (S.getNameForSlot(0).equals("addObject")) {
192      Arg = 0;
193    } else if (S.getNameForSlot(0).equals("insertObject") &&
194               S.getNameForSlot(1).equals("atIndex")) {
195      Arg = 0;
196    } else if (S.getNameForSlot(0).equals("replaceObjectAtIndex") &&
197               S.getNameForSlot(1).equals("withObject")) {
198      Arg = 1;
199    } else if (S.getNameForSlot(0).equals("setObject") &&
200               S.getNameForSlot(1).equals("atIndexedSubscript")) {
201      Arg = 0;
202      CanBeSubscript = true;
203    } else if (S.getNameForSlot(0).equals("arrayByAddingObject")) {
204      Arg = 0;
205    }
206  } else if (Class == FC_NSDictionary) {
207    Selector S = msg.getSelector();
208
209    if (S.isUnarySelector())
210      return;
211
212    if (S.getNameForSlot(0).equals("dictionaryWithObject") &&
213        S.getNameForSlot(1).equals("forKey")) {
214      Arg = 0;
215      WarnIfNilArg(C, msg, /* Arg */1, Class);
216    } else if (S.getNameForSlot(0).equals("setObject") &&
217               S.getNameForSlot(1).equals("forKey")) {
218      Arg = 0;
219      WarnIfNilArg(C, msg, /* Arg */1, Class);
220    } else if (S.getNameForSlot(0).equals("setObject") &&
221               S.getNameForSlot(1).equals("forKeyedSubscript")) {
222      CanBeSubscript = true;
223      Arg = 0;
224      WarnIfNilArg(C, msg, /* Arg */1, Class, CanBeSubscript);
225    } else if (S.getNameForSlot(0).equals("removeObjectForKey")) {
226      Arg = 0;
227    }
228  }
229
230
231  // If argument is '0', report a warning.
232  if ((Arg != InvalidArgIndex))
233    WarnIfNilArg(C, msg, Arg, Class, CanBeSubscript);
234
235}
236
237//===----------------------------------------------------------------------===//
238// Error reporting.
239//===----------------------------------------------------------------------===//
240
241namespace {
242class CFNumberCreateChecker : public Checker< check::PreStmt<CallExpr> > {
243  mutable OwningPtr<APIMisuse> BT;
244  mutable IdentifierInfo* II;
245public:
246  CFNumberCreateChecker() : II(0) {}
247
248  void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
249
250private:
251  void EmitError(const TypedRegion* R, const Expr *Ex,
252                uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind);
253};
254} // end anonymous namespace
255
256enum CFNumberType {
257  kCFNumberSInt8Type = 1,
258  kCFNumberSInt16Type = 2,
259  kCFNumberSInt32Type = 3,
260  kCFNumberSInt64Type = 4,
261  kCFNumberFloat32Type = 5,
262  kCFNumberFloat64Type = 6,
263  kCFNumberCharType = 7,
264  kCFNumberShortType = 8,
265  kCFNumberIntType = 9,
266  kCFNumberLongType = 10,
267  kCFNumberLongLongType = 11,
268  kCFNumberFloatType = 12,
269  kCFNumberDoubleType = 13,
270  kCFNumberCFIndexType = 14,
271  kCFNumberNSIntegerType = 15,
272  kCFNumberCGFloatType = 16
273};
274
275static Optional<uint64_t> GetCFNumberSize(ASTContext &Ctx, uint64_t i) {
276  static const unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 };
277
278  if (i < kCFNumberCharType)
279    return FixedSize[i-1];
280
281  QualType T;
282
283  switch (i) {
284    case kCFNumberCharType:     T = Ctx.CharTy;     break;
285    case kCFNumberShortType:    T = Ctx.ShortTy;    break;
286    case kCFNumberIntType:      T = Ctx.IntTy;      break;
287    case kCFNumberLongType:     T = Ctx.LongTy;     break;
288    case kCFNumberLongLongType: T = Ctx.LongLongTy; break;
289    case kCFNumberFloatType:    T = Ctx.FloatTy;    break;
290    case kCFNumberDoubleType:   T = Ctx.DoubleTy;   break;
291    case kCFNumberCFIndexType:
292    case kCFNumberNSIntegerType:
293    case kCFNumberCGFloatType:
294      // FIXME: We need a way to map from names to Type*.
295    default:
296      return None;
297  }
298
299  return Ctx.getTypeSize(T);
300}
301
302#if 0
303static const char* GetCFNumberTypeStr(uint64_t i) {
304  static const char* Names[] = {
305    "kCFNumberSInt8Type",
306    "kCFNumberSInt16Type",
307    "kCFNumberSInt32Type",
308    "kCFNumberSInt64Type",
309    "kCFNumberFloat32Type",
310    "kCFNumberFloat64Type",
311    "kCFNumberCharType",
312    "kCFNumberShortType",
313    "kCFNumberIntType",
314    "kCFNumberLongType",
315    "kCFNumberLongLongType",
316    "kCFNumberFloatType",
317    "kCFNumberDoubleType",
318    "kCFNumberCFIndexType",
319    "kCFNumberNSIntegerType",
320    "kCFNumberCGFloatType"
321  };
322
323  return i <= kCFNumberCGFloatType ? Names[i-1] : "Invalid CFNumberType";
324}
325#endif
326
327void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE,
328                                         CheckerContext &C) const {
329  ProgramStateRef state = C.getState();
330  const FunctionDecl *FD = C.getCalleeDecl(CE);
331  if (!FD)
332    return;
333
334  ASTContext &Ctx = C.getASTContext();
335  if (!II)
336    II = &Ctx.Idents.get("CFNumberCreate");
337
338  if (FD->getIdentifier() != II || CE->getNumArgs() != 3)
339    return;
340
341  // Get the value of the "theType" argument.
342  const LocationContext *LCtx = C.getLocationContext();
343  SVal TheTypeVal = state->getSVal(CE->getArg(1), LCtx);
344
345  // FIXME: We really should allow ranges of valid theType values, and
346  //   bifurcate the state appropriately.
347  Optional<nonloc::ConcreteInt> V = TheTypeVal.getAs<nonloc::ConcreteInt>();
348  if (!V)
349    return;
350
351  uint64_t NumberKind = V->getValue().getLimitedValue();
352  Optional<uint64_t> OptTargetSize = GetCFNumberSize(Ctx, NumberKind);
353
354  // FIXME: In some cases we can emit an error.
355  if (!OptTargetSize)
356    return;
357
358  uint64_t TargetSize = *OptTargetSize;
359
360  // Look at the value of the integer being passed by reference.  Essentially
361  // we want to catch cases where the value passed in is not equal to the
362  // size of the type being created.
363  SVal TheValueExpr = state->getSVal(CE->getArg(2), LCtx);
364
365  // FIXME: Eventually we should handle arbitrary locations.  We can do this
366  //  by having an enhanced memory model that does low-level typing.
367  Optional<loc::MemRegionVal> LV = TheValueExpr.getAs<loc::MemRegionVal>();
368  if (!LV)
369    return;
370
371  const TypedValueRegion* R = dyn_cast<TypedValueRegion>(LV->stripCasts());
372  if (!R)
373    return;
374
375  QualType T = Ctx.getCanonicalType(R->getValueType());
376
377  // FIXME: If the pointee isn't an integer type, should we flag a warning?
378  //  People can do weird stuff with pointers.
379
380  if (!T->isIntegerType())
381    return;
382
383  uint64_t SourceSize = Ctx.getTypeSize(T);
384
385  // CHECK: is SourceSize == TargetSize
386  if (SourceSize == TargetSize)
387    return;
388
389  // Generate an error.  Only generate a sink if 'SourceSize < TargetSize';
390  // otherwise generate a regular node.
391  //
392  // FIXME: We can actually create an abstract "CFNumber" object that has
393  //  the bits initialized to the provided values.
394  //
395  if (ExplodedNode *N = SourceSize < TargetSize ? C.generateSink()
396                                                : C.addTransition()) {
397    SmallString<128> sbuf;
398    llvm::raw_svector_ostream os(sbuf);
399
400    os << (SourceSize == 8 ? "An " : "A ")
401       << SourceSize << " bit integer is used to initialize a CFNumber "
402                        "object that represents "
403       << (TargetSize == 8 ? "an " : "a ")
404       << TargetSize << " bit integer. ";
405
406    if (SourceSize < TargetSize)
407      os << (TargetSize - SourceSize)
408      << " bits of the CFNumber value will be garbage." ;
409    else
410      os << (SourceSize - TargetSize)
411      << " bits of the input integer will be lost.";
412
413    if (!BT)
414      BT.reset(new APIMisuse("Bad use of CFNumberCreate"));
415
416    BugReport *report = new BugReport(*BT, os.str(), N);
417    report->addRange(CE->getArg(2)->getSourceRange());
418    C.emitReport(report);
419  }
420}
421
422//===----------------------------------------------------------------------===//
423// CFRetain/CFRelease/CFMakeCollectable checking for null arguments.
424//===----------------------------------------------------------------------===//
425
426namespace {
427class CFRetainReleaseChecker : public Checker< check::PreStmt<CallExpr> > {
428  mutable OwningPtr<APIMisuse> BT;
429  mutable IdentifierInfo *Retain, *Release, *MakeCollectable;
430public:
431  CFRetainReleaseChecker(): Retain(0), Release(0), MakeCollectable(0) {}
432  void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
433};
434} // end anonymous namespace
435
436
437void CFRetainReleaseChecker::checkPreStmt(const CallExpr *CE,
438                                          CheckerContext &C) const {
439  // If the CallExpr doesn't have exactly 1 argument just give up checking.
440  if (CE->getNumArgs() != 1)
441    return;
442
443  ProgramStateRef state = C.getState();
444  const FunctionDecl *FD = C.getCalleeDecl(CE);
445  if (!FD)
446    return;
447
448  if (!BT) {
449    ASTContext &Ctx = C.getASTContext();
450    Retain = &Ctx.Idents.get("CFRetain");
451    Release = &Ctx.Idents.get("CFRelease");
452    MakeCollectable = &Ctx.Idents.get("CFMakeCollectable");
453    BT.reset(
454      new APIMisuse("null passed to CFRetain/CFRelease/CFMakeCollectable"));
455  }
456
457  // Check if we called CFRetain/CFRelease/CFMakeCollectable.
458  const IdentifierInfo *FuncII = FD->getIdentifier();
459  if (!(FuncII == Retain || FuncII == Release || FuncII == MakeCollectable))
460    return;
461
462  // FIXME: The rest of this just checks that the argument is non-null.
463  // It should probably be refactored and combined with NonNullParamChecker.
464
465  // Get the argument's value.
466  const Expr *Arg = CE->getArg(0);
467  SVal ArgVal = state->getSVal(Arg, C.getLocationContext());
468  Optional<DefinedSVal> DefArgVal = ArgVal.getAs<DefinedSVal>();
469  if (!DefArgVal)
470    return;
471
472  // Get a NULL value.
473  SValBuilder &svalBuilder = C.getSValBuilder();
474  DefinedSVal zero =
475      svalBuilder.makeZeroVal(Arg->getType()).castAs<DefinedSVal>();
476
477  // Make an expression asserting that they're equal.
478  DefinedOrUnknownSVal ArgIsNull = svalBuilder.evalEQ(state, zero, *DefArgVal);
479
480  // Are they equal?
481  ProgramStateRef stateTrue, stateFalse;
482  llvm::tie(stateTrue, stateFalse) = state->assume(ArgIsNull);
483
484  if (stateTrue && !stateFalse) {
485    ExplodedNode *N = C.generateSink(stateTrue);
486    if (!N)
487      return;
488
489    const char *description;
490    if (FuncII == Retain)
491      description = "Null pointer argument in call to CFRetain";
492    else if (FuncII == Release)
493      description = "Null pointer argument in call to CFRelease";
494    else if (FuncII == MakeCollectable)
495      description = "Null pointer argument in call to CFMakeCollectable";
496    else
497      llvm_unreachable("impossible case");
498
499    BugReport *report = new BugReport(*BT, description, N);
500    report->addRange(Arg->getSourceRange());
501    bugreporter::trackNullOrUndefValue(N, Arg, *report);
502    C.emitReport(report);
503    return;
504  }
505
506  // From here on, we know the argument is non-null.
507  C.addTransition(stateFalse);
508}
509
510//===----------------------------------------------------------------------===//
511// Check for sending 'retain', 'release', or 'autorelease' directly to a Class.
512//===----------------------------------------------------------------------===//
513
514namespace {
515class ClassReleaseChecker : public Checker<check::PreObjCMessage> {
516  mutable Selector releaseS;
517  mutable Selector retainS;
518  mutable Selector autoreleaseS;
519  mutable Selector drainS;
520  mutable OwningPtr<BugType> BT;
521
522public:
523  void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
524};
525}
526
527void ClassReleaseChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
528                                              CheckerContext &C) const {
529
530  if (!BT) {
531    BT.reset(new APIMisuse("message incorrectly sent to class instead of class "
532                           "instance"));
533
534    ASTContext &Ctx = C.getASTContext();
535    releaseS = GetNullarySelector("release", Ctx);
536    retainS = GetNullarySelector("retain", Ctx);
537    autoreleaseS = GetNullarySelector("autorelease", Ctx);
538    drainS = GetNullarySelector("drain", Ctx);
539  }
540
541  if (msg.isInstanceMessage())
542    return;
543  const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
544  assert(Class);
545
546  Selector S = msg.getSelector();
547  if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
548    return;
549
550  if (ExplodedNode *N = C.addTransition()) {
551    SmallString<200> buf;
552    llvm::raw_svector_ostream os(buf);
553
554    os << "The '" << S.getAsString() << "' message should be sent to instances "
555          "of class '" << Class->getName()
556       << "' and not the class directly";
557
558    BugReport *report = new BugReport(*BT, os.str(), N);
559    report->addRange(msg.getSourceRange());
560    C.emitReport(report);
561  }
562}
563
564//===----------------------------------------------------------------------===//
565// Check for passing non-Objective-C types to variadic methods that expect
566// only Objective-C types.
567//===----------------------------------------------------------------------===//
568
569namespace {
570class VariadicMethodTypeChecker : public Checker<check::PreObjCMessage> {
571  mutable Selector arrayWithObjectsS;
572  mutable Selector dictionaryWithObjectsAndKeysS;
573  mutable Selector setWithObjectsS;
574  mutable Selector orderedSetWithObjectsS;
575  mutable Selector initWithObjectsS;
576  mutable Selector initWithObjectsAndKeysS;
577  mutable OwningPtr<BugType> BT;
578
579  bool isVariadicMessage(const ObjCMethodCall &msg) const;
580
581public:
582  void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
583};
584}
585
586/// isVariadicMessage - Returns whether the given message is a variadic message,
587/// where all arguments must be Objective-C types.
588bool
589VariadicMethodTypeChecker::isVariadicMessage(const ObjCMethodCall &msg) const {
590  const ObjCMethodDecl *MD = msg.getDecl();
591
592  if (!MD || !MD->isVariadic() || isa<ObjCProtocolDecl>(MD->getDeclContext()))
593    return false;
594
595  Selector S = msg.getSelector();
596
597  if (msg.isInstanceMessage()) {
598    // FIXME: Ideally we'd look at the receiver interface here, but that's not
599    // useful for init, because alloc returns 'id'. In theory, this could lead
600    // to false positives, for example if there existed a class that had an
601    // initWithObjects: implementation that does accept non-Objective-C pointer
602    // types, but the chance of that happening is pretty small compared to the
603    // gains that this analysis gives.
604    const ObjCInterfaceDecl *Class = MD->getClassInterface();
605
606    switch (findKnownClass(Class)) {
607    case FC_NSArray:
608    case FC_NSOrderedSet:
609    case FC_NSSet:
610      return S == initWithObjectsS;
611    case FC_NSDictionary:
612      return S == initWithObjectsAndKeysS;
613    default:
614      return false;
615    }
616  } else {
617    const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
618
619    switch (findKnownClass(Class)) {
620      case FC_NSArray:
621        return S == arrayWithObjectsS;
622      case FC_NSOrderedSet:
623        return S == orderedSetWithObjectsS;
624      case FC_NSSet:
625        return S == setWithObjectsS;
626      case FC_NSDictionary:
627        return S == dictionaryWithObjectsAndKeysS;
628      default:
629        return false;
630    }
631  }
632}
633
634void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
635                                                    CheckerContext &C) const {
636  if (!BT) {
637    BT.reset(new APIMisuse("Arguments passed to variadic method aren't all "
638                           "Objective-C pointer types"));
639
640    ASTContext &Ctx = C.getASTContext();
641    arrayWithObjectsS = GetUnarySelector("arrayWithObjects", Ctx);
642    dictionaryWithObjectsAndKeysS =
643      GetUnarySelector("dictionaryWithObjectsAndKeys", Ctx);
644    setWithObjectsS = GetUnarySelector("setWithObjects", Ctx);
645    orderedSetWithObjectsS = GetUnarySelector("orderedSetWithObjects", Ctx);
646
647    initWithObjectsS = GetUnarySelector("initWithObjects", Ctx);
648    initWithObjectsAndKeysS = GetUnarySelector("initWithObjectsAndKeys", Ctx);
649  }
650
651  if (!isVariadicMessage(msg))
652      return;
653
654  // We are not interested in the selector arguments since they have
655  // well-defined types, so the compiler will issue a warning for them.
656  unsigned variadicArgsBegin = msg.getSelector().getNumArgs();
657
658  // We're not interested in the last argument since it has to be nil or the
659  // compiler would have issued a warning for it elsewhere.
660  unsigned variadicArgsEnd = msg.getNumArgs() - 1;
661
662  if (variadicArgsEnd <= variadicArgsBegin)
663    return;
664
665  // Verify that all arguments have Objective-C types.
666  Optional<ExplodedNode*> errorNode;
667  ProgramStateRef state = C.getState();
668
669  for (unsigned I = variadicArgsBegin; I != variadicArgsEnd; ++I) {
670    QualType ArgTy = msg.getArgExpr(I)->getType();
671    if (ArgTy->isObjCObjectPointerType())
672      continue;
673
674    // Block pointers are treaded as Objective-C pointers.
675    if (ArgTy->isBlockPointerType())
676      continue;
677
678    // Ignore pointer constants.
679    if (msg.getArgSVal(I).getAs<loc::ConcreteInt>())
680      continue;
681
682    // Ignore pointer types annotated with 'NSObject' attribute.
683    if (C.getASTContext().isObjCNSObjectType(ArgTy))
684      continue;
685
686    // Ignore CF references, which can be toll-free bridged.
687    if (coreFoundation::isCFObjectRef(ArgTy))
688      continue;
689
690    // Generate only one error node to use for all bug reports.
691    if (!errorNode.hasValue())
692      errorNode = C.addTransition();
693
694    if (!errorNode.getValue())
695      continue;
696
697    SmallString<128> sbuf;
698    llvm::raw_svector_ostream os(sbuf);
699
700    StringRef TypeName = GetReceiverInterfaceName(msg);
701    if (!TypeName.empty())
702      os << "Argument to '" << TypeName << "' method '";
703    else
704      os << "Argument to method '";
705
706    os << msg.getSelector().getAsString()
707       << "' should be an Objective-C pointer type, not '";
708    ArgTy.print(os, C.getLangOpts());
709    os << "'";
710
711    BugReport *R = new BugReport(*BT, os.str(), errorNode.getValue());
712    R->addRange(msg.getArgSourceRange(I));
713    C.emitReport(R);
714  }
715}
716
717//===----------------------------------------------------------------------===//
718// Improves the modeling of loops over Cocoa collections.
719//===----------------------------------------------------------------------===//
720
721namespace {
722class ObjCLoopChecker
723  : public Checker<check::PostStmt<ObjCForCollectionStmt> > {
724
725public:
726  void checkPostStmt(const ObjCForCollectionStmt *FCS, CheckerContext &C) const;
727};
728}
729
730static bool isKnownNonNilCollectionType(QualType T) {
731  const ObjCObjectPointerType *PT = T->getAs<ObjCObjectPointerType>();
732  if (!PT)
733    return false;
734
735  const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();
736  if (!ID)
737    return false;
738
739  switch (findKnownClass(ID)) {
740  case FC_NSArray:
741  case FC_NSDictionary:
742  case FC_NSEnumerator:
743  case FC_NSOrderedSet:
744  case FC_NSSet:
745    return true;
746  default:
747    return false;
748  }
749}
750
751void ObjCLoopChecker::checkPostStmt(const ObjCForCollectionStmt *FCS,
752                                    CheckerContext &C) const {
753  ProgramStateRef State = C.getState();
754
755  // Check if this is the branch for the end of the loop.
756  SVal CollectionSentinel = State->getSVal(FCS, C.getLocationContext());
757  if (CollectionSentinel.isZeroConstant())
758    return;
759
760  // See if the collection is one where we /know/ the elements are non-nil.
761  const Expr *Collection = FCS->getCollection();
762  if (!isKnownNonNilCollectionType(Collection->getType()))
763    return;
764
765  // FIXME: Copied from ExprEngineObjC.
766  const Stmt *Element = FCS->getElement();
767  SVal ElementVar;
768  if (const DeclStmt *DS = dyn_cast<DeclStmt>(Element)) {
769    const VarDecl *ElemDecl = cast<VarDecl>(DS->getSingleDecl());
770    assert(ElemDecl->getInit() == 0);
771    ElementVar = State->getLValue(ElemDecl, C.getLocationContext());
772  } else {
773    ElementVar = State->getSVal(Element, C.getLocationContext());
774  }
775
776  if (!ElementVar.getAs<Loc>())
777    return;
778
779  // Go ahead and assume the value is non-nil.
780  SVal Val = State->getSVal(ElementVar.castAs<Loc>());
781  State = State->assume(Val.castAs<DefinedOrUnknownSVal>(), true);
782  C.addTransition(State);
783}
784
785namespace {
786/// \class ObjCNonNilReturnValueChecker
787/// \brief The checker restricts the return values of APIs known to
788/// never (or almost never) return 'nil'.
789class ObjCNonNilReturnValueChecker
790  : public Checker<check::PostObjCMessage> {
791    mutable bool Initialized;
792    mutable Selector ObjectAtIndex;
793    mutable Selector ObjectAtIndexedSubscript;
794
795public:
796  ObjCNonNilReturnValueChecker() : Initialized(false) {}
797  void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
798};
799}
800
801static ProgramStateRef assumeExprIsNonNull(const Expr *NonNullExpr,
802                                           ProgramStateRef State,
803                                           CheckerContext &C) {
804  SVal Val = State->getSVal(NonNullExpr, C.getLocationContext());
805  if (Optional<DefinedOrUnknownSVal> DV = Val.getAs<DefinedOrUnknownSVal>())
806    return State->assume(*DV, true);
807  return State;
808}
809
810void ObjCNonNilReturnValueChecker::checkPostObjCMessage(const ObjCMethodCall &M,
811                                                        CheckerContext &C)
812                                                        const {
813  ProgramStateRef State = C.getState();
814
815  if (!Initialized) {
816    ASTContext &Ctx = C.getASTContext();
817    ObjectAtIndex = GetUnarySelector("objectAtIndex", Ctx);
818    ObjectAtIndexedSubscript = GetUnarySelector("objectAtIndexedSubscript", Ctx);
819  }
820
821  // Check the receiver type.
822  if (const ObjCInterfaceDecl *Interface = M.getReceiverInterface()) {
823
824    // Assume that object returned from '[self init]' or '[super init]' is not
825    // 'nil' if we are processing an inlined function/method.
826    //
827    // A defensive callee will (and should) check if the object returned by
828    // '[super init]' is 'nil' before doing it's own initialization. However,
829    // since 'nil' is rarely returned in practice, we should not warn when the
830    // caller to the defensive constructor uses the object in contexts where
831    // 'nil' is not accepted.
832    if (!C.inTopFrame() && M.getDecl() &&
833        M.getDecl()->getMethodFamily() == OMF_init &&
834        M.isReceiverSelfOrSuper()) {
835      State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
836    }
837
838    // Objects returned from
839    // [NSArray|NSOrderedSet]::[ObjectAtIndex|ObjectAtIndexedSubscript]
840    // are never 'nil'.
841    FoundationClass Cl = findKnownClass(Interface);
842    if (Cl == FC_NSArray || Cl == FC_NSOrderedSet) {
843      Selector Sel = M.getSelector();
844      if (Sel == ObjectAtIndex || Sel == ObjectAtIndexedSubscript) {
845        // Go ahead and assume the value is non-nil.
846        State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
847      }
848    }
849  }
850  C.addTransition(State);
851}
852
853//===----------------------------------------------------------------------===//
854// Check registration.
855//===----------------------------------------------------------------------===//
856
857void ento::registerNilArgChecker(CheckerManager &mgr) {
858  mgr.registerChecker<NilArgChecker>();
859}
860
861void ento::registerCFNumberCreateChecker(CheckerManager &mgr) {
862  mgr.registerChecker<CFNumberCreateChecker>();
863}
864
865void ento::registerCFRetainReleaseChecker(CheckerManager &mgr) {
866  mgr.registerChecker<CFRetainReleaseChecker>();
867}
868
869void ento::registerClassReleaseChecker(CheckerManager &mgr) {
870  mgr.registerChecker<ClassReleaseChecker>();
871}
872
873void ento::registerVariadicMethodTypeChecker(CheckerManager &mgr) {
874  mgr.registerChecker<VariadicMethodTypeChecker>();
875}
876
877void ento::registerObjCLoopChecker(CheckerManager &mgr) {
878  mgr.registerChecker<ObjCLoopChecker>();
879}
880
881void ento::registerObjCNonNilReturnValueChecker(CheckerManager &mgr) {
882  mgr.registerChecker<ObjCNonNilReturnValueChecker>();
883}
884