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