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