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