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