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 "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.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/Analysis/SelectorExtras.h"
24 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
25 #include "clang/StaticAnalyzer/Core/Checker.h"
26 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
27 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
28 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
29 #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
30 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
31 #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
32 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
33 #include "llvm/ADT/SmallString.h"
34 #include "llvm/ADT/StringMap.h"
35 #include "llvm/Support/raw_ostream.h"
37 using namespace clang;
42 class APIMisuse : public BugType {
44 APIMisuse(const CheckerBase *checker, const char *name)
45 : BugType(checker, name, "API Misuse (Apple)") {}
47 } // end anonymous namespace
49 //===----------------------------------------------------------------------===//
51 //===----------------------------------------------------------------------===//
53 static StringRef GetReceiverInterfaceName(const ObjCMethodCall &msg) {
54 if (const ObjCInterfaceDecl *ID = msg.getReceiverInterface())
55 return ID->getIdentifier()->getName();
59 enum FoundationClass {
70 static FoundationClass findKnownClass(const ObjCInterfaceDecl *ID,
71 bool IncludeSuperclasses = true) {
72 static llvm::StringMap<FoundationClass> Classes;
73 if (Classes.empty()) {
74 Classes["NSArray"] = FC_NSArray;
75 Classes["NSDictionary"] = FC_NSDictionary;
76 Classes["NSEnumerator"] = FC_NSEnumerator;
77 Classes["NSNull"] = FC_NSNull;
78 Classes["NSOrderedSet"] = FC_NSOrderedSet;
79 Classes["NSSet"] = FC_NSSet;
80 Classes["NSString"] = FC_NSString;
83 // FIXME: Should we cache this at all?
84 FoundationClass result = Classes.lookup(ID->getIdentifier()->getName());
85 if (result == FC_None && IncludeSuperclasses)
86 if (const ObjCInterfaceDecl *Super = ID->getSuperClass())
87 return findKnownClass(Super);
92 //===----------------------------------------------------------------------===//
93 // NilArgChecker - Check for prohibited nil arguments to ObjC method calls.
94 //===----------------------------------------------------------------------===//
97 class NilArgChecker : public Checker<check::PreObjCMessage,
98 check::PostStmt<ObjCDictionaryLiteral>,
99 check::PostStmt<ObjCArrayLiteral> > {
100 mutable std::unique_ptr<APIMisuse> BT;
102 mutable llvm::SmallDenseMap<Selector, unsigned, 16> StringSelectors;
103 mutable Selector ArrayWithObjectSel;
104 mutable Selector AddObjectSel;
105 mutable Selector InsertObjectAtIndexSel;
106 mutable Selector ReplaceObjectAtIndexWithObjectSel;
107 mutable Selector SetObjectAtIndexedSubscriptSel;
108 mutable Selector ArrayByAddingObjectSel;
109 mutable Selector DictionaryWithObjectForKeySel;
110 mutable Selector SetObjectForKeySel;
111 mutable Selector SetObjectForKeyedSubscriptSel;
112 mutable Selector RemoveObjectForKeySel;
114 void warnIfNilExpr(const Expr *E,
116 CheckerContext &C) const;
118 void warnIfNilArg(CheckerContext &C,
119 const ObjCMethodCall &msg, unsigned Arg,
120 FoundationClass Class,
121 bool CanBeSubscript = false) const;
123 void generateBugReport(ExplodedNode *N,
127 CheckerContext &C) const;
130 void checkPreObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
131 void checkPostStmt(const ObjCDictionaryLiteral *DL,
132 CheckerContext &C) const;
133 void checkPostStmt(const ObjCArrayLiteral *AL,
134 CheckerContext &C) const;
136 } // end anonymous namespace
138 void NilArgChecker::warnIfNilExpr(const Expr *E,
140 CheckerContext &C) const {
141 ProgramStateRef State = C.getState();
142 if (State->isNull(C.getSVal(E)).isConstrainedTrue()) {
144 if (ExplodedNode *N = C.generateErrorNode()) {
145 generateBugReport(N, Msg, E->getSourceRange(), E, C);
150 void NilArgChecker::warnIfNilArg(CheckerContext &C,
151 const ObjCMethodCall &msg,
153 FoundationClass Class,
154 bool CanBeSubscript) const {
155 // Check if the argument is nil.
156 ProgramStateRef State = C.getState();
157 if (!State->isNull(msg.getArgSVal(Arg)).isConstrainedTrue())
160 // NOTE: We cannot throw non-fatal errors from warnIfNilExpr,
161 // because it's called multiple times from some callers, so it'd cause
162 // an unwanted state split if two or more non-fatal errors are thrown
163 // within the same checker callback. For now we don't want to, but
164 // it'll need to be fixed if we ever want to.
165 if (ExplodedNode *N = C.generateErrorNode()) {
166 SmallString<128> sbuf;
167 llvm::raw_svector_ostream os(sbuf);
169 if (CanBeSubscript && msg.getMessageKind() == OCM_Subscript) {
171 if (Class == FC_NSArray) {
172 os << "Array element cannot be nil";
173 } else if (Class == FC_NSDictionary) {
175 os << "Value stored into '";
176 os << GetReceiverInterfaceName(msg) << "' cannot be nil";
179 os << "'"<< GetReceiverInterfaceName(msg) << "' key cannot be nil";
182 llvm_unreachable("Missing foundation class for the subscript expr");
185 if (Class == FC_NSDictionary) {
187 os << "Value argument ";
190 os << "Key argument ";
193 msg.getSelector().print(os);
194 os << "' cannot be nil";
196 os << "Argument to '" << GetReceiverInterfaceName(msg) << "' method '";
197 msg.getSelector().print(os);
198 os << "' cannot be nil";
202 generateBugReport(N, os.str(), msg.getArgSourceRange(Arg),
203 msg.getArgExpr(Arg), C);
207 void NilArgChecker::generateBugReport(ExplodedNode *N,
211 CheckerContext &C) const {
213 BT.reset(new APIMisuse(this, "nil argument"));
215 auto R = llvm::make_unique<BugReport>(*BT, Msg, N);
217 bugreporter::trackExpressionValue(N, E, *R);
218 C.emitReport(std::move(R));
221 void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
222 CheckerContext &C) const {
223 const ObjCInterfaceDecl *ID = msg.getReceiverInterface();
227 FoundationClass Class = findKnownClass(ID);
229 static const unsigned InvalidArgIndex = UINT_MAX;
230 unsigned Arg = InvalidArgIndex;
231 bool CanBeSubscript = false;
233 if (Class == FC_NSString) {
234 Selector S = msg.getSelector();
236 if (S.isUnarySelector())
239 if (StringSelectors.empty()) {
240 ASTContext &Ctx = C.getASTContext();
242 getKeywordSelector(Ctx, "caseInsensitiveCompare"),
243 getKeywordSelector(Ctx, "compare"),
244 getKeywordSelector(Ctx, "compare", "options"),
245 getKeywordSelector(Ctx, "compare", "options", "range"),
246 getKeywordSelector(Ctx, "compare", "options", "range", "locale"),
247 getKeywordSelector(Ctx, "componentsSeparatedByCharactersInSet"),
248 getKeywordSelector(Ctx, "initWithFormat"),
249 getKeywordSelector(Ctx, "localizedCaseInsensitiveCompare"),
250 getKeywordSelector(Ctx, "localizedCompare"),
251 getKeywordSelector(Ctx, "localizedStandardCompare"),
253 for (Selector KnownSel : Sels)
254 StringSelectors[KnownSel] = 0;
256 auto I = StringSelectors.find(S);
257 if (I == StringSelectors.end())
260 } else if (Class == FC_NSArray) {
261 Selector S = msg.getSelector();
263 if (S.isUnarySelector())
266 if (ArrayWithObjectSel.isNull()) {
267 ASTContext &Ctx = C.getASTContext();
268 ArrayWithObjectSel = getKeywordSelector(Ctx, "arrayWithObject");
269 AddObjectSel = getKeywordSelector(Ctx, "addObject");
270 InsertObjectAtIndexSel =
271 getKeywordSelector(Ctx, "insertObject", "atIndex");
272 ReplaceObjectAtIndexWithObjectSel =
273 getKeywordSelector(Ctx, "replaceObjectAtIndex", "withObject");
274 SetObjectAtIndexedSubscriptSel =
275 getKeywordSelector(Ctx, "setObject", "atIndexedSubscript");
276 ArrayByAddingObjectSel = getKeywordSelector(Ctx, "arrayByAddingObject");
279 if (S == ArrayWithObjectSel || S == AddObjectSel ||
280 S == InsertObjectAtIndexSel || S == ArrayByAddingObjectSel) {
282 } else if (S == SetObjectAtIndexedSubscriptSel) {
284 CanBeSubscript = true;
285 } else if (S == ReplaceObjectAtIndexWithObjectSel) {
288 } else if (Class == FC_NSDictionary) {
289 Selector S = msg.getSelector();
291 if (S.isUnarySelector())
294 if (DictionaryWithObjectForKeySel.isNull()) {
295 ASTContext &Ctx = C.getASTContext();
296 DictionaryWithObjectForKeySel =
297 getKeywordSelector(Ctx, "dictionaryWithObject", "forKey");
298 SetObjectForKeySel = getKeywordSelector(Ctx, "setObject", "forKey");
299 SetObjectForKeyedSubscriptSel =
300 getKeywordSelector(Ctx, "setObject", "forKeyedSubscript");
301 RemoveObjectForKeySel = getKeywordSelector(Ctx, "removeObjectForKey");
304 if (S == DictionaryWithObjectForKeySel || S == SetObjectForKeySel) {
306 warnIfNilArg(C, msg, /* Arg */1, Class);
307 } else if (S == SetObjectForKeyedSubscriptSel) {
308 CanBeSubscript = true;
310 } else if (S == RemoveObjectForKeySel) {
315 // If argument is '0', report a warning.
316 if ((Arg != InvalidArgIndex))
317 warnIfNilArg(C, msg, Arg, Class, CanBeSubscript);
320 void NilArgChecker::checkPostStmt(const ObjCArrayLiteral *AL,
321 CheckerContext &C) const {
322 unsigned NumOfElements = AL->getNumElements();
323 for (unsigned i = 0; i < NumOfElements; ++i) {
324 warnIfNilExpr(AL->getElement(i), "Array element cannot be nil", C);
328 void NilArgChecker::checkPostStmt(const ObjCDictionaryLiteral *DL,
329 CheckerContext &C) const {
330 unsigned NumOfElements = DL->getNumElements();
331 for (unsigned i = 0; i < NumOfElements; ++i) {
332 ObjCDictionaryElement Element = DL->getKeyValueElement(i);
333 warnIfNilExpr(Element.Key, "Dictionary key cannot be nil", C);
334 warnIfNilExpr(Element.Value, "Dictionary value cannot be nil", C);
338 //===----------------------------------------------------------------------===//
339 // Checking for mismatched types passed to CFNumberCreate/CFNumberGetValue.
340 //===----------------------------------------------------------------------===//
343 class CFNumberChecker : public Checker< check::PreStmt<CallExpr> > {
344 mutable std::unique_ptr<APIMisuse> BT;
345 mutable IdentifierInfo *ICreate, *IGetValue;
347 CFNumberChecker() : ICreate(nullptr), IGetValue(nullptr) {}
349 void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
352 void EmitError(const TypedRegion* R, const Expr *Ex,
353 uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind);
355 } // end anonymous namespace
358 kCFNumberSInt8Type = 1,
359 kCFNumberSInt16Type = 2,
360 kCFNumberSInt32Type = 3,
361 kCFNumberSInt64Type = 4,
362 kCFNumberFloat32Type = 5,
363 kCFNumberFloat64Type = 6,
364 kCFNumberCharType = 7,
365 kCFNumberShortType = 8,
366 kCFNumberIntType = 9,
367 kCFNumberLongType = 10,
368 kCFNumberLongLongType = 11,
369 kCFNumberFloatType = 12,
370 kCFNumberDoubleType = 13,
371 kCFNumberCFIndexType = 14,
372 kCFNumberNSIntegerType = 15,
373 kCFNumberCGFloatType = 16
376 static Optional<uint64_t> GetCFNumberSize(ASTContext &Ctx, uint64_t i) {
377 static const unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 };
379 if (i < kCFNumberCharType)
380 return FixedSize[i-1];
385 case kCFNumberCharType: T = Ctx.CharTy; break;
386 case kCFNumberShortType: T = Ctx.ShortTy; break;
387 case kCFNumberIntType: T = Ctx.IntTy; break;
388 case kCFNumberLongType: T = Ctx.LongTy; break;
389 case kCFNumberLongLongType: T = Ctx.LongLongTy; break;
390 case kCFNumberFloatType: T = Ctx.FloatTy; break;
391 case kCFNumberDoubleType: T = Ctx.DoubleTy; break;
392 case kCFNumberCFIndexType:
393 case kCFNumberNSIntegerType:
394 case kCFNumberCGFloatType:
395 // FIXME: We need a way to map from names to Type*.
400 return Ctx.getTypeSize(T);
404 static const char* GetCFNumberTypeStr(uint64_t i) {
405 static const char* Names[] = {
406 "kCFNumberSInt8Type",
407 "kCFNumberSInt16Type",
408 "kCFNumberSInt32Type",
409 "kCFNumberSInt64Type",
410 "kCFNumberFloat32Type",
411 "kCFNumberFloat64Type",
413 "kCFNumberShortType",
416 "kCFNumberLongLongType",
417 "kCFNumberFloatType",
418 "kCFNumberDoubleType",
419 "kCFNumberCFIndexType",
420 "kCFNumberNSIntegerType",
421 "kCFNumberCGFloatType"
424 return i <= kCFNumberCGFloatType ? Names[i-1] : "Invalid CFNumberType";
428 void CFNumberChecker::checkPreStmt(const CallExpr *CE,
429 CheckerContext &C) const {
430 ProgramStateRef state = C.getState();
431 const FunctionDecl *FD = C.getCalleeDecl(CE);
435 ASTContext &Ctx = C.getASTContext();
437 ICreate = &Ctx.Idents.get("CFNumberCreate");
438 IGetValue = &Ctx.Idents.get("CFNumberGetValue");
440 if (!(FD->getIdentifier() == ICreate || FD->getIdentifier() == IGetValue) ||
441 CE->getNumArgs() != 3)
444 // Get the value of the "theType" argument.
445 SVal TheTypeVal = C.getSVal(CE->getArg(1));
447 // FIXME: We really should allow ranges of valid theType values, and
448 // bifurcate the state appropriately.
449 Optional<nonloc::ConcreteInt> V = TheTypeVal.getAs<nonloc::ConcreteInt>();
453 uint64_t NumberKind = V->getValue().getLimitedValue();
454 Optional<uint64_t> OptCFNumberSize = GetCFNumberSize(Ctx, NumberKind);
456 // FIXME: In some cases we can emit an error.
457 if (!OptCFNumberSize)
460 uint64_t CFNumberSize = *OptCFNumberSize;
462 // Look at the value of the integer being passed by reference. Essentially
463 // we want to catch cases where the value passed in is not equal to the
464 // size of the type being created.
465 SVal TheValueExpr = C.getSVal(CE->getArg(2));
467 // FIXME: Eventually we should handle arbitrary locations. We can do this
468 // by having an enhanced memory model that does low-level typing.
469 Optional<loc::MemRegionVal> LV = TheValueExpr.getAs<loc::MemRegionVal>();
473 const TypedValueRegion* R = dyn_cast<TypedValueRegion>(LV->stripCasts());
477 QualType T = Ctx.getCanonicalType(R->getValueType());
479 // FIXME: If the pointee isn't an integer type, should we flag a warning?
480 // People can do weird stuff with pointers.
482 if (!T->isIntegralOrEnumerationType())
485 uint64_t PrimitiveTypeSize = Ctx.getTypeSize(T);
487 if (PrimitiveTypeSize == CFNumberSize)
490 // FIXME: We can actually create an abstract "CFNumber" object that has
491 // the bits initialized to the provided values.
492 ExplodedNode *N = C.generateNonFatalErrorNode();
494 SmallString<128> sbuf;
495 llvm::raw_svector_ostream os(sbuf);
496 bool isCreate = (FD->getIdentifier() == ICreate);
499 os << (PrimitiveTypeSize == 8 ? "An " : "A ")
500 << PrimitiveTypeSize << "-bit integer is used to initialize a "
501 << "CFNumber object that represents "
502 << (CFNumberSize == 8 ? "an " : "a ")
503 << CFNumberSize << "-bit integer; ";
505 os << "A CFNumber object that represents "
506 << (CFNumberSize == 8 ? "an " : "a ")
507 << CFNumberSize << "-bit integer is used to initialize "
508 << (PrimitiveTypeSize == 8 ? "an " : "a ")
509 << PrimitiveTypeSize << "-bit integer; ";
512 if (PrimitiveTypeSize < CFNumberSize)
513 os << (CFNumberSize - PrimitiveTypeSize)
514 << " bits of the CFNumber value will "
515 << (isCreate ? "be garbage." : "overwrite adjacent storage.");
517 os << (PrimitiveTypeSize - CFNumberSize)
518 << " bits of the integer value will be "
519 << (isCreate ? "lost." : "garbage.");
522 BT.reset(new APIMisuse(this, "Bad use of CFNumber APIs"));
524 auto report = llvm::make_unique<BugReport>(*BT, os.str(), N);
525 report->addRange(CE->getArg(2)->getSourceRange());
526 C.emitReport(std::move(report));
530 //===----------------------------------------------------------------------===//
531 // CFRetain/CFRelease/CFMakeCollectable/CFAutorelease checking for null arguments.
532 //===----------------------------------------------------------------------===//
535 class CFRetainReleaseChecker : public Checker<check::PreCall> {
536 mutable APIMisuse BT{this, "null passed to CF memory management function"};
537 CallDescription CFRetain{"CFRetain", 1},
538 CFRelease{"CFRelease", 1},
539 CFMakeCollectable{"CFMakeCollectable", 1},
540 CFAutorelease{"CFAutorelease", 1};
543 void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
545 } // end anonymous namespace
547 void CFRetainReleaseChecker::checkPreCall(const CallEvent &Call,
548 CheckerContext &C) const {
549 // TODO: Make this check part of CallDescription.
550 if (!Call.isGlobalCFunction())
553 // Check if we called CFRetain/CFRelease/CFMakeCollectable/CFAutorelease.
554 if (!(Call.isCalled(CFRetain) || Call.isCalled(CFRelease) ||
555 Call.isCalled(CFMakeCollectable) || Call.isCalled(CFAutorelease)))
558 // Get the argument's value.
559 SVal ArgVal = Call.getArgSVal(0);
560 Optional<DefinedSVal> DefArgVal = ArgVal.getAs<DefinedSVal>();
565 ProgramStateRef state = C.getState();
566 ProgramStateRef stateNonNull, stateNull;
567 std::tie(stateNonNull, stateNull) = state->assume(*DefArgVal);
570 ExplodedNode *N = C.generateErrorNode(stateNull);
575 raw_svector_ostream OS(Str);
576 OS << "Null pointer argument in call to "
577 << cast<FunctionDecl>(Call.getDecl())->getName();
579 auto report = llvm::make_unique<BugReport>(BT, OS.str(), N);
580 report->addRange(Call.getArgSourceRange(0));
581 bugreporter::trackExpressionValue(N, Call.getArgExpr(0), *report);
582 C.emitReport(std::move(report));
586 // From here on, we know the argument is non-null.
587 C.addTransition(stateNonNull);
590 //===----------------------------------------------------------------------===//
591 // Check for sending 'retain', 'release', or 'autorelease' directly to a Class.
592 //===----------------------------------------------------------------------===//
595 class ClassReleaseChecker : public Checker<check::PreObjCMessage> {
596 mutable Selector releaseS;
597 mutable Selector retainS;
598 mutable Selector autoreleaseS;
599 mutable Selector drainS;
600 mutable std::unique_ptr<BugType> BT;
603 void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
605 } // end anonymous namespace
607 void ClassReleaseChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
608 CheckerContext &C) const {
610 BT.reset(new APIMisuse(
611 this, "message incorrectly sent to class instead of class instance"));
613 ASTContext &Ctx = C.getASTContext();
614 releaseS = GetNullarySelector("release", Ctx);
615 retainS = GetNullarySelector("retain", Ctx);
616 autoreleaseS = GetNullarySelector("autorelease", Ctx);
617 drainS = GetNullarySelector("drain", Ctx);
620 if (msg.isInstanceMessage())
622 const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
625 Selector S = msg.getSelector();
626 if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
629 if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
630 SmallString<200> buf;
631 llvm::raw_svector_ostream os(buf);
635 os << "' message should be sent to instances "
636 "of class '" << Class->getName()
637 << "' and not the class directly";
639 auto report = llvm::make_unique<BugReport>(*BT, os.str(), N);
640 report->addRange(msg.getSourceRange());
641 C.emitReport(std::move(report));
645 //===----------------------------------------------------------------------===//
646 // Check for passing non-Objective-C types to variadic methods that expect
647 // only Objective-C types.
648 //===----------------------------------------------------------------------===//
651 class VariadicMethodTypeChecker : public Checker<check::PreObjCMessage> {
652 mutable Selector arrayWithObjectsS;
653 mutable Selector dictionaryWithObjectsAndKeysS;
654 mutable Selector setWithObjectsS;
655 mutable Selector orderedSetWithObjectsS;
656 mutable Selector initWithObjectsS;
657 mutable Selector initWithObjectsAndKeysS;
658 mutable std::unique_ptr<BugType> BT;
660 bool isVariadicMessage(const ObjCMethodCall &msg) const;
663 void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
665 } // end anonymous namespace
667 /// isVariadicMessage - Returns whether the given message is a variadic message,
668 /// where all arguments must be Objective-C types.
670 VariadicMethodTypeChecker::isVariadicMessage(const ObjCMethodCall &msg) const {
671 const ObjCMethodDecl *MD = msg.getDecl();
673 if (!MD || !MD->isVariadic() || isa<ObjCProtocolDecl>(MD->getDeclContext()))
676 Selector S = msg.getSelector();
678 if (msg.isInstanceMessage()) {
679 // FIXME: Ideally we'd look at the receiver interface here, but that's not
680 // useful for init, because alloc returns 'id'. In theory, this could lead
681 // to false positives, for example if there existed a class that had an
682 // initWithObjects: implementation that does accept non-Objective-C pointer
683 // types, but the chance of that happening is pretty small compared to the
684 // gains that this analysis gives.
685 const ObjCInterfaceDecl *Class = MD->getClassInterface();
687 switch (findKnownClass(Class)) {
689 case FC_NSOrderedSet:
691 return S == initWithObjectsS;
692 case FC_NSDictionary:
693 return S == initWithObjectsAndKeysS;
698 const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
700 switch (findKnownClass(Class)) {
702 return S == arrayWithObjectsS;
703 case FC_NSOrderedSet:
704 return S == orderedSetWithObjectsS;
706 return S == setWithObjectsS;
707 case FC_NSDictionary:
708 return S == dictionaryWithObjectsAndKeysS;
715 void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
716 CheckerContext &C) const {
718 BT.reset(new APIMisuse(this,
719 "Arguments passed to variadic method aren't all "
720 "Objective-C pointer types"));
722 ASTContext &Ctx = C.getASTContext();
723 arrayWithObjectsS = GetUnarySelector("arrayWithObjects", Ctx);
724 dictionaryWithObjectsAndKeysS =
725 GetUnarySelector("dictionaryWithObjectsAndKeys", Ctx);
726 setWithObjectsS = GetUnarySelector("setWithObjects", Ctx);
727 orderedSetWithObjectsS = GetUnarySelector("orderedSetWithObjects", Ctx);
729 initWithObjectsS = GetUnarySelector("initWithObjects", Ctx);
730 initWithObjectsAndKeysS = GetUnarySelector("initWithObjectsAndKeys", Ctx);
733 if (!isVariadicMessage(msg))
736 // We are not interested in the selector arguments since they have
737 // well-defined types, so the compiler will issue a warning for them.
738 unsigned variadicArgsBegin = msg.getSelector().getNumArgs();
740 // We're not interested in the last argument since it has to be nil or the
741 // compiler would have issued a warning for it elsewhere.
742 unsigned variadicArgsEnd = msg.getNumArgs() - 1;
744 if (variadicArgsEnd <= variadicArgsBegin)
747 // Verify that all arguments have Objective-C types.
748 Optional<ExplodedNode*> errorNode;
750 for (unsigned I = variadicArgsBegin; I != variadicArgsEnd; ++I) {
751 QualType ArgTy = msg.getArgExpr(I)->getType();
752 if (ArgTy->isObjCObjectPointerType())
755 // Block pointers are treaded as Objective-C pointers.
756 if (ArgTy->isBlockPointerType())
759 // Ignore pointer constants.
760 if (msg.getArgSVal(I).getAs<loc::ConcreteInt>())
763 // Ignore pointer types annotated with 'NSObject' attribute.
764 if (C.getASTContext().isObjCNSObjectType(ArgTy))
767 // Ignore CF references, which can be toll-free bridged.
768 if (coreFoundation::isCFObjectRef(ArgTy))
771 // Generate only one error node to use for all bug reports.
772 if (!errorNode.hasValue())
773 errorNode = C.generateNonFatalErrorNode();
775 if (!errorNode.getValue())
778 SmallString<128> sbuf;
779 llvm::raw_svector_ostream os(sbuf);
781 StringRef TypeName = GetReceiverInterfaceName(msg);
782 if (!TypeName.empty())
783 os << "Argument to '" << TypeName << "' method '";
785 os << "Argument to method '";
787 msg.getSelector().print(os);
788 os << "' should be an Objective-C pointer type, not '";
789 ArgTy.print(os, C.getLangOpts());
792 auto R = llvm::make_unique<BugReport>(*BT, os.str(), errorNode.getValue());
793 R->addRange(msg.getArgSourceRange(I));
794 C.emitReport(std::move(R));
798 //===----------------------------------------------------------------------===//
799 // Improves the modeling of loops over Cocoa collections.
800 //===----------------------------------------------------------------------===//
802 // The map from container symbol to the container count symbol.
803 // We currently will remember the last container count symbol encountered.
804 REGISTER_MAP_WITH_PROGRAMSTATE(ContainerCountMap, SymbolRef, SymbolRef)
805 REGISTER_MAP_WITH_PROGRAMSTATE(ContainerNonEmptyMap, SymbolRef, bool)
808 class ObjCLoopChecker
809 : public Checker<check::PostStmt<ObjCForCollectionStmt>,
810 check::PostObjCMessage,
812 check::PointerEscape > {
813 mutable IdentifierInfo *CountSelectorII;
815 bool isCollectionCountMethod(const ObjCMethodCall &M,
816 CheckerContext &C) const;
819 ObjCLoopChecker() : CountSelectorII(nullptr) {}
820 void checkPostStmt(const ObjCForCollectionStmt *FCS, CheckerContext &C) const;
821 void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
822 void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
823 ProgramStateRef checkPointerEscape(ProgramStateRef State,
824 const InvalidatedSymbols &Escaped,
825 const CallEvent *Call,
826 PointerEscapeKind Kind) const;
828 } // end anonymous namespace
830 static bool isKnownNonNilCollectionType(QualType T) {
831 const ObjCObjectPointerType *PT = T->getAs<ObjCObjectPointerType>();
835 const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();
839 switch (findKnownClass(ID)) {
841 case FC_NSDictionary:
842 case FC_NSEnumerator:
843 case FC_NSOrderedSet:
851 /// Assumes that the collection is non-nil.
853 /// If the collection is known to be nil, returns NULL to indicate an infeasible
855 static ProgramStateRef checkCollectionNonNil(CheckerContext &C,
856 ProgramStateRef State,
857 const ObjCForCollectionStmt *FCS) {
861 SVal CollectionVal = C.getSVal(FCS->getCollection());
862 Optional<DefinedSVal> KnownCollection = CollectionVal.getAs<DefinedSVal>();
863 if (!KnownCollection)
866 ProgramStateRef StNonNil, StNil;
867 std::tie(StNonNil, StNil) = State->assume(*KnownCollection);
868 if (StNil && !StNonNil) {
869 // The collection is nil. This path is infeasible.
876 /// Assumes that the collection elements are non-nil.
878 /// This only applies if the collection is one of those known not to contain
880 static ProgramStateRef checkElementNonNil(CheckerContext &C,
881 ProgramStateRef State,
882 const ObjCForCollectionStmt *FCS) {
886 // See if the collection is one where we /know/ the elements are non-nil.
887 if (!isKnownNonNilCollectionType(FCS->getCollection()->getType()))
890 const LocationContext *LCtx = C.getLocationContext();
891 const Stmt *Element = FCS->getElement();
893 // FIXME: Copied from ExprEngineObjC.
894 Optional<Loc> ElementLoc;
895 if (const DeclStmt *DS = dyn_cast<DeclStmt>(Element)) {
896 const VarDecl *ElemDecl = cast<VarDecl>(DS->getSingleDecl());
897 assert(ElemDecl->getInit() == nullptr);
898 ElementLoc = State->getLValue(ElemDecl, LCtx);
900 ElementLoc = State->getSVal(Element, LCtx).getAs<Loc>();
906 // Go ahead and assume the value is non-nil.
907 SVal Val = State->getSVal(*ElementLoc);
908 return State->assume(Val.castAs<DefinedOrUnknownSVal>(), true);
911 /// Returns NULL state if the collection is known to contain elements
912 /// (or is known not to contain elements if the Assumption parameter is false.)
913 static ProgramStateRef
914 assumeCollectionNonEmpty(CheckerContext &C, ProgramStateRef State,
915 SymbolRef CollectionS, bool Assumption) {
916 if (!State || !CollectionS)
919 const SymbolRef *CountS = State->get<ContainerCountMap>(CollectionS);
921 const bool *KnownNonEmpty = State->get<ContainerNonEmptyMap>(CollectionS);
923 return State->set<ContainerNonEmptyMap>(CollectionS, Assumption);
924 return (Assumption == *KnownNonEmpty) ? State : nullptr;
927 SValBuilder &SvalBuilder = C.getSValBuilder();
928 SVal CountGreaterThanZeroVal =
929 SvalBuilder.evalBinOp(State, BO_GT,
930 nonloc::SymbolVal(*CountS),
931 SvalBuilder.makeIntVal(0, (*CountS)->getType()),
932 SvalBuilder.getConditionType());
933 Optional<DefinedSVal> CountGreaterThanZero =
934 CountGreaterThanZeroVal.getAs<DefinedSVal>();
935 if (!CountGreaterThanZero) {
936 // The SValBuilder cannot construct a valid SVal for this condition.
937 // This means we cannot properly reason about it.
941 return State->assume(*CountGreaterThanZero, Assumption);
944 static ProgramStateRef
945 assumeCollectionNonEmpty(CheckerContext &C, ProgramStateRef State,
946 const ObjCForCollectionStmt *FCS,
951 SymbolRef CollectionS = C.getSVal(FCS->getCollection()).getAsSymbol();
952 return assumeCollectionNonEmpty(C, State, CollectionS, Assumption);
955 /// If the fist block edge is a back edge, we are reentering the loop.
956 static bool alreadyExecutedAtLeastOneLoopIteration(const ExplodedNode *N,
957 const ObjCForCollectionStmt *FCS) {
961 ProgramPoint P = N->getLocation();
962 if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) {
963 return BE->getSrc()->getLoopTarget() == FCS;
966 // Keep looking for a block edge.
967 for (ExplodedNode::const_pred_iterator I = N->pred_begin(),
968 E = N->pred_end(); I != E; ++I) {
969 if (alreadyExecutedAtLeastOneLoopIteration(*I, FCS))
976 void ObjCLoopChecker::checkPostStmt(const ObjCForCollectionStmt *FCS,
977 CheckerContext &C) const {
978 ProgramStateRef State = C.getState();
980 // Check if this is the branch for the end of the loop.
981 SVal CollectionSentinel = C.getSVal(FCS);
982 if (CollectionSentinel.isZeroConstant()) {
983 if (!alreadyExecutedAtLeastOneLoopIteration(C.getPredecessor(), FCS))
984 State = assumeCollectionNonEmpty(C, State, FCS, /*Assumption*/false);
986 // Otherwise, this is a branch that goes through the loop body.
988 State = checkCollectionNonNil(C, State, FCS);
989 State = checkElementNonNil(C, State, FCS);
990 State = assumeCollectionNonEmpty(C, State, FCS, /*Assumption*/true);
994 C.generateSink(C.getState(), C.getPredecessor());
995 else if (State != C.getState())
996 C.addTransition(State);
999 bool ObjCLoopChecker::isCollectionCountMethod(const ObjCMethodCall &M,
1000 CheckerContext &C) const {
1001 Selector S = M.getSelector();
1002 // Initialize the identifiers on first use.
1003 if (!CountSelectorII)
1004 CountSelectorII = &C.getASTContext().Idents.get("count");
1006 // If the method returns collection count, record the value.
1007 return S.isUnarySelector() &&
1008 (S.getIdentifierInfoForSlot(0) == CountSelectorII);
1011 void ObjCLoopChecker::checkPostObjCMessage(const ObjCMethodCall &M,
1012 CheckerContext &C) const {
1013 if (!M.isInstanceMessage())
1016 const ObjCInterfaceDecl *ClassID = M.getReceiverInterface();
1020 FoundationClass Class = findKnownClass(ClassID);
1021 if (Class != FC_NSDictionary &&
1022 Class != FC_NSArray &&
1023 Class != FC_NSSet &&
1024 Class != FC_NSOrderedSet)
1027 SymbolRef ContainerS = M.getReceiverSVal().getAsSymbol();
1031 // If we are processing a call to "count", get the symbolic value returned by
1032 // a call to "count" and add it to the map.
1033 if (!isCollectionCountMethod(M, C))
1036 const Expr *MsgExpr = M.getOriginExpr();
1037 SymbolRef CountS = C.getSVal(MsgExpr).getAsSymbol();
1039 ProgramStateRef State = C.getState();
1041 C.getSymbolManager().addSymbolDependency(ContainerS, CountS);
1042 State = State->set<ContainerCountMap>(ContainerS, CountS);
1044 if (const bool *NonEmpty = State->get<ContainerNonEmptyMap>(ContainerS)) {
1045 State = State->remove<ContainerNonEmptyMap>(ContainerS);
1046 State = assumeCollectionNonEmpty(C, State, ContainerS, *NonEmpty);
1049 C.addTransition(State);
1053 static SymbolRef getMethodReceiverIfKnownImmutable(const CallEvent *Call) {
1054 const ObjCMethodCall *Message = dyn_cast_or_null<ObjCMethodCall>(Call);
1058 const ObjCMethodDecl *MD = Message->getDecl();
1062 const ObjCInterfaceDecl *StaticClass;
1063 if (isa<ObjCProtocolDecl>(MD->getDeclContext())) {
1064 // We can't find out where the method was declared without doing more work.
1065 // Instead, see if the receiver is statically typed as a known immutable
1067 StaticClass = Message->getOriginExpr()->getReceiverInterface();
1069 StaticClass = MD->getClassInterface();
1075 switch (findKnownClass(StaticClass, /*IncludeSuper=*/false)) {
1079 case FC_NSDictionary:
1080 case FC_NSEnumerator:
1082 case FC_NSOrderedSet:
1088 return Message->getReceiverSVal().getAsSymbol();
1092 ObjCLoopChecker::checkPointerEscape(ProgramStateRef State,
1093 const InvalidatedSymbols &Escaped,
1094 const CallEvent *Call,
1095 PointerEscapeKind Kind) const {
1096 SymbolRef ImmutableReceiver = getMethodReceiverIfKnownImmutable(Call);
1098 // Remove the invalidated symbols form the collection count map.
1099 for (InvalidatedSymbols::const_iterator I = Escaped.begin(),
1104 // Don't invalidate this symbol's count if we know the method being called
1105 // is declared on an immutable class. This isn't completely correct if the
1106 // receiver is also passed as an argument, but in most uses of NSArray,
1107 // NSDictionary, etc. this isn't likely to happen in a dangerous way.
1108 if (Sym == ImmutableReceiver)
1111 // The symbol escaped. Pessimistically, assume that the count could have
1113 State = State->remove<ContainerCountMap>(Sym);
1114 State = State->remove<ContainerNonEmptyMap>(Sym);
1119 void ObjCLoopChecker::checkDeadSymbols(SymbolReaper &SymReaper,
1120 CheckerContext &C) const {
1121 ProgramStateRef State = C.getState();
1123 // Remove the dead symbols from the collection count map.
1124 ContainerCountMapTy Tracked = State->get<ContainerCountMap>();
1125 for (ContainerCountMapTy::iterator I = Tracked.begin(),
1126 E = Tracked.end(); I != E; ++I) {
1127 SymbolRef Sym = I->first;
1128 if (SymReaper.isDead(Sym)) {
1129 State = State->remove<ContainerCountMap>(Sym);
1130 State = State->remove<ContainerNonEmptyMap>(Sym);
1134 C.addTransition(State);
1138 /// \class ObjCNonNilReturnValueChecker
1139 /// The checker restricts the return values of APIs known to
1140 /// never (or almost never) return 'nil'.
1141 class ObjCNonNilReturnValueChecker
1142 : public Checker<check::PostObjCMessage,
1143 check::PostStmt<ObjCArrayLiteral>,
1144 check::PostStmt<ObjCDictionaryLiteral>,
1145 check::PostStmt<ObjCBoxedExpr> > {
1146 mutable bool Initialized;
1147 mutable Selector ObjectAtIndex;
1148 mutable Selector ObjectAtIndexedSubscript;
1149 mutable Selector NullSelector;
1152 ObjCNonNilReturnValueChecker() : Initialized(false) {}
1154 ProgramStateRef assumeExprIsNonNull(const Expr *NonNullExpr,
1155 ProgramStateRef State,
1156 CheckerContext &C) const;
1157 void assumeExprIsNonNull(const Expr *E, CheckerContext &C) const {
1158 C.addTransition(assumeExprIsNonNull(E, C.getState(), C));
1161 void checkPostStmt(const ObjCArrayLiteral *E, CheckerContext &C) const {
1162 assumeExprIsNonNull(E, C);
1164 void checkPostStmt(const ObjCDictionaryLiteral *E, CheckerContext &C) const {
1165 assumeExprIsNonNull(E, C);
1167 void checkPostStmt(const ObjCBoxedExpr *E, CheckerContext &C) const {
1168 assumeExprIsNonNull(E, C);
1171 void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
1173 } // end anonymous namespace
1176 ObjCNonNilReturnValueChecker::assumeExprIsNonNull(const Expr *NonNullExpr,
1177 ProgramStateRef State,
1178 CheckerContext &C) const {
1179 SVal Val = C.getSVal(NonNullExpr);
1180 if (Optional<DefinedOrUnknownSVal> DV = Val.getAs<DefinedOrUnknownSVal>())
1181 return State->assume(*DV, true);
1185 void ObjCNonNilReturnValueChecker::checkPostObjCMessage(const ObjCMethodCall &M,
1188 ProgramStateRef State = C.getState();
1191 ASTContext &Ctx = C.getASTContext();
1192 ObjectAtIndex = GetUnarySelector("objectAtIndex", Ctx);
1193 ObjectAtIndexedSubscript = GetUnarySelector("objectAtIndexedSubscript", Ctx);
1194 NullSelector = GetNullarySelector("null", Ctx);
1197 // Check the receiver type.
1198 if (const ObjCInterfaceDecl *Interface = M.getReceiverInterface()) {
1200 // Assume that object returned from '[self init]' or '[super init]' is not
1201 // 'nil' if we are processing an inlined function/method.
1203 // A defensive callee will (and should) check if the object returned by
1204 // '[super init]' is 'nil' before doing it's own initialization. However,
1205 // since 'nil' is rarely returned in practice, we should not warn when the
1206 // caller to the defensive constructor uses the object in contexts where
1207 // 'nil' is not accepted.
1208 if (!C.inTopFrame() && M.getDecl() &&
1209 M.getDecl()->getMethodFamily() == OMF_init &&
1210 M.isReceiverSelfOrSuper()) {
1211 State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
1214 FoundationClass Cl = findKnownClass(Interface);
1216 // Objects returned from
1217 // [NSArray|NSOrderedSet]::[ObjectAtIndex|ObjectAtIndexedSubscript]
1219 if (Cl == FC_NSArray || Cl == FC_NSOrderedSet) {
1220 Selector Sel = M.getSelector();
1221 if (Sel == ObjectAtIndex || Sel == ObjectAtIndexedSubscript) {
1222 // Go ahead and assume the value is non-nil.
1223 State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
1227 // Objects returned from [NSNull null] are not nil.
1228 if (Cl == FC_NSNull) {
1229 if (M.getSelector() == NullSelector) {
1230 // Go ahead and assume the value is non-nil.
1231 State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
1235 C.addTransition(State);
1238 //===----------------------------------------------------------------------===//
1239 // Check registration.
1240 //===----------------------------------------------------------------------===//
1242 void ento::registerNilArgChecker(CheckerManager &mgr) {
1243 mgr.registerChecker<NilArgChecker>();
1246 void ento::registerCFNumberChecker(CheckerManager &mgr) {
1247 mgr.registerChecker<CFNumberChecker>();
1250 void ento::registerCFRetainReleaseChecker(CheckerManager &mgr) {
1251 mgr.registerChecker<CFRetainReleaseChecker>();
1254 void ento::registerClassReleaseChecker(CheckerManager &mgr) {
1255 mgr.registerChecker<ClassReleaseChecker>();
1258 void ento::registerVariadicMethodTypeChecker(CheckerManager &mgr) {
1259 mgr.registerChecker<VariadicMethodTypeChecker>();
1262 void ento::registerObjCLoopChecker(CheckerManager &mgr) {
1263 mgr.registerChecker<ObjCLoopChecker>();
1267 ento::registerObjCNonNilReturnValueChecker(CheckerManager &mgr) {
1268 mgr.registerChecker<ObjCNonNilReturnValueChecker>();