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