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