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