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