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