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