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