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 "clang/AST/ASTContext.h" 18 #include "clang/AST/DeclObjC.h" 19 #include "clang/AST/Expr.h" 20 #include "clang/AST/ExprObjC.h" 21 #include "clang/AST/StmtObjC.h" 22 #include "clang/Analysis/DomainSpecific/CocoaConventions.h" 23 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 24 #include "clang/StaticAnalyzer/Core/Checker.h" 25 #include "clang/StaticAnalyzer/Core/CheckerManager.h" 26 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" 27 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 28 #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" 29 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" 30 #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h" 31 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" 32 #include "llvm/ADT/SmallString.h" 33 #include "llvm/ADT/StringMap.h" 34 #include "llvm/Support/raw_ostream.h" 35 36 using namespace clang; 37 using namespace ento; 38 39 namespace { 40 class APIMisuse : public BugType { 41 public: 42 APIMisuse(const char* name) : BugType(name, "API Misuse (Apple)") {} 43 }; 44 } // end anonymous namespace 45 46 //===----------------------------------------------------------------------===// 47 // Utility functions. 48 //===----------------------------------------------------------------------===// 49 50 static StringRef GetReceiverInterfaceName(const ObjCMethodCall &msg) { 51 if (const ObjCInterfaceDecl *ID = msg.getReceiverInterface()) 52 return ID->getIdentifier()->getName(); 53 return StringRef(); 54 } 55 56 enum FoundationClass { 57 FC_None, 58 FC_NSArray, 59 FC_NSDictionary, 60 FC_NSEnumerator, 61 FC_NSNull, 62 FC_NSOrderedSet, 63 FC_NSSet, 64 FC_NSString 65 }; 66 67 static FoundationClass findKnownClass(const ObjCInterfaceDecl *ID) { 68 static llvm::StringMap<FoundationClass> Classes; 69 if (Classes.empty()) { 70 Classes["NSArray"] = FC_NSArray; 71 Classes["NSDictionary"] = FC_NSDictionary; 72 Classes["NSEnumerator"] = FC_NSEnumerator; 73 Classes["NSNull"] = FC_NSNull; 74 Classes["NSOrderedSet"] = FC_NSOrderedSet; 75 Classes["NSSet"] = FC_NSSet; 76 Classes["NSString"] = FC_NSString; 77 } 78 79 // FIXME: Should we cache this at all? 80 FoundationClass result = Classes.lookup(ID->getIdentifier()->getName()); 81 if (result == FC_None) 82 if (const ObjCInterfaceDecl *Super = ID->getSuperClass()) 83 return findKnownClass(Super); 84 85 return result; 86 } 87 88 //===----------------------------------------------------------------------===// 89 // NilArgChecker - Check for prohibited nil arguments to ObjC method calls. 90 //===----------------------------------------------------------------------===// 91 92 namespace { 93 class NilArgChecker : public Checker<check::PreObjCMessage> { 94 mutable OwningPtr<APIMisuse> BT; 95 96 void WarnIfNilArg(CheckerContext &C, 97 const ObjCMethodCall &msg, unsigned Arg, 98 FoundationClass Class, 99 bool CanBeSubscript = false) const; 100 101 public: 102 void checkPreObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const; 103 }; 104 } 105 106 void NilArgChecker::WarnIfNilArg(CheckerContext &C, 107 const ObjCMethodCall &msg, 108 unsigned int Arg, 109 FoundationClass Class, 110 bool CanBeSubscript) const { 111 // Check if the argument is nil. 112 ProgramStateRef State = C.getState(); 113 if (!State->isNull(msg.getArgSVal(Arg)).isConstrainedTrue()) 114 return; 115 116 if (!BT) 117 BT.reset(new APIMisuse("nil argument")); 118 119 if (ExplodedNode *N = C.generateSink()) { 120 SmallString<128> sbuf; 121 llvm::raw_svector_ostream os(sbuf); 122 123 if (CanBeSubscript && msg.getMessageKind() == OCM_Subscript) { 124 125 if (Class == FC_NSArray) { 126 os << "Array element cannot be nil"; 127 } else if (Class == FC_NSDictionary) { 128 if (Arg == 0) { 129 os << "Value stored into '"; 130 os << GetReceiverInterfaceName(msg) << "' cannot be nil"; 131 } else { 132 assert(Arg == 1); 133 os << "'"<< GetReceiverInterfaceName(msg) << "' key cannot be nil"; 134 } 135 } else 136 llvm_unreachable("Missing foundation class for the subscript expr"); 137 138 } else { 139 if (Class == FC_NSDictionary) { 140 if (Arg == 0) 141 os << "Value argument "; 142 else { 143 assert(Arg == 1); 144 os << "Key argument "; 145 } 146 os << "to '" << msg.getSelector().getAsString() << "' cannot be nil"; 147 } else { 148 os << "Argument to '" << GetReceiverInterfaceName(msg) << "' method '" 149 << msg.getSelector().getAsString() << "' cannot be nil"; 150 } 151 } 152 153 BugReport *R = new BugReport(*BT, os.str(), N); 154 R->addRange(msg.getArgSourceRange(Arg)); 155 bugreporter::trackNullOrUndefValue(N, msg.getArgExpr(Arg), *R); 156 C.emitReport(R); 157 } 158 } 159 160 void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg, 161 CheckerContext &C) const { 162 const ObjCInterfaceDecl *ID = msg.getReceiverInterface(); 163 if (!ID) 164 return; 165 166 FoundationClass Class = findKnownClass(ID); 167 168 static const unsigned InvalidArgIndex = UINT_MAX; 169 unsigned Arg = InvalidArgIndex; 170 bool CanBeSubscript = false; 171 172 if (Class == FC_NSString) { 173 Selector S = msg.getSelector(); 174 175 if (S.isUnarySelector()) 176 return; 177 178 // FIXME: This is going to be really slow doing these checks with 179 // lexical comparisons. 180 181 std::string NameStr = S.getAsString(); 182 StringRef Name(NameStr); 183 assert(!Name.empty()); 184 185 // FIXME: Checking for initWithFormat: will not work in most cases 186 // yet because [NSString alloc] returns id, not NSString*. We will 187 // need support for tracking expected-type information in the analyzer 188 // to find these errors. 189 if (Name == "caseInsensitiveCompare:" || 190 Name == "compare:" || 191 Name == "compare:options:" || 192 Name == "compare:options:range:" || 193 Name == "compare:options:range:locale:" || 194 Name == "componentsSeparatedByCharactersInSet:" || 195 Name == "initWithFormat:") { 196 Arg = 0; 197 } 198 } else if (Class == FC_NSArray) { 199 Selector S = msg.getSelector(); 200 201 if (S.isUnarySelector()) 202 return; 203 204 if (S.getNameForSlot(0).equals("addObject")) { 205 Arg = 0; 206 } else if (S.getNameForSlot(0).equals("insertObject") && 207 S.getNameForSlot(1).equals("atIndex")) { 208 Arg = 0; 209 } else if (S.getNameForSlot(0).equals("replaceObjectAtIndex") && 210 S.getNameForSlot(1).equals("withObject")) { 211 Arg = 1; 212 } else if (S.getNameForSlot(0).equals("setObject") && 213 S.getNameForSlot(1).equals("atIndexedSubscript")) { 214 Arg = 0; 215 CanBeSubscript = true; 216 } else if (S.getNameForSlot(0).equals("arrayByAddingObject")) { 217 Arg = 0; 218 } 219 } else if (Class == FC_NSDictionary) { 220 Selector S = msg.getSelector(); 221 222 if (S.isUnarySelector()) 223 return; 224 225 if (S.getNameForSlot(0).equals("dictionaryWithObject") && 226 S.getNameForSlot(1).equals("forKey")) { 227 Arg = 0; 228 WarnIfNilArg(C, msg, /* Arg */1, Class); 229 } else if (S.getNameForSlot(0).equals("setObject") && 230 S.getNameForSlot(1).equals("forKey")) { 231 Arg = 0; 232 WarnIfNilArg(C, msg, /* Arg */1, Class); 233 } else if (S.getNameForSlot(0).equals("setObject") && 234 S.getNameForSlot(1).equals("forKeyedSubscript")) { 235 CanBeSubscript = true; 236 Arg = 0; 237 WarnIfNilArg(C, msg, /* Arg */1, Class, CanBeSubscript); 238 } else if (S.getNameForSlot(0).equals("removeObjectForKey")) { 239 Arg = 0; 240 } 241 } 242 243 244 // If argument is '0', report a warning. 245 if ((Arg != InvalidArgIndex)) 246 WarnIfNilArg(C, msg, Arg, Class, CanBeSubscript); 247 248 } 249 250 //===----------------------------------------------------------------------===// 251 // Error reporting. 252 //===----------------------------------------------------------------------===// 253 254 namespace { 255 class CFNumberCreateChecker : public Checker< check::PreStmt<CallExpr> > { 256 mutable OwningPtr<APIMisuse> BT; 257 mutable IdentifierInfo* II; 258 public: 259 CFNumberCreateChecker() : II(0) {} 260 261 void checkPreStmt(const CallExpr *CE, CheckerContext &C) const; 262 263 private: 264 void EmitError(const TypedRegion* R, const Expr *Ex, 265 uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind); 266 }; 267 } // end anonymous namespace 268 269 enum CFNumberType { 270 kCFNumberSInt8Type = 1, 271 kCFNumberSInt16Type = 2, 272 kCFNumberSInt32Type = 3, 273 kCFNumberSInt64Type = 4, 274 kCFNumberFloat32Type = 5, 275 kCFNumberFloat64Type = 6, 276 kCFNumberCharType = 7, 277 kCFNumberShortType = 8, 278 kCFNumberIntType = 9, 279 kCFNumberLongType = 10, 280 kCFNumberLongLongType = 11, 281 kCFNumberFloatType = 12, 282 kCFNumberDoubleType = 13, 283 kCFNumberCFIndexType = 14, 284 kCFNumberNSIntegerType = 15, 285 kCFNumberCGFloatType = 16 286 }; 287 288 static Optional<uint64_t> GetCFNumberSize(ASTContext &Ctx, uint64_t i) { 289 static const unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 }; 290 291 if (i < kCFNumberCharType) 292 return FixedSize[i-1]; 293 294 QualType T; 295 296 switch (i) { 297 case kCFNumberCharType: T = Ctx.CharTy; break; 298 case kCFNumberShortType: T = Ctx.ShortTy; break; 299 case kCFNumberIntType: T = Ctx.IntTy; break; 300 case kCFNumberLongType: T = Ctx.LongTy; break; 301 case kCFNumberLongLongType: T = Ctx.LongLongTy; break; 302 case kCFNumberFloatType: T = Ctx.FloatTy; break; 303 case kCFNumberDoubleType: T = Ctx.DoubleTy; break; 304 case kCFNumberCFIndexType: 305 case kCFNumberNSIntegerType: 306 case kCFNumberCGFloatType: 307 // FIXME: We need a way to map from names to Type*. 308 default: 309 return None; 310 } 311 312 return Ctx.getTypeSize(T); 313 } 314 315 #if 0 316 static const char* GetCFNumberTypeStr(uint64_t i) { 317 static const char* Names[] = { 318 "kCFNumberSInt8Type", 319 "kCFNumberSInt16Type", 320 "kCFNumberSInt32Type", 321 "kCFNumberSInt64Type", 322 "kCFNumberFloat32Type", 323 "kCFNumberFloat64Type", 324 "kCFNumberCharType", 325 "kCFNumberShortType", 326 "kCFNumberIntType", 327 "kCFNumberLongType", 328 "kCFNumberLongLongType", 329 "kCFNumberFloatType", 330 "kCFNumberDoubleType", 331 "kCFNumberCFIndexType", 332 "kCFNumberNSIntegerType", 333 "kCFNumberCGFloatType" 334 }; 335 336 return i <= kCFNumberCGFloatType ? Names[i-1] : "Invalid CFNumberType"; 337 } 338 #endif 339 340 void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE, 341 CheckerContext &C) const { 342 ProgramStateRef state = C.getState(); 343 const FunctionDecl *FD = C.getCalleeDecl(CE); 344 if (!FD) 345 return; 346 347 ASTContext &Ctx = C.getASTContext(); 348 if (!II) 349 II = &Ctx.Idents.get("CFNumberCreate"); 350 351 if (FD->getIdentifier() != II || CE->getNumArgs() != 3) 352 return; 353 354 // Get the value of the "theType" argument. 355 const LocationContext *LCtx = C.getLocationContext(); 356 SVal TheTypeVal = state->getSVal(CE->getArg(1), LCtx); 357 358 // FIXME: We really should allow ranges of valid theType values, and 359 // bifurcate the state appropriately. 360 Optional<nonloc::ConcreteInt> V = TheTypeVal.getAs<nonloc::ConcreteInt>(); 361 if (!V) 362 return; 363 364 uint64_t NumberKind = V->getValue().getLimitedValue(); 365 Optional<uint64_t> OptTargetSize = GetCFNumberSize(Ctx, NumberKind); 366 367 // FIXME: In some cases we can emit an error. 368 if (!OptTargetSize) 369 return; 370 371 uint64_t TargetSize = *OptTargetSize; 372 373 // Look at the value of the integer being passed by reference. Essentially 374 // we want to catch cases where the value passed in is not equal to the 375 // size of the type being created. 376 SVal TheValueExpr = state->getSVal(CE->getArg(2), LCtx); 377 378 // FIXME: Eventually we should handle arbitrary locations. We can do this 379 // by having an enhanced memory model that does low-level typing. 380 Optional<loc::MemRegionVal> LV = TheValueExpr.getAs<loc::MemRegionVal>(); 381 if (!LV) 382 return; 383 384 const TypedValueRegion* R = dyn_cast<TypedValueRegion>(LV->stripCasts()); 385 if (!R) 386 return; 387 388 QualType T = Ctx.getCanonicalType(R->getValueType()); 389 390 // FIXME: If the pointee isn't an integer type, should we flag a warning? 391 // People can do weird stuff with pointers. 392 393 if (!T->isIntegralOrEnumerationType()) 394 return; 395 396 uint64_t SourceSize = Ctx.getTypeSize(T); 397 398 // CHECK: is SourceSize == TargetSize 399 if (SourceSize == TargetSize) 400 return; 401 402 // Generate an error. Only generate a sink if 'SourceSize < TargetSize'; 403 // otherwise generate a regular node. 404 // 405 // FIXME: We can actually create an abstract "CFNumber" object that has 406 // the bits initialized to the provided values. 407 // 408 if (ExplodedNode *N = SourceSize < TargetSize ? C.generateSink() 409 : C.addTransition()) { 410 SmallString<128> sbuf; 411 llvm::raw_svector_ostream os(sbuf); 412 413 os << (SourceSize == 8 ? "An " : "A ") 414 << SourceSize << " bit integer is used to initialize a CFNumber " 415 "object that represents " 416 << (TargetSize == 8 ? "an " : "a ") 417 << TargetSize << " bit integer. "; 418 419 if (SourceSize < TargetSize) 420 os << (TargetSize - SourceSize) 421 << " bits of the CFNumber value will be garbage." ; 422 else 423 os << (SourceSize - TargetSize) 424 << " bits of the input integer will be lost."; 425 426 if (!BT) 427 BT.reset(new APIMisuse("Bad use of CFNumberCreate")); 428 429 BugReport *report = new BugReport(*BT, os.str(), N); 430 report->addRange(CE->getArg(2)->getSourceRange()); 431 C.emitReport(report); 432 } 433 } 434 435 //===----------------------------------------------------------------------===// 436 // CFRetain/CFRelease/CFMakeCollectable checking for null arguments. 437 //===----------------------------------------------------------------------===// 438 439 namespace { 440 class CFRetainReleaseChecker : public Checker< check::PreStmt<CallExpr> > { 441 mutable OwningPtr<APIMisuse> BT; 442 mutable IdentifierInfo *Retain, *Release, *MakeCollectable; 443 public: 444 CFRetainReleaseChecker(): Retain(0), Release(0), MakeCollectable(0) {} 445 void checkPreStmt(const CallExpr *CE, CheckerContext &C) const; 446 }; 447 } // end anonymous namespace 448 449 450 void CFRetainReleaseChecker::checkPreStmt(const CallExpr *CE, 451 CheckerContext &C) const { 452 // If the CallExpr doesn't have exactly 1 argument just give up checking. 453 if (CE->getNumArgs() != 1) 454 return; 455 456 ProgramStateRef state = C.getState(); 457 const FunctionDecl *FD = C.getCalleeDecl(CE); 458 if (!FD) 459 return; 460 461 if (!BT) { 462 ASTContext &Ctx = C.getASTContext(); 463 Retain = &Ctx.Idents.get("CFRetain"); 464 Release = &Ctx.Idents.get("CFRelease"); 465 MakeCollectable = &Ctx.Idents.get("CFMakeCollectable"); 466 BT.reset( 467 new APIMisuse("null passed to CFRetain/CFRelease/CFMakeCollectable")); 468 } 469 470 // Check if we called CFRetain/CFRelease/CFMakeCollectable. 471 const IdentifierInfo *FuncII = FD->getIdentifier(); 472 if (!(FuncII == Retain || FuncII == Release || FuncII == MakeCollectable)) 473 return; 474 475 // FIXME: The rest of this just checks that the argument is non-null. 476 // It should probably be refactored and combined with NonNullParamChecker. 477 478 // Get the argument's value. 479 const Expr *Arg = CE->getArg(0); 480 SVal ArgVal = state->getSVal(Arg, C.getLocationContext()); 481 Optional<DefinedSVal> DefArgVal = ArgVal.getAs<DefinedSVal>(); 482 if (!DefArgVal) 483 return; 484 485 // Get a NULL value. 486 SValBuilder &svalBuilder = C.getSValBuilder(); 487 DefinedSVal zero = 488 svalBuilder.makeZeroVal(Arg->getType()).castAs<DefinedSVal>(); 489 490 // Make an expression asserting that they're equal. 491 DefinedOrUnknownSVal ArgIsNull = svalBuilder.evalEQ(state, zero, *DefArgVal); 492 493 // Are they equal? 494 ProgramStateRef stateTrue, stateFalse; 495 llvm::tie(stateTrue, stateFalse) = state->assume(ArgIsNull); 496 497 if (stateTrue && !stateFalse) { 498 ExplodedNode *N = C.generateSink(stateTrue); 499 if (!N) 500 return; 501 502 const char *description; 503 if (FuncII == Retain) 504 description = "Null pointer argument in call to CFRetain"; 505 else if (FuncII == Release) 506 description = "Null pointer argument in call to CFRelease"; 507 else if (FuncII == MakeCollectable) 508 description = "Null pointer argument in call to CFMakeCollectable"; 509 else 510 llvm_unreachable("impossible case"); 511 512 BugReport *report = new BugReport(*BT, description, N); 513 report->addRange(Arg->getSourceRange()); 514 bugreporter::trackNullOrUndefValue(N, Arg, *report); 515 C.emitReport(report); 516 return; 517 } 518 519 // From here on, we know the argument is non-null. 520 C.addTransition(stateFalse); 521 } 522 523 //===----------------------------------------------------------------------===// 524 // Check for sending 'retain', 'release', or 'autorelease' directly to a Class. 525 //===----------------------------------------------------------------------===// 526 527 namespace { 528 class ClassReleaseChecker : public Checker<check::PreObjCMessage> { 529 mutable Selector releaseS; 530 mutable Selector retainS; 531 mutable Selector autoreleaseS; 532 mutable Selector drainS; 533 mutable OwningPtr<BugType> BT; 534 535 public: 536 void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const; 537 }; 538 } 539 540 void ClassReleaseChecker::checkPreObjCMessage(const ObjCMethodCall &msg, 541 CheckerContext &C) const { 542 543 if (!BT) { 544 BT.reset(new APIMisuse("message incorrectly sent to class instead of class " 545 "instance")); 546 547 ASTContext &Ctx = C.getASTContext(); 548 releaseS = GetNullarySelector("release", Ctx); 549 retainS = GetNullarySelector("retain", Ctx); 550 autoreleaseS = GetNullarySelector("autorelease", Ctx); 551 drainS = GetNullarySelector("drain", Ctx); 552 } 553 554 if (msg.isInstanceMessage()) 555 return; 556 const ObjCInterfaceDecl *Class = msg.getReceiverInterface(); 557 assert(Class); 558 559 Selector S = msg.getSelector(); 560 if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS)) 561 return; 562 563 if (ExplodedNode *N = C.addTransition()) { 564 SmallString<200> buf; 565 llvm::raw_svector_ostream os(buf); 566 567 os << "The '" << S.getAsString() << "' message should be sent to instances " 568 "of class '" << Class->getName() 569 << "' and not the class directly"; 570 571 BugReport *report = new BugReport(*BT, os.str(), N); 572 report->addRange(msg.getSourceRange()); 573 C.emitReport(report); 574 } 575 } 576 577 //===----------------------------------------------------------------------===// 578 // Check for passing non-Objective-C types to variadic methods that expect 579 // only Objective-C types. 580 //===----------------------------------------------------------------------===// 581 582 namespace { 583 class VariadicMethodTypeChecker : public Checker<check::PreObjCMessage> { 584 mutable Selector arrayWithObjectsS; 585 mutable Selector dictionaryWithObjectsAndKeysS; 586 mutable Selector setWithObjectsS; 587 mutable Selector orderedSetWithObjectsS; 588 mutable Selector initWithObjectsS; 589 mutable Selector initWithObjectsAndKeysS; 590 mutable OwningPtr<BugType> BT; 591 592 bool isVariadicMessage(const ObjCMethodCall &msg) const; 593 594 public: 595 void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const; 596 }; 597 } 598 599 /// isVariadicMessage - Returns whether the given message is a variadic message, 600 /// where all arguments must be Objective-C types. 601 bool 602 VariadicMethodTypeChecker::isVariadicMessage(const ObjCMethodCall &msg) const { 603 const ObjCMethodDecl *MD = msg.getDecl(); 604 605 if (!MD || !MD->isVariadic() || isa<ObjCProtocolDecl>(MD->getDeclContext())) 606 return false; 607 608 Selector S = msg.getSelector(); 609 610 if (msg.isInstanceMessage()) { 611 // FIXME: Ideally we'd look at the receiver interface here, but that's not 612 // useful for init, because alloc returns 'id'. In theory, this could lead 613 // to false positives, for example if there existed a class that had an 614 // initWithObjects: implementation that does accept non-Objective-C pointer 615 // types, but the chance of that happening is pretty small compared to the 616 // gains that this analysis gives. 617 const ObjCInterfaceDecl *Class = MD->getClassInterface(); 618 619 switch (findKnownClass(Class)) { 620 case FC_NSArray: 621 case FC_NSOrderedSet: 622 case FC_NSSet: 623 return S == initWithObjectsS; 624 case FC_NSDictionary: 625 return S == initWithObjectsAndKeysS; 626 default: 627 return false; 628 } 629 } else { 630 const ObjCInterfaceDecl *Class = msg.getReceiverInterface(); 631 632 switch (findKnownClass(Class)) { 633 case FC_NSArray: 634 return S == arrayWithObjectsS; 635 case FC_NSOrderedSet: 636 return S == orderedSetWithObjectsS; 637 case FC_NSSet: 638 return S == setWithObjectsS; 639 case FC_NSDictionary: 640 return S == dictionaryWithObjectsAndKeysS; 641 default: 642 return false; 643 } 644 } 645 } 646 647 void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg, 648 CheckerContext &C) const { 649 if (!BT) { 650 BT.reset(new APIMisuse("Arguments passed to variadic method aren't all " 651 "Objective-C pointer types")); 652 653 ASTContext &Ctx = C.getASTContext(); 654 arrayWithObjectsS = GetUnarySelector("arrayWithObjects", Ctx); 655 dictionaryWithObjectsAndKeysS = 656 GetUnarySelector("dictionaryWithObjectsAndKeys", Ctx); 657 setWithObjectsS = GetUnarySelector("setWithObjects", Ctx); 658 orderedSetWithObjectsS = GetUnarySelector("orderedSetWithObjects", Ctx); 659 660 initWithObjectsS = GetUnarySelector("initWithObjects", Ctx); 661 initWithObjectsAndKeysS = GetUnarySelector("initWithObjectsAndKeys", Ctx); 662 } 663 664 if (!isVariadicMessage(msg)) 665 return; 666 667 // We are not interested in the selector arguments since they have 668 // well-defined types, so the compiler will issue a warning for them. 669 unsigned variadicArgsBegin = msg.getSelector().getNumArgs(); 670 671 // We're not interested in the last argument since it has to be nil or the 672 // compiler would have issued a warning for it elsewhere. 673 unsigned variadicArgsEnd = msg.getNumArgs() - 1; 674 675 if (variadicArgsEnd <= variadicArgsBegin) 676 return; 677 678 // Verify that all arguments have Objective-C types. 679 Optional<ExplodedNode*> errorNode; 680 ProgramStateRef state = C.getState(); 681 682 for (unsigned I = variadicArgsBegin; I != variadicArgsEnd; ++I) { 683 QualType ArgTy = msg.getArgExpr(I)->getType(); 684 if (ArgTy->isObjCObjectPointerType()) 685 continue; 686 687 // Block pointers are treaded as Objective-C pointers. 688 if (ArgTy->isBlockPointerType()) 689 continue; 690 691 // Ignore pointer constants. 692 if (msg.getArgSVal(I).getAs<loc::ConcreteInt>()) 693 continue; 694 695 // Ignore pointer types annotated with 'NSObject' attribute. 696 if (C.getASTContext().isObjCNSObjectType(ArgTy)) 697 continue; 698 699 // Ignore CF references, which can be toll-free bridged. 700 if (coreFoundation::isCFObjectRef(ArgTy)) 701 continue; 702 703 // Generate only one error node to use for all bug reports. 704 if (!errorNode.hasValue()) 705 errorNode = C.addTransition(); 706 707 if (!errorNode.getValue()) 708 continue; 709 710 SmallString<128> sbuf; 711 llvm::raw_svector_ostream os(sbuf); 712 713 StringRef TypeName = GetReceiverInterfaceName(msg); 714 if (!TypeName.empty()) 715 os << "Argument to '" << TypeName << "' method '"; 716 else 717 os << "Argument to method '"; 718 719 os << msg.getSelector().getAsString() 720 << "' should be an Objective-C pointer type, not '"; 721 ArgTy.print(os, C.getLangOpts()); 722 os << "'"; 723 724 BugReport *R = new BugReport(*BT, os.str(), errorNode.getValue()); 725 R->addRange(msg.getArgSourceRange(I)); 726 C.emitReport(R); 727 } 728 } 729 730 //===----------------------------------------------------------------------===// 731 // Improves the modeling of loops over Cocoa collections. 732 //===----------------------------------------------------------------------===// 733 734 namespace { 735 class ObjCLoopChecker 736 : public Checker<check::PostStmt<ObjCForCollectionStmt> > { 737 738 public: 739 void checkPostStmt(const ObjCForCollectionStmt *FCS, CheckerContext &C) const; 740 }; 741 } 742 743 static bool isKnownNonNilCollectionType(QualType T) { 744 const ObjCObjectPointerType *PT = T->getAs<ObjCObjectPointerType>(); 745 if (!PT) 746 return false; 747 748 const ObjCInterfaceDecl *ID = PT->getInterfaceDecl(); 749 if (!ID) 750 return false; 751 752 switch (findKnownClass(ID)) { 753 case FC_NSArray: 754 case FC_NSDictionary: 755 case FC_NSEnumerator: 756 case FC_NSOrderedSet: 757 case FC_NSSet: 758 return true; 759 default: 760 return false; 761 } 762 } 763 764 /// Assumes that the collection is non-nil. 765 /// 766 /// If the collection is known to be nil, returns NULL to indicate an infeasible 767 /// path. 768 static ProgramStateRef checkCollectionNonNil(CheckerContext &C, 769 ProgramStateRef State, 770 const ObjCForCollectionStmt *FCS) { 771 if (!State) 772 return NULL; 773 774 SVal CollectionVal = C.getSVal(FCS->getCollection()); 775 Optional<DefinedSVal> KnownCollection = CollectionVal.getAs<DefinedSVal>(); 776 if (!KnownCollection) 777 return State; 778 779 ProgramStateRef StNonNil, StNil; 780 llvm::tie(StNonNil, StNil) = State->assume(*KnownCollection); 781 if (StNil && !StNonNil) { 782 // The collection is nil. This path is infeasible. 783 return NULL; 784 } 785 786 return StNonNil; 787 } 788 789 /// Assumes that the collection elements are non-nil. 790 /// 791 /// This only applies if the collection is one of those known not to contain 792 /// nil values. 793 static ProgramStateRef checkElementNonNil(CheckerContext &C, 794 ProgramStateRef State, 795 const ObjCForCollectionStmt *FCS) { 796 if (!State) 797 return NULL; 798 799 // See if the collection is one where we /know/ the elements are non-nil. 800 if (!isKnownNonNilCollectionType(FCS->getCollection()->getType())) 801 return State; 802 803 const LocationContext *LCtx = C.getLocationContext(); 804 const Stmt *Element = FCS->getElement(); 805 806 // FIXME: Copied from ExprEngineObjC. 807 Optional<Loc> ElementLoc; 808 if (const DeclStmt *DS = dyn_cast<DeclStmt>(Element)) { 809 const VarDecl *ElemDecl = cast<VarDecl>(DS->getSingleDecl()); 810 assert(ElemDecl->getInit() == 0); 811 ElementLoc = State->getLValue(ElemDecl, LCtx); 812 } else { 813 ElementLoc = State->getSVal(Element, LCtx).getAs<Loc>(); 814 } 815 816 if (!ElementLoc) 817 return State; 818 819 // Go ahead and assume the value is non-nil. 820 SVal Val = State->getSVal(*ElementLoc); 821 return State->assume(Val.castAs<DefinedOrUnknownSVal>(), true); 822 } 823 824 void ObjCLoopChecker::checkPostStmt(const ObjCForCollectionStmt *FCS, 825 CheckerContext &C) const { 826 // Check if this is the branch for the end of the loop. 827 SVal CollectionSentinel = C.getSVal(FCS); 828 if (CollectionSentinel.isZeroConstant()) 829 return; 830 831 ProgramStateRef State = C.getState(); 832 State = checkCollectionNonNil(C, State, FCS); 833 State = checkElementNonNil(C, State, FCS); 834 835 if (!State) 836 C.generateSink(); 837 else if (State != C.getState()) 838 C.addTransition(State); 839 } 840 841 namespace { 842 /// \class ObjCNonNilReturnValueChecker 843 /// \brief The checker restricts the return values of APIs known to 844 /// never (or almost never) return 'nil'. 845 class ObjCNonNilReturnValueChecker 846 : public Checker<check::PostObjCMessage> { 847 mutable bool Initialized; 848 mutable Selector ObjectAtIndex; 849 mutable Selector ObjectAtIndexedSubscript; 850 mutable Selector NullSelector; 851 852 public: 853 ObjCNonNilReturnValueChecker() : Initialized(false) {} 854 void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const; 855 }; 856 } 857 858 static ProgramStateRef assumeExprIsNonNull(const Expr *NonNullExpr, 859 ProgramStateRef State, 860 CheckerContext &C) { 861 SVal Val = State->getSVal(NonNullExpr, C.getLocationContext()); 862 if (Optional<DefinedOrUnknownSVal> DV = Val.getAs<DefinedOrUnknownSVal>()) 863 return State->assume(*DV, true); 864 return State; 865 } 866 867 void ObjCNonNilReturnValueChecker::checkPostObjCMessage(const ObjCMethodCall &M, 868 CheckerContext &C) 869 const { 870 ProgramStateRef State = C.getState(); 871 872 if (!Initialized) { 873 ASTContext &Ctx = C.getASTContext(); 874 ObjectAtIndex = GetUnarySelector("objectAtIndex", Ctx); 875 ObjectAtIndexedSubscript = GetUnarySelector("objectAtIndexedSubscript", Ctx); 876 NullSelector = GetNullarySelector("null", Ctx); 877 } 878 879 // Check the receiver type. 880 if (const ObjCInterfaceDecl *Interface = M.getReceiverInterface()) { 881 882 // Assume that object returned from '[self init]' or '[super init]' is not 883 // 'nil' if we are processing an inlined function/method. 884 // 885 // A defensive callee will (and should) check if the object returned by 886 // '[super init]' is 'nil' before doing it's own initialization. However, 887 // since 'nil' is rarely returned in practice, we should not warn when the 888 // caller to the defensive constructor uses the object in contexts where 889 // 'nil' is not accepted. 890 if (!C.inTopFrame() && M.getDecl() && 891 M.getDecl()->getMethodFamily() == OMF_init && 892 M.isReceiverSelfOrSuper()) { 893 State = assumeExprIsNonNull(M.getOriginExpr(), State, C); 894 } 895 896 FoundationClass Cl = findKnownClass(Interface); 897 898 // Objects returned from 899 // [NSArray|NSOrderedSet]::[ObjectAtIndex|ObjectAtIndexedSubscript] 900 // are never 'nil'. 901 if (Cl == FC_NSArray || Cl == FC_NSOrderedSet) { 902 Selector Sel = M.getSelector(); 903 if (Sel == ObjectAtIndex || Sel == ObjectAtIndexedSubscript) { 904 // Go ahead and assume the value is non-nil. 905 State = assumeExprIsNonNull(M.getOriginExpr(), State, C); 906 } 907 } 908 909 // Objects returned from [NSNull null] are not nil. 910 if (Cl == FC_NSNull) { 911 if (M.getSelector() == NullSelector) { 912 // Go ahead and assume the value is non-nil. 913 State = assumeExprIsNonNull(M.getOriginExpr(), State, C); 914 } 915 } 916 } 917 C.addTransition(State); 918 } 919 920 //===----------------------------------------------------------------------===// 921 // Check registration. 922 //===----------------------------------------------------------------------===// 923 924 void ento::registerNilArgChecker(CheckerManager &mgr) { 925 mgr.registerChecker<NilArgChecker>(); 926 } 927 928 void ento::registerCFNumberCreateChecker(CheckerManager &mgr) { 929 mgr.registerChecker<CFNumberCreateChecker>(); 930 } 931 932 void ento::registerCFRetainReleaseChecker(CheckerManager &mgr) { 933 mgr.registerChecker<CFRetainReleaseChecker>(); 934 } 935 936 void ento::registerClassReleaseChecker(CheckerManager &mgr) { 937 mgr.registerChecker<ClassReleaseChecker>(); 938 } 939 940 void ento::registerVariadicMethodTypeChecker(CheckerManager &mgr) { 941 mgr.registerChecker<VariadicMethodTypeChecker>(); 942 } 943 944 void ento::registerObjCLoopChecker(CheckerManager &mgr) { 945 mgr.registerChecker<ObjCLoopChecker>(); 946 } 947 948 void ento::registerObjCNonNilReturnValueChecker(CheckerManager &mgr) { 949 mgr.registerChecker<ObjCNonNilReturnValueChecker>(); 950 } 951