clang  14.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 private:
352  void EmitError(const TypedRegion* R, const Expr *Ex,
353  uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind);
354 };
355 } // end anonymous namespace
356 
374 };
375 
377  static const unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 };
378 
379  if (i < kCFNumberCharType)
380  return FixedSize[i-1];
381 
382  QualType T;
383 
384  switch (i) {
385  case kCFNumberCharType: T = Ctx.CharTy; break;
386  case kCFNumberShortType: T = Ctx.ShortTy; break;
387  case kCFNumberIntType: T = Ctx.IntTy; break;
388  case kCFNumberLongType: T = Ctx.LongTy; break;
389  case kCFNumberLongLongType: T = Ctx.LongLongTy; break;
390  case kCFNumberFloatType: T = Ctx.FloatTy; break;
391  case kCFNumberDoubleType: T = Ctx.DoubleTy; break;
395  // FIXME: We need a way to map from names to Type*.
396  default:
397  return None;
398  }
399 
400  return Ctx.getTypeSize(T);
401 }
402 
403 #if 0
404 static const char* GetCFNumberTypeStr(uint64_t i) {
405  static const char* Names[] = {
406  "kCFNumberSInt8Type",
407  "kCFNumberSInt16Type",
408  "kCFNumberSInt32Type",
409  "kCFNumberSInt64Type",
410  "kCFNumberFloat32Type",
411  "kCFNumberFloat64Type",
412  "kCFNumberCharType",
413  "kCFNumberShortType",
414  "kCFNumberIntType",
415  "kCFNumberLongType",
416  "kCFNumberLongLongType",
417  "kCFNumberFloatType",
418  "kCFNumberDoubleType",
419  "kCFNumberCFIndexType",
420  "kCFNumberNSIntegerType",
421  "kCFNumberCGFloatType"
422  };
423 
424  return i <= kCFNumberCGFloatType ? Names[i-1] : "Invalid CFNumberType";
425 }
426 #endif
427 
428 void CFNumberChecker::checkPreStmt(const CallExpr *CE,
429  CheckerContext &C) const {
430  ProgramStateRef state = C.getState();
431  const FunctionDecl *FD = C.getCalleeDecl(CE);
432  if (!FD)
433  return;
434 
435  ASTContext &Ctx = C.getASTContext();
436  if (!ICreate) {
437  ICreate = &Ctx.Idents.get("CFNumberCreate");
438  IGetValue = &Ctx.Idents.get("CFNumberGetValue");
439  }
440  if (!(FD->getIdentifier() == ICreate || FD->getIdentifier() == IGetValue) ||
441  CE->getNumArgs() != 3)
442  return;
443 
444  // Get the value of the "theType" argument.
445  SVal TheTypeVal = C.getSVal(CE->getArg(1));
446 
447  // FIXME: We really should allow ranges of valid theType values, and
448  // bifurcate the state appropriately.
449  Optional<nonloc::ConcreteInt> V = TheTypeVal.getAs<nonloc::ConcreteInt>();
450  if (!V)
451  return;
452 
453  uint64_t NumberKind = V->getValue().getLimitedValue();
454  Optional<uint64_t> OptCFNumberSize = GetCFNumberSize(Ctx, NumberKind);
455 
456  // FIXME: In some cases we can emit an error.
457  if (!OptCFNumberSize)
458  return;
459 
460  uint64_t CFNumberSize = *OptCFNumberSize;
461 
462  // Look at the value of the integer being passed by reference. Essentially
463  // we want to catch cases where the value passed in is not equal to the
464  // size of the type being created.
465  SVal TheValueExpr = C.getSVal(CE->getArg(2));
466 
467  // FIXME: Eventually we should handle arbitrary locations. We can do this
468  // by having an enhanced memory model that does low-level typing.
469  Optional<loc::MemRegionVal> LV = TheValueExpr.getAs<loc::MemRegionVal>();
470  if (!LV)
471  return;
472 
473  const TypedValueRegion* R = dyn_cast<TypedValueRegion>(LV->stripCasts());
474  if (!R)
475  return;
476 
477  QualType T = Ctx.getCanonicalType(R->getValueType());
478 
479  // FIXME: If the pointee isn't an integer type, should we flag a warning?
480  // People can do weird stuff with pointers.
481 
482  if (!T->isIntegralOrEnumerationType())
483  return;
484 
485  uint64_t PrimitiveTypeSize = Ctx.getTypeSize(T);
486 
487  if (PrimitiveTypeSize == CFNumberSize)
488  return;
489 
490  // FIXME: We can actually create an abstract "CFNumber" object that has
491  // the bits initialized to the provided values.
492  ExplodedNode *N = C.generateNonFatalErrorNode();
493  if (N) {
494  SmallString<128> sbuf;
495  llvm::raw_svector_ostream os(sbuf);
496  bool isCreate = (FD->getIdentifier() == ICreate);
497 
498  if (isCreate) {
499  os << (PrimitiveTypeSize == 8 ? "An " : "A ")
500  << PrimitiveTypeSize << "-bit integer is used to initialize a "
501  << "CFNumber object that represents "
502  << (CFNumberSize == 8 ? "an " : "a ")
503  << CFNumberSize << "-bit integer; ";
504  } else {
505  os << "A CFNumber object that represents "
506  << (CFNumberSize == 8 ? "an " : "a ")
507  << CFNumberSize << "-bit integer is used to initialize "
508  << (PrimitiveTypeSize == 8 ? "an " : "a ")
509  << PrimitiveTypeSize << "-bit integer; ";
510  }
511 
512  if (PrimitiveTypeSize < CFNumberSize)
513  os << (CFNumberSize - PrimitiveTypeSize)
514  << " bits of the CFNumber value will "
515  << (isCreate ? "be garbage." : "overwrite adjacent storage.");
516  else
517  os << (PrimitiveTypeSize - CFNumberSize)
518  << " bits of the integer value will be "
519  << (isCreate ? "lost." : "garbage.");
520 
521  if (!BT)
522  BT.reset(new APIMisuse(this, "Bad use of CFNumber APIs"));
523 
524  auto report = std::make_unique<PathSensitiveBugReport>(*BT, os.str(), N);
525  report->addRange(CE->getArg(2)->getSourceRange());
526  C.emitReport(std::move(report));
527  }
528 }
529 
530 //===----------------------------------------------------------------------===//
531 // CFRetain/CFRelease/CFMakeCollectable/CFAutorelease checking for null arguments.
532 //===----------------------------------------------------------------------===//
533 
534 namespace {
535 class CFRetainReleaseChecker : public Checker<check::PreCall> {
536  mutable APIMisuse BT{this, "null passed to CF memory management function"};
537  const CallDescriptionSet ModelledCalls = {
538  {"CFRetain", 1},
539  {"CFRelease", 1},
540  {"CFMakeCollectable", 1},
541  {"CFAutorelease", 1},
542  };
543 
544 public:
545  void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
546 };
547 } // end anonymous namespace
548 
549 void CFRetainReleaseChecker::checkPreCall(const CallEvent &Call,
550  CheckerContext &C) const {
551  // TODO: Make this check part of CallDescription.
552  if (!Call.isGlobalCFunction())
553  return;
554 
555  // Check if we called CFRetain/CFRelease/CFMakeCollectable/CFAutorelease.
556  if (!ModelledCalls.contains(Call))
557  return;
558 
559  // Get the argument's value.
560  SVal ArgVal = Call.getArgSVal(0);
561  Optional<DefinedSVal> DefArgVal = ArgVal.getAs<DefinedSVal>();
562  if (!DefArgVal)
563  return;
564 
565  // Is it null?
566  ProgramStateRef state = C.getState();
567  ProgramStateRef stateNonNull, stateNull;
568  std::tie(stateNonNull, stateNull) = state->assume(*DefArgVal);
569 
570  if (!stateNonNull) {
571  ExplodedNode *N = C.generateErrorNode(stateNull);
572  if (!N)
573  return;
574 
575  SmallString<64> Str;
576  raw_svector_ostream OS(Str);
577  OS << "Null pointer argument in call to "
578  << cast<FunctionDecl>(Call.getDecl())->getName();
579 
580  auto report = std::make_unique<PathSensitiveBugReport>(BT, OS.str(), N);
581  report->addRange(Call.getArgSourceRange(0));
582  bugreporter::trackExpressionValue(N, Call.getArgExpr(0), *report);
583  C.emitReport(std::move(report));
584  return;
585  }
586 
587  // From here on, we know the argument is non-null.
588  C.addTransition(stateNonNull);
589 }
590 
591 //===----------------------------------------------------------------------===//
592 // Check for sending 'retain', 'release', or 'autorelease' directly to a Class.
593 //===----------------------------------------------------------------------===//
594 
595 namespace {
596 class ClassReleaseChecker : public Checker<check::PreObjCMessage> {
597  mutable Selector releaseS;
598  mutable Selector retainS;
599  mutable Selector autoreleaseS;
600  mutable Selector drainS;
601  mutable std::unique_ptr<BugType> BT;
602 
603 public:
604  void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
605 };
606 } // end anonymous namespace
607 
608 void ClassReleaseChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
609  CheckerContext &C) const {
610  if (!BT) {
611  BT.reset(new APIMisuse(
612  this, "message incorrectly sent to class instead of class instance"));
613 
614  ASTContext &Ctx = C.getASTContext();
615  releaseS = GetNullarySelector("release", Ctx);
616  retainS = GetNullarySelector("retain", Ctx);
617  autoreleaseS = GetNullarySelector("autorelease", Ctx);
618  drainS = GetNullarySelector("drain", Ctx);
619  }
620 
621  if (msg.isInstanceMessage())
622  return;
623  const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
624  assert(Class);
625 
626  Selector S = msg.getSelector();
627  if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
628  return;
629 
630  if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
631  SmallString<200> buf;
632  llvm::raw_svector_ostream os(buf);
633 
634  os << "The '";
635  S.print(os);
636  os << "' message should be sent to instances "
637  "of class '" << Class->getName()
638  << "' and not the class directly";
639 
640  auto report = std::make_unique<PathSensitiveBugReport>(*BT, os.str(), N);
641  report->addRange(msg.getSourceRange());
642  C.emitReport(std::move(report));
643  }
644 }
645 
646 //===----------------------------------------------------------------------===//
647 // Check for passing non-Objective-C types to variadic methods that expect
648 // only Objective-C types.
649 //===----------------------------------------------------------------------===//
650 
651 namespace {
652 class VariadicMethodTypeChecker : public Checker<check::PreObjCMessage> {
653  mutable Selector arrayWithObjectsS;
654  mutable Selector dictionaryWithObjectsAndKeysS;
655  mutable Selector setWithObjectsS;
656  mutable Selector orderedSetWithObjectsS;
657  mutable Selector initWithObjectsS;
658  mutable Selector initWithObjectsAndKeysS;
659  mutable std::unique_ptr<BugType> BT;
660 
661  bool isVariadicMessage(const ObjCMethodCall &msg) const;
662 
663 public:
664  void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
665 };
666 } // end anonymous namespace
667 
668 /// isVariadicMessage - Returns whether the given message is a variadic message,
669 /// where all arguments must be Objective-C types.
670 bool
671 VariadicMethodTypeChecker::isVariadicMessage(const ObjCMethodCall &msg) const {
672  const ObjCMethodDecl *MD = msg.getDecl();
673 
674  if (!MD || !MD->isVariadic() || isa<ObjCProtocolDecl>(MD->getDeclContext()))
675  return false;
676 
677  Selector S = msg.getSelector();
678 
679  if (msg.isInstanceMessage()) {
680  // FIXME: Ideally we'd look at the receiver interface here, but that's not
681  // useful for init, because alloc returns 'id'. In theory, this could lead
682  // to false positives, for example if there existed a class that had an
683  // initWithObjects: implementation that does accept non-Objective-C pointer
684  // types, but the chance of that happening is pretty small compared to the
685  // gains that this analysis gives.
687 
688  switch (findKnownClass(Class)) {
689  case FC_NSArray:
690  case FC_NSOrderedSet:
691  case FC_NSSet:
692  return S == initWithObjectsS;
693  case FC_NSDictionary:
694  return S == initWithObjectsAndKeysS;
695  default:
696  return false;
697  }
698  } else {
699  const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
700 
701  switch (findKnownClass(Class)) {
702  case FC_NSArray:
703  return S == arrayWithObjectsS;
704  case FC_NSOrderedSet:
705  return S == orderedSetWithObjectsS;
706  case FC_NSSet:
707  return S == setWithObjectsS;
708  case FC_NSDictionary:
709  return S == dictionaryWithObjectsAndKeysS;
710  default:
711  return false;
712  }
713  }
714 }
715 
716 void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
717  CheckerContext &C) const {
718  if (!BT) {
719  BT.reset(new APIMisuse(this,
720  "Arguments passed to variadic method aren't all "
721  "Objective-C pointer types"));
722 
723  ASTContext &Ctx = C.getASTContext();
724  arrayWithObjectsS = GetUnarySelector("arrayWithObjects", Ctx);
725  dictionaryWithObjectsAndKeysS =
726  GetUnarySelector("dictionaryWithObjectsAndKeys", Ctx);
727  setWithObjectsS = GetUnarySelector("setWithObjects", Ctx);
728  orderedSetWithObjectsS = GetUnarySelector("orderedSetWithObjects", Ctx);
729 
730  initWithObjectsS = GetUnarySelector("initWithObjects", Ctx);
731  initWithObjectsAndKeysS = GetUnarySelector("initWithObjectsAndKeys", Ctx);
732  }
733 
734  if (!isVariadicMessage(msg))
735  return;
736 
737  // We are not interested in the selector arguments since they have
738  // well-defined types, so the compiler will issue a warning for them.
739  unsigned variadicArgsBegin = msg.getSelector().getNumArgs();
740 
741  // We're not interested in the last argument since it has to be nil or the
742  // compiler would have issued a warning for it elsewhere.
743  unsigned variadicArgsEnd = msg.getNumArgs() - 1;
744 
745  if (variadicArgsEnd <= variadicArgsBegin)
746  return;
747 
748  // Verify that all arguments have Objective-C types.
749  Optional<ExplodedNode*> errorNode;
750 
751  for (unsigned I = variadicArgsBegin; I != variadicArgsEnd; ++I) {
752  QualType ArgTy = msg.getArgExpr(I)->getType();
753  if (ArgTy->isObjCObjectPointerType())
754  continue;
755 
756  // Block pointers are treaded as Objective-C pointers.
757  if (ArgTy->isBlockPointerType())
758  continue;
759 
760  // Ignore pointer constants.
761  if (msg.getArgSVal(I).getAs<loc::ConcreteInt>())
762  continue;
763 
764  // Ignore pointer types annotated with 'NSObject' attribute.
765  if (C.getASTContext().isObjCNSObjectType(ArgTy))
766  continue;
767 
768  // Ignore CF references, which can be toll-free bridged.
770  continue;
771 
772  // Generate only one error node to use for all bug reports.
773  if (!errorNode.hasValue())
774  errorNode = C.generateNonFatalErrorNode();
775 
776  if (!errorNode.getValue())
777  continue;
778 
779  SmallString<128> sbuf;
780  llvm::raw_svector_ostream os(sbuf);
781 
782  StringRef TypeName = GetReceiverInterfaceName(msg);
783  if (!TypeName.empty())
784  os << "Argument to '" << TypeName << "' method '";
785  else
786  os << "Argument to method '";
787 
788  msg.getSelector().print(os);
789  os << "' should be an Objective-C pointer type, not '";
790  ArgTy.print(os, C.getLangOpts());
791  os << "'";
792 
793  auto R = std::make_unique<PathSensitiveBugReport>(*BT, os.str(),
794  errorNode.getValue());
795  R->addRange(msg.getArgSourceRange(I));
796  C.emitReport(std::move(R));
797  }
798 }
799 
800 //===----------------------------------------------------------------------===//
801 // Improves the modeling of loops over Cocoa collections.
802 //===----------------------------------------------------------------------===//
803 
804 // The map from container symbol to the container count symbol.
805 // We currently will remember the last container count symbol encountered.
807 REGISTER_MAP_WITH_PROGRAMSTATE(ContainerNonEmptyMap, SymbolRef, bool)
808 
809 namespace {
810 class ObjCLoopChecker
811  : public Checker<check::PostStmt<ObjCForCollectionStmt>,
812  check::PostObjCMessage,
813  check::DeadSymbols,
814  check::PointerEscape > {
815  mutable IdentifierInfo *CountSelectorII;
816 
817  bool isCollectionCountMethod(const ObjCMethodCall &M,
818  CheckerContext &C) const;
819 
820 public:
821  ObjCLoopChecker() : CountSelectorII(nullptr) {}
822  void checkPostStmt(const ObjCForCollectionStmt *FCS, CheckerContext &C) const;
823  void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
824  void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
825  ProgramStateRef checkPointerEscape(ProgramStateRef State,
826  const InvalidatedSymbols &Escaped,
827  const CallEvent *Call,
828  PointerEscapeKind Kind) const;
829 };
830 } // end anonymous namespace
831 
834  if (!PT)
835  return false;
836 
837  const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();
838  if (!ID)
839  return false;
840 
841  switch (findKnownClass(ID)) {
842  case FC_NSArray:
843  case FC_NSDictionary:
844  case FC_NSEnumerator:
845  case FC_NSOrderedSet:
846  case FC_NSSet:
847  return true;
848  default:
849  return false;
850  }
851 }
852 
853 /// Assumes that the collection is non-nil.
854 ///
855 /// If the collection is known to be nil, returns NULL to indicate an infeasible
856 /// path.
857 static ProgramStateRef checkCollectionNonNil(CheckerContext &C,
859  const ObjCForCollectionStmt *FCS) {
860  if (!State)
861  return nullptr;
862 
863  SVal CollectionVal = C.getSVal(FCS->getCollection());
864  Optional<DefinedSVal> KnownCollection = CollectionVal.getAs<DefinedSVal>();
865  if (!KnownCollection)
866  return State;
867 
868  ProgramStateRef StNonNil, StNil;
869  std::tie(StNonNil, StNil) = State->assume(*KnownCollection);
870  if (StNil && !StNonNil) {
871  // The collection is nil. This path is infeasible.
872  return nullptr;
873  }
874 
875  return StNonNil;
876 }
877 
878 /// Assumes that the collection elements are non-nil.
879 ///
880 /// This only applies if the collection is one of those known not to contain
881 /// nil values.
882 static ProgramStateRef checkElementNonNil(CheckerContext &C,
884  const ObjCForCollectionStmt *FCS) {
885  if (!State)
886  return nullptr;
887 
888  // See if the collection is one where we /know/ the elements are non-nil.
890  return State;
891 
892  const LocationContext *LCtx = C.getLocationContext();
893  const Stmt *Element = FCS->getElement();
894 
895  // FIXME: Copied from ExprEngineObjC.
896  Optional<Loc> ElementLoc;
897  if (const DeclStmt *DS = dyn_cast<DeclStmt>(Element)) {
898  const VarDecl *ElemDecl = cast<VarDecl>(DS->getSingleDecl());
899  assert(ElemDecl->getInit() == nullptr);
900  ElementLoc = State->getLValue(ElemDecl, LCtx);
901  } else {
902  ElementLoc = State->getSVal(Element, LCtx).getAs<Loc>();
903  }
904 
905  if (!ElementLoc)
906  return State;
907 
908  // Go ahead and assume the value is non-nil.
909  SVal Val = State->getSVal(*ElementLoc);
910  return State->assume(Val.castAs<DefinedOrUnknownSVal>(), true);
911 }
912 
913 /// Returns NULL state if the collection is known to contain elements
914 /// (or is known not to contain elements if the Assumption parameter is false.)
915 static ProgramStateRef
917  SymbolRef CollectionS, bool Assumption) {
918  if (!State || !CollectionS)
919  return State;
920 
921  const SymbolRef *CountS = State->get<ContainerCountMap>(CollectionS);
922  if (!CountS) {
923  const bool *KnownNonEmpty = State->get<ContainerNonEmptyMap>(CollectionS);
924  if (!KnownNonEmpty)
925  return State->set<ContainerNonEmptyMap>(CollectionS, Assumption);
926  return (Assumption == *KnownNonEmpty) ? State : nullptr;
927  }
928 
929  SValBuilder &SvalBuilder = C.getSValBuilder();
930  SVal CountGreaterThanZeroVal =
931  SvalBuilder.evalBinOp(State, BO_GT,
932  nonloc::SymbolVal(*CountS),
933  SvalBuilder.makeIntVal(0, (*CountS)->getType()),
934  SvalBuilder.getConditionType());
935  Optional<DefinedSVal> CountGreaterThanZero =
936  CountGreaterThanZeroVal.getAs<DefinedSVal>();
937  if (!CountGreaterThanZero) {
938  // The SValBuilder cannot construct a valid SVal for this condition.
939  // This means we cannot properly reason about it.
940  return State;
941  }
942 
943  return State->assume(*CountGreaterThanZero, Assumption);
944 }
945 
946 static ProgramStateRef
948  const ObjCForCollectionStmt *FCS,
949  bool Assumption) {
950  if (!State)
951  return nullptr;
952 
953  SymbolRef CollectionS = C.getSVal(FCS->getCollection()).getAsSymbol();
954  return assumeCollectionNonEmpty(C, State, CollectionS, Assumption);
955 }
956 
957 /// If the fist block edge is a back edge, we are reentering the loop.
958 static bool alreadyExecutedAtLeastOneLoopIteration(const ExplodedNode *N,
959  const ObjCForCollectionStmt *FCS) {
960  if (!N)
961  return false;
962 
963  ProgramPoint P = N->getLocation();
964  if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) {
965  return BE->getSrc()->getLoopTarget() == FCS;
966  }
967 
968  // Keep looking for a block edge.
970  E = N->pred_end(); I != E; ++I) {
972  return true;
973  }
974 
975  return false;
976 }
977 
978 void ObjCLoopChecker::checkPostStmt(const ObjCForCollectionStmt *FCS,
979  CheckerContext &C) const {
980  ProgramStateRef State = C.getState();
981 
982  // Check if this is the branch for the end of the loop.
983  if (!ExprEngine::hasMoreIteration(State, FCS, C.getLocationContext())) {
984  if (!alreadyExecutedAtLeastOneLoopIteration(C.getPredecessor(), FCS))
985  State = assumeCollectionNonEmpty(C, State, FCS, /*Assumption*/false);
986 
987  // Otherwise, this is a branch that goes through the loop body.
988  } else {
989  State = checkCollectionNonNil(C, State, FCS);
990  State = checkElementNonNil(C, State, FCS);
991  State = assumeCollectionNonEmpty(C, State, FCS, /*Assumption*/true);
992  }
993 
994  if (!State)
995  C.generateSink(C.getState(), C.getPredecessor());
996  else if (State != C.getState())
997  C.addTransition(State);
998 }
999 
1000 bool ObjCLoopChecker::isCollectionCountMethod(const ObjCMethodCall &M,
1001  CheckerContext &C) const {
1002  Selector S = M.getSelector();
1003  // Initialize the identifiers on first use.
1004  if (!CountSelectorII)
1005  CountSelectorII = &C.getASTContext().Idents.get("count");
1006 
1007  // If the method returns collection count, record the value.
1008  return S.isUnarySelector() &&
1009  (S.getIdentifierInfoForSlot(0) == CountSelectorII);
1010 }
1011 
1012 void ObjCLoopChecker::checkPostObjCMessage(const ObjCMethodCall &M,
1013  CheckerContext &C) const {
1014  if (!M.isInstanceMessage())
1015  return;
1016 
1017  const ObjCInterfaceDecl *ClassID = M.getReceiverInterface();
1018  if (!ClassID)
1019  return;
1020 
1022  if (Class != FC_NSDictionary &&
1023  Class != FC_NSArray &&
1024  Class != FC_NSSet &&
1025  Class != FC_NSOrderedSet)
1026  return;
1027 
1028  SymbolRef ContainerS = M.getReceiverSVal().getAsSymbol();
1029  if (!ContainerS)
1030  return;
1031 
1032  // If we are processing a call to "count", get the symbolic value returned by
1033  // a call to "count" and add it to the map.
1034  if (!isCollectionCountMethod(M, C))
1035  return;
1036 
1037  const Expr *MsgExpr = M.getOriginExpr();
1038  SymbolRef CountS = C.getSVal(MsgExpr).getAsSymbol();
1039  if (CountS) {
1040  ProgramStateRef State = C.getState();
1041 
1042  C.getSymbolManager().addSymbolDependency(ContainerS, CountS);
1043  State = State->set<ContainerCountMap>(ContainerS, CountS);
1044 
1045  if (const bool *NonEmpty = State->get<ContainerNonEmptyMap>(ContainerS)) {
1046  State = State->remove<ContainerNonEmptyMap>(ContainerS);
1047  State = assumeCollectionNonEmpty(C, State, ContainerS, *NonEmpty);
1048  }
1049 
1050  C.addTransition(State);
1051  }
1052 }
1053 
1054 static SymbolRef getMethodReceiverIfKnownImmutable(const CallEvent *Call) {
1055  const ObjCMethodCall *Message = dyn_cast_or_null<ObjCMethodCall>(Call);
1056  if (!Message)
1057  return nullptr;
1058 
1059  const ObjCMethodDecl *MD = Message->getDecl();
1060  if (!MD)
1061  return nullptr;
1062 
1063  const ObjCInterfaceDecl *StaticClass;
1064  if (isa<ObjCProtocolDecl>(MD->getDeclContext())) {
1065  // We can't find out where the method was declared without doing more work.
1066  // Instead, see if the receiver is statically typed as a known immutable
1067  // collection.
1068  StaticClass = Message->getOriginExpr()->getReceiverInterface();
1069  } else {
1070  StaticClass = MD->getClassInterface();
1071  }
1072 
1073  if (!StaticClass)
1074  return nullptr;
1075 
1076  switch (findKnownClass(StaticClass, /*IncludeSuper=*/false)) {
1077  case FC_None:
1078  return nullptr;
1079  case FC_NSArray:
1080  case FC_NSDictionary:
1081  case FC_NSEnumerator:
1082  case FC_NSNull:
1083  case FC_NSOrderedSet:
1084  case FC_NSSet:
1085  case FC_NSString:
1086  break;
1087  }
1088 
1089  return Message->getReceiverSVal().getAsSymbol();
1090 }
1091 
1093 ObjCLoopChecker::checkPointerEscape(ProgramStateRef State,
1094  const InvalidatedSymbols &Escaped,
1095  const CallEvent *Call,
1096  PointerEscapeKind Kind) const {
1097  SymbolRef ImmutableReceiver = getMethodReceiverIfKnownImmutable(Call);
1098 
1099  // Remove the invalidated symbols form the collection count map.
1100  for (InvalidatedSymbols::const_iterator I = Escaped.begin(),
1101  E = Escaped.end();
1102  I != E; ++I) {
1103  SymbolRef Sym = *I;
1104 
1105  // Don't invalidate this symbol's count if we know the method being called
1106  // is declared on an immutable class. This isn't completely correct if the
1107  // receiver is also passed as an argument, but in most uses of NSArray,
1108  // NSDictionary, etc. this isn't likely to happen in a dangerous way.
1109  if (Sym == ImmutableReceiver)
1110  continue;
1111 
1112  // The symbol escaped. Pessimistically, assume that the count could have
1113  // changed.
1114  State = State->remove<ContainerCountMap>(Sym);
1115  State = State->remove<ContainerNonEmptyMap>(Sym);
1116  }
1117  return State;
1118 }
1119 
1120 void ObjCLoopChecker::checkDeadSymbols(SymbolReaper &SymReaper,
1121  CheckerContext &C) const {
1122  ProgramStateRef State = C.getState();
1123 
1124  // Remove the dead symbols from the collection count map.
1125  ContainerCountMapTy Tracked = State->get<ContainerCountMap>();
1126  for (ContainerCountMapTy::iterator I = Tracked.begin(),
1127  E = Tracked.end(); I != E; ++I) {
1128  SymbolRef Sym = I->first;
1129  if (SymReaper.isDead(Sym)) {
1130  State = State->remove<ContainerCountMap>(Sym);
1131  State = State->remove<ContainerNonEmptyMap>(Sym);
1132  }
1133  }
1134 
1135  C.addTransition(State);
1136 }
1137 
1138 namespace {
1139 /// \class ObjCNonNilReturnValueChecker
1140 /// The checker restricts the return values of APIs known to
1141 /// never (or almost never) return 'nil'.
1142 class ObjCNonNilReturnValueChecker
1143  : public Checker<check::PostObjCMessage,
1144  check::PostStmt<ObjCArrayLiteral>,
1145  check::PostStmt<ObjCDictionaryLiteral>,
1146  check::PostStmt<ObjCBoxedExpr> > {
1147  mutable bool Initialized;
1148  mutable Selector ObjectAtIndex;
1149  mutable Selector ObjectAtIndexedSubscript;
1150  mutable Selector NullSelector;
1151 
1152 public:
1153  ObjCNonNilReturnValueChecker() : Initialized(false) {}
1154 
1155  ProgramStateRef assumeExprIsNonNull(const Expr *NonNullExpr,
1157  CheckerContext &C) const;
1158  void assumeExprIsNonNull(const Expr *E, CheckerContext &C) const {
1159  C.addTransition(assumeExprIsNonNull(E, C.getState(), C));
1160  }
1161 
1162  void checkPostStmt(const ObjCArrayLiteral *E, CheckerContext &C) const {
1163  assumeExprIsNonNull(E, C);
1164  }
1165  void checkPostStmt(const ObjCDictionaryLiteral *E, CheckerContext &C) const {
1166  assumeExprIsNonNull(E, C);
1167  }
1168  void checkPostStmt(const ObjCBoxedExpr *E, CheckerContext &C) const {
1169  assumeExprIsNonNull(E, C);
1170  }
1171 
1172  void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
1173 };
1174 } // end anonymous namespace
1175 
1177 ObjCNonNilReturnValueChecker::assumeExprIsNonNull(const Expr *NonNullExpr,
1179  CheckerContext &C) const {
1180  SVal Val = C.getSVal(NonNullExpr);
1181  if (Optional<DefinedOrUnknownSVal> DV = Val.getAs<DefinedOrUnknownSVal>())
1182  return State->assume(*DV, true);
1183  return State;
1184 }
1185 
1186 void ObjCNonNilReturnValueChecker::checkPostObjCMessage(const ObjCMethodCall &M,
1187  CheckerContext &C)
1188  const {
1189  ProgramStateRef State = C.getState();
1190 
1191  if (!Initialized) {
1192  ASTContext &Ctx = C.getASTContext();
1193  ObjectAtIndex = GetUnarySelector("objectAtIndex", Ctx);
1194  ObjectAtIndexedSubscript = GetUnarySelector("objectAtIndexedSubscript", Ctx);
1195  NullSelector = GetNullarySelector("null", Ctx);
1196  }
1197 
1198  // Check the receiver type.
1199  if (const ObjCInterfaceDecl *Interface = M.getReceiverInterface()) {
1200 
1201  // Assume that object returned from '[self init]' or '[super init]' is not
1202  // 'nil' if we are processing an inlined function/method.
1203  //
1204  // A defensive callee will (and should) check if the object returned by
1205  // '[super init]' is 'nil' before doing it's own initialization. However,
1206  // since 'nil' is rarely returned in practice, we should not warn when the
1207  // caller to the defensive constructor uses the object in contexts where
1208  // 'nil' is not accepted.
1209  if (!C.inTopFrame() && M.getDecl() &&
1210  M.getDecl()->getMethodFamily() == OMF_init &&
1211  M.isReceiverSelfOrSuper()) {
1212  State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
1213  }
1214 
1215  FoundationClass Cl = findKnownClass(Interface);
1216 
1217  // Objects returned from
1218  // [NSArray|NSOrderedSet]::[ObjectAtIndex|ObjectAtIndexedSubscript]
1219  // are never 'nil'.
1220  if (Cl == FC_NSArray || Cl == FC_NSOrderedSet) {
1221  Selector Sel = M.getSelector();
1222  if (Sel == ObjectAtIndex || Sel == ObjectAtIndexedSubscript) {
1223  // Go ahead and assume the value is non-nil.
1224  State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
1225  }
1226  }
1227 
1228  // Objects returned from [NSNull null] are not nil.
1229  if (Cl == FC_NSNull) {
1230  if (M.getSelector() == NullSelector) {
1231  // Go ahead and assume the value is non-nil.
1232  State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
1233  }
1234  }
1235  }
1236  C.addTransition(State);
1237 }
1238 
1239 //===----------------------------------------------------------------------===//
1240 // Check registration.
1241 //===----------------------------------------------------------------------===//
1242 
1243 void ento::registerNilArgChecker(CheckerManager &mgr) {
1244  mgr.registerChecker<NilArgChecker>();
1245 }
1246 
1247 bool ento::shouldRegisterNilArgChecker(const CheckerManager &mgr) {
1248  return true;
1249 }
1250 
1251 void ento::registerCFNumberChecker(CheckerManager &mgr) {
1252  mgr.registerChecker<CFNumberChecker>();
1253 }
1254 
1255 bool ento::shouldRegisterCFNumberChecker(const CheckerManager &mgr) {
1256  return true;
1257 }
1258 
1259 void ento::registerCFRetainReleaseChecker(CheckerManager &mgr) {
1260  mgr.registerChecker<CFRetainReleaseChecker>();
1261 }
1262 
1263 bool ento::shouldRegisterCFRetainReleaseChecker(const CheckerManager &mgr) {
1264  return true;
1265 }
1266 
1267 void ento::registerClassReleaseChecker(CheckerManager &mgr) {
1268  mgr.registerChecker<ClassReleaseChecker>();
1269 }
1270 
1271 bool ento::shouldRegisterClassReleaseChecker(const CheckerManager &mgr) {
1272  return true;
1273 }
1274 
1275 void ento::registerVariadicMethodTypeChecker(CheckerManager &mgr) {
1276  mgr.registerChecker<VariadicMethodTypeChecker>();
1277 }
1278 
1279 bool ento::shouldRegisterVariadicMethodTypeChecker(const CheckerManager &mgr) {
1280  return true;
1281 }
1282 
1283 void ento::registerObjCLoopChecker(CheckerManager &mgr) {
1284  mgr.registerChecker<ObjCLoopChecker>();
1285 }
1286 
1287 bool ento::shouldRegisterObjCLoopChecker(const CheckerManager &mgr) {
1288  return true;
1289 }
1290 
1291 void ento::registerObjCNonNilReturnValueChecker(CheckerManager &mgr) {
1292  mgr.registerChecker<ObjCNonNilReturnValueChecker>();
1293 }
1294 
1295 bool ento::shouldRegisterObjCNonNilReturnValueChecker(const CheckerManager &mgr) {
1296  return true;
1297 }
clang::ObjCInterfaceDecl
Represents an ObjC class declaration.
Definition: DeclObjC.h:1151
clang::ento::ExplodedNode::pred_begin
pred_iterator pred_begin()
Definition: ExplodedGraph.h:239
llvm
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:6684
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:1099
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:365
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:857
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:592
FC_NSDictionary
@ FC_NSDictionary
Definition: BasicObjCFoundationChecks.cpp:62
clang::ento::ExprEngine::hasMoreIteration
static LLVM_NODISCARD bool hasMoreIteration(ProgramStateRef State, const ObjCForCollectionStmt *O, const LocationContext *LC)
Definition: ExprEngine.cpp:2159
clang::getKeywordSelector
static Selector getKeywordSelector(ASTContext &Ctx, IdentifierInfos *... IIs)
Definition: SelectorExtras.h:17
getMethodReceiverIfKnownImmutable
static SymbolRef getMethodReceiverIfKnownImmutable(const CallEvent *Call)
Definition: BasicObjCFoundationChecks.cpp:1054
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:673
AttributeLangSupport::C
@ C
Definition: SemaDeclAttr.cpp:54
clang::OMF_init
@ OMF_init
Definition: IdentifierTable.h:696
kCFNumberLongType
@ kCFNumberLongType
Definition: BasicObjCFoundationChecks.cpp:367
clang::ObjCMethodDecl::getClassInterface
ObjCInterfaceDecl * getClassInterface()
Definition: DeclObjC.cpp:1164
checkElementNonNil
static ProgramStateRef checkElementNonNil(CheckerContext &C, ProgramStateRef State, const ObjCForCollectionStmt *FCS)
Assumes that the collection elements are non-nil.
Definition: BasicObjCFoundationChecks.cpp:882
clang::ento::SymbolRef
const SymExpr * SymbolRef
Definition: SymExpr.h:110
findKnownClass
static FoundationClass findKnownClass(const ObjCInterfaceDecl *ID, bool IncludeSuperclasses=true)
Definition: BasicObjCFoundationChecks.cpp:70
llvm::Optional< uint64_t >
kCFNumberFloat64Type
@ kCFNumberFloat64Type
Definition: BasicObjCFoundationChecks.cpp:363
kCFNumberFloat32Type
@ kCFNumberFloat32Type
Definition: BasicObjCFoundationChecks.cpp:362
clang::ObjCForCollectionStmt
Represents Objective-C's collection statement.
Definition: StmtObjC.h:23
clang::index::SymbolRole::Call
@ Call
clang::ObjCObjectPointerType::getInterfaceDecl
ObjCInterfaceDecl * getInterfaceDecl() const
If this pointer points to an Objective @interface type, gets the declaration for that interface.
Definition: Type.h:6128
kCFNumberDoubleType
@ kCFNumberDoubleType
Definition: BasicObjCFoundationChecks.cpp:370
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:832
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:84
V
#define V(N, I)
Definition: ASTContext.h:3127
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:357
kCFNumberCharType
@ kCFNumberCharType
Definition: BasicObjCFoundationChecks.cpp:364
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:212
clang::GetUnarySelector
Selector GetUnarySelector(StringRef name, ASTContext &Ctx)
Utility function for constructing an unary selector.
Definition: ASTContext.h:3273
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:7165
clang::CallExpr::getArg
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition: Expr.h:2986
kCFNumberLongLongType
@ kCFNumberLongLongType
Definition: BasicObjCFoundationChecks.cpp:368
clang::ASTContext::getTypeSize
uint64_t getTypeSize(QualType T) const
Return the size of the specified (complete) type T, in bits.
Definition: ASTContext.h:2251
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:876
clang::ASTContext::FloatTy
CanQualType FloatTy
Definition: ASTContext.h:1087
clang::ASTContext::getCanonicalType
CanQualType getCanonicalType(QualType T) const
Return the canonical (structural) type corresponding to the specified potentially non-canonical type ...
Definition: ASTContext.h:2474
GetReceiverInterfaceName
static StringRef GetReceiverInterfaceName(const ObjCMethodCall &msg)
Definition: BasicObjCFoundationChecks.cpp:53
kCFNumberSInt8Type
@ kCFNumberSInt8Type
Definition: BasicObjCFoundationChecks.cpp:358
kCFNumberSInt16Type
@ kCFNumberSInt16Type
Definition: BasicObjCFoundationChecks.cpp:359
ExprObjC.h
FC_NSArray
@ FC_NSArray
Definition: BasicObjCFoundationChecks.cpp:61
kCFNumberIntType
@ kCFNumberIntType
Definition: BasicObjCFoundationChecks.cpp:366
ExplodedGraph.h
clang::ASTContext::ShortTy
CanQualType ShortTy
Definition: ASTContext.h:1084
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:6798
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:6076
clang::ASTContext::LongLongTy
CanQualType LongLongTy
Definition: ASTContext.h:1084
P
StringRef P
Definition: ASTMatchersInternal.cpp:563
clang::ASTContext::DoubleTy
CanQualType DoubleTy
Definition: ASTContext.h:1087
false
#define false
Definition: stdbool.h:17
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:270
clang::ASTContext::IntTy
CanQualType IntTy
Definition: ASTContext.h:1084
clang::ObjCArrayLiteral::getElement
Expr * getElement(unsigned Index)
getElement - Return the Element at the specified index.
Definition: ExprObjC.h:232
kCFNumberCFIndexType
@ kCFNumberCFIndexType
Definition: BasicObjCFoundationChecks.cpp:371
clang::ASTContext::Idents
IdentifierTable & Idents
Definition: ASTContext.h:648
clang::CallExpr::getNumArgs
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
Definition: Expr.h:2973
CocoaConventions.h
clang::ento::ExplodedNode::const_pred_iterator
const ExplodedNode *const * const_pred_iterator
Definition: ExplodedGraph.h:236
clang::ASTContext::LongTy
CanQualType LongTy
Definition: ASTContext.h:1084
clang::ento::coreFoundation::isCFObjectRef
bool isCFObjectRef(QualType T)
Definition: CocoaConventions.cpp:57
SelectorExtras.h
clang::ASTContext::CharTy
CanQualType CharTy
Definition: ASTContext.h:1077
State
LineState State
Definition: UnwrappedLineFormatter.cpp:987
kCFNumberSInt64Type
@ kCFNumberSInt64Type
Definition: BasicObjCFoundationChecks.cpp:361
clang::VarDecl::getInit
const Expr * getInit() const
Definition: Decl.h:1285
clang::IdentifierInfo
One of these records is kept for each identifier that is lexed.
Definition: IdentifierTable.h:84
CheckerContext.h
kCFNumberFloatType
@ kCFNumberFloatType
Definition: BasicObjCFoundationChecks.cpp:369
clang::ObjCPropertyAttribute::Kind
Kind
Definition: DeclObjCCommon.h:22
clang::DeclStmt
DeclStmt - Adaptor class for mixing declarations with statements and expressions.
Definition: Stmt.h:1297
ProgramState.h
Checker.h
kCFNumberCGFloatType
@ kCFNumberCGFloatType
Definition: BasicObjCFoundationChecks.cpp:373
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:48
clang
Definition: CalledOnceCheck.h:17
clang::Selector
Smart pointer class that efficiently represents Objective-C method names.
Definition: IdentifierTable.h:748
clang::GetNullarySelector
Selector GetNullarySelector(StringRef name, ASTContext &Ctx)
Utility function for constructing a nullary selector.
Definition: ASTContext.h:3267
clang::Stmt
Stmt - This represents one statement.
Definition: Stmt.h:69
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:916
MemRegion.h
clang::Expr::getType
QualType getType() const
Definition: Expr.h:141
Initialized
@ Initialized
Definition: UninitializedValues.cpp:103
GetCFNumberSize
static Optional< uint64_t > GetCFNumberSize(ASTContext &Ctx, uint64_t i)
Definition: BasicObjCFoundationChecks.cpp:376
clang::ento::PointerEscapeKind
PointerEscapeKind
Describes the different reasons a pointer escapes during analysis.
Definition: CheckerManager.h:79
clang::BlockEdge
Definition: ProgramPoint.h:503
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:2251
kCFNumberNSIntegerType
@ kCFNumberNSIntegerType
Definition: BasicObjCFoundationChecks.cpp:372
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:958
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:1857
clang::ProgramPoint
Definition: ProgramPoint.h:59
clang::CallExpr
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition: Expr.h:2795
kCFNumberSInt32Type
@ kCFNumberSInt32Type
Definition: BasicObjCFoundationChecks.cpp:360
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:7062
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:439