BasicObjCFoundationChecks.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659
  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/CheckerContext.h"
  20. #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
  21. #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
  22. #include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.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/ASTContext.h"
  30. #include "llvm/ADT/SmallString.h"
  31. using namespace clang;
  32. using namespace ento;
  33. namespace {
  34. class APIMisuse : public BugType {
  35. public:
  36. APIMisuse(const char* name) : BugType(name, "API Misuse (Apple)") {}
  37. };
  38. } // end anonymous namespace
  39. //===----------------------------------------------------------------------===//
  40. // Utility functions.
  41. //===----------------------------------------------------------------------===//
  42. static const char* GetReceiverNameType(const ObjCMessage &msg) {
  43. if (const ObjCInterfaceDecl *ID = msg.getReceiverInterface())
  44. return ID->getIdentifier()->getNameStart();
  45. return 0;
  46. }
  47. static bool isReceiverClassOrSuperclass(const ObjCInterfaceDecl *ID,
  48. StringRef ClassName) {
  49. if (ID->getIdentifier()->getName() == ClassName)
  50. return true;
  51. if (const ObjCInterfaceDecl *Super = ID->getSuperClass())
  52. return isReceiverClassOrSuperclass(Super, ClassName);
  53. return false;
  54. }
  55. static inline bool isNil(SVal X) {
  56. return isa<loc::ConcreteInt>(X);
  57. }
  58. //===----------------------------------------------------------------------===//
  59. // NilArgChecker - Check for prohibited nil arguments to ObjC method calls.
  60. //===----------------------------------------------------------------------===//
  61. namespace {
  62. class NilArgChecker : public Checker<check::PreObjCMessage> {
  63. mutable OwningPtr<APIMisuse> BT;
  64. void WarnNilArg(CheckerContext &C,
  65. const ObjCMessage &msg, unsigned Arg) const;
  66. public:
  67. void checkPreObjCMessage(ObjCMessage msg, CheckerContext &C) const;
  68. };
  69. }
  70. void NilArgChecker::WarnNilArg(CheckerContext &C,
  71. const ObjCMessage &msg,
  72. unsigned int Arg) const
  73. {
  74. if (!BT)
  75. BT.reset(new APIMisuse("nil argument"));
  76. if (ExplodedNode *N = C.generateSink()) {
  77. SmallString<128> sbuf;
  78. llvm::raw_svector_ostream os(sbuf);
  79. os << "Argument to '" << GetReceiverNameType(msg) << "' method '"
  80. << msg.getSelector().getAsString() << "' cannot be nil";
  81. BugReport *R = new BugReport(*BT, os.str(), N);
  82. R->addRange(msg.getArgSourceRange(Arg));
  83. C.EmitReport(R);
  84. }
  85. }
  86. void NilArgChecker::checkPreObjCMessage(ObjCMessage msg,
  87. CheckerContext &C) const {
  88. const ObjCInterfaceDecl *ID = msg.getReceiverInterface();
  89. if (!ID)
  90. return;
  91. if (isReceiverClassOrSuperclass(ID, "NSString")) {
  92. Selector S = msg.getSelector();
  93. if (S.isUnarySelector())
  94. return;
  95. // FIXME: This is going to be really slow doing these checks with
  96. // lexical comparisons.
  97. std::string NameStr = S.getAsString();
  98. StringRef Name(NameStr);
  99. assert(!Name.empty());
  100. // FIXME: Checking for initWithFormat: will not work in most cases
  101. // yet because [NSString alloc] returns id, not NSString*. We will
  102. // need support for tracking expected-type information in the analyzer
  103. // to find these errors.
  104. if (Name == "caseInsensitiveCompare:" ||
  105. Name == "compare:" ||
  106. Name == "compare:options:" ||
  107. Name == "compare:options:range:" ||
  108. Name == "compare:options:range:locale:" ||
  109. Name == "componentsSeparatedByCharactersInSet:" ||
  110. Name == "initWithFormat:") {
  111. if (isNil(msg.getArgSVal(0, C.getLocationContext(), C.getState())))
  112. WarnNilArg(C, msg, 0);
  113. }
  114. }
  115. }
  116. //===----------------------------------------------------------------------===//
  117. // Error reporting.
  118. //===----------------------------------------------------------------------===//
  119. namespace {
  120. class CFNumberCreateChecker : public Checker< check::PreStmt<CallExpr> > {
  121. mutable OwningPtr<APIMisuse> BT;
  122. mutable IdentifierInfo* II;
  123. public:
  124. CFNumberCreateChecker() : II(0) {}
  125. void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
  126. private:
  127. void EmitError(const TypedRegion* R, const Expr *Ex,
  128. uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind);
  129. };
  130. } // end anonymous namespace
  131. enum CFNumberType {
  132. kCFNumberSInt8Type = 1,
  133. kCFNumberSInt16Type = 2,
  134. kCFNumberSInt32Type = 3,
  135. kCFNumberSInt64Type = 4,
  136. kCFNumberFloat32Type = 5,
  137. kCFNumberFloat64Type = 6,
  138. kCFNumberCharType = 7,
  139. kCFNumberShortType = 8,
  140. kCFNumberIntType = 9,
  141. kCFNumberLongType = 10,
  142. kCFNumberLongLongType = 11,
  143. kCFNumberFloatType = 12,
  144. kCFNumberDoubleType = 13,
  145. kCFNumberCFIndexType = 14,
  146. kCFNumberNSIntegerType = 15,
  147. kCFNumberCGFloatType = 16
  148. };
  149. namespace {
  150. template<typename T>
  151. class Optional {
  152. bool IsKnown;
  153. T Val;
  154. public:
  155. Optional() : IsKnown(false), Val(0) {}
  156. Optional(const T& val) : IsKnown(true), Val(val) {}
  157. bool isKnown() const { return IsKnown; }
  158. const T& getValue() const {
  159. assert (isKnown());
  160. return Val;
  161. }
  162. operator const T&() const {
  163. return getValue();
  164. }
  165. };
  166. }
  167. static Optional<uint64_t> GetCFNumberSize(ASTContext &Ctx, uint64_t i) {
  168. static const unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 };
  169. if (i < kCFNumberCharType)
  170. return FixedSize[i-1];
  171. QualType T;
  172. switch (i) {
  173. case kCFNumberCharType: T = Ctx.CharTy; break;
  174. case kCFNumberShortType: T = Ctx.ShortTy; break;
  175. case kCFNumberIntType: T = Ctx.IntTy; break;
  176. case kCFNumberLongType: T = Ctx.LongTy; break;
  177. case kCFNumberLongLongType: T = Ctx.LongLongTy; break;
  178. case kCFNumberFloatType: T = Ctx.FloatTy; break;
  179. case kCFNumberDoubleType: T = Ctx.DoubleTy; break;
  180. case kCFNumberCFIndexType:
  181. case kCFNumberNSIntegerType:
  182. case kCFNumberCGFloatType:
  183. // FIXME: We need a way to map from names to Type*.
  184. default:
  185. return Optional<uint64_t>();
  186. }
  187. return Ctx.getTypeSize(T);
  188. }
  189. #if 0
  190. static const char* GetCFNumberTypeStr(uint64_t i) {
  191. static const char* Names[] = {
  192. "kCFNumberSInt8Type",
  193. "kCFNumberSInt16Type",
  194. "kCFNumberSInt32Type",
  195. "kCFNumberSInt64Type",
  196. "kCFNumberFloat32Type",
  197. "kCFNumberFloat64Type",
  198. "kCFNumberCharType",
  199. "kCFNumberShortType",
  200. "kCFNumberIntType",
  201. "kCFNumberLongType",
  202. "kCFNumberLongLongType",
  203. "kCFNumberFloatType",
  204. "kCFNumberDoubleType",
  205. "kCFNumberCFIndexType",
  206. "kCFNumberNSIntegerType",
  207. "kCFNumberCGFloatType"
  208. };
  209. return i <= kCFNumberCGFloatType ? Names[i-1] : "Invalid CFNumberType";
  210. }
  211. #endif
  212. void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE,
  213. CheckerContext &C) const {
  214. ProgramStateRef state = C.getState();
  215. const FunctionDecl *FD = C.getCalleeDecl(CE);
  216. if (!FD)
  217. return;
  218. ASTContext &Ctx = C.getASTContext();
  219. if (!II)
  220. II = &Ctx.Idents.get("CFNumberCreate");
  221. if (FD->getIdentifier() != II || CE->getNumArgs() != 3)
  222. return;
  223. // Get the value of the "theType" argument.
  224. const LocationContext *LCtx = C.getLocationContext();
  225. SVal TheTypeVal = state->getSVal(CE->getArg(1), LCtx);
  226. // FIXME: We really should allow ranges of valid theType values, and
  227. // bifurcate the state appropriately.
  228. nonloc::ConcreteInt* V = dyn_cast<nonloc::ConcreteInt>(&TheTypeVal);
  229. if (!V)
  230. return;
  231. uint64_t NumberKind = V->getValue().getLimitedValue();
  232. Optional<uint64_t> TargetSize = GetCFNumberSize(Ctx, NumberKind);
  233. // FIXME: In some cases we can emit an error.
  234. if (!TargetSize.isKnown())
  235. return;
  236. // Look at the value of the integer being passed by reference. Essentially
  237. // we want to catch cases where the value passed in is not equal to the
  238. // size of the type being created.
  239. SVal TheValueExpr = state->getSVal(CE->getArg(2), LCtx);
  240. // FIXME: Eventually we should handle arbitrary locations. We can do this
  241. // by having an enhanced memory model that does low-level typing.
  242. loc::MemRegionVal* LV = dyn_cast<loc::MemRegionVal>(&TheValueExpr);
  243. if (!LV)
  244. return;
  245. const TypedValueRegion* R = dyn_cast<TypedValueRegion>(LV->stripCasts());
  246. if (!R)
  247. return;
  248. QualType T = Ctx.getCanonicalType(R->getValueType());
  249. // FIXME: If the pointee isn't an integer type, should we flag a warning?
  250. // People can do weird stuff with pointers.
  251. if (!T->isIntegerType())
  252. return;
  253. uint64_t SourceSize = Ctx.getTypeSize(T);
  254. // CHECK: is SourceSize == TargetSize
  255. if (SourceSize == TargetSize)
  256. return;
  257. // Generate an error. Only generate a sink if 'SourceSize < TargetSize';
  258. // otherwise generate a regular node.
  259. //
  260. // FIXME: We can actually create an abstract "CFNumber" object that has
  261. // the bits initialized to the provided values.
  262. //
  263. if (ExplodedNode *N = SourceSize < TargetSize ? C.generateSink()
  264. : C.addTransition()) {
  265. SmallString<128> sbuf;
  266. llvm::raw_svector_ostream os(sbuf);
  267. os << (SourceSize == 8 ? "An " : "A ")
  268. << SourceSize << " bit integer is used to initialize a CFNumber "
  269. "object that represents "
  270. << (TargetSize == 8 ? "an " : "a ")
  271. << TargetSize << " bit integer. ";
  272. if (SourceSize < TargetSize)
  273. os << (TargetSize - SourceSize)
  274. << " bits of the CFNumber value will be garbage." ;
  275. else
  276. os << (SourceSize - TargetSize)
  277. << " bits of the input integer will be lost.";
  278. if (!BT)
  279. BT.reset(new APIMisuse("Bad use of CFNumberCreate"));
  280. BugReport *report = new BugReport(*BT, os.str(), N);
  281. report->addRange(CE->getArg(2)->getSourceRange());
  282. C.EmitReport(report);
  283. }
  284. }
  285. //===----------------------------------------------------------------------===//
  286. // CFRetain/CFRelease checking for null arguments.
  287. //===----------------------------------------------------------------------===//
  288. namespace {
  289. class CFRetainReleaseChecker : public Checker< check::PreStmt<CallExpr> > {
  290. mutable OwningPtr<APIMisuse> BT;
  291. mutable IdentifierInfo *Retain, *Release;
  292. public:
  293. CFRetainReleaseChecker(): Retain(0), Release(0) {}
  294. void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
  295. };
  296. } // end anonymous namespace
  297. void CFRetainReleaseChecker::checkPreStmt(const CallExpr *CE,
  298. CheckerContext &C) const {
  299. // If the CallExpr doesn't have exactly 1 argument just give up checking.
  300. if (CE->getNumArgs() != 1)
  301. return;
  302. ProgramStateRef state = C.getState();
  303. const FunctionDecl *FD = C.getCalleeDecl(CE);
  304. if (!FD)
  305. return;
  306. if (!BT) {
  307. ASTContext &Ctx = C.getASTContext();
  308. Retain = &Ctx.Idents.get("CFRetain");
  309. Release = &Ctx.Idents.get("CFRelease");
  310. BT.reset(new APIMisuse("null passed to CFRetain/CFRelease"));
  311. }
  312. // Check if we called CFRetain/CFRelease.
  313. const IdentifierInfo *FuncII = FD->getIdentifier();
  314. if (!(FuncII == Retain || FuncII == Release))
  315. return;
  316. // FIXME: The rest of this just checks that the argument is non-null.
  317. // It should probably be refactored and combined with AttrNonNullChecker.
  318. // Get the argument's value.
  319. const Expr *Arg = CE->getArg(0);
  320. SVal ArgVal = state->getSVal(Arg, C.getLocationContext());
  321. DefinedSVal *DefArgVal = dyn_cast<DefinedSVal>(&ArgVal);
  322. if (!DefArgVal)
  323. return;
  324. // Get a NULL value.
  325. SValBuilder &svalBuilder = C.getSValBuilder();
  326. DefinedSVal zero = cast<DefinedSVal>(svalBuilder.makeZeroVal(Arg->getType()));
  327. // Make an expression asserting that they're equal.
  328. DefinedOrUnknownSVal ArgIsNull = svalBuilder.evalEQ(state, zero, *DefArgVal);
  329. // Are they equal?
  330. ProgramStateRef stateTrue, stateFalse;
  331. llvm::tie(stateTrue, stateFalse) = state->assume(ArgIsNull);
  332. if (stateTrue && !stateFalse) {
  333. ExplodedNode *N = C.generateSink(stateTrue);
  334. if (!N)
  335. return;
  336. const char *description = (FuncII == Retain)
  337. ? "Null pointer argument in call to CFRetain"
  338. : "Null pointer argument in call to CFRelease";
  339. BugReport *report = new BugReport(*BT, description, N);
  340. report->addRange(Arg->getSourceRange());
  341. report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Arg));
  342. C.EmitReport(report);
  343. return;
  344. }
  345. // From here on, we know the argument is non-null.
  346. C.addTransition(stateFalse);
  347. }
  348. //===----------------------------------------------------------------------===//
  349. // Check for sending 'retain', 'release', or 'autorelease' directly to a Class.
  350. //===----------------------------------------------------------------------===//
  351. namespace {
  352. class ClassReleaseChecker : public Checker<check::PreObjCMessage> {
  353. mutable Selector releaseS;
  354. mutable Selector retainS;
  355. mutable Selector autoreleaseS;
  356. mutable Selector drainS;
  357. mutable OwningPtr<BugType> BT;
  358. public:
  359. void checkPreObjCMessage(ObjCMessage msg, CheckerContext &C) const;
  360. };
  361. }
  362. void ClassReleaseChecker::checkPreObjCMessage(ObjCMessage msg,
  363. CheckerContext &C) const {
  364. if (!BT) {
  365. BT.reset(new APIMisuse("message incorrectly sent to class instead of class "
  366. "instance"));
  367. ASTContext &Ctx = C.getASTContext();
  368. releaseS = GetNullarySelector("release", Ctx);
  369. retainS = GetNullarySelector("retain", Ctx);
  370. autoreleaseS = GetNullarySelector("autorelease", Ctx);
  371. drainS = GetNullarySelector("drain", Ctx);
  372. }
  373. if (msg.isInstanceMessage())
  374. return;
  375. const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
  376. assert(Class);
  377. Selector S = msg.getSelector();
  378. if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
  379. return;
  380. if (ExplodedNode *N = C.addTransition()) {
  381. SmallString<200> buf;
  382. llvm::raw_svector_ostream os(buf);
  383. os << "The '" << S.getAsString() << "' message should be sent to instances "
  384. "of class '" << Class->getName()
  385. << "' and not the class directly";
  386. BugReport *report = new BugReport(*BT, os.str(), N);
  387. report->addRange(msg.getSourceRange());
  388. C.EmitReport(report);
  389. }
  390. }
  391. //===----------------------------------------------------------------------===//
  392. // Check for passing non-Objective-C types to variadic methods that expect
  393. // only Objective-C types.
  394. //===----------------------------------------------------------------------===//
  395. namespace {
  396. class VariadicMethodTypeChecker : public Checker<check::PreObjCMessage> {
  397. mutable Selector arrayWithObjectsS;
  398. mutable Selector dictionaryWithObjectsAndKeysS;
  399. mutable Selector setWithObjectsS;
  400. mutable Selector initWithObjectsS;
  401. mutable Selector initWithObjectsAndKeysS;
  402. mutable OwningPtr<BugType> BT;
  403. bool isVariadicMessage(const ObjCMessage &msg) const;
  404. public:
  405. void checkPreObjCMessage(ObjCMessage msg, CheckerContext &C) const;
  406. };
  407. }
  408. /// isVariadicMessage - Returns whether the given message is a variadic message,
  409. /// where all arguments must be Objective-C types.
  410. bool
  411. VariadicMethodTypeChecker::isVariadicMessage(const ObjCMessage &msg) const {
  412. const ObjCMethodDecl *MD = msg.getMethodDecl();
  413. if (!MD || !MD->isVariadic() || isa<ObjCProtocolDecl>(MD->getDeclContext()))
  414. return false;
  415. Selector S = msg.getSelector();
  416. if (msg.isInstanceMessage()) {
  417. // FIXME: Ideally we'd look at the receiver interface here, but that's not
  418. // useful for init, because alloc returns 'id'. In theory, this could lead
  419. // to false positives, for example if there existed a class that had an
  420. // initWithObjects: implementation that does accept non-Objective-C pointer
  421. // types, but the chance of that happening is pretty small compared to the
  422. // gains that this analysis gives.
  423. const ObjCInterfaceDecl *Class = MD->getClassInterface();
  424. // -[NSArray initWithObjects:]
  425. if (isReceiverClassOrSuperclass(Class, "NSArray") &&
  426. S == initWithObjectsS)
  427. return true;
  428. // -[NSDictionary initWithObjectsAndKeys:]
  429. if (isReceiverClassOrSuperclass(Class, "NSDictionary") &&
  430. S == initWithObjectsAndKeysS)
  431. return true;
  432. // -[NSSet initWithObjects:]
  433. if (isReceiverClassOrSuperclass(Class, "NSSet") &&
  434. S == initWithObjectsS)
  435. return true;
  436. } else {
  437. const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
  438. // -[NSArray arrayWithObjects:]
  439. if (isReceiverClassOrSuperclass(Class, "NSArray") &&
  440. S == arrayWithObjectsS)
  441. return true;
  442. // -[NSDictionary dictionaryWithObjectsAndKeys:]
  443. if (isReceiverClassOrSuperclass(Class, "NSDictionary") &&
  444. S == dictionaryWithObjectsAndKeysS)
  445. return true;
  446. // -[NSSet setWithObjects:]
  447. if (isReceiverClassOrSuperclass(Class, "NSSet") &&
  448. S == setWithObjectsS)
  449. return true;
  450. }
  451. return false;
  452. }
  453. void VariadicMethodTypeChecker::checkPreObjCMessage(ObjCMessage msg,
  454. CheckerContext &C) const {
  455. if (!BT) {
  456. BT.reset(new APIMisuse("Arguments passed to variadic method aren't all "
  457. "Objective-C pointer types"));
  458. ASTContext &Ctx = C.getASTContext();
  459. arrayWithObjectsS = GetUnarySelector("arrayWithObjects", Ctx);
  460. dictionaryWithObjectsAndKeysS =
  461. GetUnarySelector("dictionaryWithObjectsAndKeys", Ctx);
  462. setWithObjectsS = GetUnarySelector("setWithObjects", Ctx);
  463. initWithObjectsS = GetUnarySelector("initWithObjects", Ctx);
  464. initWithObjectsAndKeysS = GetUnarySelector("initWithObjectsAndKeys", Ctx);
  465. }
  466. if (!isVariadicMessage(msg))
  467. return;
  468. // We are not interested in the selector arguments since they have
  469. // well-defined types, so the compiler will issue a warning for them.
  470. unsigned variadicArgsBegin = msg.getSelector().getNumArgs();
  471. // We're not interested in the last argument since it has to be nil or the
  472. // compiler would have issued a warning for it elsewhere.
  473. unsigned variadicArgsEnd = msg.getNumArgs() - 1;
  474. if (variadicArgsEnd <= variadicArgsBegin)
  475. return;
  476. // Verify that all arguments have Objective-C types.
  477. llvm::Optional<ExplodedNode*> errorNode;
  478. ProgramStateRef state = C.getState();
  479. for (unsigned I = variadicArgsBegin; I != variadicArgsEnd; ++I) {
  480. QualType ArgTy = msg.getArgType(I);
  481. if (ArgTy->isObjCObjectPointerType())
  482. continue;
  483. // Block pointers are treaded as Objective-C pointers.
  484. if (ArgTy->isBlockPointerType())
  485. continue;
  486. // Ignore pointer constants.
  487. if (isa<loc::ConcreteInt>(msg.getArgSVal(I, C.getLocationContext(),
  488. state)))
  489. continue;
  490. // Ignore pointer types annotated with 'NSObject' attribute.
  491. if (C.getASTContext().isObjCNSObjectType(ArgTy))
  492. continue;
  493. // Ignore CF references, which can be toll-free bridged.
  494. if (coreFoundation::isCFObjectRef(ArgTy))
  495. continue;
  496. // Generate only one error node to use for all bug reports.
  497. if (!errorNode.hasValue()) {
  498. errorNode = C.addTransition();
  499. }
  500. if (!errorNode.getValue())
  501. continue;
  502. SmallString<128> sbuf;
  503. llvm::raw_svector_ostream os(sbuf);
  504. if (const char *TypeName = GetReceiverNameType(msg))
  505. os << "Argument to '" << TypeName << "' method '";
  506. else
  507. os << "Argument to method '";
  508. os << msg.getSelector().getAsString()
  509. << "' should be an Objective-C pointer type, not '"
  510. << ArgTy.getAsString() << "'";
  511. BugReport *R = new BugReport(*BT, os.str(),
  512. errorNode.getValue());
  513. R->addRange(msg.getArgSourceRange(I));
  514. C.EmitReport(R);
  515. }
  516. }
  517. //===----------------------------------------------------------------------===//
  518. // Check registration.
  519. //===----------------------------------------------------------------------===//
  520. void ento::registerNilArgChecker(CheckerManager &mgr) {
  521. mgr.registerChecker<NilArgChecker>();
  522. }
  523. void ento::registerCFNumberCreateChecker(CheckerManager &mgr) {
  524. mgr.registerChecker<CFNumberCreateChecker>();
  525. }
  526. void ento::registerCFRetainReleaseChecker(CheckerManager &mgr) {
  527. mgr.registerChecker<CFRetainReleaseChecker>();
  528. }
  529. void ento::registerClassReleaseChecker(CheckerManager &mgr) {
  530. mgr.registerChecker<ClassReleaseChecker>();
  531. }
  532. void ento::registerVariadicMethodTypeChecker(CheckerManager &mgr) {
  533. mgr.registerChecker<VariadicMethodTypeChecker>();
  534. }