BasicObjCFoundationChecks.cpp 26 KB

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