clang 18.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
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
39using namespace clang;
40using namespace ento;
41using namespace llvm;
42
43namespace {
44class APIMisuse : public BugType {
45public:
46 APIMisuse(const CheckerBase *checker, const char *name)
47 : BugType(checker, name, "API Misuse (Apple)") {}
48};
49} // end anonymous namespace
50
51//===----------------------------------------------------------------------===//
52// Utility functions.
53//===----------------------------------------------------------------------===//
54
55static 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
98namespace {
99class 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
125public:
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
132void 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
160void 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
217void 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
231void 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
330void 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
338void NilArgChecker::checkPostStmt(const ObjCDictionaryLiteral *DL,
339 CheckerContext &C) const {
340 unsigned NumOfElements = DL->getNumElements();
341 for (unsigned i = 0; i < NumOfElements; ++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
352namespace {
353class CFNumberChecker : public Checker< check::PreStmt<CallExpr> > {
354 mutable std::unique_ptr<APIMisuse> BT;
355 mutable IdentifierInfo *ICreate = nullptr, *IGetValue = nullptr;
356public:
357 CFNumberChecker() = default;
358
359 void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
360};
361} // end anonymous namespace
362
381
382static 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
410static 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
434void 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
541namespace {
542class CFRetainReleaseChecker : public Checker<check::PreCall> {
543 mutable APIMisuse BT{this, "null passed to CF memory management function"};
544 const CallDescriptionSet ModelledCalls = {
545 {{"CFRetain"}, 1},
546 {{"CFRelease"}, 1},
547 {{"CFMakeCollectable"}, 1},
548 {{"CFAutorelease"}, 1},
549 };
550
551public:
552 void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
553};
554} // end anonymous namespace
555
556void CFRetainReleaseChecker::checkPreCall(const CallEvent &Call,
557 CheckerContext &C) const {
558 // TODO: Make this check part of CallDescription.
559 if (!Call.isGlobalCFunction())
560 return;
561
562 // Check if we called CFRetain/CFRelease/CFMakeCollectable/CFAutorelease.
563 if (!ModelledCalls.contains(Call))
564 return;
565
566 // Get the argument's value.
567 SVal ArgVal = Call.getArgSVal(0);
568 std::optional<DefinedSVal> DefArgVal = ArgVal.getAs<DefinedSVal>();
569 if (!DefArgVal)
570 return;
571
572 // Is it null?
573 ProgramStateRef state = C.getState();
574 ProgramStateRef stateNonNull, stateNull;
575 std::tie(stateNonNull, stateNull) = state->assume(*DefArgVal);
576
577 if (!stateNonNull) {
578 ExplodedNode *N = C.generateErrorNode(stateNull);
579 if (!N)
580 return;
581
582 SmallString<64> Str;
583 raw_svector_ostream OS(Str);
584 OS << "Null pointer argument in call to "
585 << cast<FunctionDecl>(Call.getDecl())->getName();
586
587 auto report = std::make_unique<PathSensitiveBugReport>(BT, OS.str(), N);
588 report->addRange(Call.getArgSourceRange(0));
589 bugreporter::trackExpressionValue(N, Call.getArgExpr(0), *report);
590 C.emitReport(std::move(report));
591 return;
592 }
593
594 // From here on, we know the argument is non-null.
595 C.addTransition(stateNonNull);
596}
597
598//===----------------------------------------------------------------------===//
599// Check for sending 'retain', 'release', or 'autorelease' directly to a Class.
600//===----------------------------------------------------------------------===//
601
602namespace {
603class ClassReleaseChecker : public Checker<check::PreObjCMessage> {
604 mutable Selector releaseS;
605 mutable Selector retainS;
606 mutable Selector autoreleaseS;
607 mutable Selector drainS;
608 mutable std::unique_ptr<BugType> BT;
609
610public:
611 void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
612};
613} // end anonymous namespace
614
615void ClassReleaseChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
616 CheckerContext &C) const {
617 if (!BT) {
618 BT.reset(new APIMisuse(
619 this, "message incorrectly sent to class instead of class instance"));
620
621 ASTContext &Ctx = C.getASTContext();
622 releaseS = GetNullarySelector("release", Ctx);
623 retainS = GetNullarySelector("retain", Ctx);
624 autoreleaseS = GetNullarySelector("autorelease", Ctx);
625 drainS = GetNullarySelector("drain", Ctx);
626 }
627
628 if (msg.isInstanceMessage())
629 return;
631 assert(Class);
632
633 Selector S = msg.getSelector();
634 if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
635 return;
636
637 if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
639 llvm::raw_svector_ostream os(buf);
640
641 os << "The '";
642 S.print(os);
643 os << "' message should be sent to instances "
644 "of class '" << Class->getName()
645 << "' and not the class directly";
646
647 auto report = std::make_unique<PathSensitiveBugReport>(*BT, os.str(), N);
648 report->addRange(msg.getSourceRange());
649 C.emitReport(std::move(report));
650 }
651}
652
653//===----------------------------------------------------------------------===//
654// Check for passing non-Objective-C types to variadic methods that expect
655// only Objective-C types.
656//===----------------------------------------------------------------------===//
657
658namespace {
659class VariadicMethodTypeChecker : public Checker<check::PreObjCMessage> {
660 mutable Selector arrayWithObjectsS;
661 mutable Selector dictionaryWithObjectsAndKeysS;
662 mutable Selector setWithObjectsS;
663 mutable Selector orderedSetWithObjectsS;
664 mutable Selector initWithObjectsS;
665 mutable Selector initWithObjectsAndKeysS;
666 mutable std::unique_ptr<BugType> BT;
667
668 bool isVariadicMessage(const ObjCMethodCall &msg) const;
669
670public:
671 void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
672};
673} // end anonymous namespace
674
675/// isVariadicMessage - Returns whether the given message is a variadic message,
676/// where all arguments must be Objective-C types.
677bool
678VariadicMethodTypeChecker::isVariadicMessage(const ObjCMethodCall &msg) const {
679 const ObjCMethodDecl *MD = msg.getDecl();
680
681 if (!MD || !MD->isVariadic() || isa<ObjCProtocolDecl>(MD->getDeclContext()))
682 return false;
683
684 Selector S = msg.getSelector();
685
686 if (msg.isInstanceMessage()) {
687 // FIXME: Ideally we'd look at the receiver interface here, but that's not
688 // useful for init, because alloc returns 'id'. In theory, this could lead
689 // to false positives, for example if there existed a class that had an
690 // initWithObjects: implementation that does accept non-Objective-C pointer
691 // types, but the chance of that happening is pretty small compared to the
692 // gains that this analysis gives.
694
695 switch (findKnownClass(Class)) {
696 case FC_NSArray:
697 case FC_NSOrderedSet:
698 case FC_NSSet:
699 return S == initWithObjectsS;
700 case FC_NSDictionary:
701 return S == initWithObjectsAndKeysS;
702 default:
703 return false;
704 }
705 } else {
707
708 switch (findKnownClass(Class)) {
709 case FC_NSArray:
710 return S == arrayWithObjectsS;
711 case FC_NSOrderedSet:
712 return S == orderedSetWithObjectsS;
713 case FC_NSSet:
714 return S == setWithObjectsS;
715 case FC_NSDictionary:
716 return S == dictionaryWithObjectsAndKeysS;
717 default:
718 return false;
719 }
720 }
721}
722
723void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
724 CheckerContext &C) const {
725 if (!BT) {
726 BT.reset(new APIMisuse(this,
727 "Arguments passed to variadic method aren't all "
728 "Objective-C pointer types"));
729
730 ASTContext &Ctx = C.getASTContext();
731 arrayWithObjectsS = GetUnarySelector("arrayWithObjects", Ctx);
732 dictionaryWithObjectsAndKeysS =
733 GetUnarySelector("dictionaryWithObjectsAndKeys", Ctx);
734 setWithObjectsS = GetUnarySelector("setWithObjects", Ctx);
735 orderedSetWithObjectsS = GetUnarySelector("orderedSetWithObjects", Ctx);
736
737 initWithObjectsS = GetUnarySelector("initWithObjects", Ctx);
738 initWithObjectsAndKeysS = GetUnarySelector("initWithObjectsAndKeys", Ctx);
739 }
740
741 if (!isVariadicMessage(msg))
742 return;
743
744 // We are not interested in the selector arguments since they have
745 // well-defined types, so the compiler will issue a warning for them.
746 unsigned variadicArgsBegin = msg.getSelector().getNumArgs();
747
748 // We're not interested in the last argument since it has to be nil or the
749 // compiler would have issued a warning for it elsewhere.
750 unsigned variadicArgsEnd = msg.getNumArgs() - 1;
751
752 if (variadicArgsEnd <= variadicArgsBegin)
753 return;
754
755 // Verify that all arguments have Objective-C types.
756 std::optional<ExplodedNode *> errorNode;
757
758 for (unsigned I = variadicArgsBegin; I != variadicArgsEnd; ++I) {
759 QualType ArgTy = msg.getArgExpr(I)->getType();
760 if (ArgTy->isObjCObjectPointerType())
761 continue;
762
763 // Block pointers are treaded as Objective-C pointers.
764 if (ArgTy->isBlockPointerType())
765 continue;
766
767 // Ignore pointer constants.
768 if (isa<loc::ConcreteInt>(msg.getArgSVal(I)))
769 continue;
770
771 // Ignore pointer types annotated with 'NSObject' attribute.
772 if (C.getASTContext().isObjCNSObjectType(ArgTy))
773 continue;
774
775 // Ignore CF references, which can be toll-free bridged.
777 continue;
778
779 // Generate only one error node to use for all bug reports.
780 if (!errorNode)
781 errorNode = C.generateNonFatalErrorNode();
782
783 if (!*errorNode)
784 continue;
785
786 SmallString<128> sbuf;
787 llvm::raw_svector_ostream os(sbuf);
788
789 StringRef TypeName = GetReceiverInterfaceName(msg);
790 if (!TypeName.empty())
791 os << "Argument to '" << TypeName << "' method '";
792 else
793 os << "Argument to method '";
794
795 msg.getSelector().print(os);
796 os << "' should be an Objective-C pointer type, not '";
797 ArgTy.print(os, C.getLangOpts());
798 os << "'";
799
800 auto R =
801 std::make_unique<PathSensitiveBugReport>(*BT, os.str(), *errorNode);
802 R->addRange(msg.getArgSourceRange(I));
803 C.emitReport(std::move(R));
804 }
805}
806
807//===----------------------------------------------------------------------===//
808// Improves the modeling of loops over Cocoa collections.
809//===----------------------------------------------------------------------===//
810
811// The map from container symbol to the container count symbol.
812// We currently will remember the last container count symbol encountered.
814REGISTER_MAP_WITH_PROGRAMSTATE(ContainerNonEmptyMap, SymbolRef, bool)
815
816namespace {
817class ObjCLoopChecker
818 : public Checker<check::PostStmt<ObjCForCollectionStmt>,
819 check::PostObjCMessage,
820 check::DeadSymbols,
821 check::PointerEscape > {
822 mutable IdentifierInfo *CountSelectorII = nullptr;
823
824 bool isCollectionCountMethod(const ObjCMethodCall &M,
825 CheckerContext &C) const;
826
827public:
828 ObjCLoopChecker() = default;
829 void checkPostStmt(const ObjCForCollectionStmt *FCS, CheckerContext &C) const;
830 void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
831 void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
832 ProgramStateRef checkPointerEscape(ProgramStateRef State,
833 const InvalidatedSymbols &Escaped,
834 const CallEvent *Call,
835 PointerEscapeKind Kind) const;
836};
837} // end anonymous namespace
838
841 if (!PT)
842 return false;
843
844 const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();
845 if (!ID)
846 return false;
847
848 switch (findKnownClass(ID)) {
849 case FC_NSArray:
850 case FC_NSDictionary:
851 case FC_NSEnumerator:
852 case FC_NSOrderedSet:
853 case FC_NSSet:
854 return true;
855 default:
856 return false;
857 }
858}
859
860/// Assumes that the collection is non-nil.
861///
862/// If the collection is known to be nil, returns NULL to indicate an infeasible
863/// path.
865 ProgramStateRef State,
866 const ObjCForCollectionStmt *FCS) {
867 if (!State)
868 return nullptr;
869
870 SVal CollectionVal = C.getSVal(FCS->getCollection());
871 std::optional<DefinedSVal> KnownCollection =
872 CollectionVal.getAs<DefinedSVal>();
873 if (!KnownCollection)
874 return State;
875
876 ProgramStateRef StNonNil, StNil;
877 std::tie(StNonNil, StNil) = State->assume(*KnownCollection);
878 if (StNil && !StNonNil) {
879 // The collection is nil. This path is infeasible.
880 return nullptr;
881 }
882
883 return StNonNil;
884}
885
886/// Assumes that the collection elements are non-nil.
887///
888/// This only applies if the collection is one of those known not to contain
889/// nil values.
891 ProgramStateRef State,
892 const ObjCForCollectionStmt *FCS) {
893 if (!State)
894 return nullptr;
895
896 // See if the collection is one where we /know/ the elements are non-nil.
898 return State;
899
900 const LocationContext *LCtx = C.getLocationContext();
901 const Stmt *Element = FCS->getElement();
902
903 // FIXME: Copied from ExprEngineObjC.
904 std::optional<Loc> ElementLoc;
905 if (const DeclStmt *DS = dyn_cast<DeclStmt>(Element)) {
906 const VarDecl *ElemDecl = cast<VarDecl>(DS->getSingleDecl());
907 assert(ElemDecl->getInit() == nullptr);
908 ElementLoc = State->getLValue(ElemDecl, LCtx);
909 } else {
910 ElementLoc = State->getSVal(Element, LCtx).getAs<Loc>();
911 }
912
913 if (!ElementLoc)
914 return State;
915
916 // Go ahead and assume the value is non-nil.
917 SVal Val = State->getSVal(*ElementLoc);
918 return State->assume(cast<DefinedOrUnknownSVal>(Val), true);
919}
920
921/// Returns NULL state if the collection is known to contain elements
922/// (or is known not to contain elements if the Assumption parameter is false.)
923static ProgramStateRef
925 SymbolRef CollectionS, bool Assumption) {
926 if (!State || !CollectionS)
927 return State;
928
929 const SymbolRef *CountS = State->get<ContainerCountMap>(CollectionS);
930 if (!CountS) {
931 const bool *KnownNonEmpty = State->get<ContainerNonEmptyMap>(CollectionS);
932 if (!KnownNonEmpty)
933 return State->set<ContainerNonEmptyMap>(CollectionS, Assumption);
934 return (Assumption == *KnownNonEmpty) ? State : nullptr;
935 }
936
937 SValBuilder &SvalBuilder = C.getSValBuilder();
938 SVal CountGreaterThanZeroVal =
939 SvalBuilder.evalBinOp(State, BO_GT,
940 nonloc::SymbolVal(*CountS),
941 SvalBuilder.makeIntVal(0, (*CountS)->getType()),
942 SvalBuilder.getConditionType());
943 std::optional<DefinedSVal> CountGreaterThanZero =
944 CountGreaterThanZeroVal.getAs<DefinedSVal>();
945 if (!CountGreaterThanZero) {
946 // The SValBuilder cannot construct a valid SVal for this condition.
947 // This means we cannot properly reason about it.
948 return State;
949 }
950
951 return State->assume(*CountGreaterThanZero, Assumption);
952}
953
954static ProgramStateRef
956 const ObjCForCollectionStmt *FCS,
957 bool Assumption) {
958 if (!State)
959 return nullptr;
960
961 SymbolRef CollectionS = C.getSVal(FCS->getCollection()).getAsSymbol();
962 return assumeCollectionNonEmpty(C, State, CollectionS, Assumption);
963}
964
965/// If the fist block edge is a back edge, we are reentering the loop.
967 const ObjCForCollectionStmt *FCS) {
968 if (!N)
969 return false;
970
972 if (std::optional<BlockEdge> BE = P.getAs<BlockEdge>()) {
973 return BE->getSrc()->getLoopTarget() == FCS;
974 }
975
976 // Keep looking for a block edge.
977 for (const ExplodedNode *N : N->preds()) {
979 return true;
980 }
981
982 return false;
983}
984
985void ObjCLoopChecker::checkPostStmt(const ObjCForCollectionStmt *FCS,
986 CheckerContext &C) const {
987 ProgramStateRef State = C.getState();
988
989 // Check if this is the branch for the end of the loop.
990 if (!ExprEngine::hasMoreIteration(State, FCS, C.getLocationContext())) {
991 if (!alreadyExecutedAtLeastOneLoopIteration(C.getPredecessor(), FCS))
992 State = assumeCollectionNonEmpty(C, State, FCS, /*Assumption*/false);
993
994 // Otherwise, this is a branch that goes through the loop body.
995 } else {
996 State = checkCollectionNonNil(C, State, FCS);
997 State = checkElementNonNil(C, State, FCS);
998 State = assumeCollectionNonEmpty(C, State, FCS, /*Assumption*/true);
999 }
1000
1001 if (!State)
1002 C.generateSink(C.getState(), C.getPredecessor());
1003 else if (State != C.getState())
1004 C.addTransition(State);
1005}
1006
1007bool ObjCLoopChecker::isCollectionCountMethod(const ObjCMethodCall &M,
1008 CheckerContext &C) const {
1009 Selector S = M.getSelector();
1010 // Initialize the identifiers on first use.
1011 if (!CountSelectorII)
1012 CountSelectorII = &C.getASTContext().Idents.get("count");
1013
1014 // If the method returns collection count, record the value.
1015 return S.isUnarySelector() &&
1016 (S.getIdentifierInfoForSlot(0) == CountSelectorII);
1017}
1018
1019void ObjCLoopChecker::checkPostObjCMessage(const ObjCMethodCall &M,
1020 CheckerContext &C) const {
1021 if (!M.isInstanceMessage())
1022 return;
1023
1024 const ObjCInterfaceDecl *ClassID = M.getReceiverInterface();
1025 if (!ClassID)
1026 return;
1027
1029 if (Class != FC_NSDictionary &&
1030 Class != FC_NSArray &&
1031 Class != FC_NSSet &&
1032 Class != FC_NSOrderedSet)
1033 return;
1034
1035 SymbolRef ContainerS = M.getReceiverSVal().getAsSymbol();
1036 if (!ContainerS)
1037 return;
1038
1039 // If we are processing a call to "count", get the symbolic value returned by
1040 // a call to "count" and add it to the map.
1041 if (!isCollectionCountMethod(M, C))
1042 return;
1043
1044 const Expr *MsgExpr = M.getOriginExpr();
1045 SymbolRef CountS = C.getSVal(MsgExpr).getAsSymbol();
1046 if (CountS) {
1047 ProgramStateRef State = C.getState();
1048
1049 C.getSymbolManager().addSymbolDependency(ContainerS, CountS);
1050 State = State->set<ContainerCountMap>(ContainerS, CountS);
1051
1052 if (const bool *NonEmpty = State->get<ContainerNonEmptyMap>(ContainerS)) {
1053 State = State->remove<ContainerNonEmptyMap>(ContainerS);
1054 State = assumeCollectionNonEmpty(C, State, ContainerS, *NonEmpty);
1055 }
1056
1057 C.addTransition(State);
1058 }
1059}
1060
1062 const ObjCMethodCall *Message = dyn_cast_or_null<ObjCMethodCall>(Call);
1063 if (!Message)
1064 return nullptr;
1065
1066 const ObjCMethodDecl *MD = Message->getDecl();
1067 if (!MD)
1068 return nullptr;
1069
1070 const ObjCInterfaceDecl *StaticClass;
1071 if (isa<ObjCProtocolDecl>(MD->getDeclContext())) {
1072 // We can't find out where the method was declared without doing more work.
1073 // Instead, see if the receiver is statically typed as a known immutable
1074 // collection.
1075 StaticClass = Message->getOriginExpr()->getReceiverInterface();
1076 } else {
1077 StaticClass = MD->getClassInterface();
1078 }
1079
1080 if (!StaticClass)
1081 return nullptr;
1082
1083 switch (findKnownClass(StaticClass, /*IncludeSuper=*/false)) {
1084 case FC_None:
1085 return nullptr;
1086 case FC_NSArray:
1087 case FC_NSDictionary:
1088 case FC_NSEnumerator:
1089 case FC_NSNull:
1090 case FC_NSOrderedSet:
1091 case FC_NSSet:
1092 case FC_NSString:
1093 break;
1094 }
1095
1096 return Message->getReceiverSVal().getAsSymbol();
1097}
1098
1100ObjCLoopChecker::checkPointerEscape(ProgramStateRef State,
1101 const InvalidatedSymbols &Escaped,
1102 const CallEvent *Call,
1103 PointerEscapeKind Kind) const {
1105
1106 // Remove the invalidated symbols from the collection count map.
1107 for (SymbolRef Sym : Escaped) {
1108 // Don't invalidate this symbol's count if we know the method being called
1109 // is declared on an immutable class. This isn't completely correct if the
1110 // receiver is also passed as an argument, but in most uses of NSArray,
1111 // NSDictionary, etc. this isn't likely to happen in a dangerous way.
1112 if (Sym == ImmutableReceiver)
1113 continue;
1114
1115 // The symbol escaped. Pessimistically, assume that the count could have
1116 // changed.
1117 State = State->remove<ContainerCountMap>(Sym);
1118 State = State->remove<ContainerNonEmptyMap>(Sym);
1119 }
1120 return State;
1121}
1122
1123void ObjCLoopChecker::checkDeadSymbols(SymbolReaper &SymReaper,
1124 CheckerContext &C) const {
1125 ProgramStateRef State = C.getState();
1126
1127 // Remove the dead symbols from the collection count map.
1128 ContainerCountMapTy Tracked = State->get<ContainerCountMap>();
1129 for (SymbolRef Sym : llvm::make_first_range(Tracked)) {
1130 if (SymReaper.isDead(Sym)) {
1131 State = State->remove<ContainerCountMap>(Sym);
1132 State = State->remove<ContainerNonEmptyMap>(Sym);
1133 }
1134 }
1135
1136 C.addTransition(State);
1137}
1138
1139namespace {
1140/// \class ObjCNonNilReturnValueChecker
1141/// The checker restricts the return values of APIs known to
1142/// never (or almost never) return 'nil'.
1143class ObjCNonNilReturnValueChecker
1144 : public Checker<check::PostObjCMessage,
1145 check::PostStmt<ObjCArrayLiteral>,
1146 check::PostStmt<ObjCDictionaryLiteral>,
1147 check::PostStmt<ObjCBoxedExpr> > {
1148 mutable bool Initialized = false;
1149 mutable Selector ObjectAtIndex;
1150 mutable Selector ObjectAtIndexedSubscript;
1151 mutable Selector NullSelector;
1152
1153public:
1154 ObjCNonNilReturnValueChecker() = default;
1155
1156 ProgramStateRef assumeExprIsNonNull(const Expr *NonNullExpr,
1157 ProgramStateRef State,
1158 CheckerContext &C) const;
1159 void assumeExprIsNonNull(const Expr *E, CheckerContext &C) const {
1160 C.addTransition(assumeExprIsNonNull(E, C.getState(), C));
1161 }
1162
1163 void checkPostStmt(const ObjCArrayLiteral *E, CheckerContext &C) const {
1164 assumeExprIsNonNull(E, C);
1165 }
1166 void checkPostStmt(const ObjCDictionaryLiteral *E, CheckerContext &C) const {
1167 assumeExprIsNonNull(E, C);
1168 }
1169 void checkPostStmt(const ObjCBoxedExpr *E, CheckerContext &C) const {
1170 assumeExprIsNonNull(E, C);
1171 }
1172
1173 void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
1174};
1175} // end anonymous namespace
1176
1178ObjCNonNilReturnValueChecker::assumeExprIsNonNull(const Expr *NonNullExpr,
1179 ProgramStateRef State,
1180 CheckerContext &C) const {
1181 SVal Val = C.getSVal(NonNullExpr);
1182 if (std::optional<DefinedOrUnknownSVal> DV =
1184 return State->assume(*DV, true);
1185 return State;
1186}
1187
1188void ObjCNonNilReturnValueChecker::checkPostObjCMessage(const ObjCMethodCall &M,
1190 const {
1191 ProgramStateRef State = C.getState();
1192
1193 if (!Initialized) {
1194 ASTContext &Ctx = C.getASTContext();
1195 ObjectAtIndex = GetUnarySelector("objectAtIndex", Ctx);
1196 ObjectAtIndexedSubscript = GetUnarySelector("objectAtIndexedSubscript", Ctx);
1197 NullSelector = GetNullarySelector("null", Ctx);
1198 }
1199
1200 // Check the receiver type.
1202
1203 // Assume that object returned from '[self init]' or '[super init]' is not
1204 // 'nil' if we are processing an inlined function/method.
1205 //
1206 // A defensive callee will (and should) check if the object returned by
1207 // '[super init]' is 'nil' before doing it's own initialization. However,
1208 // since 'nil' is rarely returned in practice, we should not warn when the
1209 // caller to the defensive constructor uses the object in contexts where
1210 // 'nil' is not accepted.
1211 if (!C.inTopFrame() && M.getDecl() &&
1212 M.getDecl()->getMethodFamily() == OMF_init &&
1214 State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
1215 }
1216
1218
1219 // Objects returned from
1220 // [NSArray|NSOrderedSet]::[ObjectAtIndex|ObjectAtIndexedSubscript]
1221 // are never 'nil'.
1222 if (Cl == FC_NSArray || Cl == FC_NSOrderedSet) {
1223 Selector Sel = M.getSelector();
1224 if (Sel == ObjectAtIndex || Sel == ObjectAtIndexedSubscript) {
1225 // Go ahead and assume the value is non-nil.
1226 State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
1227 }
1228 }
1229
1230 // Objects returned from [NSNull null] are not nil.
1231 if (Cl == FC_NSNull) {
1232 if (M.getSelector() == NullSelector) {
1233 // Go ahead and assume the value is non-nil.
1234 State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
1235 }
1236 }
1237 }
1238 C.addTransition(State);
1239}
1240
1241//===----------------------------------------------------------------------===//
1242// Check registration.
1243//===----------------------------------------------------------------------===//
1244
1245void ento::registerNilArgChecker(CheckerManager &mgr) {
1246 mgr.registerChecker<NilArgChecker>();
1247}
1248
1249bool ento::shouldRegisterNilArgChecker(const CheckerManager &mgr) {
1250 return true;
1251}
1252
1253void ento::registerCFNumberChecker(CheckerManager &mgr) {
1254 mgr.registerChecker<CFNumberChecker>();
1255}
1256
1257bool ento::shouldRegisterCFNumberChecker(const CheckerManager &mgr) {
1258 return true;
1259}
1260
1261void ento::registerCFRetainReleaseChecker(CheckerManager &mgr) {
1262 mgr.registerChecker<CFRetainReleaseChecker>();
1263}
1264
1265bool ento::shouldRegisterCFRetainReleaseChecker(const CheckerManager &mgr) {
1266 return true;
1267}
1268
1269void ento::registerClassReleaseChecker(CheckerManager &mgr) {
1270 mgr.registerChecker<ClassReleaseChecker>();
1271}
1272
1273bool ento::shouldRegisterClassReleaseChecker(const CheckerManager &mgr) {
1274 return true;
1275}
1276
1277void ento::registerVariadicMethodTypeChecker(CheckerManager &mgr) {
1278 mgr.registerChecker<VariadicMethodTypeChecker>();
1279}
1280
1281bool ento::shouldRegisterVariadicMethodTypeChecker(const CheckerManager &mgr) {
1282 return true;
1283}
1284
1285void ento::registerObjCLoopChecker(CheckerManager &mgr) {
1286 mgr.registerChecker<ObjCLoopChecker>();
1287}
1288
1289bool ento::shouldRegisterObjCLoopChecker(const CheckerManager &mgr) {
1290 return true;
1291}
1292
1293void ento::registerObjCNonNilReturnValueChecker(CheckerManager &mgr) {
1294 mgr.registerChecker<ObjCNonNilReturnValueChecker>();
1295}
1296
1297bool ento::shouldRegisterObjCNonNilReturnValueChecker(const CheckerManager &mgr) {
1298 return true;
1299}
Defines the clang::ASTContext interface.
#define V(N, I)
Definition: ASTContext.h:3241
StringRef P
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 std::optional< uint64_t > GetCFNumberSize(ASTContext &Ctx, uint64_t i)
static ProgramStateRef checkElementNonNil(CheckerContext &C, ProgramStateRef State, const ObjCForCollectionStmt *FCS)
Assumes that the collection elements are non-nil.
#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.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:182
CanQualType LongTy
Definition: ASTContext.h:1092
CanQualType FloatTy
Definition: ASTContext.h:1095
CanQualType getCanonicalType(QualType T) const
Return the canonical (structural) type corresponding to the specified potentially non-canonical type ...
Definition: ASTContext.h:2535
CanQualType DoubleTy
Definition: ASTContext.h:1095
IdentifierTable & Idents
Definition: ASTContext.h:636
CanQualType CharTy
Definition: ASTContext.h:1085
CanQualType IntTy
Definition: ASTContext.h:1092
uint64_t getTypeSize(QualType T) const
Return the size of the specified (complete) type T, in bits.
Definition: ASTContext.h:2307
CanQualType ShortTy
Definition: ASTContext.h:1092
CanQualType LongLongTy
Definition: ASTContext.h:1092
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition: Expr.h:2847
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition: Expr.h:3038
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
Definition: Expr.h:3025
DeclStmt - Adaptor class for mixing declarations with statements and expressions.
Definition: Stmt.h:1493
DeclContext * getDeclContext()
Definition: DeclBase.h:453
The return type of classify().
Definition: Expr.h:324
This represents one expression.
Definition: Expr.h:110
QualType getType() const
Definition: Expr.h:142
Represents a function declaration or definition.
Definition: Decl.h:1957
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:269
ObjCArrayLiteral - used for objective-c array containers; as in: @["Hello", NSApp,...
Definition: ExprObjC.h:191
Expr * getElement(unsigned Index)
getElement - Return the Element at the specified index.
Definition: ExprObjC.h:231
unsigned getNumElements() const
getNumElements - Return number of elements of objective-c array literal.
Definition: ExprObjC.h:228
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:1150
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:6430
ObjCInterfaceDecl * getInterfaceDecl() const
If this pointer points to an Objective @interface type, gets the declaration for that interface.
Definition: Type.h:6482
A (possibly-)qualified type.
Definition: Type.h:736
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:325
bool isBlockPointerType() const
Definition: Type.h:7041
bool isIntegralOrEnumerationType() const
Determine whether this type is an integral or enumeration type.
Definition: Type.h:7455
bool isObjCObjectPointerType() const
Definition: Type.h:7161
const T * getAs() const
Member-template getAs<specific type>'.
Definition: Type.h:7558
Represents a variable declaration or definition.
Definition: Decl.h:916
const Expr * getInit() const
Definition: Decl.h:1350
An immutable set of CallDescriptions.
Represents an abstract call to a function or method along a particular path.
Definition: CallEvent.h:152
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:1171
const ObjCMethodDecl * getDecl() const override
Returns the declaration of the function or method that will be called.
Definition: CallEvent.h:1201
bool isInstanceMessage() const
Definition: CallEvent.h:1211
const Expr * getArgExpr(unsigned Index) const override
Returns the expression associated with a given argument.
Definition: CallEvent.h:1207
ObjCMessageKind getMessageKind() const
Returns how the message was written in the source (property access, subscript, or explicit message se...
Definition: CallEvent.cpp:1065
unsigned getNumArgs() const override
Returns the number of arguments (explicit and implicit).
Definition: CallEvent.h:1205
const ObjCMessageExpr * getOriginExpr() const override
Returns the expression whose value will be the result of this call.
Definition: CallEvent.h:1197
SourceRange getSourceRange() const override
Returns a source range for the entire call, suitable for outputting in diagnostics.
Definition: CallEvent.cpp:1034
SVal getReceiverSVal() const
Returns the value of the receiver at the time of this call.
Definition: CallEvent.cpp:1004
const ObjCInterfaceDecl * getReceiverInterface() const
Get the interface for the receiver.
Definition: CallEvent.h:1230
bool isReceiverSelfOrSuper() const
Checks if the receiver refers to 'self' or 'super'.
Definition: CallEvent.cpp:1020
Selector getSelector() const
Definition: CallEvent.h:1219
A Range represents the closed range [from, to].
nonloc::ConcreteInt makeIntVal(const IntegerLiteral *integer)
Definition: SValBuilder.h:286
QualType getConditionType() const
Definition: SValBuilder.h:149
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:530
virtual QualType getValueType() const =0
Represents symbolic expression that isn't a location.
Definition: SVals.h:284
#define UINT_MAX
Definition: limits.h:60
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.
PointerEscapeKind
Describes the different reasons a pointer escapes during analysis.
bool Null(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1702
RangeSelector name(std::string ID)
Given a node with a "name", (like NamedDecl, DeclRefExpr, CxxCtorInitializer, and TypeLoc) selects th...
@ 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:3387
Selector GetNullarySelector(StringRef name, ASTContext &Ctx)
Utility function for constructing a nullary selector.
Definition: ASTContext.h:3381
@ Interface
The "__interface" keyword introduces the elaborated-type-specifier.
@ Class
The "class" keyword introduces the elaborated-type-specifier.
static Selector getKeywordSelector(ASTContext &Ctx, IdentifierInfos *... IIs)
unsigned long uint64_t
YAML serialization mapping.
Definition: Dominators.h:30
An element in an Objective-C dictionary literal.
Definition: ExprObjC.h:262