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