1 //== BasicObjCFoundationChecks.cpp - Simple Apple-Foundation checks -*- C++ -*-- 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 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 12 // classes. 13 // 14 //===----------------------------------------------------------------------===// 15 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" 36 37 using namespace clang; 38 using namespace ento; 39 40 namespace { 41 class APIMisuse : public BugType { 42 public: 43 APIMisuse(const CheckerBase *checker, const char *name) 44 : BugType(checker, name, "API Misuse (Apple)") {} 45 }; 46 } // end anonymous namespace 47 48 //===----------------------------------------------------------------------===// 49 // Utility functions. 50 //===----------------------------------------------------------------------===// 51 52 static StringRef GetReceiverInterfaceName(const ObjCMethodCall &msg) { 53 if (const ObjCInterfaceDecl *ID = msg.getReceiverInterface()) 54 return ID->getIdentifier()->getName(); 55 return StringRef(); 56 } 57 58 enum FoundationClass { 59 FC_None, 60 FC_NSArray, 61 FC_NSDictionary, 62 FC_NSEnumerator, 63 FC_NSNull, 64 FC_NSOrderedSet, 65 FC_NSSet, 66 FC_NSString 67 }; 68 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; 80 } 81 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); 87 88 return result; 89 } 90 91 //===----------------------------------------------------------------------===// 92 // NilArgChecker - Check for prohibited nil arguments to ObjC method calls. 93 //===----------------------------------------------------------------------===// 94 95 namespace { 96 class NilArgChecker : public Checker<check::PreObjCMessage, 97 check::PostStmt<ObjCDictionaryLiteral>, 98 check::PostStmt<ObjCArrayLiteral> > { 99 mutable std::unique_ptr<APIMisuse> BT; 100 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; 112 113 void warnIfNilExpr(const Expr *E, 114 const char *Msg, 115 CheckerContext &C) const; 116 117 void warnIfNilArg(CheckerContext &C, 118 const ObjCMethodCall &msg, unsigned Arg, 119 FoundationClass Class, 120 bool CanBeSubscript = false) const; 121 122 void generateBugReport(ExplodedNode *N, 123 StringRef Msg, 124 SourceRange Range, 125 const Expr *Expr, 126 CheckerContext &C) const; 127 128 public: 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; 134 }; 135 } 136 137 void NilArgChecker::warnIfNilExpr(const Expr *E, 138 const char *Msg, 139 CheckerContext &C) const { 140 ProgramStateRef State = C.getState(); 141 if (State->isNull(C.getSVal(E)).isConstrainedTrue()) { 142 143 if (ExplodedNode *N = C.generateErrorNode()) { 144 generateBugReport(N, Msg, E->getSourceRange(), E, C); 145 } 146 147 } 148 } 149 150 void NilArgChecker::warnIfNilArg(CheckerContext &C, 151 const ObjCMethodCall &msg, 152 unsigned int Arg, 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()) 158 return; 159 160 if (ExplodedNode *N = C.generateErrorNode()) { 161 SmallString<128> sbuf; 162 llvm::raw_svector_ostream os(sbuf); 163 164 if (CanBeSubscript && msg.getMessageKind() == OCM_Subscript) { 165 166 if (Class == FC_NSArray) { 167 os << "Array element cannot be nil"; 168 } else if (Class == FC_NSDictionary) { 169 if (Arg == 0) { 170 os << "Value stored into '"; 171 os << GetReceiverInterfaceName(msg) << "' cannot be nil"; 172 } else { 173 assert(Arg == 1); 174 os << "'"<< GetReceiverInterfaceName(msg) << "' key cannot be nil"; 175 } 176 } else 177 llvm_unreachable("Missing foundation class for the subscript expr"); 178 179 } else { 180 if (Class == FC_NSDictionary) { 181 if (Arg == 0) 182 os << "Value argument "; 183 else { 184 assert(Arg == 1); 185 os << "Key argument "; 186 } 187 os << "to '"; 188 msg.getSelector().print(os); 189 os << "' cannot be nil"; 190 } else { 191 os << "Argument to '" << GetReceiverInterfaceName(msg) << "' method '"; 192 msg.getSelector().print(os); 193 os << "' cannot be nil"; 194 } 195 } 196 197 generateBugReport(N, os.str(), msg.getArgSourceRange(Arg), 198 msg.getArgExpr(Arg), C); 199 } 200 } 201 202 void NilArgChecker::generateBugReport(ExplodedNode *N, 203 StringRef Msg, 204 SourceRange Range, 205 const Expr *E, 206 CheckerContext &C) const { 207 if (!BT) 208 BT.reset(new APIMisuse(this, "nil argument")); 209 210 auto R = llvm::make_unique<BugReport>(*BT, Msg, N); 211 R->addRange(Range); 212 bugreporter::trackNullOrUndefValue(N, E, *R); 213 C.emitReport(std::move(R)); 214 } 215 216 void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg, 217 CheckerContext &C) const { 218 const ObjCInterfaceDecl *ID = msg.getReceiverInterface(); 219 if (!ID) 220 return; 221 222 FoundationClass Class = findKnownClass(ID); 223 224 static const unsigned InvalidArgIndex = UINT_MAX; 225 unsigned Arg = InvalidArgIndex; 226 bool CanBeSubscript = false; 227 228 if (Class == FC_NSString) { 229 Selector S = msg.getSelector(); 230 231 if (S.isUnarySelector()) 232 return; 233 234 if (StringSelectors.empty()) { 235 ASTContext &Ctx = C.getASTContext(); 236 Selector Sels[] = { 237 getKeywordSelector(Ctx, "caseInsensitiveCompare", nullptr), 238 getKeywordSelector(Ctx, "compare", nullptr), 239 getKeywordSelector(Ctx, "compare", "options", nullptr), 240 getKeywordSelector(Ctx, "compare", "options", "range", nullptr), 241 getKeywordSelector(Ctx, "compare", "options", "range", "locale", 242 nullptr), 243 getKeywordSelector(Ctx, "componentsSeparatedByCharactersInSet", 244 nullptr), 245 getKeywordSelector(Ctx, "initWithFormat", 246 nullptr), 247 getKeywordSelector(Ctx, "localizedCaseInsensitiveCompare", nullptr), 248 getKeywordSelector(Ctx, "localizedCompare", nullptr), 249 getKeywordSelector(Ctx, "localizedStandardCompare", nullptr), 250 }; 251 for (Selector KnownSel : Sels) 252 StringSelectors[KnownSel] = 0; 253 } 254 auto I = StringSelectors.find(S); 255 if (I == StringSelectors.end()) 256 return; 257 Arg = I->second; 258 } else if (Class == FC_NSArray) { 259 Selector S = msg.getSelector(); 260 261 if (S.isUnarySelector()) 262 return; 263 264 if (ArrayWithObjectSel.isNull()) { 265 ASTContext &Ctx = C.getASTContext(); 266 ArrayWithObjectSel = getKeywordSelector(Ctx, "arrayWithObject", nullptr); 267 AddObjectSel = getKeywordSelector(Ctx, "addObject", nullptr); 268 InsertObjectAtIndexSel = 269 getKeywordSelector(Ctx, "insertObject", "atIndex", nullptr); 270 ReplaceObjectAtIndexWithObjectSel = 271 getKeywordSelector(Ctx, "replaceObjectAtIndex", "withObject", nullptr); 272 SetObjectAtIndexedSubscriptSel = 273 getKeywordSelector(Ctx, "setObject", "atIndexedSubscript", nullptr); 274 ArrayByAddingObjectSel = 275 getKeywordSelector(Ctx, "arrayByAddingObject", nullptr); 276 } 277 278 if (S == ArrayWithObjectSel || S == AddObjectSel || 279 S == InsertObjectAtIndexSel || S == ArrayByAddingObjectSel) { 280 Arg = 0; 281 } else if (S == SetObjectAtIndexedSubscriptSel) { 282 Arg = 0; 283 CanBeSubscript = true; 284 } else if (S == ReplaceObjectAtIndexWithObjectSel) { 285 Arg = 1; 286 } 287 } else if (Class == FC_NSDictionary) { 288 Selector S = msg.getSelector(); 289 290 if (S.isUnarySelector()) 291 return; 292 293 if (DictionaryWithObjectForKeySel.isNull()) { 294 ASTContext &Ctx = C.getASTContext(); 295 DictionaryWithObjectForKeySel = 296 getKeywordSelector(Ctx, "dictionaryWithObject", "forKey", nullptr); 297 SetObjectForKeySel = 298 getKeywordSelector(Ctx, "setObject", "forKey", nullptr); 299 SetObjectForKeyedSubscriptSel = 300 getKeywordSelector(Ctx, "setObject", "forKeyedSubscript", nullptr); 301 RemoveObjectForKeySel = 302 getKeywordSelector(Ctx, "removeObjectForKey", nullptr); 303 } 304 305 if (S == DictionaryWithObjectForKeySel || S == SetObjectForKeySel) { 306 Arg = 0; 307 warnIfNilArg(C, msg, /* Arg */1, Class); 308 } else if (S == SetObjectForKeyedSubscriptSel) { 309 CanBeSubscript = true; 310 Arg = 0; 311 warnIfNilArg(C, msg, /* Arg */1, Class, CanBeSubscript); 312 } else if (S == RemoveObjectForKeySel) { 313 Arg = 0; 314 } 315 } 316 317 // If argument is '0', report a warning. 318 if ((Arg != InvalidArgIndex)) 319 warnIfNilArg(C, msg, Arg, Class, CanBeSubscript); 320 } 321 322 void NilArgChecker::checkPostStmt(const ObjCArrayLiteral *AL, 323 CheckerContext &C) const { 324 unsigned NumOfElements = AL->getNumElements(); 325 for (unsigned i = 0; i < NumOfElements; ++i) { 326 warnIfNilExpr(AL->getElement(i), "Array element cannot be nil", C); 327 } 328 } 329 330 void NilArgChecker::checkPostStmt(const ObjCDictionaryLiteral *DL, 331 CheckerContext &C) const { 332 unsigned NumOfElements = DL->getNumElements(); 333 for (unsigned i = 0; i < NumOfElements; ++i) { 334 ObjCDictionaryElement Element = DL->getKeyValueElement(i); 335 warnIfNilExpr(Element.Key, "Dictionary key cannot be nil", C); 336 warnIfNilExpr(Element.Value, "Dictionary value cannot be nil", C); 337 } 338 } 339 340 //===----------------------------------------------------------------------===// 341 // Error reporting. 342 //===----------------------------------------------------------------------===// 343 344 namespace { 345 class CFNumberCreateChecker : public Checker< check::PreStmt<CallExpr> > { 346 mutable std::unique_ptr<APIMisuse> BT; 347 mutable IdentifierInfo* II; 348 public: 349 CFNumberCreateChecker() : II(nullptr) {} 350 351 void checkPreStmt(const CallExpr *CE, CheckerContext &C) const; 352 353 private: 354 void EmitError(const TypedRegion* R, const Expr *Ex, 355 uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind); 356 }; 357 } // end anonymous namespace 358 359 enum CFNumberType { 360 kCFNumberSInt8Type = 1, 361 kCFNumberSInt16Type = 2, 362 kCFNumberSInt32Type = 3, 363 kCFNumberSInt64Type = 4, 364 kCFNumberFloat32Type = 5, 365 kCFNumberFloat64Type = 6, 366 kCFNumberCharType = 7, 367 kCFNumberShortType = 8, 368 kCFNumberIntType = 9, 369 kCFNumberLongType = 10, 370 kCFNumberLongLongType = 11, 371 kCFNumberFloatType = 12, 372 kCFNumberDoubleType = 13, 373 kCFNumberCFIndexType = 14, 374 kCFNumberNSIntegerType = 15, 375 kCFNumberCGFloatType = 16 376 }; 377 378 static Optional<uint64_t> GetCFNumberSize(ASTContext &Ctx, uint64_t i) { 379 static const unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 }; 380 381 if (i < kCFNumberCharType) 382 return FixedSize[i-1]; 383 384 QualType T; 385 386 switch (i) { 387 case kCFNumberCharType: T = Ctx.CharTy; break; 388 case kCFNumberShortType: T = Ctx.ShortTy; break; 389 case kCFNumberIntType: T = Ctx.IntTy; break; 390 case kCFNumberLongType: T = Ctx.LongTy; break; 391 case kCFNumberLongLongType: T = Ctx.LongLongTy; break; 392 case kCFNumberFloatType: T = Ctx.FloatTy; break; 393 case kCFNumberDoubleType: T = Ctx.DoubleTy; break; 394 case kCFNumberCFIndexType: 395 case kCFNumberNSIntegerType: 396 case kCFNumberCGFloatType: 397 // FIXME: We need a way to map from names to Type*. 398 default: 399 return None; 400 } 401 402 return Ctx.getTypeSize(T); 403 } 404 405 #if 0 406 static const char* GetCFNumberTypeStr(uint64_t i) { 407 static const char* Names[] = { 408 "kCFNumberSInt8Type", 409 "kCFNumberSInt16Type", 410 "kCFNumberSInt32Type", 411 "kCFNumberSInt64Type", 412 "kCFNumberFloat32Type", 413 "kCFNumberFloat64Type", 414 "kCFNumberCharType", 415 "kCFNumberShortType", 416 "kCFNumberIntType", 417 "kCFNumberLongType", 418 "kCFNumberLongLongType", 419 "kCFNumberFloatType", 420 "kCFNumberDoubleType", 421 "kCFNumberCFIndexType", 422 "kCFNumberNSIntegerType", 423 "kCFNumberCGFloatType" 424 }; 425 426 return i <= kCFNumberCGFloatType ? Names[i-1] : "Invalid CFNumberType"; 427 } 428 #endif 429 430 void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE, 431 CheckerContext &C) const { 432 ProgramStateRef state = C.getState(); 433 const FunctionDecl *FD = C.getCalleeDecl(CE); 434 if (!FD) 435 return; 436 437 ASTContext &Ctx = C.getASTContext(); 438 if (!II) 439 II = &Ctx.Idents.get("CFNumberCreate"); 440 441 if (FD->getIdentifier() != II || CE->getNumArgs() != 3) 442 return; 443 444 // Get the value of the "theType" argument. 445 const LocationContext *LCtx = C.getLocationContext(); 446 SVal TheTypeVal = state->getSVal(CE->getArg(1), LCtx); 447 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>(); 451 if (!V) 452 return; 453 454 uint64_t NumberKind = V->getValue().getLimitedValue(); 455 Optional<uint64_t> OptTargetSize = GetCFNumberSize(Ctx, NumberKind); 456 457 // FIXME: In some cases we can emit an error. 458 if (!OptTargetSize) 459 return; 460 461 uint64_t TargetSize = *OptTargetSize; 462 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); 467 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>(); 471 if (!LV) 472 return; 473 474 const TypedValueRegion* R = dyn_cast<TypedValueRegion>(LV->stripCasts()); 475 if (!R) 476 return; 477 478 QualType T = Ctx.getCanonicalType(R->getValueType()); 479 480 // FIXME: If the pointee isn't an integer type, should we flag a warning? 481 // People can do weird stuff with pointers. 482 483 if (!T->isIntegralOrEnumerationType()) 484 return; 485 486 uint64_t SourceSize = Ctx.getTypeSize(T); 487 488 // CHECK: is SourceSize == TargetSize 489 if (SourceSize == TargetSize) 490 return; 491 492 // Generate an error. Only generate a sink error node 493 // if 'SourceSize < TargetSize'; otherwise generate a non-fatal error node. 494 // 495 // FIXME: We can actually create an abstract "CFNumber" object that has 496 // the bits initialized to the provided values. 497 // 498 ExplodedNode *N = SourceSize < TargetSize ? C.generateErrorNode() 499 : C.generateNonFatalErrorNode(); 500 if (N) { 501 SmallString<128> sbuf; 502 llvm::raw_svector_ostream os(sbuf); 503 504 os << (SourceSize == 8 ? "An " : "A ") 505 << SourceSize << " bit integer is used to initialize a CFNumber " 506 "object that represents " 507 << (TargetSize == 8 ? "an " : "a ") 508 << TargetSize << " bit integer. "; 509 510 if (SourceSize < TargetSize) 511 os << (TargetSize - SourceSize) 512 << " bits of the CFNumber value will be garbage." ; 513 else 514 os << (SourceSize - TargetSize) 515 << " bits of the input integer will be lost."; 516 517 if (!BT) 518 BT.reset(new APIMisuse(this, "Bad use of CFNumberCreate")); 519 520 auto report = llvm::make_unique<BugReport>(*BT, os.str(), N); 521 report->addRange(CE->getArg(2)->getSourceRange()); 522 C.emitReport(std::move(report)); 523 } 524 } 525 526 //===----------------------------------------------------------------------===// 527 // CFRetain/CFRelease/CFMakeCollectable/CFAutorelease checking for null arguments. 528 //===----------------------------------------------------------------------===// 529 530 namespace { 531 class CFRetainReleaseChecker : public Checker< check::PreStmt<CallExpr> > { 532 mutable std::unique_ptr<APIMisuse> BT; 533 mutable IdentifierInfo *Retain, *Release, *MakeCollectable, *Autorelease; 534 public: 535 CFRetainReleaseChecker() 536 : Retain(nullptr), Release(nullptr), MakeCollectable(nullptr), 537 Autorelease(nullptr) {} 538 void checkPreStmt(const CallExpr *CE, CheckerContext &C) const; 539 }; 540 } // end anonymous namespace 541 542 543 void CFRetainReleaseChecker::checkPreStmt(const CallExpr *CE, 544 CheckerContext &C) const { 545 // If the CallExpr doesn't have exactly 1 argument just give up checking. 546 if (CE->getNumArgs() != 1) 547 return; 548 549 ProgramStateRef state = C.getState(); 550 const FunctionDecl *FD = C.getCalleeDecl(CE); 551 if (!FD) 552 return; 553 554 if (!BT) { 555 ASTContext &Ctx = C.getASTContext(); 556 Retain = &Ctx.Idents.get("CFRetain"); 557 Release = &Ctx.Idents.get("CFRelease"); 558 MakeCollectable = &Ctx.Idents.get("CFMakeCollectable"); 559 Autorelease = &Ctx.Idents.get("CFAutorelease"); 560 BT.reset(new APIMisuse( 561 this, "null passed to CF memory management function")); 562 } 563 564 // Check if we called CFRetain/CFRelease/CFMakeCollectable/CFAutorelease. 565 const IdentifierInfo *FuncII = FD->getIdentifier(); 566 if (!(FuncII == Retain || FuncII == Release || FuncII == MakeCollectable || 567 FuncII == Autorelease)) 568 return; 569 570 // FIXME: The rest of this just checks that the argument is non-null. 571 // It should probably be refactored and combined with NonNullParamChecker. 572 573 // Get the argument's value. 574 const Expr *Arg = CE->getArg(0); 575 SVal ArgVal = state->getSVal(Arg, C.getLocationContext()); 576 Optional<DefinedSVal> DefArgVal = ArgVal.getAs<DefinedSVal>(); 577 if (!DefArgVal) 578 return; 579 580 // Get a NULL value. 581 SValBuilder &svalBuilder = C.getSValBuilder(); 582 DefinedSVal zero = 583 svalBuilder.makeZeroVal(Arg->getType()).castAs<DefinedSVal>(); 584 585 // Make an expression asserting that they're equal. 586 DefinedOrUnknownSVal ArgIsNull = svalBuilder.evalEQ(state, zero, *DefArgVal); 587 588 // Are they equal? 589 ProgramStateRef stateTrue, stateFalse; 590 std::tie(stateTrue, stateFalse) = state->assume(ArgIsNull); 591 592 if (stateTrue && !stateFalse) { 593 ExplodedNode *N = C.generateErrorNode(stateTrue); 594 if (!N) 595 return; 596 597 const char *description; 598 if (FuncII == Retain) 599 description = "Null pointer argument in call to CFRetain"; 600 else if (FuncII == Release) 601 description = "Null pointer argument in call to CFRelease"; 602 else if (FuncII == MakeCollectable) 603 description = "Null pointer argument in call to CFMakeCollectable"; 604 else if (FuncII == Autorelease) 605 description = "Null pointer argument in call to CFAutorelease"; 606 else 607 llvm_unreachable("impossible case"); 608 609 auto report = llvm::make_unique<BugReport>(*BT, description, N); 610 report->addRange(Arg->getSourceRange()); 611 bugreporter::trackNullOrUndefValue(N, Arg, *report); 612 C.emitReport(std::move(report)); 613 return; 614 } 615 616 // From here on, we know the argument is non-null. 617 C.addTransition(stateFalse); 618 } 619 620 //===----------------------------------------------------------------------===// 621 // Check for sending 'retain', 'release', or 'autorelease' directly to a Class. 622 //===----------------------------------------------------------------------===// 623 624 namespace { 625 class ClassReleaseChecker : public Checker<check::PreObjCMessage> { 626 mutable Selector releaseS; 627 mutable Selector retainS; 628 mutable Selector autoreleaseS; 629 mutable Selector drainS; 630 mutable std::unique_ptr<BugType> BT; 631 632 public: 633 void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const; 634 }; 635 } 636 637 void ClassReleaseChecker::checkPreObjCMessage(const ObjCMethodCall &msg, 638 CheckerContext &C) const { 639 640 if (!BT) { 641 BT.reset(new APIMisuse( 642 this, "message incorrectly sent to class instead of class instance")); 643 644 ASTContext &Ctx = C.getASTContext(); 645 releaseS = GetNullarySelector("release", Ctx); 646 retainS = GetNullarySelector("retain", Ctx); 647 autoreleaseS = GetNullarySelector("autorelease", Ctx); 648 drainS = GetNullarySelector("drain", Ctx); 649 } 650 651 if (msg.isInstanceMessage()) 652 return; 653 const ObjCInterfaceDecl *Class = msg.getReceiverInterface(); 654 assert(Class); 655 656 Selector S = msg.getSelector(); 657 if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS)) 658 return; 659 660 if (ExplodedNode *N = C.generateNonFatalErrorNode()) { 661 SmallString<200> buf; 662 llvm::raw_svector_ostream os(buf); 663 664 os << "The '"; 665 S.print(os); 666 os << "' message should be sent to instances " 667 "of class '" << Class->getName() 668 << "' and not the class directly"; 669 670 auto report = llvm::make_unique<BugReport>(*BT, os.str(), N); 671 report->addRange(msg.getSourceRange()); 672 C.emitReport(std::move(report)); 673 } 674 } 675 676 //===----------------------------------------------------------------------===// 677 // Check for passing non-Objective-C types to variadic methods that expect 678 // only Objective-C types. 679 //===----------------------------------------------------------------------===// 680 681 namespace { 682 class VariadicMethodTypeChecker : public Checker<check::PreObjCMessage> { 683 mutable Selector arrayWithObjectsS; 684 mutable Selector dictionaryWithObjectsAndKeysS; 685 mutable Selector setWithObjectsS; 686 mutable Selector orderedSetWithObjectsS; 687 mutable Selector initWithObjectsS; 688 mutable Selector initWithObjectsAndKeysS; 689 mutable std::unique_ptr<BugType> BT; 690 691 bool isVariadicMessage(const ObjCMethodCall &msg) const; 692 693 public: 694 void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const; 695 }; 696 } 697 698 /// isVariadicMessage - Returns whether the given message is a variadic message, 699 /// where all arguments must be Objective-C types. 700 bool 701 VariadicMethodTypeChecker::isVariadicMessage(const ObjCMethodCall &msg) const { 702 const ObjCMethodDecl *MD = msg.getDecl(); 703 704 if (!MD || !MD->isVariadic() || isa<ObjCProtocolDecl>(MD->getDeclContext())) 705 return false; 706 707 Selector S = msg.getSelector(); 708 709 if (msg.isInstanceMessage()) { 710 // FIXME: Ideally we'd look at the receiver interface here, but that's not 711 // useful for init, because alloc returns 'id'. In theory, this could lead 712 // to false positives, for example if there existed a class that had an 713 // initWithObjects: implementation that does accept non-Objective-C pointer 714 // types, but the chance of that happening is pretty small compared to the 715 // gains that this analysis gives. 716 const ObjCInterfaceDecl *Class = MD->getClassInterface(); 717 718 switch (findKnownClass(Class)) { 719 case FC_NSArray: 720 case FC_NSOrderedSet: 721 case FC_NSSet: 722 return S == initWithObjectsS; 723 case FC_NSDictionary: 724 return S == initWithObjectsAndKeysS; 725 default: 726 return false; 727 } 728 } else { 729 const ObjCInterfaceDecl *Class = msg.getReceiverInterface(); 730 731 switch (findKnownClass(Class)) { 732 case FC_NSArray: 733 return S == arrayWithObjectsS; 734 case FC_NSOrderedSet: 735 return S == orderedSetWithObjectsS; 736 case FC_NSSet: 737 return S == setWithObjectsS; 738 case FC_NSDictionary: 739 return S == dictionaryWithObjectsAndKeysS; 740 default: 741 return false; 742 } 743 } 744 } 745 746 void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg, 747 CheckerContext &C) const { 748 if (!BT) { 749 BT.reset(new APIMisuse(this, 750 "Arguments passed to variadic method aren't all " 751 "Objective-C pointer types")); 752 753 ASTContext &Ctx = C.getASTContext(); 754 arrayWithObjectsS = GetUnarySelector("arrayWithObjects", Ctx); 755 dictionaryWithObjectsAndKeysS = 756 GetUnarySelector("dictionaryWithObjectsAndKeys", Ctx); 757 setWithObjectsS = GetUnarySelector("setWithObjects", Ctx); 758 orderedSetWithObjectsS = GetUnarySelector("orderedSetWithObjects", Ctx); 759 760 initWithObjectsS = GetUnarySelector("initWithObjects", Ctx); 761 initWithObjectsAndKeysS = GetUnarySelector("initWithObjectsAndKeys", Ctx); 762 } 763 764 if (!isVariadicMessage(msg)) 765 return; 766 767 // We are not interested in the selector arguments since they have 768 // well-defined types, so the compiler will issue a warning for them. 769 unsigned variadicArgsBegin = msg.getSelector().getNumArgs(); 770 771 // We're not interested in the last argument since it has to be nil or the 772 // compiler would have issued a warning for it elsewhere. 773 unsigned variadicArgsEnd = msg.getNumArgs() - 1; 774 775 if (variadicArgsEnd <= variadicArgsBegin) 776 return; 777 778 // Verify that all arguments have Objective-C types. 779 Optional<ExplodedNode*> errorNode; 780 781 for (unsigned I = variadicArgsBegin; I != variadicArgsEnd; ++I) { 782 QualType ArgTy = msg.getArgExpr(I)->getType(); 783 if (ArgTy->isObjCObjectPointerType()) 784 continue; 785 786 // Block pointers are treaded as Objective-C pointers. 787 if (ArgTy->isBlockPointerType()) 788 continue; 789 790 // Ignore pointer constants. 791 if (msg.getArgSVal(I).getAs<loc::ConcreteInt>()) 792 continue; 793 794 // Ignore pointer types annotated with 'NSObject' attribute. 795 if (C.getASTContext().isObjCNSObjectType(ArgTy)) 796 continue; 797 798 // Ignore CF references, which can be toll-free bridged. 799 if (coreFoundation::isCFObjectRef(ArgTy)) 800 continue; 801 802 // Generate only one error node to use for all bug reports. 803 if (!errorNode.hasValue()) 804 errorNode = C.generateNonFatalErrorNode(); 805 806 if (!errorNode.getValue()) 807 continue; 808 809 SmallString<128> sbuf; 810 llvm::raw_svector_ostream os(sbuf); 811 812 StringRef TypeName = GetReceiverInterfaceName(msg); 813 if (!TypeName.empty()) 814 os << "Argument to '" << TypeName << "' method '"; 815 else 816 os << "Argument to method '"; 817 818 msg.getSelector().print(os); 819 os << "' should be an Objective-C pointer type, not '"; 820 ArgTy.print(os, C.getLangOpts()); 821 os << "'"; 822 823 auto R = llvm::make_unique<BugReport>(*BT, os.str(), errorNode.getValue()); 824 R->addRange(msg.getArgSourceRange(I)); 825 C.emitReport(std::move(R)); 826 } 827 } 828 829 //===----------------------------------------------------------------------===// 830 // Improves the modeling of loops over Cocoa collections. 831 //===----------------------------------------------------------------------===// 832 833 // The map from container symbol to the container count symbol. 834 // We currently will remember the last countainer count symbol encountered. 835 REGISTER_MAP_WITH_PROGRAMSTATE(ContainerCountMap, SymbolRef, SymbolRef) 836 REGISTER_MAP_WITH_PROGRAMSTATE(ContainerNonEmptyMap, SymbolRef, bool) 837 838 namespace { 839 class ObjCLoopChecker 840 : public Checker<check::PostStmt<ObjCForCollectionStmt>, 841 check::PostObjCMessage, 842 check::DeadSymbols, 843 check::PointerEscape > { 844 mutable IdentifierInfo *CountSelectorII; 845 846 bool isCollectionCountMethod(const ObjCMethodCall &M, 847 CheckerContext &C) const; 848 849 public: 850 ObjCLoopChecker() : CountSelectorII(nullptr) {} 851 void checkPostStmt(const ObjCForCollectionStmt *FCS, CheckerContext &C) const; 852 void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const; 853 void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const; 854 ProgramStateRef checkPointerEscape(ProgramStateRef State, 855 const InvalidatedSymbols &Escaped, 856 const CallEvent *Call, 857 PointerEscapeKind Kind) const; 858 }; 859 } 860 861 static bool isKnownNonNilCollectionType(QualType T) { 862 const ObjCObjectPointerType *PT = T->getAs<ObjCObjectPointerType>(); 863 if (!PT) 864 return false; 865 866 const ObjCInterfaceDecl *ID = PT->getInterfaceDecl(); 867 if (!ID) 868 return false; 869 870 switch (findKnownClass(ID)) { 871 case FC_NSArray: 872 case FC_NSDictionary: 873 case FC_NSEnumerator: 874 case FC_NSOrderedSet: 875 case FC_NSSet: 876 return true; 877 default: 878 return false; 879 } 880 } 881 882 /// Assumes that the collection is non-nil. 883 /// 884 /// If the collection is known to be nil, returns NULL to indicate an infeasible 885 /// path. 886 static ProgramStateRef checkCollectionNonNil(CheckerContext &C, 887 ProgramStateRef State, 888 const ObjCForCollectionStmt *FCS) { 889 if (!State) 890 return nullptr; 891 892 SVal CollectionVal = C.getSVal(FCS->getCollection()); 893 Optional<DefinedSVal> KnownCollection = CollectionVal.getAs<DefinedSVal>(); 894 if (!KnownCollection) 895 return State; 896 897 ProgramStateRef StNonNil, StNil; 898 std::tie(StNonNil, StNil) = State->assume(*KnownCollection); 899 if (StNil && !StNonNil) { 900 // The collection is nil. This path is infeasible. 901 return nullptr; 902 } 903 904 return StNonNil; 905 } 906 907 /// Assumes that the collection elements are non-nil. 908 /// 909 /// This only applies if the collection is one of those known not to contain 910 /// nil values. 911 static ProgramStateRef checkElementNonNil(CheckerContext &C, 912 ProgramStateRef State, 913 const ObjCForCollectionStmt *FCS) { 914 if (!State) 915 return nullptr; 916 917 // See if the collection is one where we /know/ the elements are non-nil. 918 if (!isKnownNonNilCollectionType(FCS->getCollection()->getType())) 919 return State; 920 921 const LocationContext *LCtx = C.getLocationContext(); 922 const Stmt *Element = FCS->getElement(); 923 924 // FIXME: Copied from ExprEngineObjC. 925 Optional<Loc> ElementLoc; 926 if (const DeclStmt *DS = dyn_cast<DeclStmt>(Element)) { 927 const VarDecl *ElemDecl = cast<VarDecl>(DS->getSingleDecl()); 928 assert(ElemDecl->getInit() == nullptr); 929 ElementLoc = State->getLValue(ElemDecl, LCtx); 930 } else { 931 ElementLoc = State->getSVal(Element, LCtx).getAs<Loc>(); 932 } 933 934 if (!ElementLoc) 935 return State; 936 937 // Go ahead and assume the value is non-nil. 938 SVal Val = State->getSVal(*ElementLoc); 939 return State->assume(Val.castAs<DefinedOrUnknownSVal>(), true); 940 } 941 942 /// Returns NULL state if the collection is known to contain elements 943 /// (or is known not to contain elements if the Assumption parameter is false.) 944 static ProgramStateRef 945 assumeCollectionNonEmpty(CheckerContext &C, ProgramStateRef State, 946 SymbolRef CollectionS, bool Assumption) { 947 if (!State || !CollectionS) 948 return State; 949 950 const SymbolRef *CountS = State->get<ContainerCountMap>(CollectionS); 951 if (!CountS) { 952 const bool *KnownNonEmpty = State->get<ContainerNonEmptyMap>(CollectionS); 953 if (!KnownNonEmpty) 954 return State->set<ContainerNonEmptyMap>(CollectionS, Assumption); 955 return (Assumption == *KnownNonEmpty) ? State : nullptr; 956 } 957 958 SValBuilder &SvalBuilder = C.getSValBuilder(); 959 SVal CountGreaterThanZeroVal = 960 SvalBuilder.evalBinOp(State, BO_GT, 961 nonloc::SymbolVal(*CountS), 962 SvalBuilder.makeIntVal(0, (*CountS)->getType()), 963 SvalBuilder.getConditionType()); 964 Optional<DefinedSVal> CountGreaterThanZero = 965 CountGreaterThanZeroVal.getAs<DefinedSVal>(); 966 if (!CountGreaterThanZero) { 967 // The SValBuilder cannot construct a valid SVal for this condition. 968 // This means we cannot properly reason about it. 969 return State; 970 } 971 972 return State->assume(*CountGreaterThanZero, Assumption); 973 } 974 975 static ProgramStateRef 976 assumeCollectionNonEmpty(CheckerContext &C, ProgramStateRef State, 977 const ObjCForCollectionStmt *FCS, 978 bool Assumption) { 979 if (!State) 980 return nullptr; 981 982 SymbolRef CollectionS = 983 State->getSVal(FCS->getCollection(), C.getLocationContext()).getAsSymbol(); 984 return assumeCollectionNonEmpty(C, State, CollectionS, Assumption); 985 } 986 987 988 /// If the fist block edge is a back edge, we are reentering the loop. 989 static bool alreadyExecutedAtLeastOneLoopIteration(const ExplodedNode *N, 990 const ObjCForCollectionStmt *FCS) { 991 if (!N) 992 return false; 993 994 ProgramPoint P = N->getLocation(); 995 if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) { 996 if (BE->getSrc()->getLoopTarget() == FCS) 997 return true; 998 return false; 999 } 1000 1001 // Keep looking for a block edge. 1002 for (ExplodedNode::const_pred_iterator I = N->pred_begin(), 1003 E = N->pred_end(); I != E; ++I) { 1004 if (alreadyExecutedAtLeastOneLoopIteration(*I, FCS)) 1005 return true; 1006 } 1007 1008 return false; 1009 } 1010 1011 void ObjCLoopChecker::checkPostStmt(const ObjCForCollectionStmt *FCS, 1012 CheckerContext &C) const { 1013 ProgramStateRef State = C.getState(); 1014 1015 // Check if this is the branch for the end of the loop. 1016 SVal CollectionSentinel = C.getSVal(FCS); 1017 if (CollectionSentinel.isZeroConstant()) { 1018 if (!alreadyExecutedAtLeastOneLoopIteration(C.getPredecessor(), FCS)) 1019 State = assumeCollectionNonEmpty(C, State, FCS, /*Assumption*/false); 1020 1021 // Otherwise, this is a branch that goes through the loop body. 1022 } else { 1023 State = checkCollectionNonNil(C, State, FCS); 1024 State = checkElementNonNil(C, State, FCS); 1025 State = assumeCollectionNonEmpty(C, State, FCS, /*Assumption*/true); 1026 } 1027 1028 if (!State) 1029 C.generateSink(C.getState(), C.getPredecessor()); 1030 else if (State != C.getState()) 1031 C.addTransition(State); 1032 } 1033 1034 bool ObjCLoopChecker::isCollectionCountMethod(const ObjCMethodCall &M, 1035 CheckerContext &C) const { 1036 Selector S = M.getSelector(); 1037 // Initialize the identifiers on first use. 1038 if (!CountSelectorII) 1039 CountSelectorII = &C.getASTContext().Idents.get("count"); 1040 1041 // If the method returns collection count, record the value. 1042 if (S.isUnarySelector() && 1043 (S.getIdentifierInfoForSlot(0) == CountSelectorII)) 1044 return true; 1045 1046 return false; 1047 } 1048 1049 void ObjCLoopChecker::checkPostObjCMessage(const ObjCMethodCall &M, 1050 CheckerContext &C) const { 1051 if (!M.isInstanceMessage()) 1052 return; 1053 1054 const ObjCInterfaceDecl *ClassID = M.getReceiverInterface(); 1055 if (!ClassID) 1056 return; 1057 1058 FoundationClass Class = findKnownClass(ClassID); 1059 if (Class != FC_NSDictionary && 1060 Class != FC_NSArray && 1061 Class != FC_NSSet && 1062 Class != FC_NSOrderedSet) 1063 return; 1064 1065 SymbolRef ContainerS = M.getReceiverSVal().getAsSymbol(); 1066 if (!ContainerS) 1067 return; 1068 1069 // If we are processing a call to "count", get the symbolic value returned by 1070 // a call to "count" and add it to the map. 1071 if (!isCollectionCountMethod(M, C)) 1072 return; 1073 1074 const Expr *MsgExpr = M.getOriginExpr(); 1075 SymbolRef CountS = C.getSVal(MsgExpr).getAsSymbol(); 1076 if (CountS) { 1077 ProgramStateRef State = C.getState(); 1078 1079 C.getSymbolManager().addSymbolDependency(ContainerS, CountS); 1080 State = State->set<ContainerCountMap>(ContainerS, CountS); 1081 1082 if (const bool *NonEmpty = State->get<ContainerNonEmptyMap>(ContainerS)) { 1083 State = State->remove<ContainerNonEmptyMap>(ContainerS); 1084 State = assumeCollectionNonEmpty(C, State, ContainerS, *NonEmpty); 1085 } 1086 1087 C.addTransition(State); 1088 } 1089 return; 1090 } 1091 1092 static SymbolRef getMethodReceiverIfKnownImmutable(const CallEvent *Call) { 1093 const ObjCMethodCall *Message = dyn_cast_or_null<ObjCMethodCall>(Call); 1094 if (!Message) 1095 return nullptr; 1096 1097 const ObjCMethodDecl *MD = Message->getDecl(); 1098 if (!MD) 1099 return nullptr; 1100 1101 const ObjCInterfaceDecl *StaticClass; 1102 if (isa<ObjCProtocolDecl>(MD->getDeclContext())) { 1103 // We can't find out where the method was declared without doing more work. 1104 // Instead, see if the receiver is statically typed as a known immutable 1105 // collection. 1106 StaticClass = Message->getOriginExpr()->getReceiverInterface(); 1107 } else { 1108 StaticClass = MD->getClassInterface(); 1109 } 1110 1111 if (!StaticClass) 1112 return nullptr; 1113 1114 switch (findKnownClass(StaticClass, /*IncludeSuper=*/false)) { 1115 case FC_None: 1116 return nullptr; 1117 case FC_NSArray: 1118 case FC_NSDictionary: 1119 case FC_NSEnumerator: 1120 case FC_NSNull: 1121 case FC_NSOrderedSet: 1122 case FC_NSSet: 1123 case FC_NSString: 1124 break; 1125 } 1126 1127 return Message->getReceiverSVal().getAsSymbol(); 1128 } 1129 1130 ProgramStateRef 1131 ObjCLoopChecker::checkPointerEscape(ProgramStateRef State, 1132 const InvalidatedSymbols &Escaped, 1133 const CallEvent *Call, 1134 PointerEscapeKind Kind) const { 1135 SymbolRef ImmutableReceiver = getMethodReceiverIfKnownImmutable(Call); 1136 1137 // Remove the invalidated symbols form the collection count map. 1138 for (InvalidatedSymbols::const_iterator I = Escaped.begin(), 1139 E = Escaped.end(); 1140 I != E; ++I) { 1141 SymbolRef Sym = *I; 1142 1143 // Don't invalidate this symbol's count if we know the method being called 1144 // is declared on an immutable class. This isn't completely correct if the 1145 // receiver is also passed as an argument, but in most uses of NSArray, 1146 // NSDictionary, etc. this isn't likely to happen in a dangerous way. 1147 if (Sym == ImmutableReceiver) 1148 continue; 1149 1150 // The symbol escaped. Pessimistically, assume that the count could have 1151 // changed. 1152 State = State->remove<ContainerCountMap>(Sym); 1153 State = State->remove<ContainerNonEmptyMap>(Sym); 1154 } 1155 return State; 1156 } 1157 1158 void ObjCLoopChecker::checkDeadSymbols(SymbolReaper &SymReaper, 1159 CheckerContext &C) const { 1160 ProgramStateRef State = C.getState(); 1161 1162 // Remove the dead symbols from the collection count map. 1163 ContainerCountMapTy Tracked = State->get<ContainerCountMap>(); 1164 for (ContainerCountMapTy::iterator I = Tracked.begin(), 1165 E = Tracked.end(); I != E; ++I) { 1166 SymbolRef Sym = I->first; 1167 if (SymReaper.isDead(Sym)) { 1168 State = State->remove<ContainerCountMap>(Sym); 1169 State = State->remove<ContainerNonEmptyMap>(Sym); 1170 } 1171 } 1172 1173 C.addTransition(State); 1174 } 1175 1176 namespace { 1177 /// \class ObjCNonNilReturnValueChecker 1178 /// \brief The checker restricts the return values of APIs known to 1179 /// never (or almost never) return 'nil'. 1180 class ObjCNonNilReturnValueChecker 1181 : public Checker<check::PostObjCMessage, 1182 check::PostStmt<ObjCArrayLiteral>, 1183 check::PostStmt<ObjCDictionaryLiteral>, 1184 check::PostStmt<ObjCBoxedExpr> > { 1185 mutable bool Initialized; 1186 mutable Selector ObjectAtIndex; 1187 mutable Selector ObjectAtIndexedSubscript; 1188 mutable Selector NullSelector; 1189 1190 public: 1191 ObjCNonNilReturnValueChecker() : Initialized(false) {} 1192 1193 ProgramStateRef assumeExprIsNonNull(const Expr *NonNullExpr, 1194 ProgramStateRef State, 1195 CheckerContext &C) const; 1196 void assumeExprIsNonNull(const Expr *E, CheckerContext &C) const { 1197 C.addTransition(assumeExprIsNonNull(E, C.getState(), C)); 1198 } 1199 1200 void checkPostStmt(const ObjCArrayLiteral *E, CheckerContext &C) const { 1201 assumeExprIsNonNull(E, C); 1202 } 1203 void checkPostStmt(const ObjCDictionaryLiteral *E, CheckerContext &C) const { 1204 assumeExprIsNonNull(E, C); 1205 } 1206 void checkPostStmt(const ObjCBoxedExpr *E, CheckerContext &C) const { 1207 assumeExprIsNonNull(E, C); 1208 } 1209 1210 void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const; 1211 }; 1212 } 1213 1214 ProgramStateRef 1215 ObjCNonNilReturnValueChecker::assumeExprIsNonNull(const Expr *NonNullExpr, 1216 ProgramStateRef State, 1217 CheckerContext &C) const { 1218 SVal Val = State->getSVal(NonNullExpr, C.getLocationContext()); 1219 if (Optional<DefinedOrUnknownSVal> DV = Val.getAs<DefinedOrUnknownSVal>()) 1220 return State->assume(*DV, true); 1221 return State; 1222 } 1223 1224 void ObjCNonNilReturnValueChecker::checkPostObjCMessage(const ObjCMethodCall &M, 1225 CheckerContext &C) 1226 const { 1227 ProgramStateRef State = C.getState(); 1228 1229 if (!Initialized) { 1230 ASTContext &Ctx = C.getASTContext(); 1231 ObjectAtIndex = GetUnarySelector("objectAtIndex", Ctx); 1232 ObjectAtIndexedSubscript = GetUnarySelector("objectAtIndexedSubscript", Ctx); 1233 NullSelector = GetNullarySelector("null", Ctx); 1234 } 1235 1236 // Check the receiver type. 1237 if (const ObjCInterfaceDecl *Interface = M.getReceiverInterface()) { 1238 1239 // Assume that object returned from '[self init]' or '[super init]' is not 1240 // 'nil' if we are processing an inlined function/method. 1241 // 1242 // A defensive callee will (and should) check if the object returned by 1243 // '[super init]' is 'nil' before doing it's own initialization. However, 1244 // since 'nil' is rarely returned in practice, we should not warn when the 1245 // caller to the defensive constructor uses the object in contexts where 1246 // 'nil' is not accepted. 1247 if (!C.inTopFrame() && M.getDecl() && 1248 M.getDecl()->getMethodFamily() == OMF_init && 1249 M.isReceiverSelfOrSuper()) { 1250 State = assumeExprIsNonNull(M.getOriginExpr(), State, C); 1251 } 1252 1253 FoundationClass Cl = findKnownClass(Interface); 1254 1255 // Objects returned from 1256 // [NSArray|NSOrderedSet]::[ObjectAtIndex|ObjectAtIndexedSubscript] 1257 // are never 'nil'. 1258 if (Cl == FC_NSArray || Cl == FC_NSOrderedSet) { 1259 Selector Sel = M.getSelector(); 1260 if (Sel == ObjectAtIndex || Sel == ObjectAtIndexedSubscript) { 1261 // Go ahead and assume the value is non-nil. 1262 State = assumeExprIsNonNull(M.getOriginExpr(), State, C); 1263 } 1264 } 1265 1266 // Objects returned from [NSNull null] are not nil. 1267 if (Cl == FC_NSNull) { 1268 if (M.getSelector() == NullSelector) { 1269 // Go ahead and assume the value is non-nil. 1270 State = assumeExprIsNonNull(M.getOriginExpr(), State, C); 1271 } 1272 } 1273 } 1274 C.addTransition(State); 1275 } 1276 1277 //===----------------------------------------------------------------------===// 1278 // Check registration. 1279 //===----------------------------------------------------------------------===// 1280 1281 void ento::registerNilArgChecker(CheckerManager &mgr) { 1282 mgr.registerChecker<NilArgChecker>(); 1283 } 1284 1285 void ento::registerCFNumberCreateChecker(CheckerManager &mgr) { 1286 mgr.registerChecker<CFNumberCreateChecker>(); 1287 } 1288 1289 void ento::registerCFRetainReleaseChecker(CheckerManager &mgr) { 1290 mgr.registerChecker<CFRetainReleaseChecker>(); 1291 } 1292 1293 void ento::registerClassReleaseChecker(CheckerManager &mgr) { 1294 mgr.registerChecker<ClassReleaseChecker>(); 1295 } 1296 1297 void ento::registerVariadicMethodTypeChecker(CheckerManager &mgr) { 1298 mgr.registerChecker<VariadicMethodTypeChecker>(); 1299 } 1300 1301 void ento::registerObjCLoopChecker(CheckerManager &mgr) { 1302 mgr.registerChecker<ObjCLoopChecker>(); 1303 } 1304 1305 void 1306 ento::registerObjCNonNilReturnValueChecker(CheckerManager &mgr) { 1307 mgr.registerChecker<ObjCNonNilReturnValueChecker>(); 1308 } 1309