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 "SelectorExtras.h"
18 #include "clang/AST/ASTContext.h"
19 #include "clang/AST/DeclObjC.h"
20 #include "clang/AST/Expr.h"
21 #include "clang/AST/ExprObjC.h"
22 #include "clang/AST/StmtObjC.h"
23 #include "clang/Analysis/DomainSpecific/CocoaConventions.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;
41 class APIMisuse : public BugType {
43 APIMisuse(const CheckerBase *checker, const char *name)
44 : BugType(checker, name, "API Misuse (Apple)") {}
46 } // end anonymous namespace
48 //===----------------------------------------------------------------------===//
50 //===----------------------------------------------------------------------===//
52 static StringRef GetReceiverInterfaceName(const ObjCMethodCall &msg) {
53 if (const ObjCInterfaceDecl *ID = msg.getReceiverInterface())
54 return ID->getIdentifier()->getName();
58 enum FoundationClass {
69 static FoundationClass findKnownClass(const ObjCInterfaceDecl *ID,
70 bool IncludeSuperclasses = true) {
71 static llvm::StringMap<FoundationClass> Classes;
72 if (Classes.empty()) {
73 Classes["NSArray"] = FC_NSArray;
74 Classes["NSDictionary"] = FC_NSDictionary;
75 Classes["NSEnumerator"] = FC_NSEnumerator;
76 Classes["NSNull"] = FC_NSNull;
77 Classes["NSOrderedSet"] = FC_NSOrderedSet;
78 Classes["NSSet"] = FC_NSSet;
79 Classes["NSString"] = FC_NSString;
82 // FIXME: Should we cache this at all?
83 FoundationClass result = Classes.lookup(ID->getIdentifier()->getName());
84 if (result == FC_None && IncludeSuperclasses)
85 if (const ObjCInterfaceDecl *Super = ID->getSuperClass())
86 return findKnownClass(Super);
91 //===----------------------------------------------------------------------===//
92 // NilArgChecker - Check for prohibited nil arguments to ObjC method calls.
93 //===----------------------------------------------------------------------===//
96 class NilArgChecker : public Checker<check::PreObjCMessage,
97 check::PostStmt<ObjCDictionaryLiteral>,
98 check::PostStmt<ObjCArrayLiteral> > {
99 mutable std::unique_ptr<APIMisuse> BT;
101 mutable llvm::SmallDenseMap<Selector, unsigned, 16> StringSelectors;
102 mutable Selector ArrayWithObjectSel;
103 mutable Selector AddObjectSel;
104 mutable Selector InsertObjectAtIndexSel;
105 mutable Selector ReplaceObjectAtIndexWithObjectSel;
106 mutable Selector SetObjectAtIndexedSubscriptSel;
107 mutable Selector ArrayByAddingObjectSel;
108 mutable Selector DictionaryWithObjectForKeySel;
109 mutable Selector SetObjectForKeySel;
110 mutable Selector SetObjectForKeyedSubscriptSel;
111 mutable Selector RemoveObjectForKeySel;
113 void warnIfNilExpr(const Expr *E,
115 CheckerContext &C) const;
117 void warnIfNilArg(CheckerContext &C,
118 const ObjCMethodCall &msg, unsigned Arg,
119 FoundationClass Class,
120 bool CanBeSubscript = false) const;
122 void generateBugReport(ExplodedNode *N,
126 CheckerContext &C) const;
129 void checkPreObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
130 void checkPostStmt(const ObjCDictionaryLiteral *DL,
131 CheckerContext &C) const;
132 void checkPostStmt(const ObjCArrayLiteral *AL,
133 CheckerContext &C) const;
135 } // end anonymous namespace
137 void NilArgChecker::warnIfNilExpr(const Expr *E,
139 CheckerContext &C) const {
140 ProgramStateRef State = C.getState();
141 if (State->isNull(C.getSVal(E)).isConstrainedTrue()) {
143 if (ExplodedNode *N = C.generateErrorNode()) {
144 generateBugReport(N, Msg, E->getSourceRange(), E, C);
149 void NilArgChecker::warnIfNilArg(CheckerContext &C,
150 const ObjCMethodCall &msg,
152 FoundationClass Class,
153 bool CanBeSubscript) const {
154 // Check if the argument is nil.
155 ProgramStateRef State = C.getState();
156 if (!State->isNull(msg.getArgSVal(Arg)).isConstrainedTrue())
159 if (ExplodedNode *N = C.generateErrorNode()) {
160 SmallString<128> sbuf;
161 llvm::raw_svector_ostream os(sbuf);
163 if (CanBeSubscript && msg.getMessageKind() == OCM_Subscript) {
165 if (Class == FC_NSArray) {
166 os << "Array element cannot be nil";
167 } else if (Class == FC_NSDictionary) {
169 os << "Value stored into '";
170 os << GetReceiverInterfaceName(msg) << "' cannot be nil";
173 os << "'"<< GetReceiverInterfaceName(msg) << "' key cannot be nil";
176 llvm_unreachable("Missing foundation class for the subscript expr");
179 if (Class == FC_NSDictionary) {
181 os << "Value argument ";
184 os << "Key argument ";
187 msg.getSelector().print(os);
188 os << "' cannot be nil";
190 os << "Argument to '" << GetReceiverInterfaceName(msg) << "' method '";
191 msg.getSelector().print(os);
192 os << "' cannot be nil";
196 generateBugReport(N, os.str(), msg.getArgSourceRange(Arg),
197 msg.getArgExpr(Arg), C);
201 void NilArgChecker::generateBugReport(ExplodedNode *N,
205 CheckerContext &C) const {
207 BT.reset(new APIMisuse(this, "nil argument"));
209 auto R = llvm::make_unique<BugReport>(*BT, Msg, N);
211 bugreporter::trackNullOrUndefValue(N, E, *R);
212 C.emitReport(std::move(R));
215 void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
216 CheckerContext &C) const {
217 const ObjCInterfaceDecl *ID = msg.getReceiverInterface();
221 FoundationClass Class = findKnownClass(ID);
223 static const unsigned InvalidArgIndex = UINT_MAX;
224 unsigned Arg = InvalidArgIndex;
225 bool CanBeSubscript = false;
227 if (Class == FC_NSString) {
228 Selector S = msg.getSelector();
230 if (S.isUnarySelector())
233 if (StringSelectors.empty()) {
234 ASTContext &Ctx = C.getASTContext();
236 getKeywordSelector(Ctx, "caseInsensitiveCompare", nullptr),
237 getKeywordSelector(Ctx, "compare", nullptr),
238 getKeywordSelector(Ctx, "compare", "options", nullptr),
239 getKeywordSelector(Ctx, "compare", "options", "range", nullptr),
240 getKeywordSelector(Ctx, "compare", "options", "range", "locale",
242 getKeywordSelector(Ctx, "componentsSeparatedByCharactersInSet",
244 getKeywordSelector(Ctx, "initWithFormat",
246 getKeywordSelector(Ctx, "localizedCaseInsensitiveCompare", nullptr),
247 getKeywordSelector(Ctx, "localizedCompare", nullptr),
248 getKeywordSelector(Ctx, "localizedStandardCompare", nullptr),
250 for (Selector KnownSel : Sels)
251 StringSelectors[KnownSel] = 0;
253 auto I = StringSelectors.find(S);
254 if (I == StringSelectors.end())
257 } else if (Class == FC_NSArray) {
258 Selector S = msg.getSelector();
260 if (S.isUnarySelector())
263 if (ArrayWithObjectSel.isNull()) {
264 ASTContext &Ctx = C.getASTContext();
265 ArrayWithObjectSel = getKeywordSelector(Ctx, "arrayWithObject", nullptr);
266 AddObjectSel = getKeywordSelector(Ctx, "addObject", nullptr);
267 InsertObjectAtIndexSel =
268 getKeywordSelector(Ctx, "insertObject", "atIndex", nullptr);
269 ReplaceObjectAtIndexWithObjectSel =
270 getKeywordSelector(Ctx, "replaceObjectAtIndex", "withObject", nullptr);
271 SetObjectAtIndexedSubscriptSel =
272 getKeywordSelector(Ctx, "setObject", "atIndexedSubscript", nullptr);
273 ArrayByAddingObjectSel =
274 getKeywordSelector(Ctx, "arrayByAddingObject", nullptr);
277 if (S == ArrayWithObjectSel || S == AddObjectSel ||
278 S == InsertObjectAtIndexSel || S == ArrayByAddingObjectSel) {
280 } else if (S == SetObjectAtIndexedSubscriptSel) {
282 CanBeSubscript = true;
283 } else if (S == ReplaceObjectAtIndexWithObjectSel) {
286 } else if (Class == FC_NSDictionary) {
287 Selector S = msg.getSelector();
289 if (S.isUnarySelector())
292 if (DictionaryWithObjectForKeySel.isNull()) {
293 ASTContext &Ctx = C.getASTContext();
294 DictionaryWithObjectForKeySel =
295 getKeywordSelector(Ctx, "dictionaryWithObject", "forKey", nullptr);
297 getKeywordSelector(Ctx, "setObject", "forKey", nullptr);
298 SetObjectForKeyedSubscriptSel =
299 getKeywordSelector(Ctx, "setObject", "forKeyedSubscript", nullptr);
300 RemoveObjectForKeySel =
301 getKeywordSelector(Ctx, "removeObjectForKey", nullptr);
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 const LocationContext *LCtx = C.getLocationContext();
446 SVal TheTypeVal = state->getSVal(CE->getArg(1), LCtx);
448 // FIXME: We really should allow ranges of valid theType values, and
449 // bifurcate the state appropriately.
450 Optional<nonloc::ConcreteInt> V = TheTypeVal.getAs<nonloc::ConcreteInt>();
454 uint64_t NumberKind = V->getValue().getLimitedValue();
455 Optional<uint64_t> OptCFNumberSize = GetCFNumberSize(Ctx, NumberKind);
457 // FIXME: In some cases we can emit an error.
458 if (!OptCFNumberSize)
461 uint64_t CFNumberSize = *OptCFNumberSize;
463 // Look at the value of the integer being passed by reference. Essentially
464 // we want to catch cases where the value passed in is not equal to the
465 // size of the type being created.
466 SVal TheValueExpr = state->getSVal(CE->getArg(2), LCtx);
468 // FIXME: Eventually we should handle arbitrary locations. We can do this
469 // by having an enhanced memory model that does low-level typing.
470 Optional<loc::MemRegionVal> LV = TheValueExpr.getAs<loc::MemRegionVal>();
474 const TypedValueRegion* R = dyn_cast<TypedValueRegion>(LV->stripCasts());
478 QualType T = Ctx.getCanonicalType(R->getValueType());
480 // FIXME: If the pointee isn't an integer type, should we flag a warning?
481 // People can do weird stuff with pointers.
483 if (!T->isIntegralOrEnumerationType())
486 uint64_t PrimitiveTypeSize = Ctx.getTypeSize(T);
488 if (PrimitiveTypeSize == CFNumberSize)
491 // FIXME: We can actually create an abstract "CFNumber" object that has
492 // the bits initialized to the provided values.
493 ExplodedNode *N = C.generateNonFatalErrorNode();
495 SmallString<128> sbuf;
496 llvm::raw_svector_ostream os(sbuf);
497 bool isCreate = (FD->getIdentifier() == ICreate);
500 os << (PrimitiveTypeSize == 8 ? "An " : "A ")
501 << PrimitiveTypeSize << "-bit integer is used to initialize a "
502 << "CFNumber object that represents "
503 << (CFNumberSize == 8 ? "an " : "a ")
504 << CFNumberSize << "-bit integer; ";
506 os << "A CFNumber object that represents "
507 << (CFNumberSize == 8 ? "an " : "a ")
508 << CFNumberSize << "-bit integer is used to initialize "
509 << (PrimitiveTypeSize == 8 ? "an " : "a ")
510 << PrimitiveTypeSize << "-bit integer; ";
513 if (PrimitiveTypeSize < CFNumberSize)
514 os << (CFNumberSize - PrimitiveTypeSize)
515 << " bits of the CFNumber value will "
516 << (isCreate ? "be garbage." : "overwrite adjacent storage.");
518 os << (PrimitiveTypeSize - CFNumberSize)
519 << " bits of the integer value will be "
520 << (isCreate ? "lost." : "garbage.");
523 BT.reset(new APIMisuse(this, "Bad use of CFNumber APIs"));
525 auto report = llvm::make_unique<BugReport>(*BT, os.str(), N);
526 report->addRange(CE->getArg(2)->getSourceRange());
527 C.emitReport(std::move(report));
531 //===----------------------------------------------------------------------===//
532 // CFRetain/CFRelease/CFMakeCollectable/CFAutorelease checking for null arguments.
533 //===----------------------------------------------------------------------===//
536 class CFRetainReleaseChecker : public Checker< check::PreStmt<CallExpr> > {
537 mutable std::unique_ptr<APIMisuse> BT;
538 mutable IdentifierInfo *Retain, *Release, *MakeCollectable, *Autorelease;
541 CFRetainReleaseChecker()
542 : Retain(nullptr), Release(nullptr), MakeCollectable(nullptr),
543 Autorelease(nullptr) {}
544 void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
546 } // end anonymous namespace
548 void CFRetainReleaseChecker::checkPreStmt(const CallExpr *CE,
549 CheckerContext &C) const {
550 // If the CallExpr doesn't have exactly 1 argument just give up checking.
551 if (CE->getNumArgs() != 1)
554 ProgramStateRef state = C.getState();
555 const FunctionDecl *FD = C.getCalleeDecl(CE);
560 ASTContext &Ctx = C.getASTContext();
561 Retain = &Ctx.Idents.get("CFRetain");
562 Release = &Ctx.Idents.get("CFRelease");
563 MakeCollectable = &Ctx.Idents.get("CFMakeCollectable");
564 Autorelease = &Ctx.Idents.get("CFAutorelease");
565 BT.reset(new APIMisuse(
566 this, "null passed to CF memory management function"));
569 // Check if we called CFRetain/CFRelease/CFMakeCollectable/CFAutorelease.
570 const IdentifierInfo *FuncII = FD->getIdentifier();
571 if (!(FuncII == Retain || FuncII == Release || FuncII == MakeCollectable ||
572 FuncII == Autorelease))
575 // FIXME: The rest of this just checks that the argument is non-null.
576 // It should probably be refactored and combined with NonNullParamChecker.
578 // Get the argument's value.
579 const Expr *Arg = CE->getArg(0);
580 SVal ArgVal = state->getSVal(Arg, C.getLocationContext());
581 Optional<DefinedSVal> DefArgVal = ArgVal.getAs<DefinedSVal>();
586 SValBuilder &svalBuilder = C.getSValBuilder();
588 svalBuilder.makeZeroVal(Arg->getType()).castAs<DefinedSVal>();
590 // Make an expression asserting that they're equal.
591 DefinedOrUnknownSVal ArgIsNull = svalBuilder.evalEQ(state, zero, *DefArgVal);
594 ProgramStateRef stateTrue, stateFalse;
595 std::tie(stateTrue, stateFalse) = state->assume(ArgIsNull);
597 if (stateTrue && !stateFalse) {
598 ExplodedNode *N = C.generateErrorNode(stateTrue);
602 const char *description;
603 if (FuncII == Retain)
604 description = "Null pointer argument in call to CFRetain";
605 else if (FuncII == Release)
606 description = "Null pointer argument in call to CFRelease";
607 else if (FuncII == MakeCollectable)
608 description = "Null pointer argument in call to CFMakeCollectable";
609 else if (FuncII == Autorelease)
610 description = "Null pointer argument in call to CFAutorelease";
612 llvm_unreachable("impossible case");
614 auto report = llvm::make_unique<BugReport>(*BT, description, N);
615 report->addRange(Arg->getSourceRange());
616 bugreporter::trackNullOrUndefValue(N, Arg, *report);
617 C.emitReport(std::move(report));
621 // From here on, we know the argument is non-null.
622 C.addTransition(stateFalse);
625 //===----------------------------------------------------------------------===//
626 // Check for sending 'retain', 'release', or 'autorelease' directly to a Class.
627 //===----------------------------------------------------------------------===//
630 class ClassReleaseChecker : public Checker<check::PreObjCMessage> {
631 mutable Selector releaseS;
632 mutable Selector retainS;
633 mutable Selector autoreleaseS;
634 mutable Selector drainS;
635 mutable std::unique_ptr<BugType> BT;
638 void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
640 } // end anonymous namespace
642 void ClassReleaseChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
643 CheckerContext &C) const {
645 BT.reset(new APIMisuse(
646 this, "message incorrectly sent to class instead of class instance"));
648 ASTContext &Ctx = C.getASTContext();
649 releaseS = GetNullarySelector("release", Ctx);
650 retainS = GetNullarySelector("retain", Ctx);
651 autoreleaseS = GetNullarySelector("autorelease", Ctx);
652 drainS = GetNullarySelector("drain", Ctx);
655 if (msg.isInstanceMessage())
657 const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
660 Selector S = msg.getSelector();
661 if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
664 if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
665 SmallString<200> buf;
666 llvm::raw_svector_ostream os(buf);
670 os << "' message should be sent to instances "
671 "of class '" << Class->getName()
672 << "' and not the class directly";
674 auto report = llvm::make_unique<BugReport>(*BT, os.str(), N);
675 report->addRange(msg.getSourceRange());
676 C.emitReport(std::move(report));
680 //===----------------------------------------------------------------------===//
681 // Check for passing non-Objective-C types to variadic methods that expect
682 // only Objective-C types.
683 //===----------------------------------------------------------------------===//
686 class VariadicMethodTypeChecker : public Checker<check::PreObjCMessage> {
687 mutable Selector arrayWithObjectsS;
688 mutable Selector dictionaryWithObjectsAndKeysS;
689 mutable Selector setWithObjectsS;
690 mutable Selector orderedSetWithObjectsS;
691 mutable Selector initWithObjectsS;
692 mutable Selector initWithObjectsAndKeysS;
693 mutable std::unique_ptr<BugType> BT;
695 bool isVariadicMessage(const ObjCMethodCall &msg) const;
698 void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
700 } // end anonymous namespace
702 /// isVariadicMessage - Returns whether the given message is a variadic message,
703 /// where all arguments must be Objective-C types.
705 VariadicMethodTypeChecker::isVariadicMessage(const ObjCMethodCall &msg) const {
706 const ObjCMethodDecl *MD = msg.getDecl();
708 if (!MD || !MD->isVariadic() || isa<ObjCProtocolDecl>(MD->getDeclContext()))
711 Selector S = msg.getSelector();
713 if (msg.isInstanceMessage()) {
714 // FIXME: Ideally we'd look at the receiver interface here, but that's not
715 // useful for init, because alloc returns 'id'. In theory, this could lead
716 // to false positives, for example if there existed a class that had an
717 // initWithObjects: implementation that does accept non-Objective-C pointer
718 // types, but the chance of that happening is pretty small compared to the
719 // gains that this analysis gives.
720 const ObjCInterfaceDecl *Class = MD->getClassInterface();
722 switch (findKnownClass(Class)) {
724 case FC_NSOrderedSet:
726 return S == initWithObjectsS;
727 case FC_NSDictionary:
728 return S == initWithObjectsAndKeysS;
733 const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
735 switch (findKnownClass(Class)) {
737 return S == arrayWithObjectsS;
738 case FC_NSOrderedSet:
739 return S == orderedSetWithObjectsS;
741 return S == setWithObjectsS;
742 case FC_NSDictionary:
743 return S == dictionaryWithObjectsAndKeysS;
750 void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
751 CheckerContext &C) const {
753 BT.reset(new APIMisuse(this,
754 "Arguments passed to variadic method aren't all "
755 "Objective-C pointer types"));
757 ASTContext &Ctx = C.getASTContext();
758 arrayWithObjectsS = GetUnarySelector("arrayWithObjects", Ctx);
759 dictionaryWithObjectsAndKeysS =
760 GetUnarySelector("dictionaryWithObjectsAndKeys", Ctx);
761 setWithObjectsS = GetUnarySelector("setWithObjects", Ctx);
762 orderedSetWithObjectsS = GetUnarySelector("orderedSetWithObjects", Ctx);
764 initWithObjectsS = GetUnarySelector("initWithObjects", Ctx);
765 initWithObjectsAndKeysS = GetUnarySelector("initWithObjectsAndKeys", Ctx);
768 if (!isVariadicMessage(msg))
771 // We are not interested in the selector arguments since they have
772 // well-defined types, so the compiler will issue a warning for them.
773 unsigned variadicArgsBegin = msg.getSelector().getNumArgs();
775 // We're not interested in the last argument since it has to be nil or the
776 // compiler would have issued a warning for it elsewhere.
777 unsigned variadicArgsEnd = msg.getNumArgs() - 1;
779 if (variadicArgsEnd <= variadicArgsBegin)
782 // Verify that all arguments have Objective-C types.
783 Optional<ExplodedNode*> errorNode;
785 for (unsigned I = variadicArgsBegin; I != variadicArgsEnd; ++I) {
786 QualType ArgTy = msg.getArgExpr(I)->getType();
787 if (ArgTy->isObjCObjectPointerType())
790 // Block pointers are treaded as Objective-C pointers.
791 if (ArgTy->isBlockPointerType())
794 // Ignore pointer constants.
795 if (msg.getArgSVal(I).getAs<loc::ConcreteInt>())
798 // Ignore pointer types annotated with 'NSObject' attribute.
799 if (C.getASTContext().isObjCNSObjectType(ArgTy))
802 // Ignore CF references, which can be toll-free bridged.
803 if (coreFoundation::isCFObjectRef(ArgTy))
806 // Generate only one error node to use for all bug reports.
807 if (!errorNode.hasValue())
808 errorNode = C.generateNonFatalErrorNode();
810 if (!errorNode.getValue())
813 SmallString<128> sbuf;
814 llvm::raw_svector_ostream os(sbuf);
816 StringRef TypeName = GetReceiverInterfaceName(msg);
817 if (!TypeName.empty())
818 os << "Argument to '" << TypeName << "' method '";
820 os << "Argument to method '";
822 msg.getSelector().print(os);
823 os << "' should be an Objective-C pointer type, not '";
824 ArgTy.print(os, C.getLangOpts());
827 auto R = llvm::make_unique<BugReport>(*BT, os.str(), errorNode.getValue());
828 R->addRange(msg.getArgSourceRange(I));
829 C.emitReport(std::move(R));
833 //===----------------------------------------------------------------------===//
834 // Improves the modeling of loops over Cocoa collections.
835 //===----------------------------------------------------------------------===//
837 // The map from container symbol to the container count symbol.
838 // We currently will remember the last countainer count symbol encountered.
839 REGISTER_MAP_WITH_PROGRAMSTATE(ContainerCountMap, SymbolRef, SymbolRef)
840 REGISTER_MAP_WITH_PROGRAMSTATE(ContainerNonEmptyMap, SymbolRef, bool)
843 class ObjCLoopChecker
844 : public Checker<check::PostStmt<ObjCForCollectionStmt>,
845 check::PostObjCMessage,
847 check::PointerEscape > {
848 mutable IdentifierInfo *CountSelectorII;
850 bool isCollectionCountMethod(const ObjCMethodCall &M,
851 CheckerContext &C) const;
854 ObjCLoopChecker() : CountSelectorII(nullptr) {}
855 void checkPostStmt(const ObjCForCollectionStmt *FCS, CheckerContext &C) const;
856 void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
857 void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
858 ProgramStateRef checkPointerEscape(ProgramStateRef State,
859 const InvalidatedSymbols &Escaped,
860 const CallEvent *Call,
861 PointerEscapeKind Kind) const;
863 } // end anonymous namespace
865 static bool isKnownNonNilCollectionType(QualType T) {
866 const ObjCObjectPointerType *PT = T->getAs<ObjCObjectPointerType>();
870 const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();
874 switch (findKnownClass(ID)) {
876 case FC_NSDictionary:
877 case FC_NSEnumerator:
878 case FC_NSOrderedSet:
886 /// Assumes that the collection is non-nil.
888 /// If the collection is known to be nil, returns NULL to indicate an infeasible
890 static ProgramStateRef checkCollectionNonNil(CheckerContext &C,
891 ProgramStateRef State,
892 const ObjCForCollectionStmt *FCS) {
896 SVal CollectionVal = C.getSVal(FCS->getCollection());
897 Optional<DefinedSVal> KnownCollection = CollectionVal.getAs<DefinedSVal>();
898 if (!KnownCollection)
901 ProgramStateRef StNonNil, StNil;
902 std::tie(StNonNil, StNil) = State->assume(*KnownCollection);
903 if (StNil && !StNonNil) {
904 // The collection is nil. This path is infeasible.
911 /// Assumes that the collection elements are non-nil.
913 /// This only applies if the collection is one of those known not to contain
915 static ProgramStateRef checkElementNonNil(CheckerContext &C,
916 ProgramStateRef State,
917 const ObjCForCollectionStmt *FCS) {
921 // See if the collection is one where we /know/ the elements are non-nil.
922 if (!isKnownNonNilCollectionType(FCS->getCollection()->getType()))
925 const LocationContext *LCtx = C.getLocationContext();
926 const Stmt *Element = FCS->getElement();
928 // FIXME: Copied from ExprEngineObjC.
929 Optional<Loc> ElementLoc;
930 if (const DeclStmt *DS = dyn_cast<DeclStmt>(Element)) {
931 const VarDecl *ElemDecl = cast<VarDecl>(DS->getSingleDecl());
932 assert(ElemDecl->getInit() == nullptr);
933 ElementLoc = State->getLValue(ElemDecl, LCtx);
935 ElementLoc = State->getSVal(Element, LCtx).getAs<Loc>();
941 // Go ahead and assume the value is non-nil.
942 SVal Val = State->getSVal(*ElementLoc);
943 return State->assume(Val.castAs<DefinedOrUnknownSVal>(), true);
946 /// Returns NULL state if the collection is known to contain elements
947 /// (or is known not to contain elements if the Assumption parameter is false.)
948 static ProgramStateRef
949 assumeCollectionNonEmpty(CheckerContext &C, ProgramStateRef State,
950 SymbolRef CollectionS, bool Assumption) {
951 if (!State || !CollectionS)
954 const SymbolRef *CountS = State->get<ContainerCountMap>(CollectionS);
956 const bool *KnownNonEmpty = State->get<ContainerNonEmptyMap>(CollectionS);
958 return State->set<ContainerNonEmptyMap>(CollectionS, Assumption);
959 return (Assumption == *KnownNonEmpty) ? State : nullptr;
962 SValBuilder &SvalBuilder = C.getSValBuilder();
963 SVal CountGreaterThanZeroVal =
964 SvalBuilder.evalBinOp(State, BO_GT,
965 nonloc::SymbolVal(*CountS),
966 SvalBuilder.makeIntVal(0, (*CountS)->getType()),
967 SvalBuilder.getConditionType());
968 Optional<DefinedSVal> CountGreaterThanZero =
969 CountGreaterThanZeroVal.getAs<DefinedSVal>();
970 if (!CountGreaterThanZero) {
971 // The SValBuilder cannot construct a valid SVal for this condition.
972 // This means we cannot properly reason about it.
976 return State->assume(*CountGreaterThanZero, Assumption);
979 static ProgramStateRef
980 assumeCollectionNonEmpty(CheckerContext &C, ProgramStateRef State,
981 const ObjCForCollectionStmt *FCS,
986 SymbolRef CollectionS =
987 State->getSVal(FCS->getCollection(), C.getLocationContext()).getAsSymbol();
988 return assumeCollectionNonEmpty(C, State, CollectionS, Assumption);
991 /// If the fist block edge is a back edge, we are reentering the loop.
992 static bool alreadyExecutedAtLeastOneLoopIteration(const ExplodedNode *N,
993 const ObjCForCollectionStmt *FCS) {
997 ProgramPoint P = N->getLocation();
998 if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) {
999 return BE->getSrc()->getLoopTarget() == FCS;
1002 // Keep looking for a block edge.
1003 for (ExplodedNode::const_pred_iterator I = N->pred_begin(),
1004 E = N->pred_end(); I != E; ++I) {
1005 if (alreadyExecutedAtLeastOneLoopIteration(*I, FCS))
1012 void ObjCLoopChecker::checkPostStmt(const ObjCForCollectionStmt *FCS,
1013 CheckerContext &C) const {
1014 ProgramStateRef State = C.getState();
1016 // Check if this is the branch for the end of the loop.
1017 SVal CollectionSentinel = C.getSVal(FCS);
1018 if (CollectionSentinel.isZeroConstant()) {
1019 if (!alreadyExecutedAtLeastOneLoopIteration(C.getPredecessor(), FCS))
1020 State = assumeCollectionNonEmpty(C, State, FCS, /*Assumption*/false);
1022 // Otherwise, this is a branch that goes through the loop body.
1024 State = checkCollectionNonNil(C, State, FCS);
1025 State = checkElementNonNil(C, State, FCS);
1026 State = assumeCollectionNonEmpty(C, State, FCS, /*Assumption*/true);
1030 C.generateSink(C.getState(), C.getPredecessor());
1031 else if (State != C.getState())
1032 C.addTransition(State);
1035 bool ObjCLoopChecker::isCollectionCountMethod(const ObjCMethodCall &M,
1036 CheckerContext &C) const {
1037 Selector S = M.getSelector();
1038 // Initialize the identifiers on first use.
1039 if (!CountSelectorII)
1040 CountSelectorII = &C.getASTContext().Idents.get("count");
1042 // If the method returns collection count, record the value.
1043 return S.isUnarySelector() &&
1044 (S.getIdentifierInfoForSlot(0) == CountSelectorII);
1047 void ObjCLoopChecker::checkPostObjCMessage(const ObjCMethodCall &M,
1048 CheckerContext &C) const {
1049 if (!M.isInstanceMessage())
1052 const ObjCInterfaceDecl *ClassID = M.getReceiverInterface();
1056 FoundationClass Class = findKnownClass(ClassID);
1057 if (Class != FC_NSDictionary &&
1058 Class != FC_NSArray &&
1059 Class != FC_NSSet &&
1060 Class != FC_NSOrderedSet)
1063 SymbolRef ContainerS = M.getReceiverSVal().getAsSymbol();
1067 // If we are processing a call to "count", get the symbolic value returned by
1068 // a call to "count" and add it to the map.
1069 if (!isCollectionCountMethod(M, C))
1072 const Expr *MsgExpr = M.getOriginExpr();
1073 SymbolRef CountS = C.getSVal(MsgExpr).getAsSymbol();
1075 ProgramStateRef State = C.getState();
1077 C.getSymbolManager().addSymbolDependency(ContainerS, CountS);
1078 State = State->set<ContainerCountMap>(ContainerS, CountS);
1080 if (const bool *NonEmpty = State->get<ContainerNonEmptyMap>(ContainerS)) {
1081 State = State->remove<ContainerNonEmptyMap>(ContainerS);
1082 State = assumeCollectionNonEmpty(C, State, ContainerS, *NonEmpty);
1085 C.addTransition(State);
1089 static SymbolRef getMethodReceiverIfKnownImmutable(const CallEvent *Call) {
1090 const ObjCMethodCall *Message = dyn_cast_or_null<ObjCMethodCall>(Call);
1094 const ObjCMethodDecl *MD = Message->getDecl();
1098 const ObjCInterfaceDecl *StaticClass;
1099 if (isa<ObjCProtocolDecl>(MD->getDeclContext())) {
1100 // We can't find out where the method was declared without doing more work.
1101 // Instead, see if the receiver is statically typed as a known immutable
1103 StaticClass = Message->getOriginExpr()->getReceiverInterface();
1105 StaticClass = MD->getClassInterface();
1111 switch (findKnownClass(StaticClass, /*IncludeSuper=*/false)) {
1115 case FC_NSDictionary:
1116 case FC_NSEnumerator:
1118 case FC_NSOrderedSet:
1124 return Message->getReceiverSVal().getAsSymbol();
1128 ObjCLoopChecker::checkPointerEscape(ProgramStateRef State,
1129 const InvalidatedSymbols &Escaped,
1130 const CallEvent *Call,
1131 PointerEscapeKind Kind) const {
1132 SymbolRef ImmutableReceiver = getMethodReceiverIfKnownImmutable(Call);
1134 // Remove the invalidated symbols form the collection count map.
1135 for (InvalidatedSymbols::const_iterator I = Escaped.begin(),
1140 // Don't invalidate this symbol's count if we know the method being called
1141 // is declared on an immutable class. This isn't completely correct if the
1142 // receiver is also passed as an argument, but in most uses of NSArray,
1143 // NSDictionary, etc. this isn't likely to happen in a dangerous way.
1144 if (Sym == ImmutableReceiver)
1147 // The symbol escaped. Pessimistically, assume that the count could have
1149 State = State->remove<ContainerCountMap>(Sym);
1150 State = State->remove<ContainerNonEmptyMap>(Sym);
1155 void ObjCLoopChecker::checkDeadSymbols(SymbolReaper &SymReaper,
1156 CheckerContext &C) const {
1157 ProgramStateRef State = C.getState();
1159 // Remove the dead symbols from the collection count map.
1160 ContainerCountMapTy Tracked = State->get<ContainerCountMap>();
1161 for (ContainerCountMapTy::iterator I = Tracked.begin(),
1162 E = Tracked.end(); I != E; ++I) {
1163 SymbolRef Sym = I->first;
1164 if (SymReaper.isDead(Sym)) {
1165 State = State->remove<ContainerCountMap>(Sym);
1166 State = State->remove<ContainerNonEmptyMap>(Sym);
1170 C.addTransition(State);
1174 /// \class ObjCNonNilReturnValueChecker
1175 /// \brief The checker restricts the return values of APIs known to
1176 /// never (or almost never) return 'nil'.
1177 class ObjCNonNilReturnValueChecker
1178 : public Checker<check::PostObjCMessage,
1179 check::PostStmt<ObjCArrayLiteral>,
1180 check::PostStmt<ObjCDictionaryLiteral>,
1181 check::PostStmt<ObjCBoxedExpr> > {
1182 mutable bool Initialized;
1183 mutable Selector ObjectAtIndex;
1184 mutable Selector ObjectAtIndexedSubscript;
1185 mutable Selector NullSelector;
1188 ObjCNonNilReturnValueChecker() : Initialized(false) {}
1190 ProgramStateRef assumeExprIsNonNull(const Expr *NonNullExpr,
1191 ProgramStateRef State,
1192 CheckerContext &C) const;
1193 void assumeExprIsNonNull(const Expr *E, CheckerContext &C) const {
1194 C.addTransition(assumeExprIsNonNull(E, C.getState(), C));
1197 void checkPostStmt(const ObjCArrayLiteral *E, CheckerContext &C) const {
1198 assumeExprIsNonNull(E, C);
1200 void checkPostStmt(const ObjCDictionaryLiteral *E, CheckerContext &C) const {
1201 assumeExprIsNonNull(E, C);
1203 void checkPostStmt(const ObjCBoxedExpr *E, CheckerContext &C) const {
1204 assumeExprIsNonNull(E, C);
1207 void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
1209 } // end anonymous namespace
1212 ObjCNonNilReturnValueChecker::assumeExprIsNonNull(const Expr *NonNullExpr,
1213 ProgramStateRef State,
1214 CheckerContext &C) const {
1215 SVal Val = State->getSVal(NonNullExpr, C.getLocationContext());
1216 if (Optional<DefinedOrUnknownSVal> DV = Val.getAs<DefinedOrUnknownSVal>())
1217 return State->assume(*DV, true);
1221 void ObjCNonNilReturnValueChecker::checkPostObjCMessage(const ObjCMethodCall &M,
1224 ProgramStateRef State = C.getState();
1227 ASTContext &Ctx = C.getASTContext();
1228 ObjectAtIndex = GetUnarySelector("objectAtIndex", Ctx);
1229 ObjectAtIndexedSubscript = GetUnarySelector("objectAtIndexedSubscript", Ctx);
1230 NullSelector = GetNullarySelector("null", Ctx);
1233 // Check the receiver type.
1234 if (const ObjCInterfaceDecl *Interface = M.getReceiverInterface()) {
1236 // Assume that object returned from '[self init]' or '[super init]' is not
1237 // 'nil' if we are processing an inlined function/method.
1239 // A defensive callee will (and should) check if the object returned by
1240 // '[super init]' is 'nil' before doing it's own initialization. However,
1241 // since 'nil' is rarely returned in practice, we should not warn when the
1242 // caller to the defensive constructor uses the object in contexts where
1243 // 'nil' is not accepted.
1244 if (!C.inTopFrame() && M.getDecl() &&
1245 M.getDecl()->getMethodFamily() == OMF_init &&
1246 M.isReceiverSelfOrSuper()) {
1247 State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
1250 FoundationClass Cl = findKnownClass(Interface);
1252 // Objects returned from
1253 // [NSArray|NSOrderedSet]::[ObjectAtIndex|ObjectAtIndexedSubscript]
1255 if (Cl == FC_NSArray || Cl == FC_NSOrderedSet) {
1256 Selector Sel = M.getSelector();
1257 if (Sel == ObjectAtIndex || Sel == ObjectAtIndexedSubscript) {
1258 // Go ahead and assume the value is non-nil.
1259 State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
1263 // Objects returned from [NSNull null] are not nil.
1264 if (Cl == FC_NSNull) {
1265 if (M.getSelector() == NullSelector) {
1266 // Go ahead and assume the value is non-nil.
1267 State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
1271 C.addTransition(State);
1274 //===----------------------------------------------------------------------===//
1275 // Check registration.
1276 //===----------------------------------------------------------------------===//
1278 void ento::registerNilArgChecker(CheckerManager &mgr) {
1279 mgr.registerChecker<NilArgChecker>();
1282 void ento::registerCFNumberChecker(CheckerManager &mgr) {
1283 mgr.registerChecker<CFNumberChecker>();
1286 void ento::registerCFRetainReleaseChecker(CheckerManager &mgr) {
1287 mgr.registerChecker<CFRetainReleaseChecker>();
1290 void ento::registerClassReleaseChecker(CheckerManager &mgr) {
1291 mgr.registerChecker<ClassReleaseChecker>();
1294 void ento::registerVariadicMethodTypeChecker(CheckerManager &mgr) {
1295 mgr.registerChecker<VariadicMethodTypeChecker>();
1298 void ento::registerObjCLoopChecker(CheckerManager &mgr) {
1299 mgr.registerChecker<ObjCLoopChecker>();
1303 ento::registerObjCNonNilReturnValueChecker(CheckerManager &mgr) {
1304 mgr.registerChecker<ObjCNonNilReturnValueChecker>();