clang  6.0.0svn
BasicObjCFoundationChecks.cpp
Go to the documentation of this file.
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 "SelectorExtras.h"
18 #include "clang/AST/ASTContext.h"
19 #include "clang/AST/DeclObjC.h"
20 #include "clang/AST/Expr.h"
21 #include "clang/AST/ExprObjC.h"
22 #include "clang/AST/StmtObjC.h"
33 #include "llvm/ADT/SmallString.h"
34 #include "llvm/ADT/StringMap.h"
35 #include "llvm/Support/raw_ostream.h"
36 
37 using namespace clang;
38 using namespace ento;
39 
40 namespace {
41 class APIMisuse : public BugType {
42 public:
43  APIMisuse(const CheckerBase *checker, const char *name)
44  : BugType(checker, name, "API Misuse (Apple)") {}
45 };
46 } // end anonymous namespace
47 
48 //===----------------------------------------------------------------------===//
49 // Utility functions.
50 //===----------------------------------------------------------------------===//
51 
52 static StringRef GetReceiverInterfaceName(const ObjCMethodCall &msg) {
53  if (const ObjCInterfaceDecl *ID = msg.getReceiverInterface())
54  return ID->getIdentifier()->getName();
55  return StringRef();
56 }
57 
67 };
68 
70  bool IncludeSuperclasses = true) {
71  static llvm::StringMap<FoundationClass> Classes;
72  if (Classes.empty()) {
73  Classes["NSArray"] = FC_NSArray;
74  Classes["NSDictionary"] = FC_NSDictionary;
75  Classes["NSEnumerator"] = FC_NSEnumerator;
76  Classes["NSNull"] = FC_NSNull;
77  Classes["NSOrderedSet"] = FC_NSOrderedSet;
78  Classes["NSSet"] = FC_NSSet;
79  Classes["NSString"] = FC_NSString;
80  }
81 
82  // FIXME: Should we cache this at all?
83  FoundationClass result = Classes.lookup(ID->getIdentifier()->getName());
84  if (result == FC_None && IncludeSuperclasses)
85  if (const ObjCInterfaceDecl *Super = ID->getSuperClass())
86  return findKnownClass(Super);
87 
88  return result;
89 }
90 
91 //===----------------------------------------------------------------------===//
92 // NilArgChecker - Check for prohibited nil arguments to ObjC method calls.
93 //===----------------------------------------------------------------------===//
94 
95 namespace {
96  class NilArgChecker : public Checker<check::PreObjCMessage,
97  check::PostStmt<ObjCDictionaryLiteral>,
98  check::PostStmt<ObjCArrayLiteral> > {
99  mutable std::unique_ptr<APIMisuse> BT;
100 
101  mutable llvm::SmallDenseMap<Selector, unsigned, 16> StringSelectors;
102  mutable Selector ArrayWithObjectSel;
103  mutable Selector AddObjectSel;
104  mutable Selector InsertObjectAtIndexSel;
105  mutable Selector ReplaceObjectAtIndexWithObjectSel;
106  mutable Selector SetObjectAtIndexedSubscriptSel;
107  mutable Selector ArrayByAddingObjectSel;
108  mutable Selector DictionaryWithObjectForKeySel;
109  mutable Selector SetObjectForKeySel;
110  mutable Selector SetObjectForKeyedSubscriptSel;
111  mutable Selector RemoveObjectForKeySel;
112 
113  void warnIfNilExpr(const Expr *E,
114  const char *Msg,
115  CheckerContext &C) const;
116 
117  void warnIfNilArg(CheckerContext &C,
118  const ObjCMethodCall &msg, unsigned Arg,
119  FoundationClass Class,
120  bool CanBeSubscript = false) const;
121 
122  void generateBugReport(ExplodedNode *N,
123  StringRef Msg,
124  SourceRange Range,
125  const Expr *Expr,
126  CheckerContext &C) const;
127 
128  public:
129  void checkPreObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
130  void checkPostStmt(const ObjCDictionaryLiteral *DL,
131  CheckerContext &C) const;
132  void checkPostStmt(const ObjCArrayLiteral *AL,
133  CheckerContext &C) const;
134  };
135 } // end anonymous namespace
136 
137 void NilArgChecker::warnIfNilExpr(const Expr *E,
138  const char *Msg,
139  CheckerContext &C) const {
141  if (State->isNull(C.getSVal(E)).isConstrainedTrue()) {
142 
143  if (ExplodedNode *N = C.generateErrorNode()) {
144  generateBugReport(N, Msg, E->getSourceRange(), E, C);
145  }
146  }
147 }
148 
149 void NilArgChecker::warnIfNilArg(CheckerContext &C,
150  const ObjCMethodCall &msg,
151  unsigned int Arg,
152  FoundationClass Class,
153  bool CanBeSubscript) const {
154  // Check if the argument is nil.
156  if (!State->isNull(msg.getArgSVal(Arg)).isConstrainedTrue())
157  return;
158 
159  if (ExplodedNode *N = C.generateErrorNode()) {
160  SmallString<128> sbuf;
161  llvm::raw_svector_ostream os(sbuf);
162 
163  if (CanBeSubscript && msg.getMessageKind() == OCM_Subscript) {
164 
165  if (Class == FC_NSArray) {
166  os << "Array element cannot be nil";
167  } else if (Class == FC_NSDictionary) {
168  if (Arg == 0) {
169  os << "Value stored into '";
170  os << GetReceiverInterfaceName(msg) << "' cannot be nil";
171  } else {
172  assert(Arg == 1);
173  os << "'"<< GetReceiverInterfaceName(msg) << "' key cannot be nil";
174  }
175  } else
176  llvm_unreachable("Missing foundation class for the subscript expr");
177 
178  } else {
179  if (Class == FC_NSDictionary) {
180  if (Arg == 0)
181  os << "Value argument ";
182  else {
183  assert(Arg == 1);
184  os << "Key argument ";
185  }
186  os << "to '";
187  msg.getSelector().print(os);
188  os << "' cannot be nil";
189  } else {
190  os << "Argument to '" << GetReceiverInterfaceName(msg) << "' method '";
191  msg.getSelector().print(os);
192  os << "' cannot be nil";
193  }
194  }
195 
196  generateBugReport(N, os.str(), msg.getArgSourceRange(Arg),
197  msg.getArgExpr(Arg), C);
198  }
199 }
200 
201 void NilArgChecker::generateBugReport(ExplodedNode *N,
202  StringRef Msg,
203  SourceRange Range,
204  const Expr *E,
205  CheckerContext &C) const {
206  if (!BT)
207  BT.reset(new APIMisuse(this, "nil argument"));
208 
209  auto R = llvm::make_unique<BugReport>(*BT, Msg, N);
210  R->addRange(Range);
212  C.emitReport(std::move(R));
213 }
214 
215 void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
216  CheckerContext &C) const {
218  if (!ID)
219  return;
220 
221  FoundationClass Class = findKnownClass(ID);
222 
223  static const unsigned InvalidArgIndex = UINT_MAX;
224  unsigned Arg = InvalidArgIndex;
225  bool CanBeSubscript = false;
226 
227  if (Class == FC_NSString) {
228  Selector S = msg.getSelector();
229 
230  if (S.isUnarySelector())
231  return;
232 
233  if (StringSelectors.empty()) {
234  ASTContext &Ctx = C.getASTContext();
235  Selector Sels[] = {
236  getKeywordSelector(Ctx, "caseInsensitiveCompare"),
237  getKeywordSelector(Ctx, "compare"),
238  getKeywordSelector(Ctx, "compare", "options"),
239  getKeywordSelector(Ctx, "compare", "options", "range"),
240  getKeywordSelector(Ctx, "compare", "options", "range", "locale"),
241  getKeywordSelector(Ctx, "componentsSeparatedByCharactersInSet"),
242  getKeywordSelector(Ctx, "initWithFormat"),
243  getKeywordSelector(Ctx, "localizedCaseInsensitiveCompare"),
244  getKeywordSelector(Ctx, "localizedCompare"),
245  getKeywordSelector(Ctx, "localizedStandardCompare"),
246  };
247  for (Selector KnownSel : Sels)
248  StringSelectors[KnownSel] = 0;
249  }
250  auto I = StringSelectors.find(S);
251  if (I == StringSelectors.end())
252  return;
253  Arg = I->second;
254  } else if (Class == FC_NSArray) {
255  Selector S = msg.getSelector();
256 
257  if (S.isUnarySelector())
258  return;
259 
260  if (ArrayWithObjectSel.isNull()) {
261  ASTContext &Ctx = C.getASTContext();
262  ArrayWithObjectSel = getKeywordSelector(Ctx, "arrayWithObject");
263  AddObjectSel = getKeywordSelector(Ctx, "addObject");
264  InsertObjectAtIndexSel =
265  getKeywordSelector(Ctx, "insertObject", "atIndex");
266  ReplaceObjectAtIndexWithObjectSel =
267  getKeywordSelector(Ctx, "replaceObjectAtIndex", "withObject");
268  SetObjectAtIndexedSubscriptSel =
269  getKeywordSelector(Ctx, "setObject", "atIndexedSubscript");
270  ArrayByAddingObjectSel = getKeywordSelector(Ctx, "arrayByAddingObject");
271  }
272 
273  if (S == ArrayWithObjectSel || S == AddObjectSel ||
274  S == InsertObjectAtIndexSel || S == ArrayByAddingObjectSel) {
275  Arg = 0;
276  } else if (S == SetObjectAtIndexedSubscriptSel) {
277  Arg = 0;
278  CanBeSubscript = true;
279  } else if (S == ReplaceObjectAtIndexWithObjectSel) {
280  Arg = 1;
281  }
282  } else if (Class == FC_NSDictionary) {
283  Selector S = msg.getSelector();
284 
285  if (S.isUnarySelector())
286  return;
287 
288  if (DictionaryWithObjectForKeySel.isNull()) {
289  ASTContext &Ctx = C.getASTContext();
290  DictionaryWithObjectForKeySel =
291  getKeywordSelector(Ctx, "dictionaryWithObject", "forKey");
292  SetObjectForKeySel = getKeywordSelector(Ctx, "setObject", "forKey");
293  SetObjectForKeyedSubscriptSel =
294  getKeywordSelector(Ctx, "setObject", "forKeyedSubscript");
295  RemoveObjectForKeySel = getKeywordSelector(Ctx, "removeObjectForKey");
296  }
297 
298  if (S == DictionaryWithObjectForKeySel || S == SetObjectForKeySel) {
299  Arg = 0;
300  warnIfNilArg(C, msg, /* Arg */1, Class);
301  } else if (S == SetObjectForKeyedSubscriptSel) {
302  CanBeSubscript = true;
303  Arg = 1;
304  } else if (S == RemoveObjectForKeySel) {
305  Arg = 0;
306  }
307  }
308 
309  // If argument is '0', report a warning.
310  if ((Arg != InvalidArgIndex))
311  warnIfNilArg(C, msg, Arg, Class, CanBeSubscript);
312 }
313 
314 void NilArgChecker::checkPostStmt(const ObjCArrayLiteral *AL,
315  CheckerContext &C) const {
316  unsigned NumOfElements = AL->getNumElements();
317  for (unsigned i = 0; i < NumOfElements; ++i) {
318  warnIfNilExpr(AL->getElement(i), "Array element cannot be nil", C);
319  }
320 }
321 
322 void NilArgChecker::checkPostStmt(const ObjCDictionaryLiteral *DL,
323  CheckerContext &C) const {
324  unsigned NumOfElements = DL->getNumElements();
325  for (unsigned i = 0; i < NumOfElements; ++i) {
326  ObjCDictionaryElement Element = DL->getKeyValueElement(i);
327  warnIfNilExpr(Element.Key, "Dictionary key cannot be nil", C);
328  warnIfNilExpr(Element.Value, "Dictionary value cannot be nil", C);
329  }
330 }
331 
332 //===----------------------------------------------------------------------===//
333 // Checking for mismatched types passed to CFNumberCreate/CFNumberGetValue.
334 //===----------------------------------------------------------------------===//
335 
336 namespace {
337 class CFNumberChecker : public Checker< check::PreStmt<CallExpr> > {
338  mutable std::unique_ptr<APIMisuse> BT;
339  mutable IdentifierInfo *ICreate, *IGetValue;
340 public:
341  CFNumberChecker() : ICreate(nullptr), IGetValue(nullptr) {}
342 
343  void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
344 
345 private:
346  void EmitError(const TypedRegion* R, const Expr *Ex,
347  uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind);
348 };
349 } // end anonymous namespace
350 
368 };
369 
371  static const unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 };
372 
373  if (i < kCFNumberCharType)
374  return FixedSize[i-1];
375 
376  QualType T;
377 
378  switch (i) {
379  case kCFNumberCharType: T = Ctx.CharTy; break;
380  case kCFNumberShortType: T = Ctx.ShortTy; break;
381  case kCFNumberIntType: T = Ctx.IntTy; break;
382  case kCFNumberLongType: T = Ctx.LongTy; break;
383  case kCFNumberLongLongType: T = Ctx.LongLongTy; break;
384  case kCFNumberFloatType: T = Ctx.FloatTy; break;
385  case kCFNumberDoubleType: T = Ctx.DoubleTy; break;
389  // FIXME: We need a way to map from names to Type*.
390  default:
391  return None;
392  }
393 
394  return Ctx.getTypeSize(T);
395 }
396 
397 #if 0
398 static const char* GetCFNumberTypeStr(uint64_t i) {
399  static const char* Names[] = {
400  "kCFNumberSInt8Type",
401  "kCFNumberSInt16Type",
402  "kCFNumberSInt32Type",
403  "kCFNumberSInt64Type",
404  "kCFNumberFloat32Type",
405  "kCFNumberFloat64Type",
406  "kCFNumberCharType",
407  "kCFNumberShortType",
408  "kCFNumberIntType",
409  "kCFNumberLongType",
410  "kCFNumberLongLongType",
411  "kCFNumberFloatType",
412  "kCFNumberDoubleType",
413  "kCFNumberCFIndexType",
414  "kCFNumberNSIntegerType",
415  "kCFNumberCGFloatType"
416  };
417 
418  return i <= kCFNumberCGFloatType ? Names[i-1] : "Invalid CFNumberType";
419 }
420 #endif
421 
422 void CFNumberChecker::checkPreStmt(const CallExpr *CE,
423  CheckerContext &C) const {
425  const FunctionDecl *FD = C.getCalleeDecl(CE);
426  if (!FD)
427  return;
428 
429  ASTContext &Ctx = C.getASTContext();
430  if (!ICreate) {
431  ICreate = &Ctx.Idents.get("CFNumberCreate");
432  IGetValue = &Ctx.Idents.get("CFNumberGetValue");
433  }
434  if (!(FD->getIdentifier() == ICreate || FD->getIdentifier() == IGetValue) ||
435  CE->getNumArgs() != 3)
436  return;
437 
438  // Get the value of the "theType" argument.
439  const LocationContext *LCtx = C.getLocationContext();
440  SVal TheTypeVal = state->getSVal(CE->getArg(1), LCtx);
441 
442  // FIXME: We really should allow ranges of valid theType values, and
443  // bifurcate the state appropriately.
445  if (!V)
446  return;
447 
448  uint64_t NumberKind = V->getValue().getLimitedValue();
449  Optional<uint64_t> OptCFNumberSize = GetCFNumberSize(Ctx, NumberKind);
450 
451  // FIXME: In some cases we can emit an error.
452  if (!OptCFNumberSize)
453  return;
454 
455  uint64_t CFNumberSize = *OptCFNumberSize;
456 
457  // Look at the value of the integer being passed by reference. Essentially
458  // we want to catch cases where the value passed in is not equal to the
459  // size of the type being created.
460  SVal TheValueExpr = state->getSVal(CE->getArg(2), LCtx);
461 
462  // FIXME: Eventually we should handle arbitrary locations. We can do this
463  // by having an enhanced memory model that does low-level typing.
465  if (!LV)
466  return;
467 
468  const TypedValueRegion* R = dyn_cast<TypedValueRegion>(LV->stripCasts());
469  if (!R)
470  return;
471 
473 
474  // FIXME: If the pointee isn't an integer type, should we flag a warning?
475  // People can do weird stuff with pointers.
476 
477  if (!T->isIntegralOrEnumerationType())
478  return;
479 
480  uint64_t PrimitiveTypeSize = Ctx.getTypeSize(T);
481 
482  if (PrimitiveTypeSize == CFNumberSize)
483  return;
484 
485  // FIXME: We can actually create an abstract "CFNumber" object that has
486  // the bits initialized to the provided values.
488  if (N) {
489  SmallString<128> sbuf;
490  llvm::raw_svector_ostream os(sbuf);
491  bool isCreate = (FD->getIdentifier() == ICreate);
492 
493  if (isCreate) {
494  os << (PrimitiveTypeSize == 8 ? "An " : "A ")
495  << PrimitiveTypeSize << "-bit integer is used to initialize a "
496  << "CFNumber object that represents "
497  << (CFNumberSize == 8 ? "an " : "a ")
498  << CFNumberSize << "-bit integer; ";
499  } else {
500  os << "A CFNumber object that represents "
501  << (CFNumberSize == 8 ? "an " : "a ")
502  << CFNumberSize << "-bit integer is used to initialize "
503  << (PrimitiveTypeSize == 8 ? "an " : "a ")
504  << PrimitiveTypeSize << "-bit integer; ";
505  }
506 
507  if (PrimitiveTypeSize < CFNumberSize)
508  os << (CFNumberSize - PrimitiveTypeSize)
509  << " bits of the CFNumber value will "
510  << (isCreate ? "be garbage." : "overwrite adjacent storage.");
511  else
512  os << (PrimitiveTypeSize - CFNumberSize)
513  << " bits of the integer value will be "
514  << (isCreate ? "lost." : "garbage.");
515 
516  if (!BT)
517  BT.reset(new APIMisuse(this, "Bad use of CFNumber APIs"));
518 
519  auto report = llvm::make_unique<BugReport>(*BT, os.str(), N);
520  report->addRange(CE->getArg(2)->getSourceRange());
521  C.emitReport(std::move(report));
522  }
523 }
524 
525 //===----------------------------------------------------------------------===//
526 // CFRetain/CFRelease/CFMakeCollectable/CFAutorelease checking for null arguments.
527 //===----------------------------------------------------------------------===//
528 
529 namespace {
530 class CFRetainReleaseChecker : public Checker< check::PreStmt<CallExpr> > {
531  mutable std::unique_ptr<APIMisuse> BT;
532  mutable IdentifierInfo *Retain, *Release, *MakeCollectable, *Autorelease;
533 
534 public:
535  CFRetainReleaseChecker()
536  : Retain(nullptr), Release(nullptr), MakeCollectable(nullptr),
537  Autorelease(nullptr) {}
538  void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
539 };
540 } // end anonymous namespace
541 
542 void CFRetainReleaseChecker::checkPreStmt(const CallExpr *CE,
543  CheckerContext &C) const {
544  // If the CallExpr doesn't have exactly 1 argument just give up checking.
545  if (CE->getNumArgs() != 1)
546  return;
547 
549  const FunctionDecl *FD = C.getCalleeDecl(CE);
550  if (!FD)
551  return;
552 
553  if (!BT) {
554  ASTContext &Ctx = C.getASTContext();
555  Retain = &Ctx.Idents.get("CFRetain");
556  Release = &Ctx.Idents.get("CFRelease");
557  MakeCollectable = &Ctx.Idents.get("CFMakeCollectable");
558  Autorelease = &Ctx.Idents.get("CFAutorelease");
559  BT.reset(new APIMisuse(
560  this, "null passed to CF memory management function"));
561  }
562 
563  // Check if we called CFRetain/CFRelease/CFMakeCollectable/CFAutorelease.
564  const IdentifierInfo *FuncII = FD->getIdentifier();
565  if (!(FuncII == Retain || FuncII == Release || FuncII == MakeCollectable ||
566  FuncII == Autorelease))
567  return;
568 
569  // FIXME: The rest of this just checks that the argument is non-null.
570  // It should probably be refactored and combined with NonNullParamChecker.
571 
572  // Get the argument's value.
573  const Expr *Arg = CE->getArg(0);
574  SVal ArgVal = state->getSVal(Arg, C.getLocationContext());
575  Optional<DefinedSVal> DefArgVal = ArgVal.getAs<DefinedSVal>();
576  if (!DefArgVal)
577  return;
578 
579  // Get a NULL value.
580  SValBuilder &svalBuilder = C.getSValBuilder();
581  DefinedSVal zero =
582  svalBuilder.makeZeroVal(Arg->getType()).castAs<DefinedSVal>();
583 
584  // Make an expression asserting that they're equal.
585  DefinedOrUnknownSVal ArgIsNull = svalBuilder.evalEQ(state, zero, *DefArgVal);
586 
587  // Are they equal?
588  ProgramStateRef stateTrue, stateFalse;
589  std::tie(stateTrue, stateFalse) = state->assume(ArgIsNull);
590 
591  if (stateTrue && !stateFalse) {
592  ExplodedNode *N = C.generateErrorNode(stateTrue);
593  if (!N)
594  return;
595 
596  const char *description;
597  if (FuncII == Retain)
598  description = "Null pointer argument in call to CFRetain";
599  else if (FuncII == Release)
600  description = "Null pointer argument in call to CFRelease";
601  else if (FuncII == MakeCollectable)
602  description = "Null pointer argument in call to CFMakeCollectable";
603  else if (FuncII == Autorelease)
604  description = "Null pointer argument in call to CFAutorelease";
605  else
606  llvm_unreachable("impossible case");
607 
608  auto report = llvm::make_unique<BugReport>(*BT, description, N);
609  report->addRange(Arg->getSourceRange());
610  bugreporter::trackNullOrUndefValue(N, Arg, *report);
611  C.emitReport(std::move(report));
612  return;
613  }
614 
615  // From here on, we know the argument is non-null.
616  C.addTransition(stateFalse);
617 }
618 
619 //===----------------------------------------------------------------------===//
620 // Check for sending 'retain', 'release', or 'autorelease' directly to a Class.
621 //===----------------------------------------------------------------------===//
622 
623 namespace {
624 class ClassReleaseChecker : public Checker<check::PreObjCMessage> {
625  mutable Selector releaseS;
626  mutable Selector retainS;
627  mutable Selector autoreleaseS;
628  mutable Selector drainS;
629  mutable std::unique_ptr<BugType> BT;
630 
631 public:
632  void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
633 };
634 } // end anonymous namespace
635 
636 void ClassReleaseChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
637  CheckerContext &C) const {
638  if (!BT) {
639  BT.reset(new APIMisuse(
640  this, "message incorrectly sent to class instead of class instance"));
641 
642  ASTContext &Ctx = C.getASTContext();
643  releaseS = GetNullarySelector("release", Ctx);
644  retainS = GetNullarySelector("retain", Ctx);
645  autoreleaseS = GetNullarySelector("autorelease", Ctx);
646  drainS = GetNullarySelector("drain", Ctx);
647  }
648 
649  if (msg.isInstanceMessage())
650  return;
651  const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
652  assert(Class);
653 
654  Selector S = msg.getSelector();
655  if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
656  return;
657 
659  SmallString<200> buf;
660  llvm::raw_svector_ostream os(buf);
661 
662  os << "The '";
663  S.print(os);
664  os << "' message should be sent to instances "
665  "of class '" << Class->getName()
666  << "' and not the class directly";
667 
668  auto report = llvm::make_unique<BugReport>(*BT, os.str(), N);
669  report->addRange(msg.getSourceRange());
670  C.emitReport(std::move(report));
671  }
672 }
673 
674 //===----------------------------------------------------------------------===//
675 // Check for passing non-Objective-C types to variadic methods that expect
676 // only Objective-C types.
677 //===----------------------------------------------------------------------===//
678 
679 namespace {
680 class VariadicMethodTypeChecker : public Checker<check::PreObjCMessage> {
681  mutable Selector arrayWithObjectsS;
682  mutable Selector dictionaryWithObjectsAndKeysS;
683  mutable Selector setWithObjectsS;
684  mutable Selector orderedSetWithObjectsS;
685  mutable Selector initWithObjectsS;
686  mutable Selector initWithObjectsAndKeysS;
687  mutable std::unique_ptr<BugType> BT;
688 
689  bool isVariadicMessage(const ObjCMethodCall &msg) const;
690 
691 public:
692  void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
693 };
694 } // end anonymous namespace
695 
696 /// isVariadicMessage - Returns whether the given message is a variadic message,
697 /// where all arguments must be Objective-C types.
698 bool
699 VariadicMethodTypeChecker::isVariadicMessage(const ObjCMethodCall &msg) const {
700  const ObjCMethodDecl *MD = msg.getDecl();
701 
702  if (!MD || !MD->isVariadic() || isa<ObjCProtocolDecl>(MD->getDeclContext()))
703  return false;
704 
705  Selector S = msg.getSelector();
706 
707  if (msg.isInstanceMessage()) {
708  // FIXME: Ideally we'd look at the receiver interface here, but that's not
709  // useful for init, because alloc returns 'id'. In theory, this could lead
710  // to false positives, for example if there existed a class that had an
711  // initWithObjects: implementation that does accept non-Objective-C pointer
712  // types, but the chance of that happening is pretty small compared to the
713  // gains that this analysis gives.
714  const ObjCInterfaceDecl *Class = MD->getClassInterface();
715 
716  switch (findKnownClass(Class)) {
717  case FC_NSArray:
718  case FC_NSOrderedSet:
719  case FC_NSSet:
720  return S == initWithObjectsS;
721  case FC_NSDictionary:
722  return S == initWithObjectsAndKeysS;
723  default:
724  return false;
725  }
726  } else {
727  const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
728 
729  switch (findKnownClass(Class)) {
730  case FC_NSArray:
731  return S == arrayWithObjectsS;
732  case FC_NSOrderedSet:
733  return S == orderedSetWithObjectsS;
734  case FC_NSSet:
735  return S == setWithObjectsS;
736  case FC_NSDictionary:
737  return S == dictionaryWithObjectsAndKeysS;
738  default:
739  return false;
740  }
741  }
742 }
743 
744 void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
745  CheckerContext &C) const {
746  if (!BT) {
747  BT.reset(new APIMisuse(this,
748  "Arguments passed to variadic method aren't all "
749  "Objective-C pointer types"));
750 
751  ASTContext &Ctx = C.getASTContext();
752  arrayWithObjectsS = GetUnarySelector("arrayWithObjects", Ctx);
753  dictionaryWithObjectsAndKeysS =
754  GetUnarySelector("dictionaryWithObjectsAndKeys", Ctx);
755  setWithObjectsS = GetUnarySelector("setWithObjects", Ctx);
756  orderedSetWithObjectsS = GetUnarySelector("orderedSetWithObjects", Ctx);
757 
758  initWithObjectsS = GetUnarySelector("initWithObjects", Ctx);
759  initWithObjectsAndKeysS = GetUnarySelector("initWithObjectsAndKeys", Ctx);
760  }
761 
762  if (!isVariadicMessage(msg))
763  return;
764 
765  // We are not interested in the selector arguments since they have
766  // well-defined types, so the compiler will issue a warning for them.
767  unsigned variadicArgsBegin = msg.getSelector().getNumArgs();
768 
769  // We're not interested in the last argument since it has to be nil or the
770  // compiler would have issued a warning for it elsewhere.
771  unsigned variadicArgsEnd = msg.getNumArgs() - 1;
772 
773  if (variadicArgsEnd <= variadicArgsBegin)
774  return;
775 
776  // Verify that all arguments have Objective-C types.
777  Optional<ExplodedNode*> errorNode;
778 
779  for (unsigned I = variadicArgsBegin; I != variadicArgsEnd; ++I) {
780  QualType ArgTy = msg.getArgExpr(I)->getType();
781  if (ArgTy->isObjCObjectPointerType())
782  continue;
783 
784  // Block pointers are treaded as Objective-C pointers.
785  if (ArgTy->isBlockPointerType())
786  continue;
787 
788  // Ignore pointer constants.
789  if (msg.getArgSVal(I).getAs<loc::ConcreteInt>())
790  continue;
791 
792  // Ignore pointer types annotated with 'NSObject' attribute.
793  if (C.getASTContext().isObjCNSObjectType(ArgTy))
794  continue;
795 
796  // Ignore CF references, which can be toll-free bridged.
798  continue;
799 
800  // Generate only one error node to use for all bug reports.
801  if (!errorNode.hasValue())
802  errorNode = C.generateNonFatalErrorNode();
803 
804  if (!errorNode.getValue())
805  continue;
806 
807  SmallString<128> sbuf;
808  llvm::raw_svector_ostream os(sbuf);
809 
810  StringRef TypeName = GetReceiverInterfaceName(msg);
811  if (!TypeName.empty())
812  os << "Argument to '" << TypeName << "' method '";
813  else
814  os << "Argument to method '";
815 
816  msg.getSelector().print(os);
817  os << "' should be an Objective-C pointer type, not '";
818  ArgTy.print(os, C.getLangOpts());
819  os << "'";
820 
821  auto R = llvm::make_unique<BugReport>(*BT, os.str(), errorNode.getValue());
822  R->addRange(msg.getArgSourceRange(I));
823  C.emitReport(std::move(R));
824  }
825 }
826 
827 //===----------------------------------------------------------------------===//
828 // Improves the modeling of loops over Cocoa collections.
829 //===----------------------------------------------------------------------===//
830 
831 // The map from container symbol to the container count symbol.
832 // We currently will remember the last countainer count symbol encountered.
834 REGISTER_MAP_WITH_PROGRAMSTATE(ContainerNonEmptyMap, SymbolRef, bool)
835 
836 namespace {
837 class ObjCLoopChecker
838  : public Checker<check::PostStmt<ObjCForCollectionStmt>,
839  check::PostObjCMessage,
840  check::DeadSymbols,
841  check::PointerEscape > {
842  mutable IdentifierInfo *CountSelectorII;
843 
844  bool isCollectionCountMethod(const ObjCMethodCall &M,
845  CheckerContext &C) const;
846 
847 public:
848  ObjCLoopChecker() : CountSelectorII(nullptr) {}
849  void checkPostStmt(const ObjCForCollectionStmt *FCS, CheckerContext &C) const;
850  void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
851  void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
852  ProgramStateRef checkPointerEscape(ProgramStateRef State,
853  const InvalidatedSymbols &Escaped,
854  const CallEvent *Call,
855  PointerEscapeKind Kind) const;
856 };
857 } // end anonymous namespace
858 
861  if (!PT)
862  return false;
863 
864  const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();
865  if (!ID)
866  return false;
867 
868  switch (findKnownClass(ID)) {
869  case FC_NSArray:
870  case FC_NSDictionary:
871  case FC_NSEnumerator:
872  case FC_NSOrderedSet:
873  case FC_NSSet:
874  return true;
875  default:
876  return false;
877  }
878 }
879 
880 /// Assumes that the collection is non-nil.
881 ///
882 /// If the collection is known to be nil, returns NULL to indicate an infeasible
883 /// path.
886  const ObjCForCollectionStmt *FCS) {
887  if (!State)
888  return nullptr;
889 
890  SVal CollectionVal = C.getSVal(FCS->getCollection());
891  Optional<DefinedSVal> KnownCollection = CollectionVal.getAs<DefinedSVal>();
892  if (!KnownCollection)
893  return State;
894 
895  ProgramStateRef StNonNil, StNil;
896  std::tie(StNonNil, StNil) = State->assume(*KnownCollection);
897  if (StNil && !StNonNil) {
898  // The collection is nil. This path is infeasible.
899  return nullptr;
900  }
901 
902  return StNonNil;
903 }
904 
905 /// Assumes that the collection elements are non-nil.
906 ///
907 /// This only applies if the collection is one of those known not to contain
908 /// nil values.
911  const ObjCForCollectionStmt *FCS) {
912  if (!State)
913  return nullptr;
914 
915  // See if the collection is one where we /know/ the elements are non-nil.
917  return State;
918 
919  const LocationContext *LCtx = C.getLocationContext();
920  const Stmt *Element = FCS->getElement();
921 
922  // FIXME: Copied from ExprEngineObjC.
923  Optional<Loc> ElementLoc;
924  if (const DeclStmt *DS = dyn_cast<DeclStmt>(Element)) {
925  const VarDecl *ElemDecl = cast<VarDecl>(DS->getSingleDecl());
926  assert(ElemDecl->getInit() == nullptr);
927  ElementLoc = State->getLValue(ElemDecl, LCtx);
928  } else {
929  ElementLoc = State->getSVal(Element, LCtx).getAs<Loc>();
930  }
931 
932  if (!ElementLoc)
933  return State;
934 
935  // Go ahead and assume the value is non-nil.
936  SVal Val = State->getSVal(*ElementLoc);
937  return State->assume(Val.castAs<DefinedOrUnknownSVal>(), true);
938 }
939 
940 /// Returns NULL state if the collection is known to contain elements
941 /// (or is known not to contain elements if the Assumption parameter is false.)
942 static ProgramStateRef
944  SymbolRef CollectionS, bool Assumption) {
945  if (!State || !CollectionS)
946  return State;
947 
948  const SymbolRef *CountS = State->get<ContainerCountMap>(CollectionS);
949  if (!CountS) {
950  const bool *KnownNonEmpty = State->get<ContainerNonEmptyMap>(CollectionS);
951  if (!KnownNonEmpty)
952  return State->set<ContainerNonEmptyMap>(CollectionS, Assumption);
953  return (Assumption == *KnownNonEmpty) ? State : nullptr;
954  }
955 
956  SValBuilder &SvalBuilder = C.getSValBuilder();
957  SVal CountGreaterThanZeroVal =
958  SvalBuilder.evalBinOp(State, BO_GT,
959  nonloc::SymbolVal(*CountS),
960  SvalBuilder.makeIntVal(0, (*CountS)->getType()),
961  SvalBuilder.getConditionType());
962  Optional<DefinedSVal> CountGreaterThanZero =
963  CountGreaterThanZeroVal.getAs<DefinedSVal>();
964  if (!CountGreaterThanZero) {
965  // The SValBuilder cannot construct a valid SVal for this condition.
966  // This means we cannot properly reason about it.
967  return State;
968  }
969 
970  return State->assume(*CountGreaterThanZero, Assumption);
971 }
972 
973 static ProgramStateRef
975  const ObjCForCollectionStmt *FCS,
976  bool Assumption) {
977  if (!State)
978  return nullptr;
979 
980  SymbolRef CollectionS =
981  State->getSVal(FCS->getCollection(), C.getLocationContext()).getAsSymbol();
982  return assumeCollectionNonEmpty(C, State, CollectionS, Assumption);
983 }
984 
985 /// If the fist block edge is a back edge, we are reentering the loop.
987  const ObjCForCollectionStmt *FCS) {
988  if (!N)
989  return false;
990 
991  ProgramPoint P = N->getLocation();
992  if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) {
993  return BE->getSrc()->getLoopTarget() == FCS;
994  }
995 
996  // Keep looking for a block edge.
998  E = N->pred_end(); I != E; ++I) {
1000  return true;
1001  }
1002 
1003  return false;
1004 }
1005 
1006 void ObjCLoopChecker::checkPostStmt(const ObjCForCollectionStmt *FCS,
1007  CheckerContext &C) const {
1009 
1010  // Check if this is the branch for the end of the loop.
1011  SVal CollectionSentinel = C.getSVal(FCS);
1012  if (CollectionSentinel.isZeroConstant()) {
1014  State = assumeCollectionNonEmpty(C, State, FCS, /*Assumption*/false);
1015 
1016  // Otherwise, this is a branch that goes through the loop body.
1017  } else {
1018  State = checkCollectionNonNil(C, State, FCS);
1019  State = checkElementNonNil(C, State, FCS);
1020  State = assumeCollectionNonEmpty(C, State, FCS, /*Assumption*/true);
1021  }
1022 
1023  if (!State)
1024  C.generateSink(C.getState(), C.getPredecessor());
1025  else if (State != C.getState())
1026  C.addTransition(State);
1027 }
1028 
1029 bool ObjCLoopChecker::isCollectionCountMethod(const ObjCMethodCall &M,
1030  CheckerContext &C) const {
1031  Selector S = M.getSelector();
1032  // Initialize the identifiers on first use.
1033  if (!CountSelectorII)
1034  CountSelectorII = &C.getASTContext().Idents.get("count");
1035 
1036  // If the method returns collection count, record the value.
1037  return S.isUnarySelector() &&
1038  (S.getIdentifierInfoForSlot(0) == CountSelectorII);
1039 }
1040 
1041 void ObjCLoopChecker::checkPostObjCMessage(const ObjCMethodCall &M,
1042  CheckerContext &C) const {
1043  if (!M.isInstanceMessage())
1044  return;
1045 
1046  const ObjCInterfaceDecl *ClassID = M.getReceiverInterface();
1047  if (!ClassID)
1048  return;
1049 
1050  FoundationClass Class = findKnownClass(ClassID);
1051  if (Class != FC_NSDictionary &&
1052  Class != FC_NSArray &&
1053  Class != FC_NSSet &&
1054  Class != FC_NSOrderedSet)
1055  return;
1056 
1057  SymbolRef ContainerS = M.getReceiverSVal().getAsSymbol();
1058  if (!ContainerS)
1059  return;
1060 
1061  // If we are processing a call to "count", get the symbolic value returned by
1062  // a call to "count" and add it to the map.
1063  if (!isCollectionCountMethod(M, C))
1064  return;
1065 
1066  const Expr *MsgExpr = M.getOriginExpr();
1067  SymbolRef CountS = C.getSVal(MsgExpr).getAsSymbol();
1068  if (CountS) {
1070 
1071  C.getSymbolManager().addSymbolDependency(ContainerS, CountS);
1072  State = State->set<ContainerCountMap>(ContainerS, CountS);
1073 
1074  if (const bool *NonEmpty = State->get<ContainerNonEmptyMap>(ContainerS)) {
1075  State = State->remove<ContainerNonEmptyMap>(ContainerS);
1076  State = assumeCollectionNonEmpty(C, State, ContainerS, *NonEmpty);
1077  }
1078 
1079  C.addTransition(State);
1080  }
1081 }
1082 
1084  const ObjCMethodCall *Message = dyn_cast_or_null<ObjCMethodCall>(Call);
1085  if (!Message)
1086  return nullptr;
1087 
1088  const ObjCMethodDecl *MD = Message->getDecl();
1089  if (!MD)
1090  return nullptr;
1091 
1092  const ObjCInterfaceDecl *StaticClass;
1093  if (isa<ObjCProtocolDecl>(MD->getDeclContext())) {
1094  // We can't find out where the method was declared without doing more work.
1095  // Instead, see if the receiver is statically typed as a known immutable
1096  // collection.
1097  StaticClass = Message->getOriginExpr()->getReceiverInterface();
1098  } else {
1099  StaticClass = MD->getClassInterface();
1100  }
1101 
1102  if (!StaticClass)
1103  return nullptr;
1104 
1105  switch (findKnownClass(StaticClass, /*IncludeSuper=*/false)) {
1106  case FC_None:
1107  return nullptr;
1108  case FC_NSArray:
1109  case FC_NSDictionary:
1110  case FC_NSEnumerator:
1111  case FC_NSNull:
1112  case FC_NSOrderedSet:
1113  case FC_NSSet:
1114  case FC_NSString:
1115  break;
1116  }
1117 
1118  return Message->getReceiverSVal().getAsSymbol();
1119 }
1120 
1122 ObjCLoopChecker::checkPointerEscape(ProgramStateRef State,
1123  const InvalidatedSymbols &Escaped,
1124  const CallEvent *Call,
1125  PointerEscapeKind Kind) const {
1126  SymbolRef ImmutableReceiver = getMethodReceiverIfKnownImmutable(Call);
1127 
1128  // Remove the invalidated symbols form the collection count map.
1129  for (InvalidatedSymbols::const_iterator I = Escaped.begin(),
1130  E = Escaped.end();
1131  I != E; ++I) {
1132  SymbolRef Sym = *I;
1133 
1134  // Don't invalidate this symbol's count if we know the method being called
1135  // is declared on an immutable class. This isn't completely correct if the
1136  // receiver is also passed as an argument, but in most uses of NSArray,
1137  // NSDictionary, etc. this isn't likely to happen in a dangerous way.
1138  if (Sym == ImmutableReceiver)
1139  continue;
1140 
1141  // The symbol escaped. Pessimistically, assume that the count could have
1142  // changed.
1143  State = State->remove<ContainerCountMap>(Sym);
1144  State = State->remove<ContainerNonEmptyMap>(Sym);
1145  }
1146  return State;
1147 }
1148 
1149 void ObjCLoopChecker::checkDeadSymbols(SymbolReaper &SymReaper,
1150  CheckerContext &C) const {
1151  ProgramStateRef State = C.getState();
1152 
1153  // Remove the dead symbols from the collection count map.
1154  ContainerCountMapTy Tracked = State->get<ContainerCountMap>();
1155  for (ContainerCountMapTy::iterator I = Tracked.begin(),
1156  E = Tracked.end(); I != E; ++I) {
1157  SymbolRef Sym = I->first;
1158  if (SymReaper.isDead(Sym)) {
1159  State = State->remove<ContainerCountMap>(Sym);
1160  State = State->remove<ContainerNonEmptyMap>(Sym);
1161  }
1162  }
1163 
1164  C.addTransition(State);
1165 }
1166 
1167 namespace {
1168 /// \class ObjCNonNilReturnValueChecker
1169 /// \brief The checker restricts the return values of APIs known to
1170 /// never (or almost never) return 'nil'.
1171 class ObjCNonNilReturnValueChecker
1172  : public Checker<check::PostObjCMessage,
1173  check::PostStmt<ObjCArrayLiteral>,
1174  check::PostStmt<ObjCDictionaryLiteral>,
1175  check::PostStmt<ObjCBoxedExpr> > {
1176  mutable bool Initialized;
1177  mutable Selector ObjectAtIndex;
1178  mutable Selector ObjectAtIndexedSubscript;
1179  mutable Selector NullSelector;
1180 
1181 public:
1182  ObjCNonNilReturnValueChecker() : Initialized(false) {}
1183 
1184  ProgramStateRef assumeExprIsNonNull(const Expr *NonNullExpr,
1185  ProgramStateRef State,
1186  CheckerContext &C) const;
1187  void assumeExprIsNonNull(const Expr *E, CheckerContext &C) const {
1188  C.addTransition(assumeExprIsNonNull(E, C.getState(), C));
1189  }
1190 
1191  void checkPostStmt(const ObjCArrayLiteral *E, CheckerContext &C) const {
1192  assumeExprIsNonNull(E, C);
1193  }
1194  void checkPostStmt(const ObjCDictionaryLiteral *E, CheckerContext &C) const {
1195  assumeExprIsNonNull(E, C);
1196  }
1197  void checkPostStmt(const ObjCBoxedExpr *E, CheckerContext &C) const {
1198  assumeExprIsNonNull(E, C);
1199  }
1200 
1201  void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
1202 };
1203 } // end anonymous namespace
1204 
1206 ObjCNonNilReturnValueChecker::assumeExprIsNonNull(const Expr *NonNullExpr,
1207  ProgramStateRef State,
1208  CheckerContext &C) const {
1209  SVal Val = State->getSVal(NonNullExpr, C.getLocationContext());
1211  return State->assume(*DV, true);
1212  return State;
1213 }
1214 
1215 void ObjCNonNilReturnValueChecker::checkPostObjCMessage(const ObjCMethodCall &M,
1216  CheckerContext &C)
1217  const {
1218  ProgramStateRef State = C.getState();
1219 
1220  if (!Initialized) {
1221  ASTContext &Ctx = C.getASTContext();
1222  ObjectAtIndex = GetUnarySelector("objectAtIndex", Ctx);
1223  ObjectAtIndexedSubscript = GetUnarySelector("objectAtIndexedSubscript", Ctx);
1224  NullSelector = GetNullarySelector("null", Ctx);
1225  }
1226 
1227  // Check the receiver type.
1228  if (const ObjCInterfaceDecl *Interface = M.getReceiverInterface()) {
1229 
1230  // Assume that object returned from '[self init]' or '[super init]' is not
1231  // 'nil' if we are processing an inlined function/method.
1232  //
1233  // A defensive callee will (and should) check if the object returned by
1234  // '[super init]' is 'nil' before doing it's own initialization. However,
1235  // since 'nil' is rarely returned in practice, we should not warn when the
1236  // caller to the defensive constructor uses the object in contexts where
1237  // 'nil' is not accepted.
1238  if (!C.inTopFrame() && M.getDecl() &&
1239  M.getDecl()->getMethodFamily() == OMF_init &&
1240  M.isReceiverSelfOrSuper()) {
1241  State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
1242  }
1243 
1244  FoundationClass Cl = findKnownClass(Interface);
1245 
1246  // Objects returned from
1247  // [NSArray|NSOrderedSet]::[ObjectAtIndex|ObjectAtIndexedSubscript]
1248  // are never 'nil'.
1249  if (Cl == FC_NSArray || Cl == FC_NSOrderedSet) {
1250  Selector Sel = M.getSelector();
1251  if (Sel == ObjectAtIndex || Sel == ObjectAtIndexedSubscript) {
1252  // Go ahead and assume the value is non-nil.
1253  State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
1254  }
1255  }
1256 
1257  // Objects returned from [NSNull null] are not nil.
1258  if (Cl == FC_NSNull) {
1259  if (M.getSelector() == NullSelector) {
1260  // Go ahead and assume the value is non-nil.
1261  State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
1262  }
1263  }
1264  }
1265  C.addTransition(State);
1266 }
1267 
1268 //===----------------------------------------------------------------------===//
1269 // Check registration.
1270 //===----------------------------------------------------------------------===//
1271 
1272 void ento::registerNilArgChecker(CheckerManager &mgr) {
1273  mgr.registerChecker<NilArgChecker>();
1274 }
1275 
1276 void ento::registerCFNumberChecker(CheckerManager &mgr) {
1277  mgr.registerChecker<CFNumberChecker>();
1278 }
1279 
1280 void ento::registerCFRetainReleaseChecker(CheckerManager &mgr) {
1281  mgr.registerChecker<CFRetainReleaseChecker>();
1282 }
1283 
1284 void ento::registerClassReleaseChecker(CheckerManager &mgr) {
1285  mgr.registerChecker<ClassReleaseChecker>();
1286 }
1287 
1288 void ento::registerVariadicMethodTypeChecker(CheckerManager &mgr) {
1289  mgr.registerChecker<VariadicMethodTypeChecker>();
1290 }
1291 
1292 void ento::registerObjCLoopChecker(CheckerManager &mgr) {
1293  mgr.registerChecker<ObjCLoopChecker>();
1294 }
1295 
1296 void
1297 ento::registerObjCNonNilReturnValueChecker(CheckerManager &mgr) {
1298  mgr.registerChecker<ObjCNonNilReturnValueChecker>();
1299 }
Defines the clang::ASTContext interface.
SVal getReceiverSVal() const
Returns the value of the receiver at the time of this call.
Definition: CallEvent.cpp:748
CanQualType LongLongTy
Definition: ASTContext.h:973
FunctionDecl - An instance of this class is created to represent a function declaration or definition...
Definition: Decl.h:1698
TypedValueRegion - An abstract class representing regions having a typed value.
Definition: MemRegion.h:511
nonloc::ConcreteInt makeIntVal(const IntegerLiteral *integer)
Definition: SValBuilder.h:254
ObjCDictionaryElement getKeyValueElement(unsigned Index) const
Definition: ExprObjC.h:309
Smart pointer class that efficiently represents Objective-C method names.
A (possibly-)qualified type.
Definition: Type.h:614
bool isBlockPointerType() const
Definition: Type.h:5778
ExplodedNode * generateErrorNode(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generate a transition to a node that will be used to report an error.
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition: Expr.h:2339
ObjCInterfaceDecl * getClassInterface()
Definition: DeclObjC.cpp:1089
void print(raw_ostream &OS, const PrintingPolicy &Policy, const Twine &PlaceHolder=Twine(), unsigned Indentation=0) const
Definition: Type.h:954
static ProgramStateRef assumeCollectionNonEmpty(CheckerContext &C, ProgramStateRef State, SymbolRef CollectionS, bool Assumption)
Returns NULL state if the collection is known to contain elements (or is known not to contain element...
Stmt - This represents one statement.
Definition: Stmt.h:66
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
Definition: Expr.h:2327
ObjCInterfaceDecl * getReceiverInterface() const
Retrieve the Objective-C interface to which this message is being directed, if known.
Definition: ExprObjC.cpp:327
The argument acts as if has been passed to CFMakeCollectable, which transfers the object to the Garba...
ExplodedNode * addTransition(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generates a new transition in the program state graph (ExplodedGraph).
virtual QualType getValueType() const =0
StringRef P
static StringRef GetReceiverInterfaceName(const ObjCMethodCall &msg)
CanQualType LongTy
Definition: ASTContext.h:973
SourceRange getSourceRange() const override
Definition: CallEvent.cpp:777
Value representing integer constant.
Definition: SVals.h:353
static ProgramStateRef checkCollectionNonNil(CheckerContext &C, ProgramStateRef State, const ObjCForCollectionStmt *FCS)
Assumes that the collection is non-nil.
VarDecl - An instance of this class is created to represent a variable declaration or definition...
Definition: Decl.h:807
const T * getAs() const
Member-template getAs<specific type>&#39;.
Definition: Type.h:6105
const FunctionDecl * getCalleeDecl(const CallExpr *CE) const
Get the declaration of the called function (path-sensitive).
ObjCMethodDecl - Represents an instance or class method declaration.
Definition: DeclObjC.h:113
bool isDead(SymbolRef sym) const
Returns whether or not a symbol has been confirmed dead.
ExplodedNode * getPredecessor()
Returns the previous node in the exploded graph, which includes the state of the program before the c...
Defines the Objective-C statement AST node classes.
SVal getSVal(const Stmt *S) const
Get the value of arbitrary expressions at this point in the path.
Symbolic value.
Definition: SymExpr.h:29
IdentifierInfo * getIdentifier() const
getIdentifier - Get the identifier that names this declaration, if there is one.
Definition: Decl.h:265
One of these records is kept for each identifier that is lexed.
An element in an Objective-C dictionary literal.
Definition: ExprObjC.h:212
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:128
static Selector getKeywordSelector(ASTContext &Ctx, IdentifierInfos *... IIs)
LineState State
The argument is treated as if an -autorelease message had been sent to the referenced object...
static ProgramStateRef checkElementNonNil(CheckerContext &C, ProgramStateRef State, const ObjCForCollectionStmt *FCS)
Assumes that the collection elements are non-nil.
const ObjCInterfaceDecl * getReceiverInterface() const
Get the interface for the receiver.
Definition: CallEvent.h:928
void addSymbolDependency(const SymbolRef Primary, const SymbolRef Dependent)
Add artificial symbol dependency.
ObjCArrayLiteral - used for objective-c array containers; as in: @["Hello", NSApp, [NSNumber numberWithInt:42]];.
Definition: ExprObjC.h:144
i32 captured_struct **param SharedsTy A type which contains references the shared variables *param Shareds Context with the list of shared variables from the p *TaskFunction *param Data Additional data for task generation like final * state
bool isIntegralOrEnumerationType() const
Determine whether this type is an integral or enumeration type.
Definition: Type.h:6019
IdentifierTable & Idents
Definition: ASTContext.h:515
bool isUnarySelector() const
ObjCMethodFamily getMethodFamily() const
Determines the family of this method.
Definition: DeclObjC.cpp:931
Represents any expression that calls an Objective-C method.
Definition: CallEvent.h:870
Selector GetNullarySelector(StringRef name, ASTContext &Ctx)
Utility function for constructing a nullary selector.
Definition: ASTContext.h:2782
Expr * Key
The key for the dictionary element.
Definition: ExprObjC.h:214
#define UINT_MAX
Definition: limits.h:72
Represents an ObjC class declaration.
Definition: DeclObjC.h:1108
static SymbolRef getMethodReceiverIfKnownImmutable(const CallEvent *Call)
static bool isKnownNonNilCollectionType(QualType T)
SymbolRef getAsSymbol(bool IncludeBaseRegions=false) const
If this SVal wraps a symbol return that SymbolRef.
Definition: SVals.cpp:116
bool isReceiverSelfOrSuper() const
Checks if the receiver refers to &#39;self&#39; or &#39;super&#39;.
Definition: CallEvent.cpp:764
The return type of classify().
Definition: Expr.h:316
#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)
Declares an immutable map of type NameTy, suitable for placement into the ProgramState.
DefinedOrUnknownSVal makeZeroVal(QualType type)
Construct an SVal representing &#39;0&#39; for the specified type.
Definition: SValBuilder.cpp:32
Expr - This represents one expression.
Definition: Expr.h:119
static FoundationClass findKnownClass(const ObjCInterfaceDecl *ID, bool IncludeSuperclasses=true)
pred_iterator pred_end()
const FunctionProtoType * T
ObjCDictionaryLiteral - AST node to represent objective-c dictionary literals; as in:"name" : NSUserN...
Definition: ExprObjC.h:257
DeclContext * getDeclContext()
Definition: DeclBase.h:425
QualType getConditionType() const
Definition: SValBuilder.h:136
ObjCInterfaceDecl * getSuperClass() const
Definition: DeclObjC.cpp:314
CanQualType ShortTy
Definition: ASTContext.h:973
SymbolManager & getSymbolManager()
void print(llvm::raw_ostream &OS) const
Prints the full selector name (e.g. "foo:bar:").
QualType getType() const
Definition: Expr.h:140
Expr * getElement(unsigned Index)
getExpr - Return the Expr at the specified index.
Definition: ExprObjC.h:187
SVal evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op, SVal lhs, SVal rhs, QualType type)
unsigned getNumArgs() const
ExplodedNode * generateNonFatalErrorNode(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generate a transition to a node that will be used to report an error.
Optional< T > getAs() const
Convert to the specified SVal type, returning None if this SVal is not of the desired type...
Definition: SVals.h:100
void emitReport(std::unique_ptr< BugReport > R)
Emit the diagnostics report.
Kind
CHECKER * registerChecker()
Used to register checkers.
IdentifierInfo * getIdentifierInfoForSlot(unsigned argIndex) const
Retrieve the identifier at a given position in the selector.
IdentifierInfo & get(StringRef Name)
Return the identifier token info for the specified named identifier.
ExplodedNode * generateSink(ProgramStateRef State, ExplodedNode *Pred, const ProgramPointTag *Tag=nullptr)
Generate a sink node.
unsigned getNumElements() const
getNumElements - Return number of elements of objective-c dictionary literal.
Definition: ExprObjC.h:307
DeclStmt - Adaptor class for mixing declarations with statements and expressions. ...
Definition: Stmt.h:487
CanQualType FloatTy
Definition: ASTContext.h:976
ProgramPoint getLocation() const
getLocation - Returns the edge associated with the given node.
SVal - This represents a symbolic expression, which can be either an L-value or an R-value...
Definition: SVals.h:63
bool isObjCObjectPointerType() const
Definition: Type.h:5847
A class responsible for cleaning up unused symbols.
ObjCBoxedExpr - used for generalized expression boxing.
Definition: ExprObjC.h:94
const ObjCMethodDecl * getDecl() const override
Definition: CallEvent.h:896
Expr * Value
The value of the dictionary element.
Definition: ExprObjC.h:217
StringRef getName() const
Return the actual identifier string.
virtual const ObjCMessageExpr * getOriginExpr() const
Definition: CallEvent.h:893
CanQualType CharTy
Definition: ASTContext.h:967
Selector getSelector() const
Definition: CallEvent.h:912
Dataflow Directional Tag Classes.
bool isZeroConstant() const
Definition: SVals.cpp:219
static bool alreadyExecutedAtLeastOneLoopIteration(const ExplodedNode *N, const ObjCForCollectionStmt *FCS)
If the fist block edge is a back edge, we are reentering the loop.
const Expr * getInit() const
Definition: Decl.h:1213
Represents symbolic expression.
Definition: SVals.h:327
Represents an abstract call to a function or method along a particular path.
Definition: CallEvent.h:140
ObjCMessageKind getMessageKind() const
Returns how the message was written in the source (property access, subscript, or explicit message se...
Definition: CallEvent.cpp:808
PointerEscapeKind
Describes the different reasons a pointer escapes during analysis.
Represents a pointer to an Objective C object.
Definition: Type.h:5280
bool isInstanceMessage() const
Definition: CallEvent.h:906
T castAs() const
Convert to the specified SVal type, asserting that this SVal is of the desired type.
Definition: SVals.h:92
const ExplodedNode *const * const_pred_iterator
ObjCInterfaceDecl * getInterfaceDecl() const
If this pointer points to an Objective @interface type, gets the declaration for that interface...
Definition: Type.h:5335
unsigned getNumElements() const
getNumElements - Return number of elements of objective-c array literal.
Definition: ExprObjC.h:184
Represents Objective-C&#39;s collection statement.
Definition: StmtObjC.h:24
const ProgramStateRef & getState() const
unsigned getNumArgs() const override
Definition: CallEvent.h:899
uint64_t getTypeSize(QualType T) const
Return the size of the specified (complete) type T, in bits.
Definition: ASTContext.h:1961
CanQualType getCanonicalType(QualType T) const
Return the canonical (structural) type corresponding to the specified potentially non-canonical type ...
Definition: ASTContext.h:2124
const Expr * getArgExpr(unsigned Index) const override
Definition: CallEvent.h:902
DefinedOrUnknownSVal evalEQ(ProgramStateRef state, DefinedOrUnknownSVal lhs, DefinedOrUnknownSVal rhs)
Selector GetUnarySelector(StringRef name, ASTContext &Ctx)
Utility function for constructing an unary selector.
Definition: ASTContext.h:2788
bool trackNullOrUndefValue(const ExplodedNode *N, const Stmt *S, BugReport &R, bool IsArg=false, bool EnableNullFPSuppression=true)
Attempts to add visitors to trace a null or undefined value back to its point of origin, whether it is a symbol constrained to null or an explicit assignment.
pred_iterator pred_begin()
bool isVariadic() const
Definition: DeclObjC.h:418
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition: Stmt.cpp:265
SValBuilder & getSValBuilder()
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition: Expr.h:2270
StringRef getName() const
getName - Get the name of identifier for this declaration as a StringRef.
Definition: Decl.h:270
static Optional< uint64_t > GetCFNumberSize(ASTContext &Ctx, uint64_t i)
CanQualType IntTy
Definition: ASTContext.h:973
A trivial tuple used to represent a source range.
Optional< T > getAs() const
Convert to the specified ProgramPoint type, returning None if this ProgramPoint is not of the desired...
Definition: ProgramPoint.h:151
bool inTopFrame() const
Return true if the current LocationContext has no caller context.
CanQualType DoubleTy
Definition: ASTContext.h:976
static bool isObjCNSObjectType(QualType Ty)
Return true if this is an NSObject object with its NSObject attribute set.
Definition: ASTContext.h:1941
const LocationContext * getLocationContext() const
const LangOptions & getLangOpts() const
TypedRegion - An abstract class representing regions that are typed.
Definition: MemRegion.h:487