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