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