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