1 //== BasicObjCFoundationChecks.cpp - Simple Apple-Foundation checks -*- C++ -*--
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file defines BasicObjCFoundationChecks, a class that encapsulates
11 // a set of simple checks to run on Objective-C code using Apple's Foundation
14 //===----------------------------------------------------------------------===//
16 #include "ClangSACheckers.h"
17 #include "clang/AST/ASTContext.h"
18 #include "clang/AST/DeclObjC.h"
19 #include "clang/AST/Expr.h"
20 #include "clang/AST/ExprObjC.h"
21 #include "clang/AST/StmtObjC.h"
22 #include "clang/Analysis/DomainSpecific/CocoaConventions.h"
23 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
24 #include "clang/StaticAnalyzer/Core/Checker.h"
25 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
26 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
27 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
28 #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
29 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
30 #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
31 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
32 #include "llvm/ADT/SmallString.h"
33 #include "llvm/ADT/StringMap.h"
34 #include "llvm/Support/raw_ostream.h"
36 using namespace clang;
40 class APIMisuse : public BugType {
42 APIMisuse(const char* name) : BugType(name, "API Misuse (Apple)") {}
44 } // end anonymous namespace
46 //===----------------------------------------------------------------------===//
48 //===----------------------------------------------------------------------===//
50 static StringRef GetReceiverInterfaceName(const ObjCMethodCall &msg) {
51 if (const ObjCInterfaceDecl *ID = msg.getReceiverInterface())
52 return ID->getIdentifier()->getName();
56 enum FoundationClass {
66 static FoundationClass findKnownClass(const ObjCInterfaceDecl *ID) {
67 static llvm::StringMap<FoundationClass> Classes;
68 if (Classes.empty()) {
69 Classes["NSArray"] = FC_NSArray;
70 Classes["NSDictionary"] = FC_NSDictionary;
71 Classes["NSEnumerator"] = FC_NSEnumerator;
72 Classes["NSOrderedSet"] = FC_NSOrderedSet;
73 Classes["NSSet"] = FC_NSSet;
74 Classes["NSString"] = FC_NSString;
77 // FIXME: Should we cache this at all?
78 FoundationClass result = Classes.lookup(ID->getIdentifier()->getName());
79 if (result == FC_None)
80 if (const ObjCInterfaceDecl *Super = ID->getSuperClass())
81 return findKnownClass(Super);
86 //===----------------------------------------------------------------------===//
87 // NilArgChecker - Check for prohibited nil arguments to ObjC method calls.
88 //===----------------------------------------------------------------------===//
91 class NilArgChecker : public Checker<check::PreObjCMessage> {
92 mutable OwningPtr<APIMisuse> BT;
94 void WarnIfNilArg(CheckerContext &C,
95 const ObjCMethodCall &msg, unsigned Arg,
96 FoundationClass Class,
97 bool CanBeSubscript = false) const;
100 void checkPreObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
104 void NilArgChecker::WarnIfNilArg(CheckerContext &C,
105 const ObjCMethodCall &msg,
107 FoundationClass Class,
108 bool CanBeSubscript) const {
109 // Check if the argument is nil.
110 ProgramStateRef State = C.getState();
111 if (!State->isNull(msg.getArgSVal(Arg)).isConstrainedTrue())
115 BT.reset(new APIMisuse("nil argument"));
117 if (ExplodedNode *N = C.generateSink()) {
118 SmallString<128> sbuf;
119 llvm::raw_svector_ostream os(sbuf);
121 if (CanBeSubscript && msg.getMessageKind() == OCM_Subscript) {
123 if (Class == FC_NSArray) {
124 os << "Array element cannot be nil";
125 } else if (Class == FC_NSDictionary) {
127 os << "Value stored into '";
128 os << GetReceiverInterfaceName(msg) << "' cannot be nil";
131 os << "'"<< GetReceiverInterfaceName(msg) << "' key cannot be nil";
134 llvm_unreachable("Missing foundation class for the subscript expr");
137 if (Class == FC_NSDictionary) {
139 os << "Value argument ";
142 os << "Key argument ";
144 os << "to '" << msg.getSelector().getAsString() << "' cannot be nil";
146 os << "Argument to '" << GetReceiverInterfaceName(msg) << "' method '"
147 << msg.getSelector().getAsString() << "' cannot be nil";
151 BugReport *R = new BugReport(*BT, os.str(), N);
152 R->addRange(msg.getArgSourceRange(Arg));
153 bugreporter::trackNullOrUndefValue(N, msg.getArgExpr(Arg), *R);
158 void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
159 CheckerContext &C) const {
160 const ObjCInterfaceDecl *ID = msg.getReceiverInterface();
164 FoundationClass Class = findKnownClass(ID);
166 static const unsigned InvalidArgIndex = UINT_MAX;
167 unsigned Arg = InvalidArgIndex;
168 bool CanBeSubscript = false;
170 if (Class == FC_NSString) {
171 Selector S = msg.getSelector();
173 if (S.isUnarySelector())
176 // FIXME: This is going to be really slow doing these checks with
177 // lexical comparisons.
179 std::string NameStr = S.getAsString();
180 StringRef Name(NameStr);
181 assert(!Name.empty());
183 // FIXME: Checking for initWithFormat: will not work in most cases
184 // yet because [NSString alloc] returns id, not NSString*. We will
185 // need support for tracking expected-type information in the analyzer
186 // to find these errors.
187 if (Name == "caseInsensitiveCompare:" ||
188 Name == "compare:" ||
189 Name == "compare:options:" ||
190 Name == "compare:options:range:" ||
191 Name == "compare:options:range:locale:" ||
192 Name == "componentsSeparatedByCharactersInSet:" ||
193 Name == "initWithFormat:") {
196 } else if (Class == FC_NSArray) {
197 Selector S = msg.getSelector();
199 if (S.isUnarySelector())
202 if (S.getNameForSlot(0).equals("addObject")) {
204 } else if (S.getNameForSlot(0).equals("insertObject") &&
205 S.getNameForSlot(1).equals("atIndex")) {
207 } else if (S.getNameForSlot(0).equals("replaceObjectAtIndex") &&
208 S.getNameForSlot(1).equals("withObject")) {
210 } else if (S.getNameForSlot(0).equals("setObject") &&
211 S.getNameForSlot(1).equals("atIndexedSubscript")) {
213 CanBeSubscript = true;
214 } else if (S.getNameForSlot(0).equals("arrayByAddingObject")) {
217 } else if (Class == FC_NSDictionary) {
218 Selector S = msg.getSelector();
220 if (S.isUnarySelector())
223 if (S.getNameForSlot(0).equals("dictionaryWithObject") &&
224 S.getNameForSlot(1).equals("forKey")) {
226 WarnIfNilArg(C, msg, /* Arg */1, Class);
227 } else if (S.getNameForSlot(0).equals("setObject") &&
228 S.getNameForSlot(1).equals("forKey")) {
230 WarnIfNilArg(C, msg, /* Arg */1, Class);
231 } else if (S.getNameForSlot(0).equals("setObject") &&
232 S.getNameForSlot(1).equals("forKeyedSubscript")) {
233 CanBeSubscript = true;
235 WarnIfNilArg(C, msg, /* Arg */1, Class, CanBeSubscript);
236 } else if (S.getNameForSlot(0).equals("removeObjectForKey")) {
242 // If argument is '0', report a warning.
243 if ((Arg != InvalidArgIndex))
244 WarnIfNilArg(C, msg, Arg, Class, CanBeSubscript);
248 //===----------------------------------------------------------------------===//
250 //===----------------------------------------------------------------------===//
253 class CFNumberCreateChecker : public Checker< check::PreStmt<CallExpr> > {
254 mutable OwningPtr<APIMisuse> BT;
255 mutable IdentifierInfo* II;
257 CFNumberCreateChecker() : II(0) {}
259 void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
262 void EmitError(const TypedRegion* R, const Expr *Ex,
263 uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind);
265 } // end anonymous namespace
268 kCFNumberSInt8Type = 1,
269 kCFNumberSInt16Type = 2,
270 kCFNumberSInt32Type = 3,
271 kCFNumberSInt64Type = 4,
272 kCFNumberFloat32Type = 5,
273 kCFNumberFloat64Type = 6,
274 kCFNumberCharType = 7,
275 kCFNumberShortType = 8,
276 kCFNumberIntType = 9,
277 kCFNumberLongType = 10,
278 kCFNumberLongLongType = 11,
279 kCFNumberFloatType = 12,
280 kCFNumberDoubleType = 13,
281 kCFNumberCFIndexType = 14,
282 kCFNumberNSIntegerType = 15,
283 kCFNumberCGFloatType = 16
286 static Optional<uint64_t> GetCFNumberSize(ASTContext &Ctx, uint64_t i) {
287 static const unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 };
289 if (i < kCFNumberCharType)
290 return FixedSize[i-1];
295 case kCFNumberCharType: T = Ctx.CharTy; break;
296 case kCFNumberShortType: T = Ctx.ShortTy; break;
297 case kCFNumberIntType: T = Ctx.IntTy; break;
298 case kCFNumberLongType: T = Ctx.LongTy; break;
299 case kCFNumberLongLongType: T = Ctx.LongLongTy; break;
300 case kCFNumberFloatType: T = Ctx.FloatTy; break;
301 case kCFNumberDoubleType: T = Ctx.DoubleTy; break;
302 case kCFNumberCFIndexType:
303 case kCFNumberNSIntegerType:
304 case kCFNumberCGFloatType:
305 // FIXME: We need a way to map from names to Type*.
310 return Ctx.getTypeSize(T);
314 static const char* GetCFNumberTypeStr(uint64_t i) {
315 static const char* Names[] = {
316 "kCFNumberSInt8Type",
317 "kCFNumberSInt16Type",
318 "kCFNumberSInt32Type",
319 "kCFNumberSInt64Type",
320 "kCFNumberFloat32Type",
321 "kCFNumberFloat64Type",
323 "kCFNumberShortType",
326 "kCFNumberLongLongType",
327 "kCFNumberFloatType",
328 "kCFNumberDoubleType",
329 "kCFNumberCFIndexType",
330 "kCFNumberNSIntegerType",
331 "kCFNumberCGFloatType"
334 return i <= kCFNumberCGFloatType ? Names[i-1] : "Invalid CFNumberType";
338 void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE,
339 CheckerContext &C) const {
340 ProgramStateRef state = C.getState();
341 const FunctionDecl *FD = C.getCalleeDecl(CE);
345 ASTContext &Ctx = C.getASTContext();
347 II = &Ctx.Idents.get("CFNumberCreate");
349 if (FD->getIdentifier() != II || CE->getNumArgs() != 3)
352 // Get the value of the "theType" argument.
353 const LocationContext *LCtx = C.getLocationContext();
354 SVal TheTypeVal = state->getSVal(CE->getArg(1), LCtx);
356 // FIXME: We really should allow ranges of valid theType values, and
357 // bifurcate the state appropriately.
358 Optional<nonloc::ConcreteInt> V = TheTypeVal.getAs<nonloc::ConcreteInt>();
362 uint64_t NumberKind = V->getValue().getLimitedValue();
363 Optional<uint64_t> OptTargetSize = GetCFNumberSize(Ctx, NumberKind);
365 // FIXME: In some cases we can emit an error.
369 uint64_t TargetSize = *OptTargetSize;
371 // Look at the value of the integer being passed by reference. Essentially
372 // we want to catch cases where the value passed in is not equal to the
373 // size of the type being created.
374 SVal TheValueExpr = state->getSVal(CE->getArg(2), LCtx);
376 // FIXME: Eventually we should handle arbitrary locations. We can do this
377 // by having an enhanced memory model that does low-level typing.
378 Optional<loc::MemRegionVal> LV = TheValueExpr.getAs<loc::MemRegionVal>();
382 const TypedValueRegion* R = dyn_cast<TypedValueRegion>(LV->stripCasts());
386 QualType T = Ctx.getCanonicalType(R->getValueType());
388 // FIXME: If the pointee isn't an integer type, should we flag a warning?
389 // People can do weird stuff with pointers.
391 if (!T->isIntegralOrEnumerationType())
394 uint64_t SourceSize = Ctx.getTypeSize(T);
396 // CHECK: is SourceSize == TargetSize
397 if (SourceSize == TargetSize)
400 // Generate an error. Only generate a sink if 'SourceSize < TargetSize';
401 // otherwise generate a regular node.
403 // FIXME: We can actually create an abstract "CFNumber" object that has
404 // the bits initialized to the provided values.
406 if (ExplodedNode *N = SourceSize < TargetSize ? C.generateSink()
407 : C.addTransition()) {
408 SmallString<128> sbuf;
409 llvm::raw_svector_ostream os(sbuf);
411 os << (SourceSize == 8 ? "An " : "A ")
412 << SourceSize << " bit integer is used to initialize a CFNumber "
413 "object that represents "
414 << (TargetSize == 8 ? "an " : "a ")
415 << TargetSize << " bit integer. ";
417 if (SourceSize < TargetSize)
418 os << (TargetSize - SourceSize)
419 << " bits of the CFNumber value will be garbage." ;
421 os << (SourceSize - TargetSize)
422 << " bits of the input integer will be lost.";
425 BT.reset(new APIMisuse("Bad use of CFNumberCreate"));
427 BugReport *report = new BugReport(*BT, os.str(), N);
428 report->addRange(CE->getArg(2)->getSourceRange());
429 C.emitReport(report);
433 //===----------------------------------------------------------------------===//
434 // CFRetain/CFRelease/CFMakeCollectable checking for null arguments.
435 //===----------------------------------------------------------------------===//
438 class CFRetainReleaseChecker : public Checker< check::PreStmt<CallExpr> > {
439 mutable OwningPtr<APIMisuse> BT;
440 mutable IdentifierInfo *Retain, *Release, *MakeCollectable;
442 CFRetainReleaseChecker(): Retain(0), Release(0), MakeCollectable(0) {}
443 void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
445 } // end anonymous namespace
448 void CFRetainReleaseChecker::checkPreStmt(const CallExpr *CE,
449 CheckerContext &C) const {
450 // If the CallExpr doesn't have exactly 1 argument just give up checking.
451 if (CE->getNumArgs() != 1)
454 ProgramStateRef state = C.getState();
455 const FunctionDecl *FD = C.getCalleeDecl(CE);
460 ASTContext &Ctx = C.getASTContext();
461 Retain = &Ctx.Idents.get("CFRetain");
462 Release = &Ctx.Idents.get("CFRelease");
463 MakeCollectable = &Ctx.Idents.get("CFMakeCollectable");
465 new APIMisuse("null passed to CFRetain/CFRelease/CFMakeCollectable"));
468 // Check if we called CFRetain/CFRelease/CFMakeCollectable.
469 const IdentifierInfo *FuncII = FD->getIdentifier();
470 if (!(FuncII == Retain || FuncII == Release || FuncII == MakeCollectable))
473 // FIXME: The rest of this just checks that the argument is non-null.
474 // It should probably be refactored and combined with NonNullParamChecker.
476 // Get the argument's value.
477 const Expr *Arg = CE->getArg(0);
478 SVal ArgVal = state->getSVal(Arg, C.getLocationContext());
479 Optional<DefinedSVal> DefArgVal = ArgVal.getAs<DefinedSVal>();
484 SValBuilder &svalBuilder = C.getSValBuilder();
486 svalBuilder.makeZeroVal(Arg->getType()).castAs<DefinedSVal>();
488 // Make an expression asserting that they're equal.
489 DefinedOrUnknownSVal ArgIsNull = svalBuilder.evalEQ(state, zero, *DefArgVal);
492 ProgramStateRef stateTrue, stateFalse;
493 llvm::tie(stateTrue, stateFalse) = state->assume(ArgIsNull);
495 if (stateTrue && !stateFalse) {
496 ExplodedNode *N = C.generateSink(stateTrue);
500 const char *description;
501 if (FuncII == Retain)
502 description = "Null pointer argument in call to CFRetain";
503 else if (FuncII == Release)
504 description = "Null pointer argument in call to CFRelease";
505 else if (FuncII == MakeCollectable)
506 description = "Null pointer argument in call to CFMakeCollectable";
508 llvm_unreachable("impossible case");
510 BugReport *report = new BugReport(*BT, description, N);
511 report->addRange(Arg->getSourceRange());
512 bugreporter::trackNullOrUndefValue(N, Arg, *report);
513 C.emitReport(report);
517 // From here on, we know the argument is non-null.
518 C.addTransition(stateFalse);
521 //===----------------------------------------------------------------------===//
522 // Check for sending 'retain', 'release', or 'autorelease' directly to a Class.
523 //===----------------------------------------------------------------------===//
526 class ClassReleaseChecker : public Checker<check::PreObjCMessage> {
527 mutable Selector releaseS;
528 mutable Selector retainS;
529 mutable Selector autoreleaseS;
530 mutable Selector drainS;
531 mutable OwningPtr<BugType> BT;
534 void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
538 void ClassReleaseChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
539 CheckerContext &C) const {
542 BT.reset(new APIMisuse("message incorrectly sent to class instead of class "
545 ASTContext &Ctx = C.getASTContext();
546 releaseS = GetNullarySelector("release", Ctx);
547 retainS = GetNullarySelector("retain", Ctx);
548 autoreleaseS = GetNullarySelector("autorelease", Ctx);
549 drainS = GetNullarySelector("drain", Ctx);
552 if (msg.isInstanceMessage())
554 const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
557 Selector S = msg.getSelector();
558 if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
561 if (ExplodedNode *N = C.addTransition()) {
562 SmallString<200> buf;
563 llvm::raw_svector_ostream os(buf);
565 os << "The '" << S.getAsString() << "' message should be sent to instances "
566 "of class '" << Class->getName()
567 << "' and not the class directly";
569 BugReport *report = new BugReport(*BT, os.str(), N);
570 report->addRange(msg.getSourceRange());
571 C.emitReport(report);
575 //===----------------------------------------------------------------------===//
576 // Check for passing non-Objective-C types to variadic methods that expect
577 // only Objective-C types.
578 //===----------------------------------------------------------------------===//
581 class VariadicMethodTypeChecker : public Checker<check::PreObjCMessage> {
582 mutable Selector arrayWithObjectsS;
583 mutable Selector dictionaryWithObjectsAndKeysS;
584 mutable Selector setWithObjectsS;
585 mutable Selector orderedSetWithObjectsS;
586 mutable Selector initWithObjectsS;
587 mutable Selector initWithObjectsAndKeysS;
588 mutable OwningPtr<BugType> BT;
590 bool isVariadicMessage(const ObjCMethodCall &msg) const;
593 void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
597 /// isVariadicMessage - Returns whether the given message is a variadic message,
598 /// where all arguments must be Objective-C types.
600 VariadicMethodTypeChecker::isVariadicMessage(const ObjCMethodCall &msg) const {
601 const ObjCMethodDecl *MD = msg.getDecl();
603 if (!MD || !MD->isVariadic() || isa<ObjCProtocolDecl>(MD->getDeclContext()))
606 Selector S = msg.getSelector();
608 if (msg.isInstanceMessage()) {
609 // FIXME: Ideally we'd look at the receiver interface here, but that's not
610 // useful for init, because alloc returns 'id'. In theory, this could lead
611 // to false positives, for example if there existed a class that had an
612 // initWithObjects: implementation that does accept non-Objective-C pointer
613 // types, but the chance of that happening is pretty small compared to the
614 // gains that this analysis gives.
615 const ObjCInterfaceDecl *Class = MD->getClassInterface();
617 switch (findKnownClass(Class)) {
619 case FC_NSOrderedSet:
621 return S == initWithObjectsS;
622 case FC_NSDictionary:
623 return S == initWithObjectsAndKeysS;
628 const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
630 switch (findKnownClass(Class)) {
632 return S == arrayWithObjectsS;
633 case FC_NSOrderedSet:
634 return S == orderedSetWithObjectsS;
636 return S == setWithObjectsS;
637 case FC_NSDictionary:
638 return S == dictionaryWithObjectsAndKeysS;
645 void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
646 CheckerContext &C) const {
648 BT.reset(new APIMisuse("Arguments passed to variadic method aren't all "
649 "Objective-C pointer types"));
651 ASTContext &Ctx = C.getASTContext();
652 arrayWithObjectsS = GetUnarySelector("arrayWithObjects", Ctx);
653 dictionaryWithObjectsAndKeysS =
654 GetUnarySelector("dictionaryWithObjectsAndKeys", Ctx);
655 setWithObjectsS = GetUnarySelector("setWithObjects", Ctx);
656 orderedSetWithObjectsS = GetUnarySelector("orderedSetWithObjects", Ctx);
658 initWithObjectsS = GetUnarySelector("initWithObjects", Ctx);
659 initWithObjectsAndKeysS = GetUnarySelector("initWithObjectsAndKeys", Ctx);
662 if (!isVariadicMessage(msg))
665 // We are not interested in the selector arguments since they have
666 // well-defined types, so the compiler will issue a warning for them.
667 unsigned variadicArgsBegin = msg.getSelector().getNumArgs();
669 // We're not interested in the last argument since it has to be nil or the
670 // compiler would have issued a warning for it elsewhere.
671 unsigned variadicArgsEnd = msg.getNumArgs() - 1;
673 if (variadicArgsEnd <= variadicArgsBegin)
676 // Verify that all arguments have Objective-C types.
677 Optional<ExplodedNode*> errorNode;
678 ProgramStateRef state = C.getState();
680 for (unsigned I = variadicArgsBegin; I != variadicArgsEnd; ++I) {
681 QualType ArgTy = msg.getArgExpr(I)->getType();
682 if (ArgTy->isObjCObjectPointerType())
685 // Block pointers are treaded as Objective-C pointers.
686 if (ArgTy->isBlockPointerType())
689 // Ignore pointer constants.
690 if (msg.getArgSVal(I).getAs<loc::ConcreteInt>())
693 // Ignore pointer types annotated with 'NSObject' attribute.
694 if (C.getASTContext().isObjCNSObjectType(ArgTy))
697 // Ignore CF references, which can be toll-free bridged.
698 if (coreFoundation::isCFObjectRef(ArgTy))
701 // Generate only one error node to use for all bug reports.
702 if (!errorNode.hasValue())
703 errorNode = C.addTransition();
705 if (!errorNode.getValue())
708 SmallString<128> sbuf;
709 llvm::raw_svector_ostream os(sbuf);
711 StringRef TypeName = GetReceiverInterfaceName(msg);
712 if (!TypeName.empty())
713 os << "Argument to '" << TypeName << "' method '";
715 os << "Argument to method '";
717 os << msg.getSelector().getAsString()
718 << "' should be an Objective-C pointer type, not '";
719 ArgTy.print(os, C.getLangOpts());
722 BugReport *R = new BugReport(*BT, os.str(), errorNode.getValue());
723 R->addRange(msg.getArgSourceRange(I));
728 //===----------------------------------------------------------------------===//
729 // Improves the modeling of loops over Cocoa collections.
730 //===----------------------------------------------------------------------===//
733 class ObjCLoopChecker
734 : public Checker<check::PostStmt<ObjCForCollectionStmt> > {
737 void checkPostStmt(const ObjCForCollectionStmt *FCS, CheckerContext &C) const;
741 static bool isKnownNonNilCollectionType(QualType T) {
742 const ObjCObjectPointerType *PT = T->getAs<ObjCObjectPointerType>();
746 const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();
750 switch (findKnownClass(ID)) {
752 case FC_NSDictionary:
753 case FC_NSEnumerator:
754 case FC_NSOrderedSet:
762 /// Assumes that the collection is non-nil.
764 /// If the collection is known to be nil, returns NULL to indicate an infeasible
766 static ProgramStateRef checkCollectionNonNil(CheckerContext &C,
767 ProgramStateRef State,
768 const ObjCForCollectionStmt *FCS) {
772 SVal CollectionVal = C.getSVal(FCS->getCollection());
773 Optional<DefinedSVal> KnownCollection = CollectionVal.getAs<DefinedSVal>();
774 if (!KnownCollection)
777 ProgramStateRef StNonNil, StNil;
778 llvm::tie(StNonNil, StNil) = State->assume(*KnownCollection);
779 if (StNil && !StNonNil) {
780 // The collection is nil. This path is infeasible.
787 /// Assumes that the collection elements are non-nil.
789 /// This only applies if the collection is one of those known not to contain
791 static ProgramStateRef checkElementNonNil(CheckerContext &C,
792 ProgramStateRef State,
793 const ObjCForCollectionStmt *FCS) {
797 // See if the collection is one where we /know/ the elements are non-nil.
798 if (!isKnownNonNilCollectionType(FCS->getCollection()->getType()))
801 const LocationContext *LCtx = C.getLocationContext();
802 const Stmt *Element = FCS->getElement();
804 // FIXME: Copied from ExprEngineObjC.
805 Optional<Loc> ElementLoc;
806 if (const DeclStmt *DS = dyn_cast<DeclStmt>(Element)) {
807 const VarDecl *ElemDecl = cast<VarDecl>(DS->getSingleDecl());
808 assert(ElemDecl->getInit() == 0);
809 ElementLoc = State->getLValue(ElemDecl, LCtx);
811 ElementLoc = State->getSVal(Element, LCtx).getAs<Loc>();
817 // Go ahead and assume the value is non-nil.
818 SVal Val = State->getSVal(*ElementLoc);
819 return State->assume(Val.castAs<DefinedOrUnknownSVal>(), true);
822 void ObjCLoopChecker::checkPostStmt(const ObjCForCollectionStmt *FCS,
823 CheckerContext &C) const {
824 // Check if this is the branch for the end of the loop.
825 SVal CollectionSentinel = C.getSVal(FCS);
826 if (CollectionSentinel.isZeroConstant())
829 ProgramStateRef State = C.getState();
830 State = checkCollectionNonNil(C, State, FCS);
831 State = checkElementNonNil(C, State, FCS);
835 else if (State != C.getState())
836 C.addTransition(State);
840 /// \class ObjCNonNilReturnValueChecker
841 /// \brief The checker restricts the return values of APIs known to
842 /// never (or almost never) return 'nil'.
843 class ObjCNonNilReturnValueChecker
844 : public Checker<check::PostObjCMessage> {
845 mutable bool Initialized;
846 mutable Selector ObjectAtIndex;
847 mutable Selector ObjectAtIndexedSubscript;
850 ObjCNonNilReturnValueChecker() : Initialized(false) {}
851 void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
855 static ProgramStateRef assumeExprIsNonNull(const Expr *NonNullExpr,
856 ProgramStateRef State,
858 SVal Val = State->getSVal(NonNullExpr, C.getLocationContext());
859 if (Optional<DefinedOrUnknownSVal> DV = Val.getAs<DefinedOrUnknownSVal>())
860 return State->assume(*DV, true);
864 void ObjCNonNilReturnValueChecker::checkPostObjCMessage(const ObjCMethodCall &M,
867 ProgramStateRef State = C.getState();
870 ASTContext &Ctx = C.getASTContext();
871 ObjectAtIndex = GetUnarySelector("objectAtIndex", Ctx);
872 ObjectAtIndexedSubscript = GetUnarySelector("objectAtIndexedSubscript", Ctx);
875 // Check the receiver type.
876 if (const ObjCInterfaceDecl *Interface = M.getReceiverInterface()) {
878 // Assume that object returned from '[self init]' or '[super init]' is not
879 // 'nil' if we are processing an inlined function/method.
881 // A defensive callee will (and should) check if the object returned by
882 // '[super init]' is 'nil' before doing it's own initialization. However,
883 // since 'nil' is rarely returned in practice, we should not warn when the
884 // caller to the defensive constructor uses the object in contexts where
885 // 'nil' is not accepted.
886 if (!C.inTopFrame() && M.getDecl() &&
887 M.getDecl()->getMethodFamily() == OMF_init &&
888 M.isReceiverSelfOrSuper()) {
889 State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
892 // Objects returned from
893 // [NSArray|NSOrderedSet]::[ObjectAtIndex|ObjectAtIndexedSubscript]
895 FoundationClass Cl = findKnownClass(Interface);
896 if (Cl == FC_NSArray || Cl == FC_NSOrderedSet) {
897 Selector Sel = M.getSelector();
898 if (Sel == ObjectAtIndex || Sel == ObjectAtIndexedSubscript) {
899 // Go ahead and assume the value is non-nil.
900 State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
904 C.addTransition(State);
907 //===----------------------------------------------------------------------===//
908 // Check registration.
909 //===----------------------------------------------------------------------===//
911 void ento::registerNilArgChecker(CheckerManager &mgr) {
912 mgr.registerChecker<NilArgChecker>();
915 void ento::registerCFNumberCreateChecker(CheckerManager &mgr) {
916 mgr.registerChecker<CFNumberCreateChecker>();
919 void ento::registerCFRetainReleaseChecker(CheckerManager &mgr) {
920 mgr.registerChecker<CFRetainReleaseChecker>();
923 void ento::registerClassReleaseChecker(CheckerManager &mgr) {
924 mgr.registerChecker<ClassReleaseChecker>();
927 void ento::registerVariadicMethodTypeChecker(CheckerManager &mgr) {
928 mgr.registerChecker<VariadicMethodTypeChecker>();
931 void ento::registerObjCLoopChecker(CheckerManager &mgr) {
932 mgr.registerChecker<ObjCLoopChecker>();
935 void ento::registerObjCNonNilReturnValueChecker(CheckerManager &mgr) {
936 mgr.registerChecker<ObjCNonNilReturnValueChecker>();