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