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