blob: eba534e08f6b7465dd4ab9a25547ba00c0cd6122 [file] [log] [blame]
Ted Kremenekc0414922008-03-27 07:25:52 +00001//== 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
Argyrios Kyrtzidis9d4d4f92011-02-16 01:40:52 +000016#include "ClangSACheckers.h"
Ted Kremenek6fa1dae2011-03-17 04:01:35 +000017#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
Argyrios Kyrtzidis6a5674f2011-03-01 01:16:21 +000018#include "clang/StaticAnalyzer/Core/Checker.h"
Argyrios Kyrtzidis507ff532011-02-17 21:39:17 +000019#include "clang/StaticAnalyzer/Core/CheckerManager.h"
Jordan Rose4f7df9b2012-07-26 21:39:41 +000020#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
Argyrios Kyrtzidisdff865d2011-02-23 01:05:36 +000021#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
Ted Kremenekf8cbac42011-02-10 01:03:03 +000022#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
Ted Kremenekf8cbac42011-02-10 01:03:03 +000023#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
Ted Kremenek001fd5b2011-08-15 22:09:50 +000024#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
Ted Kremenekf8cbac42011-02-10 01:03:03 +000025#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
26#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
Daniel Dunbar6e8aa532008-08-11 05:35:13 +000027#include "clang/AST/DeclObjC.h"
Ted Kremenekc0414922008-03-27 07:25:52 +000028#include "clang/AST/Expr.h"
Steve Naroff021ca182008-05-29 21:12:08 +000029#include "clang/AST/ExprObjC.h"
Jordan Roseefef7602012-06-11 16:40:41 +000030#include "clang/AST/StmtObjC.h"
Ted Kremenekc0414922008-03-27 07:25:52 +000031#include "clang/AST/ASTContext.h"
Benjamin Kramer49038022012-02-04 13:45:25 +000032#include "llvm/ADT/SmallString.h"
Jordan Rose3ba8ae32012-06-11 16:40:37 +000033#include "llvm/ADT/StringMap.h"
Ted Kremenekc0414922008-03-27 07:25:52 +000034
Ted Kremenekc0414922008-03-27 07:25:52 +000035using namespace clang;
Ted Kremenek98857c92010-12-23 07:20:52 +000036using namespace ento;
Ted Kremeneka4d60b62008-03-27 17:17:22 +000037
Ted Kremenekbd2c8002010-10-20 23:38:56 +000038namespace {
39class APIMisuse : public BugType {
40public:
41 APIMisuse(const char* name) : BugType(name, "API Misuse (Apple)") {}
42};
43} // end anonymous namespace
44
45//===----------------------------------------------------------------------===//
46// Utility functions.
47//===----------------------------------------------------------------------===//
48
Jordan Rose547060b2012-07-02 19:28:04 +000049static StringRef GetReceiverInterfaceName(const ObjCMethodCall &msg) {
Anders Carlsson3c50aea2011-03-08 20:05:26 +000050 if (const ObjCInterfaceDecl *ID = msg.getReceiverInterface())
Jordan Rose547060b2012-07-02 19:28:04 +000051 return ID->getIdentifier()->getName();
52 return StringRef();
Ted Kremenek276278e2008-03-27 22:05:32 +000053}
Ted Kremeneka4d60b62008-03-27 17:17:22 +000054
Jordan Rose3ba8ae32012-06-11 16:40:37 +000055enum FoundationClass {
56 FC_None,
57 FC_NSArray,
58 FC_NSDictionary,
59 FC_NSEnumerator,
60 FC_NSOrderedSet,
61 FC_NSSet,
62 FC_NSString
63};
Anders Carlsson3c50aea2011-03-08 20:05:26 +000064
Jordan Rose3ba8ae32012-06-11 16:40:37 +000065static FoundationClass findKnownClass(const ObjCInterfaceDecl *ID) {
66 static llvm::StringMap<FoundationClass> Classes;
67 if (Classes.empty()) {
68 Classes["NSArray"] = FC_NSArray;
69 Classes["NSDictionary"] = FC_NSDictionary;
70 Classes["NSEnumerator"] = FC_NSEnumerator;
71 Classes["NSOrderedSet"] = FC_NSOrderedSet;
72 Classes["NSSet"] = FC_NSSet;
73 Classes["NSString"] = FC_NSString;
74 }
Anders Carlsson3c50aea2011-03-08 20:05:26 +000075
Jordan Rose3ba8ae32012-06-11 16:40:37 +000076 // FIXME: Should we cache this at all?
77 FoundationClass result = Classes.lookup(ID->getIdentifier()->getName());
78 if (result == FC_None)
79 if (const ObjCInterfaceDecl *Super = ID->getSuperClass())
80 return findKnownClass(Super);
81
82 return result;
Ted Kremenekc0414922008-03-27 07:25:52 +000083}
84
Zhongxing Xu27f17422008-10-17 05:57:07 +000085static inline bool isNil(SVal X) {
Mike Stump11289f42009-09-09 15:08:12 +000086 return isa<loc::ConcreteInt>(X);
Ted Kremenek27156c82008-03-27 21:15:17 +000087}
88
Ted Kremenekc0414922008-03-27 07:25:52 +000089//===----------------------------------------------------------------------===//
Ted Kremenekbd2c8002010-10-20 23:38:56 +000090// NilArgChecker - Check for prohibited nil arguments to ObjC method calls.
Ted Kremenekc0414922008-03-27 07:25:52 +000091//===----------------------------------------------------------------------===//
92
Benjamin Kramer2fc373e2010-10-22 16:33:16 +000093namespace {
Argyrios Kyrtzidis6a5674f2011-03-01 01:16:21 +000094 class NilArgChecker : public Checker<check::PreObjCMessage> {
Dylan Noblesmithe2778992012-02-05 02:12:40 +000095 mutable OwningPtr<APIMisuse> BT;
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +000096
97 void WarnNilArg(CheckerContext &C,
Jordan Rose547060b2012-07-02 19:28:04 +000098 const ObjCMethodCall &msg, unsigned Arg) const;
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +000099
Benjamin Kramer2fc373e2010-10-22 16:33:16 +0000100 public:
Jordan Rose547060b2012-07-02 19:28:04 +0000101 void checkPreObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
Benjamin Kramer2fc373e2010-10-22 16:33:16 +0000102 };
103}
Mike Stump11289f42009-09-09 15:08:12 +0000104
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000105void NilArgChecker::WarnNilArg(CheckerContext &C,
Jordan Rose547060b2012-07-02 19:28:04 +0000106 const ObjCMethodCall &msg,
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000107 unsigned int Arg) const
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000108{
109 if (!BT)
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000110 BT.reset(new APIMisuse("nil argument"));
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000111
Ted Kremenek750b7ac2010-12-20 21:19:09 +0000112 if (ExplodedNode *N = C.generateSink()) {
Dylan Noblesmith2c1dd272012-02-05 02:13:05 +0000113 SmallString<128> sbuf;
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000114 llvm::raw_svector_ostream os(sbuf);
Jordan Rose547060b2012-07-02 19:28:04 +0000115 os << "Argument to '" << GetReceiverInterfaceName(msg) << "' method '"
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +0000116 << msg.getSelector().getAsString() << "' cannot be nil";
Mike Stump11289f42009-09-09 15:08:12 +0000117
Anna Zaks3a6bdf82011-08-17 23:00:25 +0000118 BugReport *R = new BugReport(*BT, os.str(), N);
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +0000119 R->addRange(msg.getArgSourceRange(Arg));
Jordan Rosee10d5a72012-11-02 01:53:40 +0000120 C.emitReport(R);
Ted Kremenek276278e2008-03-27 22:05:32 +0000121 }
Ted Kremenek276278e2008-03-27 22:05:32 +0000122}
123
Jordan Rose547060b2012-07-02 19:28:04 +0000124void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000125 CheckerContext &C) const {
Anders Carlsson3c50aea2011-03-08 20:05:26 +0000126 const ObjCInterfaceDecl *ID = msg.getReceiverInterface();
127 if (!ID)
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000128 return;
129
Jordan Rose3ba8ae32012-06-11 16:40:37 +0000130 if (findKnownClass(ID) == FC_NSString) {
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +0000131 Selector S = msg.getSelector();
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000132
133 if (S.isUnarySelector())
134 return;
135
136 // FIXME: This is going to be really slow doing these checks with
137 // lexical comparisons.
138
139 std::string NameStr = S.getAsString();
Chris Lattner0e62c1c2011-07-23 10:55:15 +0000140 StringRef Name(NameStr);
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000141 assert(!Name.empty());
142
143 // FIXME: Checking for initWithFormat: will not work in most cases
144 // yet because [NSString alloc] returns id, not NSString*. We will
145 // need support for tracking expected-type information in the analyzer
146 // to find these errors.
147 if (Name == "caseInsensitiveCompare:" ||
148 Name == "compare:" ||
149 Name == "compare:options:" ||
150 Name == "compare:options:range:" ||
151 Name == "compare:options:range:locale:" ||
152 Name == "componentsSeparatedByCharactersInSet:" ||
153 Name == "initWithFormat:") {
Jordan Rose547060b2012-07-02 19:28:04 +0000154 if (isNil(msg.getArgSVal(0)))
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +0000155 WarnNilArg(C, msg, 0);
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000156 }
157 }
Ted Kremenekc0414922008-03-27 07:25:52 +0000158}
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000159
160//===----------------------------------------------------------------------===//
161// Error reporting.
162//===----------------------------------------------------------------------===//
163
164namespace {
Argyrios Kyrtzidis6a5674f2011-03-01 01:16:21 +0000165class CFNumberCreateChecker : public Checker< check::PreStmt<CallExpr> > {
Dylan Noblesmithe2778992012-02-05 02:12:40 +0000166 mutable OwningPtr<APIMisuse> BT;
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000167 mutable IdentifierInfo* II;
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000168public:
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000169 CFNumberCreateChecker() : II(0) {}
170
171 void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
172
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000173private:
Ted Kremenek5ef32db2011-08-12 23:37:29 +0000174 void EmitError(const TypedRegion* R, const Expr *Ex,
Mike Stump11289f42009-09-09 15:08:12 +0000175 uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind);
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000176};
177} // end anonymous namespace
178
179enum CFNumberType {
180 kCFNumberSInt8Type = 1,
181 kCFNumberSInt16Type = 2,
182 kCFNumberSInt32Type = 3,
183 kCFNumberSInt64Type = 4,
184 kCFNumberFloat32Type = 5,
185 kCFNumberFloat64Type = 6,
186 kCFNumberCharType = 7,
187 kCFNumberShortType = 8,
188 kCFNumberIntType = 9,
189 kCFNumberLongType = 10,
190 kCFNumberLongLongType = 11,
191 kCFNumberFloatType = 12,
192 kCFNumberDoubleType = 13,
193 kCFNumberCFIndexType = 14,
194 kCFNumberNSIntegerType = 15,
195 kCFNumberCGFloatType = 16
196};
197
198namespace {
199 template<typename T>
200 class Optional {
201 bool IsKnown;
202 T Val;
203 public:
204 Optional() : IsKnown(false), Val(0) {}
205 Optional(const T& val) : IsKnown(true), Val(val) {}
Mike Stump11289f42009-09-09 15:08:12 +0000206
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000207 bool isKnown() const { return IsKnown; }
208
209 const T& getValue() const {
210 assert (isKnown());
211 return Val;
212 }
213
214 operator const T&() const {
215 return getValue();
216 }
217 };
218}
219
Ted Kremenek5ef32db2011-08-12 23:37:29 +0000220static Optional<uint64_t> GetCFNumberSize(ASTContext &Ctx, uint64_t i) {
Nuno Lopescfca1f02009-12-23 17:49:57 +0000221 static const unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 };
Mike Stump11289f42009-09-09 15:08:12 +0000222
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000223 if (i < kCFNumberCharType)
224 return FixedSize[i-1];
Mike Stump11289f42009-09-09 15:08:12 +0000225
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000226 QualType T;
Mike Stump11289f42009-09-09 15:08:12 +0000227
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000228 switch (i) {
229 case kCFNumberCharType: T = Ctx.CharTy; break;
230 case kCFNumberShortType: T = Ctx.ShortTy; break;
231 case kCFNumberIntType: T = Ctx.IntTy; break;
232 case kCFNumberLongType: T = Ctx.LongTy; break;
233 case kCFNumberLongLongType: T = Ctx.LongLongTy; break;
234 case kCFNumberFloatType: T = Ctx.FloatTy; break;
235 case kCFNumberDoubleType: T = Ctx.DoubleTy; break;
236 case kCFNumberCFIndexType:
237 case kCFNumberNSIntegerType:
238 case kCFNumberCGFloatType:
Mike Stump11289f42009-09-09 15:08:12 +0000239 // FIXME: We need a way to map from names to Type*.
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000240 default:
241 return Optional<uint64_t>();
242 }
Mike Stump11289f42009-09-09 15:08:12 +0000243
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000244 return Ctx.getTypeSize(T);
245}
246
247#if 0
248static const char* GetCFNumberTypeStr(uint64_t i) {
249 static const char* Names[] = {
250 "kCFNumberSInt8Type",
251 "kCFNumberSInt16Type",
252 "kCFNumberSInt32Type",
253 "kCFNumberSInt64Type",
254 "kCFNumberFloat32Type",
255 "kCFNumberFloat64Type",
256 "kCFNumberCharType",
257 "kCFNumberShortType",
258 "kCFNumberIntType",
259 "kCFNumberLongType",
260 "kCFNumberLongLongType",
261 "kCFNumberFloatType",
262 "kCFNumberDoubleType",
263 "kCFNumberCFIndexType",
264 "kCFNumberNSIntegerType",
265 "kCFNumberCGFloatType"
266 };
Mike Stump11289f42009-09-09 15:08:12 +0000267
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000268 return i <= kCFNumberCGFloatType ? Names[i-1] : "Invalid CFNumberType";
269}
270#endif
271
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000272void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE,
273 CheckerContext &C) const {
Ted Kremenek49b1e382012-01-26 21:29:00 +0000274 ProgramStateRef state = C.getState();
Anna Zaksc6aa5312011-12-01 05:57:37 +0000275 const FunctionDecl *FD = C.getCalleeDecl(CE);
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000276 if (!FD)
277 return;
278
279 ASTContext &Ctx = C.getASTContext();
280 if (!II)
281 II = &Ctx.Idents.get("CFNumberCreate");
282
283 if (FD->getIdentifier() != II || CE->getNumArgs() != 3)
284 return;
Mike Stump11289f42009-09-09 15:08:12 +0000285
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000286 // Get the value of the "theType" argument.
Ted Kremenek632e3b72012-01-06 22:09:28 +0000287 const LocationContext *LCtx = C.getLocationContext();
288 SVal TheTypeVal = state->getSVal(CE->getArg(1), LCtx);
Mike Stump11289f42009-09-09 15:08:12 +0000289
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000290 // FIXME: We really should allow ranges of valid theType values, and
291 // bifurcate the state appropriately.
Zhongxing Xu27f17422008-10-17 05:57:07 +0000292 nonloc::ConcreteInt* V = dyn_cast<nonloc::ConcreteInt>(&TheTypeVal);
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000293 if (!V)
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000294 return;
Mike Stump11289f42009-09-09 15:08:12 +0000295
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000296 uint64_t NumberKind = V->getValue().getLimitedValue();
297 Optional<uint64_t> TargetSize = GetCFNumberSize(Ctx, NumberKind);
Mike Stump11289f42009-09-09 15:08:12 +0000298
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000299 // FIXME: In some cases we can emit an error.
300 if (!TargetSize.isKnown())
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000301 return;
Mike Stump11289f42009-09-09 15:08:12 +0000302
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000303 // Look at the value of the integer being passed by reference. Essentially
304 // we want to catch cases where the value passed in is not equal to the
305 // size of the type being created.
Ted Kremenek632e3b72012-01-06 22:09:28 +0000306 SVal TheValueExpr = state->getSVal(CE->getArg(2), LCtx);
Mike Stump11289f42009-09-09 15:08:12 +0000307
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000308 // FIXME: Eventually we should handle arbitrary locations. We can do this
309 // by having an enhanced memory model that does low-level typing.
Zhongxing Xu27f17422008-10-17 05:57:07 +0000310 loc::MemRegionVal* LV = dyn_cast<loc::MemRegionVal>(&TheValueExpr);
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000311 if (!LV)
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000312 return;
Mike Stump11289f42009-09-09 15:08:12 +0000313
Ted Kremenek8df44b262011-08-12 20:02:48 +0000314 const TypedValueRegion* R = dyn_cast<TypedValueRegion>(LV->stripCasts());
Ted Kremenek87a7a452009-07-29 18:17:40 +0000315 if (!R)
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000316 return;
Ted Kremenek87a7a452009-07-29 18:17:40 +0000317
Zhongxing Xu8de0a3d2010-08-11 06:10:55 +0000318 QualType T = Ctx.getCanonicalType(R->getValueType());
Mike Stump11289f42009-09-09 15:08:12 +0000319
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000320 // FIXME: If the pointee isn't an integer type, should we flag a warning?
321 // People can do weird stuff with pointers.
Mike Stump11289f42009-09-09 15:08:12 +0000322
323 if (!T->isIntegerType())
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000324 return;
Mike Stump11289f42009-09-09 15:08:12 +0000325
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000326 uint64_t SourceSize = Ctx.getTypeSize(T);
Mike Stump11289f42009-09-09 15:08:12 +0000327
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000328 // CHECK: is SourceSize == TargetSize
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000329 if (SourceSize == TargetSize)
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000330 return;
Mike Stump11289f42009-09-09 15:08:12 +0000331
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000332 // Generate an error. Only generate a sink if 'SourceSize < TargetSize';
333 // otherwise generate a regular node.
334 //
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000335 // FIXME: We can actually create an abstract "CFNumber" object that has
336 // the bits initialized to the provided values.
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000337 //
Ted Kremenek750b7ac2010-12-20 21:19:09 +0000338 if (ExplodedNode *N = SourceSize < TargetSize ? C.generateSink()
Anna Zaksda4c8d62011-10-26 21:06:34 +0000339 : C.addTransition()) {
Dylan Noblesmith2c1dd272012-02-05 02:13:05 +0000340 SmallString<128> sbuf;
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000341 llvm::raw_svector_ostream os(sbuf);
342
343 os << (SourceSize == 8 ? "An " : "A ")
344 << SourceSize << " bit integer is used to initialize a CFNumber "
345 "object that represents "
346 << (TargetSize == 8 ? "an " : "a ")
347 << TargetSize << " bit integer. ";
348
349 if (SourceSize < TargetSize)
350 os << (TargetSize - SourceSize)
351 << " bits of the CFNumber value will be garbage." ;
352 else
353 os << (SourceSize - TargetSize)
354 << " bits of the input integer will be lost.";
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000355
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000356 if (!BT)
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000357 BT.reset(new APIMisuse("Bad use of CFNumberCreate"));
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000358
Anna Zaks3a6bdf82011-08-17 23:00:25 +0000359 BugReport *report = new BugReport(*BT, os.str(), N);
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000360 report->addRange(CE->getArg(2)->getSourceRange());
Jordan Rosee10d5a72012-11-02 01:53:40 +0000361 C.emitReport(report);
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000362 }
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000363}
364
Ted Kremenek1f352db2008-07-22 16:21:24 +0000365//===----------------------------------------------------------------------===//
Jordan Rose721567a2012-11-07 17:12:37 +0000366// CFRetain/CFRelease/CFMakeCollectable checking for null arguments.
Ted Kremenekc057f412009-07-14 00:43:42 +0000367//===----------------------------------------------------------------------===//
368
369namespace {
Argyrios Kyrtzidis6a5674f2011-03-01 01:16:21 +0000370class CFRetainReleaseChecker : public Checker< check::PreStmt<CallExpr> > {
Dylan Noblesmithe2778992012-02-05 02:12:40 +0000371 mutable OwningPtr<APIMisuse> BT;
Jordan Rose721567a2012-11-07 17:12:37 +0000372 mutable IdentifierInfo *Retain, *Release, *MakeCollectable;
Ted Kremenekc057f412009-07-14 00:43:42 +0000373public:
Jordan Rose721567a2012-11-07 17:12:37 +0000374 CFRetainReleaseChecker(): Retain(0), Release(0), MakeCollectable(0) {}
Ted Kremenek5ef32db2011-08-12 23:37:29 +0000375 void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
Ted Kremenekc057f412009-07-14 00:43:42 +0000376};
377} // end anonymous namespace
378
379
Ted Kremenek5ef32db2011-08-12 23:37:29 +0000380void CFRetainReleaseChecker::checkPreStmt(const CallExpr *CE,
381 CheckerContext &C) const {
Ted Kremenekc057f412009-07-14 00:43:42 +0000382 // If the CallExpr doesn't have exactly 1 argument just give up checking.
383 if (CE->getNumArgs() != 1)
Jordy Rose40c5c242010-07-06 02:34:42 +0000384 return;
Mike Stump11289f42009-09-09 15:08:12 +0000385
Ted Kremenek49b1e382012-01-26 21:29:00 +0000386 ProgramStateRef state = C.getState();
Anna Zaksc6aa5312011-12-01 05:57:37 +0000387 const FunctionDecl *FD = C.getCalleeDecl(CE);
Ted Kremenekc057f412009-07-14 00:43:42 +0000388 if (!FD)
Jordy Rose40c5c242010-07-06 02:34:42 +0000389 return;
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000390
391 if (!BT) {
392 ASTContext &Ctx = C.getASTContext();
393 Retain = &Ctx.Idents.get("CFRetain");
394 Release = &Ctx.Idents.get("CFRelease");
Jordan Rose721567a2012-11-07 17:12:37 +0000395 MakeCollectable = &Ctx.Idents.get("CFMakeCollectable");
396 BT.reset(
397 new APIMisuse("null passed to CFRetain/CFRelease/CFMakeCollectable"));
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000398 }
Mike Stump11289f42009-09-09 15:08:12 +0000399
Jordan Rose721567a2012-11-07 17:12:37 +0000400 // Check if we called CFRetain/CFRelease/CFMakeCollectable.
Mike Stump11289f42009-09-09 15:08:12 +0000401 const IdentifierInfo *FuncII = FD->getIdentifier();
Jordan Rose721567a2012-11-07 17:12:37 +0000402 if (!(FuncII == Retain || FuncII == Release || FuncII == MakeCollectable))
Jordy Rose40c5c242010-07-06 02:34:42 +0000403 return;
Mike Stump11289f42009-09-09 15:08:12 +0000404
Jordy Rose40c5c242010-07-06 02:34:42 +0000405 // FIXME: The rest of this just checks that the argument is non-null.
406 // It should probably be refactored and combined with AttrNonNullChecker.
407
408 // Get the argument's value.
409 const Expr *Arg = CE->getArg(0);
Ted Kremenek632e3b72012-01-06 22:09:28 +0000410 SVal ArgVal = state->getSVal(Arg, C.getLocationContext());
Jordy Rose40c5c242010-07-06 02:34:42 +0000411 DefinedSVal *DefArgVal = dyn_cast<DefinedSVal>(&ArgVal);
412 if (!DefArgVal)
413 return;
414
415 // Get a NULL value.
Ted Kremenek90af9092010-12-02 07:49:45 +0000416 SValBuilder &svalBuilder = C.getSValBuilder();
417 DefinedSVal zero = cast<DefinedSVal>(svalBuilder.makeZeroVal(Arg->getType()));
Jordy Rose40c5c242010-07-06 02:34:42 +0000418
419 // Make an expression asserting that they're equal.
Ted Kremenek90af9092010-12-02 07:49:45 +0000420 DefinedOrUnknownSVal ArgIsNull = svalBuilder.evalEQ(state, zero, *DefArgVal);
Jordy Rose40c5c242010-07-06 02:34:42 +0000421
422 // Are they equal?
Ted Kremenek49b1e382012-01-26 21:29:00 +0000423 ProgramStateRef stateTrue, stateFalse;
Ted Kremenekc5bea1e2010-12-01 22:16:56 +0000424 llvm::tie(stateTrue, stateFalse) = state->assume(ArgIsNull);
Jordy Rose40c5c242010-07-06 02:34:42 +0000425
426 if (stateTrue && !stateFalse) {
Ted Kremenek750b7ac2010-12-20 21:19:09 +0000427 ExplodedNode *N = C.generateSink(stateTrue);
Jordy Rose40c5c242010-07-06 02:34:42 +0000428 if (!N)
429 return;
430
Jordan Rose721567a2012-11-07 17:12:37 +0000431 const char *description;
432 if (FuncII == Retain)
433 description = "Null pointer argument in call to CFRetain";
434 else if (FuncII == Release)
435 description = "Null pointer argument in call to CFRelease";
436 else if (FuncII == MakeCollectable)
437 description = "Null pointer argument in call to CFMakeCollectable";
438 else
439 llvm_unreachable("impossible case");
Ted Kremenekc057f412009-07-14 00:43:42 +0000440
Anna Zaks3a6bdf82011-08-17 23:00:25 +0000441 BugReport *report = new BugReport(*BT, description, N);
Jordy Rose40c5c242010-07-06 02:34:42 +0000442 report->addRange(Arg->getSourceRange());
Jordan Rosea0f7d352012-08-28 00:50:51 +0000443 bugreporter::trackNullOrUndefValue(N, Arg, *report);
Jordan Rosee10d5a72012-11-02 01:53:40 +0000444 C.emitReport(report);
Jordy Rose40c5c242010-07-06 02:34:42 +0000445 return;
Ted Kremenekc057f412009-07-14 00:43:42 +0000446 }
447
Jordy Rose40c5c242010-07-06 02:34:42 +0000448 // From here on, we know the argument is non-null.
Anna Zaksda4c8d62011-10-26 21:06:34 +0000449 C.addTransition(stateFalse);
Ted Kremenekc057f412009-07-14 00:43:42 +0000450}
451
452//===----------------------------------------------------------------------===//
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000453// Check for sending 'retain', 'release', or 'autorelease' directly to a Class.
454//===----------------------------------------------------------------------===//
455
456namespace {
Argyrios Kyrtzidis6a5674f2011-03-01 01:16:21 +0000457class ClassReleaseChecker : public Checker<check::PreObjCMessage> {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000458 mutable Selector releaseS;
459 mutable Selector retainS;
460 mutable Selector autoreleaseS;
461 mutable Selector drainS;
Dylan Noblesmithe2778992012-02-05 02:12:40 +0000462 mutable OwningPtr<BugType> BT;
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000463
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000464public:
Jordan Rose547060b2012-07-02 19:28:04 +0000465 void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000466};
467}
468
Jordan Rose547060b2012-07-02 19:28:04 +0000469void ClassReleaseChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000470 CheckerContext &C) const {
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000471
472 if (!BT) {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000473 BT.reset(new APIMisuse("message incorrectly sent to class instead of class "
474 "instance"));
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000475
476 ASTContext &Ctx = C.getASTContext();
477 releaseS = GetNullarySelector("release", Ctx);
478 retainS = GetNullarySelector("retain", Ctx);
479 autoreleaseS = GetNullarySelector("autorelease", Ctx);
480 drainS = GetNullarySelector("drain", Ctx);
481 }
482
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +0000483 if (msg.isInstanceMessage())
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000484 return;
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +0000485 const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
486 assert(Class);
Douglas Gregor9a129192010-04-21 00:45:42 +0000487
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +0000488 Selector S = msg.getSelector();
Benjamin Kramer7d875c72009-11-20 10:03:00 +0000489 if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000490 return;
491
Anna Zaksda4c8d62011-10-26 21:06:34 +0000492 if (ExplodedNode *N = C.addTransition()) {
Dylan Noblesmith2c1dd272012-02-05 02:13:05 +0000493 SmallString<200> buf;
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000494 llvm::raw_svector_ostream os(buf);
Ted Kremenekf5735152009-11-23 22:22:01 +0000495
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000496 os << "The '" << S.getAsString() << "' message should be sent to instances "
497 "of class '" << Class->getName()
498 << "' and not the class directly";
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000499
Anna Zaks3a6bdf82011-08-17 23:00:25 +0000500 BugReport *report = new BugReport(*BT, os.str(), N);
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +0000501 report->addRange(msg.getSourceRange());
Jordan Rosee10d5a72012-11-02 01:53:40 +0000502 C.emitReport(report);
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000503 }
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000504}
505
506//===----------------------------------------------------------------------===//
Anders Carlssond91d5f12011-03-13 20:35:21 +0000507// Check for passing non-Objective-C types to variadic methods that expect
508// only Objective-C types.
509//===----------------------------------------------------------------------===//
510
511namespace {
512class VariadicMethodTypeChecker : public Checker<check::PreObjCMessage> {
513 mutable Selector arrayWithObjectsS;
514 mutable Selector dictionaryWithObjectsAndKeysS;
515 mutable Selector setWithObjectsS;
Jordy Rosec0230d72012-04-06 19:06:01 +0000516 mutable Selector orderedSetWithObjectsS;
Anders Carlssond91d5f12011-03-13 20:35:21 +0000517 mutable Selector initWithObjectsS;
518 mutable Selector initWithObjectsAndKeysS;
Dylan Noblesmithe2778992012-02-05 02:12:40 +0000519 mutable OwningPtr<BugType> BT;
Anders Carlssond91d5f12011-03-13 20:35:21 +0000520
Jordan Rose547060b2012-07-02 19:28:04 +0000521 bool isVariadicMessage(const ObjCMethodCall &msg) const;
Anders Carlssond91d5f12011-03-13 20:35:21 +0000522
523public:
Jordan Rose547060b2012-07-02 19:28:04 +0000524 void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
Anders Carlssond91d5f12011-03-13 20:35:21 +0000525};
526}
527
528/// isVariadicMessage - Returns whether the given message is a variadic message,
529/// where all arguments must be Objective-C types.
530bool
Jordan Rose547060b2012-07-02 19:28:04 +0000531VariadicMethodTypeChecker::isVariadicMessage(const ObjCMethodCall &msg) const {
532 const ObjCMethodDecl *MD = msg.getDecl();
Ted Kremenekced5fea2011-04-12 21:47:05 +0000533
534 if (!MD || !MD->isVariadic() || isa<ObjCProtocolDecl>(MD->getDeclContext()))
Anders Carlssond91d5f12011-03-13 20:35:21 +0000535 return false;
536
537 Selector S = msg.getSelector();
538
539 if (msg.isInstanceMessage()) {
540 // FIXME: Ideally we'd look at the receiver interface here, but that's not
541 // useful for init, because alloc returns 'id'. In theory, this could lead
542 // to false positives, for example if there existed a class that had an
543 // initWithObjects: implementation that does accept non-Objective-C pointer
544 // types, but the chance of that happening is pretty small compared to the
545 // gains that this analysis gives.
546 const ObjCInterfaceDecl *Class = MD->getClassInterface();
547
Jordan Rose3ba8ae32012-06-11 16:40:37 +0000548 switch (findKnownClass(Class)) {
549 case FC_NSArray:
550 case FC_NSOrderedSet:
551 case FC_NSSet:
552 return S == initWithObjectsS;
553 case FC_NSDictionary:
554 return S == initWithObjectsAndKeysS;
555 default:
556 return false;
557 }
Anders Carlssond91d5f12011-03-13 20:35:21 +0000558 } else {
559 const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
560
Jordan Rose3ba8ae32012-06-11 16:40:37 +0000561 switch (findKnownClass(Class)) {
562 case FC_NSArray:
563 return S == arrayWithObjectsS;
564 case FC_NSOrderedSet:
565 return S == orderedSetWithObjectsS;
566 case FC_NSSet:
567 return S == setWithObjectsS;
568 case FC_NSDictionary:
569 return S == dictionaryWithObjectsAndKeysS;
570 default:
571 return false;
572 }
Anders Carlssond91d5f12011-03-13 20:35:21 +0000573 }
Anders Carlssond91d5f12011-03-13 20:35:21 +0000574}
575
Jordan Rose547060b2012-07-02 19:28:04 +0000576void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
Anders Carlssond91d5f12011-03-13 20:35:21 +0000577 CheckerContext &C) const {
578 if (!BT) {
579 BT.reset(new APIMisuse("Arguments passed to variadic method aren't all "
580 "Objective-C pointer types"));
581
582 ASTContext &Ctx = C.getASTContext();
583 arrayWithObjectsS = GetUnarySelector("arrayWithObjects", Ctx);
584 dictionaryWithObjectsAndKeysS =
585 GetUnarySelector("dictionaryWithObjectsAndKeys", Ctx);
586 setWithObjectsS = GetUnarySelector("setWithObjects", Ctx);
Jordy Rosec0230d72012-04-06 19:06:01 +0000587 orderedSetWithObjectsS = GetUnarySelector("orderedSetWithObjects", Ctx);
Anders Carlssond91d5f12011-03-13 20:35:21 +0000588
589 initWithObjectsS = GetUnarySelector("initWithObjects", Ctx);
590 initWithObjectsAndKeysS = GetUnarySelector("initWithObjectsAndKeys", Ctx);
591 }
592
593 if (!isVariadicMessage(msg))
594 return;
595
596 // We are not interested in the selector arguments since they have
597 // well-defined types, so the compiler will issue a warning for them.
598 unsigned variadicArgsBegin = msg.getSelector().getNumArgs();
599
600 // We're not interested in the last argument since it has to be nil or the
601 // compiler would have issued a warning for it elsewhere.
602 unsigned variadicArgsEnd = msg.getNumArgs() - 1;
603
604 if (variadicArgsEnd <= variadicArgsBegin)
605 return;
606
607 // Verify that all arguments have Objective-C types.
Ted Kremenek066b2262011-03-14 19:50:37 +0000608 llvm::Optional<ExplodedNode*> errorNode;
Ted Kremenek49b1e382012-01-26 21:29:00 +0000609 ProgramStateRef state = C.getState();
Ted Kremenek066b2262011-03-14 19:50:37 +0000610
Anders Carlssond91d5f12011-03-13 20:35:21 +0000611 for (unsigned I = variadicArgsBegin; I != variadicArgsEnd; ++I) {
Jordan Rose547060b2012-07-02 19:28:04 +0000612 QualType ArgTy = msg.getArgExpr(I)->getType();
Anders Carlssond91d5f12011-03-13 20:35:21 +0000613 if (ArgTy->isObjCObjectPointerType())
614 continue;
615
Anders Carlssond1f65f62011-04-19 01:16:46 +0000616 // Block pointers are treaded as Objective-C pointers.
617 if (ArgTy->isBlockPointerType())
618 continue;
619
Ted Kremenek4ceebbf2011-03-16 00:22:51 +0000620 // Ignore pointer constants.
Jordan Rose547060b2012-07-02 19:28:04 +0000621 if (isa<loc::ConcreteInt>(msg.getArgSVal(I)))
Ted Kremenek4ceebbf2011-03-16 00:22:51 +0000622 continue;
Ted Kremenek6fa1dae2011-03-17 04:01:35 +0000623
Ted Kremenek70727342011-03-17 04:10:25 +0000624 // Ignore pointer types annotated with 'NSObject' attribute.
625 if (C.getASTContext().isObjCNSObjectType(ArgTy))
626 continue;
627
Ted Kremenek6fa1dae2011-03-17 04:01:35 +0000628 // Ignore CF references, which can be toll-free bridged.
Ted Kremenekc85964e2011-07-16 19:50:32 +0000629 if (coreFoundation::isCFObjectRef(ArgTy))
Ted Kremenek6fa1dae2011-03-17 04:01:35 +0000630 continue;
Ted Kremenek4ceebbf2011-03-16 00:22:51 +0000631
Ted Kremenek066b2262011-03-14 19:50:37 +0000632 // Generate only one error node to use for all bug reports.
Jordan Rose547060b2012-07-02 19:28:04 +0000633 if (!errorNode.hasValue())
Anna Zaksda4c8d62011-10-26 21:06:34 +0000634 errorNode = C.addTransition();
Ted Kremenek066b2262011-03-14 19:50:37 +0000635
636 if (!errorNode.getValue())
Anders Carlssond91d5f12011-03-13 20:35:21 +0000637 continue;
638
Dylan Noblesmith2c1dd272012-02-05 02:13:05 +0000639 SmallString<128> sbuf;
Anders Carlssond91d5f12011-03-13 20:35:21 +0000640 llvm::raw_svector_ostream os(sbuf);
641
Jordan Rose547060b2012-07-02 19:28:04 +0000642 StringRef TypeName = GetReceiverInterfaceName(msg);
643 if (!TypeName.empty())
Anders Carlssond91d5f12011-03-13 20:35:21 +0000644 os << "Argument to '" << TypeName << "' method '";
645 else
646 os << "Argument to method '";
647
648 os << msg.getSelector().getAsString()
Jordan Rose547060b2012-07-02 19:28:04 +0000649 << "' should be an Objective-C pointer type, not '";
650 ArgTy.print(os, C.getLangOpts());
651 os << "'";
Anders Carlssond91d5f12011-03-13 20:35:21 +0000652
Jordan Rose547060b2012-07-02 19:28:04 +0000653 BugReport *R = new BugReport(*BT, os.str(), errorNode.getValue());
Anders Carlssond91d5f12011-03-13 20:35:21 +0000654 R->addRange(msg.getArgSourceRange(I));
Jordan Rosee10d5a72012-11-02 01:53:40 +0000655 C.emitReport(R);
Anders Carlssond91d5f12011-03-13 20:35:21 +0000656 }
657}
658
659//===----------------------------------------------------------------------===//
Jordan Roseefef7602012-06-11 16:40:41 +0000660// Improves the modeling of loops over Cocoa collections.
661//===----------------------------------------------------------------------===//
662
663namespace {
664class ObjCLoopChecker
665 : public Checker<check::PostStmt<ObjCForCollectionStmt> > {
666
667public:
668 void checkPostStmt(const ObjCForCollectionStmt *FCS, CheckerContext &C) const;
669};
670}
671
672static bool isKnownNonNilCollectionType(QualType T) {
673 const ObjCObjectPointerType *PT = T->getAs<ObjCObjectPointerType>();
674 if (!PT)
675 return false;
676
677 const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();
678 if (!ID)
679 return false;
680
681 switch (findKnownClass(ID)) {
682 case FC_NSArray:
683 case FC_NSDictionary:
684 case FC_NSEnumerator:
685 case FC_NSOrderedSet:
686 case FC_NSSet:
687 return true;
688 default:
689 return false;
690 }
691}
692
693void ObjCLoopChecker::checkPostStmt(const ObjCForCollectionStmt *FCS,
694 CheckerContext &C) const {
695 ProgramStateRef State = C.getState();
696
697 // Check if this is the branch for the end of the loop.
698 SVal CollectionSentinel = State->getSVal(FCS, C.getLocationContext());
699 if (CollectionSentinel.isZeroConstant())
700 return;
701
702 // See if the collection is one where we /know/ the elements are non-nil.
703 const Expr *Collection = FCS->getCollection();
704 if (!isKnownNonNilCollectionType(Collection->getType()))
705 return;
706
707 // FIXME: Copied from ExprEngineObjC.
708 const Stmt *Element = FCS->getElement();
709 SVal ElementVar;
710 if (const DeclStmt *DS = dyn_cast<DeclStmt>(Element)) {
711 const VarDecl *ElemDecl = cast<VarDecl>(DS->getSingleDecl());
712 assert(ElemDecl->getInit() == 0);
713 ElementVar = State->getLValue(ElemDecl, C.getLocationContext());
714 } else {
715 ElementVar = State->getSVal(Element, C.getLocationContext());
716 }
717
718 if (!isa<Loc>(ElementVar))
719 return;
720
721 // Go ahead and assume the value is non-nil.
722 SVal Val = State->getSVal(cast<Loc>(ElementVar));
723 State = State->assume(cast<DefinedOrUnknownSVal>(Val), true);
724 C.addTransition(State);
725}
726
Anna Zaks5a5a1752012-08-22 21:19:56 +0000727namespace {
728/// \class ObjCNonNilReturnValueChecker
Anna Zaks4818bbe2012-08-30 19:40:52 +0000729/// \brief The checker restricts the return values of APIs known to
730/// never (or almost never) return 'nil'.
Anna Zaks5a5a1752012-08-22 21:19:56 +0000731class ObjCNonNilReturnValueChecker
732 : public Checker<check::PostObjCMessage> {
733 mutable bool Initialized;
734 mutable Selector ObjectAtIndex;
735 mutable Selector ObjectAtIndexedSubscript;
Anna Zaks9159e162012-08-22 22:47:58 +0000736
Anna Zaks5a5a1752012-08-22 21:19:56 +0000737public:
Anna Zaks9159e162012-08-22 22:47:58 +0000738 ObjCNonNilReturnValueChecker() : Initialized(false) {}
Anna Zaks5a5a1752012-08-22 21:19:56 +0000739 void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
740};
741}
742
Benjamin Kramer199f8da2012-09-10 11:57:16 +0000743static ProgramStateRef assumeExprIsNonNull(const Expr *NonNullExpr,
744 ProgramStateRef State,
745 CheckerContext &C) {
Anna Zaks4818bbe2012-08-30 19:40:52 +0000746 SVal Val = State->getSVal(NonNullExpr, C.getLocationContext());
Anna Zaksb504f442012-08-30 22:42:41 +0000747 if (DefinedOrUnknownSVal *DV = dyn_cast<DefinedOrUnknownSVal>(&Val))
Anna Zaks830c48e2012-08-30 22:55:32 +0000748 return State->assume(*DV, true);
Anna Zaksb504f442012-08-30 22:42:41 +0000749 return State;
Anna Zaks4818bbe2012-08-30 19:40:52 +0000750}
751
Anna Zaks5a5a1752012-08-22 21:19:56 +0000752void ObjCNonNilReturnValueChecker::checkPostObjCMessage(const ObjCMethodCall &M,
753 CheckerContext &C)
Anna Zaks4818bbe2012-08-30 19:40:52 +0000754 const {
Anna Zaks5a5a1752012-08-22 21:19:56 +0000755 ProgramStateRef State = C.getState();
756
757 if (!Initialized) {
758 ASTContext &Ctx = C.getASTContext();
759 ObjectAtIndex = GetUnarySelector("objectAtIndex", Ctx);
760 ObjectAtIndexedSubscript = GetUnarySelector("objectAtIndexedSubscript", Ctx);
761 }
762
763 // Check the receiver type.
764 if (const ObjCInterfaceDecl *Interface = M.getReceiverInterface()) {
Anna Zaks4818bbe2012-08-30 19:40:52 +0000765
766 // Assume that object returned from '[self init]' or '[super init]' is not
767 // 'nil' if we are processing an inlined function/method.
768 //
769 // A defensive callee will (and should) check if the object returned by
770 // '[super init]' is 'nil' before doing it's own initialization. However,
771 // since 'nil' is rarely returned in practice, we should not warn when the
772 // caller to the defensive constructor uses the object in contexts where
773 // 'nil' is not accepted.
Anna Zaks49bb6502012-11-06 04:20:54 +0000774 if (!C.inTopFrame() && M.getDecl() &&
Anna Zaks4818bbe2012-08-30 19:40:52 +0000775 M.getDecl()->getMethodFamily() == OMF_init &&
776 M.isReceiverSelfOrSuper()) {
777 State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
778 }
779
780 // Objects returned from
781 // [NSArray|NSOrderedSet]::[ObjectAtIndex|ObjectAtIndexedSubscript]
782 // are never 'nil'.
Anna Zaks5a5a1752012-08-22 21:19:56 +0000783 FoundationClass Cl = findKnownClass(Interface);
784 if (Cl == FC_NSArray || Cl == FC_NSOrderedSet) {
785 Selector Sel = M.getSelector();
786 if (Sel == ObjectAtIndex || Sel == ObjectAtIndexedSubscript) {
787 // Go ahead and assume the value is non-nil.
Anna Zaks4818bbe2012-08-30 19:40:52 +0000788 State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
Anna Zaks5a5a1752012-08-22 21:19:56 +0000789 }
790 }
791 }
Anna Zaks4818bbe2012-08-30 19:40:52 +0000792 C.addTransition(State);
Anna Zaks5a5a1752012-08-22 21:19:56 +0000793}
Jordan Roseefef7602012-06-11 16:40:41 +0000794
795//===----------------------------------------------------------------------===//
Ted Kremenek1f352db2008-07-22 16:21:24 +0000796// Check registration.
Ted Kremenekc057f412009-07-14 00:43:42 +0000797//===----------------------------------------------------------------------===//
Argyrios Kyrtzidis9d4d4f92011-02-16 01:40:52 +0000798
Argyrios Kyrtzidis507ff532011-02-17 21:39:17 +0000799void ento::registerNilArgChecker(CheckerManager &mgr) {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000800 mgr.registerChecker<NilArgChecker>();
Argyrios Kyrtzidis9d4d4f92011-02-16 01:40:52 +0000801}
802
Argyrios Kyrtzidis507ff532011-02-17 21:39:17 +0000803void ento::registerCFNumberCreateChecker(CheckerManager &mgr) {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000804 mgr.registerChecker<CFNumberCreateChecker>();
Argyrios Kyrtzidis9d4d4f92011-02-16 01:40:52 +0000805}
806
Argyrios Kyrtzidis507ff532011-02-17 21:39:17 +0000807void ento::registerCFRetainReleaseChecker(CheckerManager &mgr) {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000808 mgr.registerChecker<CFRetainReleaseChecker>();
Ted Kremenek1f352db2008-07-22 16:21:24 +0000809}
Argyrios Kyrtzidis507ff532011-02-17 21:39:17 +0000810
811void ento::registerClassReleaseChecker(CheckerManager &mgr) {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000812 mgr.registerChecker<ClassReleaseChecker>();
Argyrios Kyrtzidis507ff532011-02-17 21:39:17 +0000813}
Anders Carlssond91d5f12011-03-13 20:35:21 +0000814
815void ento::registerVariadicMethodTypeChecker(CheckerManager &mgr) {
816 mgr.registerChecker<VariadicMethodTypeChecker>();
817}
Jordan Roseefef7602012-06-11 16:40:41 +0000818
819void ento::registerObjCLoopChecker(CheckerManager &mgr) {
820 mgr.registerChecker<ObjCLoopChecker>();
821}
Anna Zaks5a5a1752012-08-22 21:19:56 +0000822
823void ento::registerObjCNonNilReturnValueChecker(CheckerManager &mgr) {
824 mgr.registerChecker<ObjCNonNilReturnValueChecker>();
825}