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