BasicObjCFoundationChecks.cpp revision 251662
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 into '";
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->isIntegralOrEnumerationType())
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
762/// Assumes that the collection is non-nil.
763///
764/// If the collection is known to be nil, returns NULL to indicate an infeasible
765/// path.
766static ProgramStateRef checkCollectionNonNil(CheckerContext &C,
767                                             ProgramStateRef State,
768                                             const ObjCForCollectionStmt *FCS) {
769  if (!State)
770    return NULL;
771
772  SVal CollectionVal = C.getSVal(FCS->getCollection());
773  Optional<DefinedSVal> KnownCollection = CollectionVal.getAs<DefinedSVal>();
774  if (!KnownCollection)
775    return State;
776
777  ProgramStateRef StNonNil, StNil;
778  llvm::tie(StNonNil, StNil) = State->assume(*KnownCollection);
779  if (StNil && !StNonNil) {
780    // The collection is nil. This path is infeasible.
781    return NULL;
782  }
783
784  return StNonNil;
785}
786
787/// Assumes that the collection elements are non-nil.
788///
789/// This only applies if the collection is one of those known not to contain
790/// nil values.
791static ProgramStateRef checkElementNonNil(CheckerContext &C,
792                                          ProgramStateRef State,
793                                          const ObjCForCollectionStmt *FCS) {
794  if (!State)
795    return NULL;
796
797  // See if the collection is one where we /know/ the elements are non-nil.
798  if (!isKnownNonNilCollectionType(FCS->getCollection()->getType()))
799    return State;
800
801  const LocationContext *LCtx = C.getLocationContext();
802  const Stmt *Element = FCS->getElement();
803
804  // FIXME: Copied from ExprEngineObjC.
805  Optional<Loc> ElementLoc;
806  if (const DeclStmt *DS = dyn_cast<DeclStmt>(Element)) {
807    const VarDecl *ElemDecl = cast<VarDecl>(DS->getSingleDecl());
808    assert(ElemDecl->getInit() == 0);
809    ElementLoc = State->getLValue(ElemDecl, LCtx);
810  } else {
811    ElementLoc = State->getSVal(Element, LCtx).getAs<Loc>();
812  }
813
814  if (!ElementLoc)
815    return State;
816
817  // Go ahead and assume the value is non-nil.
818  SVal Val = State->getSVal(*ElementLoc);
819  return State->assume(Val.castAs<DefinedOrUnknownSVal>(), true);
820}
821
822void ObjCLoopChecker::checkPostStmt(const ObjCForCollectionStmt *FCS,
823                                    CheckerContext &C) const {
824  // Check if this is the branch for the end of the loop.
825  SVal CollectionSentinel = C.getSVal(FCS);
826  if (CollectionSentinel.isZeroConstant())
827    return;
828
829  ProgramStateRef State = C.getState();
830  State = checkCollectionNonNil(C, State, FCS);
831  State = checkElementNonNil(C, State, FCS);
832
833  if (!State)
834    C.generateSink();
835  else if (State != C.getState())
836    C.addTransition(State);
837}
838
839namespace {
840/// \class ObjCNonNilReturnValueChecker
841/// \brief The checker restricts the return values of APIs known to
842/// never (or almost never) return 'nil'.
843class ObjCNonNilReturnValueChecker
844  : public Checker<check::PostObjCMessage> {
845    mutable bool Initialized;
846    mutable Selector ObjectAtIndex;
847    mutable Selector ObjectAtIndexedSubscript;
848
849public:
850  ObjCNonNilReturnValueChecker() : Initialized(false) {}
851  void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
852};
853}
854
855static ProgramStateRef assumeExprIsNonNull(const Expr *NonNullExpr,
856                                           ProgramStateRef State,
857                                           CheckerContext &C) {
858  SVal Val = State->getSVal(NonNullExpr, C.getLocationContext());
859  if (Optional<DefinedOrUnknownSVal> DV = Val.getAs<DefinedOrUnknownSVal>())
860    return State->assume(*DV, true);
861  return State;
862}
863
864void ObjCNonNilReturnValueChecker::checkPostObjCMessage(const ObjCMethodCall &M,
865                                                        CheckerContext &C)
866                                                        const {
867  ProgramStateRef State = C.getState();
868
869  if (!Initialized) {
870    ASTContext &Ctx = C.getASTContext();
871    ObjectAtIndex = GetUnarySelector("objectAtIndex", Ctx);
872    ObjectAtIndexedSubscript = GetUnarySelector("objectAtIndexedSubscript", Ctx);
873  }
874
875  // Check the receiver type.
876  if (const ObjCInterfaceDecl *Interface = M.getReceiverInterface()) {
877
878    // Assume that object returned from '[self init]' or '[super init]' is not
879    // 'nil' if we are processing an inlined function/method.
880    //
881    // A defensive callee will (and should) check if the object returned by
882    // '[super init]' is 'nil' before doing it's own initialization. However,
883    // since 'nil' is rarely returned in practice, we should not warn when the
884    // caller to the defensive constructor uses the object in contexts where
885    // 'nil' is not accepted.
886    if (!C.inTopFrame() && M.getDecl() &&
887        M.getDecl()->getMethodFamily() == OMF_init &&
888        M.isReceiverSelfOrSuper()) {
889      State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
890    }
891
892    // Objects returned from
893    // [NSArray|NSOrderedSet]::[ObjectAtIndex|ObjectAtIndexedSubscript]
894    // are never 'nil'.
895    FoundationClass Cl = findKnownClass(Interface);
896    if (Cl == FC_NSArray || Cl == FC_NSOrderedSet) {
897      Selector Sel = M.getSelector();
898      if (Sel == ObjectAtIndex || Sel == ObjectAtIndexedSubscript) {
899        // Go ahead and assume the value is non-nil.
900        State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
901      }
902    }
903  }
904  C.addTransition(State);
905}
906
907//===----------------------------------------------------------------------===//
908// Check registration.
909//===----------------------------------------------------------------------===//
910
911void ento::registerNilArgChecker(CheckerManager &mgr) {
912  mgr.registerChecker<NilArgChecker>();
913}
914
915void ento::registerCFNumberCreateChecker(CheckerManager &mgr) {
916  mgr.registerChecker<CFNumberCreateChecker>();
917}
918
919void ento::registerCFRetainReleaseChecker(CheckerManager &mgr) {
920  mgr.registerChecker<CFRetainReleaseChecker>();
921}
922
923void ento::registerClassReleaseChecker(CheckerManager &mgr) {
924  mgr.registerChecker<ClassReleaseChecker>();
925}
926
927void ento::registerVariadicMethodTypeChecker(CheckerManager &mgr) {
928  mgr.registerChecker<VariadicMethodTypeChecker>();
929}
930
931void ento::registerObjCLoopChecker(CheckerManager &mgr) {
932  mgr.registerChecker<ObjCLoopChecker>();
933}
934
935void ento::registerObjCNonNilReturnValueChecker(CheckerManager &mgr) {
936  mgr.registerChecker<ObjCNonNilReturnValueChecker>();
937}
938