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