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