blob: 533a324e7507925f988529bed66dbf74e6123cbd [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"
Chandler Carruth3a022472012-12-04 09:13:33 +000017#include "clang/AST/ASTContext.h"
18#include "clang/AST/DeclObjC.h"
19#include "clang/AST/Expr.h"
20#include "clang/AST/ExprObjC.h"
21#include "clang/AST/StmtObjC.h"
Ted Kremenek6fa1dae2011-03-17 04:01:35 +000022#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
Chandler Carruth3a022472012-12-04 09:13:33 +000023#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
Argyrios Kyrtzidis6a5674f2011-03-01 01:16:21 +000024#include "clang/StaticAnalyzer/Core/Checker.h"
Argyrios Kyrtzidis507ff532011-02-17 21:39:17 +000025#include "clang/StaticAnalyzer/Core/CheckerManager.h"
Jordan Rose4f7df9b2012-07-26 21:39:41 +000026#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
Argyrios Kyrtzidisdff865d2011-02-23 01:05:36 +000027#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
Ted Kremenekf8cbac42011-02-10 01:03:03 +000028#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
Ted Kremenekf8cbac42011-02-10 01:03:03 +000029#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
Ted Kremenekf8cbac42011-02-10 01:03:03 +000030#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
Chandler Carruth3a022472012-12-04 09:13:33 +000031#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.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"
Benjamin Kramer444a1302012-12-01 17:12:56 +000034#include "llvm/Support/raw_ostream.h"
Ted Kremenekc0414922008-03-27 07:25:52 +000035
Ted Kremenekc0414922008-03-27 07:25:52 +000036using namespace clang;
Ted Kremenek98857c92010-12-23 07:20:52 +000037using namespace ento;
Ted Kremeneka4d60b62008-03-27 17:17:22 +000038
Ted Kremenekbd2c8002010-10-20 23:38:56 +000039namespace {
40class APIMisuse : public BugType {
41public:
42 APIMisuse(const char* name) : BugType(name, "API Misuse (Apple)") {}
43};
44} // end anonymous namespace
45
46//===----------------------------------------------------------------------===//
47// Utility functions.
48//===----------------------------------------------------------------------===//
49
Jordan Rose547060b2012-07-02 19:28:04 +000050static StringRef GetReceiverInterfaceName(const ObjCMethodCall &msg) {
Anders Carlsson3c50aea2011-03-08 20:05:26 +000051 if (const ObjCInterfaceDecl *ID = msg.getReceiverInterface())
Jordan Rose547060b2012-07-02 19:28:04 +000052 return ID->getIdentifier()->getName();
53 return StringRef();
Ted Kremenek276278e2008-03-27 22:05:32 +000054}
Ted Kremeneka4d60b62008-03-27 17:17:22 +000055
Jordan Rose3ba8ae32012-06-11 16:40:37 +000056enum FoundationClass {
57 FC_None,
58 FC_NSArray,
59 FC_NSDictionary,
60 FC_NSEnumerator,
61 FC_NSOrderedSet,
62 FC_NSSet,
63 FC_NSString
64};
Anders Carlsson3c50aea2011-03-08 20:05:26 +000065
Jordan Rose3ba8ae32012-06-11 16:40:37 +000066static FoundationClass findKnownClass(const ObjCInterfaceDecl *ID) {
67 static llvm::StringMap<FoundationClass> Classes;
68 if (Classes.empty()) {
69 Classes["NSArray"] = FC_NSArray;
70 Classes["NSDictionary"] = FC_NSDictionary;
71 Classes["NSEnumerator"] = FC_NSEnumerator;
72 Classes["NSOrderedSet"] = FC_NSOrderedSet;
73 Classes["NSSet"] = FC_NSSet;
74 Classes["NSString"] = FC_NSString;
75 }
Anders Carlsson3c50aea2011-03-08 20:05:26 +000076
Jordan Rose3ba8ae32012-06-11 16:40:37 +000077 // FIXME: Should we cache this at all?
78 FoundationClass result = Classes.lookup(ID->getIdentifier()->getName());
79 if (result == FC_None)
80 if (const ObjCInterfaceDecl *Super = ID->getSuperClass())
81 return findKnownClass(Super);
82
83 return result;
Ted Kremenekc0414922008-03-27 07:25:52 +000084}
85
86//===----------------------------------------------------------------------===//
Ted Kremenekbd2c8002010-10-20 23:38:56 +000087// NilArgChecker - Check for prohibited nil arguments to ObjC method calls.
Ted Kremenekc0414922008-03-27 07:25:52 +000088//===----------------------------------------------------------------------===//
89
Benjamin Kramer2fc373e2010-10-22 16:33:16 +000090namespace {
Argyrios Kyrtzidis6a5674f2011-03-01 01:16:21 +000091 class NilArgChecker : public Checker<check::PreObjCMessage> {
Dylan Noblesmithe2778992012-02-05 02:12:40 +000092 mutable OwningPtr<APIMisuse> BT;
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +000093
Anna Zaks130df4b2013-03-23 00:39:21 +000094 void WarnIfNilArg(CheckerContext &C,
95 const ObjCMethodCall &msg, unsigned Arg,
96 FoundationClass Class,
97 bool CanBeSubscript = false) const;
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +000098
Benjamin Kramer2fc373e2010-10-22 16:33:16 +000099 public:
Jordan Rose547060b2012-07-02 19:28:04 +0000100 void checkPreObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
Benjamin Kramer2fc373e2010-10-22 16:33:16 +0000101 };
102}
Mike Stump11289f42009-09-09 15:08:12 +0000103
Anna Zaks130df4b2013-03-23 00:39:21 +0000104void NilArgChecker::WarnIfNilArg(CheckerContext &C,
105 const ObjCMethodCall &msg,
106 unsigned int Arg,
107 FoundationClass Class,
108 bool CanBeSubscript) const {
109 // Check if the argument is nil.
110 ProgramStateRef State = C.getState();
111 if (!State->isNull(msg.getArgSVal(Arg)).isConstrainedTrue())
112 return;
113
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000114 if (!BT)
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000115 BT.reset(new APIMisuse("nil argument"));
Anna Zaks130df4b2013-03-23 00:39:21 +0000116
Ted Kremenek750b7ac2010-12-20 21:19:09 +0000117 if (ExplodedNode *N = C.generateSink()) {
Dylan Noblesmith2c1dd272012-02-05 02:13:05 +0000118 SmallString<128> sbuf;
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000119 llvm::raw_svector_ostream os(sbuf);
Anna Zaks130df4b2013-03-23 00:39:21 +0000120
121 if (CanBeSubscript && msg.getMessageKind() == OCM_Subscript) {
122
123 if (Class == FC_NSArray) {
124 os << "Array element cannot be nil";
125 } else if (Class == FC_NSDictionary) {
126 if (Arg == 0)
127 os << "Dictionary object cannot be nil";
128 else {
129 assert(Arg == 1);
130 os << "Dictionary key cannot be nil";
131 }
132 } else
133 llvm_unreachable("Missing foundation class for the subscript expr");
134
135 } else {
136 os << "Argument to '" << GetReceiverInterfaceName(msg) << "' method '"
137 << msg.getSelector().getAsString() << "' cannot be nil";
138 }
Mike Stump11289f42009-09-09 15:08:12 +0000139
Anna Zaks3a6bdf82011-08-17 23:00:25 +0000140 BugReport *R = new BugReport(*BT, os.str(), N);
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +0000141 R->addRange(msg.getArgSourceRange(Arg));
Anna Zaksbd8f60d2013-03-26 23:58:49 +0000142 bugreporter::trackNullOrUndefValue(N, msg.getArgExpr(Arg), *R);
Jordan Rosee10d5a72012-11-02 01:53:40 +0000143 C.emitReport(R);
Ted Kremenek276278e2008-03-27 22:05:32 +0000144 }
Ted Kremenek276278e2008-03-27 22:05:32 +0000145}
146
Jordan Rose547060b2012-07-02 19:28:04 +0000147void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000148 CheckerContext &C) const {
Anders Carlsson3c50aea2011-03-08 20:05:26 +0000149 const ObjCInterfaceDecl *ID = msg.getReceiverInterface();
150 if (!ID)
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000151 return;
Anna Zaks6457ad22013-03-18 20:46:56 +0000152
153 FoundationClass Class = findKnownClass(ID);
154
155 static const unsigned InvalidArgIndex = UINT_MAX;
156 unsigned Arg = InvalidArgIndex;
Anna Zaks130df4b2013-03-23 00:39:21 +0000157 bool CanBeSubscript = false;
158
Anna Zaks6457ad22013-03-18 20:46:56 +0000159 if (Class == FC_NSString) {
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +0000160 Selector S = msg.getSelector();
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000161
162 if (S.isUnarySelector())
163 return;
164
165 // FIXME: This is going to be really slow doing these checks with
166 // lexical comparisons.
167
168 std::string NameStr = S.getAsString();
Chris Lattner0e62c1c2011-07-23 10:55:15 +0000169 StringRef Name(NameStr);
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000170 assert(!Name.empty());
171
172 // FIXME: Checking for initWithFormat: will not work in most cases
173 // yet because [NSString alloc] returns id, not NSString*. We will
174 // need support for tracking expected-type information in the analyzer
175 // to find these errors.
176 if (Name == "caseInsensitiveCompare:" ||
177 Name == "compare:" ||
178 Name == "compare:options:" ||
179 Name == "compare:options:range:" ||
180 Name == "compare:options:range:locale:" ||
181 Name == "componentsSeparatedByCharactersInSet:" ||
182 Name == "initWithFormat:") {
Anna Zaks6457ad22013-03-18 20:46:56 +0000183 Arg = 0;
184 }
185 } else if (Class == FC_NSArray) {
186 Selector S = msg.getSelector();
187
188 if (S.isUnarySelector())
189 return;
190
191 if (S.getNameForSlot(0).equals("addObject")) {
192 Arg = 0;
193 } else if (S.getNameForSlot(0).equals("insertObject") &&
194 S.getNameForSlot(1).equals("atIndex")) {
195 Arg = 0;
196 } else if (S.getNameForSlot(0).equals("replaceObjectAtIndex") &&
197 S.getNameForSlot(1).equals("withObject")) {
198 Arg = 1;
199 } else if (S.getNameForSlot(0).equals("setObject") &&
200 S.getNameForSlot(1).equals("atIndexedSubscript")) {
201 Arg = 0;
Anna Zaks130df4b2013-03-23 00:39:21 +0000202 CanBeSubscript = true;
Anna Zaks6457ad22013-03-18 20:46:56 +0000203 } else if (S.getNameForSlot(0).equals("arrayByAddingObject")) {
204 Arg = 0;
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000205 }
Anna Zaks130df4b2013-03-23 00:39:21 +0000206 } else if (Class == FC_NSDictionary) {
207 Selector S = msg.getSelector();
208
209 if (S.isUnarySelector())
210 return;
211
212 if (S.getNameForSlot(0).equals("dictionaryWithObject") &&
213 S.getNameForSlot(1).equals("forKey")) {
214 Arg = 0;
215 WarnIfNilArg(C, msg, /* Arg */1, Class);
216 } else if (S.getNameForSlot(0).equals("setObject") &&
217 S.getNameForSlot(1).equals("forKey")) {
218 Arg = 0;
219 WarnIfNilArg(C, msg, /* Arg */1, Class);
220 } else if (S.getNameForSlot(0).equals("setObject") &&
221 S.getNameForSlot(1).equals("forKeyedSubscript")) {
222 CanBeSubscript = true;
223 Arg = 0;
224 WarnIfNilArg(C, msg, /* Arg */1, Class, CanBeSubscript);
225 } else if (S.getNameForSlot(0).equals("removeObjectForKey")) {
226 Arg = 0;
227 }
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000228 }
Anna Zaks6457ad22013-03-18 20:46:56 +0000229
Anna Zaks130df4b2013-03-23 00:39:21 +0000230
Anna Zaks6457ad22013-03-18 20:46:56 +0000231 // If argument is '0', report a warning.
Anna Zaks130df4b2013-03-23 00:39:21 +0000232 if ((Arg != InvalidArgIndex))
233 WarnIfNilArg(C, msg, Arg, Class, CanBeSubscript);
Anna Zaks6457ad22013-03-18 20:46:56 +0000234
Ted Kremenekc0414922008-03-27 07:25:52 +0000235}
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000236
237//===----------------------------------------------------------------------===//
238// Error reporting.
239//===----------------------------------------------------------------------===//
240
241namespace {
Argyrios Kyrtzidis6a5674f2011-03-01 01:16:21 +0000242class CFNumberCreateChecker : public Checker< check::PreStmt<CallExpr> > {
Dylan Noblesmithe2778992012-02-05 02:12:40 +0000243 mutable OwningPtr<APIMisuse> BT;
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000244 mutable IdentifierInfo* II;
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000245public:
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000246 CFNumberCreateChecker() : II(0) {}
247
248 void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
249
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000250private:
Ted Kremenek5ef32db2011-08-12 23:37:29 +0000251 void EmitError(const TypedRegion* R, const Expr *Ex,
Mike Stump11289f42009-09-09 15:08:12 +0000252 uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind);
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000253};
254} // end anonymous namespace
255
256enum CFNumberType {
257 kCFNumberSInt8Type = 1,
258 kCFNumberSInt16Type = 2,
259 kCFNumberSInt32Type = 3,
260 kCFNumberSInt64Type = 4,
261 kCFNumberFloat32Type = 5,
262 kCFNumberFloat64Type = 6,
263 kCFNumberCharType = 7,
264 kCFNumberShortType = 8,
265 kCFNumberIntType = 9,
266 kCFNumberLongType = 10,
267 kCFNumberLongLongType = 11,
268 kCFNumberFloatType = 12,
269 kCFNumberDoubleType = 13,
270 kCFNumberCFIndexType = 14,
271 kCFNumberNSIntegerType = 15,
272 kCFNumberCGFloatType = 16
273};
274
Ted Kremenek5ef32db2011-08-12 23:37:29 +0000275static Optional<uint64_t> GetCFNumberSize(ASTContext &Ctx, uint64_t i) {
Nuno Lopescfca1f02009-12-23 17:49:57 +0000276 static const unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 };
Mike Stump11289f42009-09-09 15:08:12 +0000277
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000278 if (i < kCFNumberCharType)
279 return FixedSize[i-1];
Mike Stump11289f42009-09-09 15:08:12 +0000280
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000281 QualType T;
Mike Stump11289f42009-09-09 15:08:12 +0000282
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000283 switch (i) {
284 case kCFNumberCharType: T = Ctx.CharTy; break;
285 case kCFNumberShortType: T = Ctx.ShortTy; break;
286 case kCFNumberIntType: T = Ctx.IntTy; break;
287 case kCFNumberLongType: T = Ctx.LongTy; break;
288 case kCFNumberLongLongType: T = Ctx.LongLongTy; break;
289 case kCFNumberFloatType: T = Ctx.FloatTy; break;
290 case kCFNumberDoubleType: T = Ctx.DoubleTy; break;
291 case kCFNumberCFIndexType:
292 case kCFNumberNSIntegerType:
293 case kCFNumberCGFloatType:
Mike Stump11289f42009-09-09 15:08:12 +0000294 // FIXME: We need a way to map from names to Type*.
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000295 default:
David Blaikie7a30dc52013-02-21 01:47:18 +0000296 return None;
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000297 }
Mike Stump11289f42009-09-09 15:08:12 +0000298
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000299 return Ctx.getTypeSize(T);
300}
301
302#if 0
303static const char* GetCFNumberTypeStr(uint64_t i) {
304 static const char* Names[] = {
305 "kCFNumberSInt8Type",
306 "kCFNumberSInt16Type",
307 "kCFNumberSInt32Type",
308 "kCFNumberSInt64Type",
309 "kCFNumberFloat32Type",
310 "kCFNumberFloat64Type",
311 "kCFNumberCharType",
312 "kCFNumberShortType",
313 "kCFNumberIntType",
314 "kCFNumberLongType",
315 "kCFNumberLongLongType",
316 "kCFNumberFloatType",
317 "kCFNumberDoubleType",
318 "kCFNumberCFIndexType",
319 "kCFNumberNSIntegerType",
320 "kCFNumberCGFloatType"
321 };
Mike Stump11289f42009-09-09 15:08:12 +0000322
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000323 return i <= kCFNumberCGFloatType ? Names[i-1] : "Invalid CFNumberType";
324}
325#endif
326
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000327void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE,
328 CheckerContext &C) const {
Ted Kremenek49b1e382012-01-26 21:29:00 +0000329 ProgramStateRef state = C.getState();
Anna Zaksc6aa5312011-12-01 05:57:37 +0000330 const FunctionDecl *FD = C.getCalleeDecl(CE);
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000331 if (!FD)
332 return;
333
334 ASTContext &Ctx = C.getASTContext();
335 if (!II)
336 II = &Ctx.Idents.get("CFNumberCreate");
337
338 if (FD->getIdentifier() != II || CE->getNumArgs() != 3)
339 return;
Mike Stump11289f42009-09-09 15:08:12 +0000340
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000341 // Get the value of the "theType" argument.
Ted Kremenek632e3b72012-01-06 22:09:28 +0000342 const LocationContext *LCtx = C.getLocationContext();
343 SVal TheTypeVal = state->getSVal(CE->getArg(1), LCtx);
Mike Stump11289f42009-09-09 15:08:12 +0000344
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000345 // FIXME: We really should allow ranges of valid theType values, and
346 // bifurcate the state appropriately.
David Blaikie05785d12013-02-20 22:23:23 +0000347 Optional<nonloc::ConcreteInt> V = TheTypeVal.getAs<nonloc::ConcreteInt>();
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000348 if (!V)
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000349 return;
Mike Stump11289f42009-09-09 15:08:12 +0000350
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000351 uint64_t NumberKind = V->getValue().getLimitedValue();
David Blaikie05785d12013-02-20 22:23:23 +0000352 Optional<uint64_t> OptTargetSize = GetCFNumberSize(Ctx, NumberKind);
Mike Stump11289f42009-09-09 15:08:12 +0000353
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000354 // FIXME: In some cases we can emit an error.
David Blaikiee359f3c2013-02-20 22:23:03 +0000355 if (!OptTargetSize)
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000356 return;
Mike Stump11289f42009-09-09 15:08:12 +0000357
David Blaikiee359f3c2013-02-20 22:23:03 +0000358 uint64_t TargetSize = *OptTargetSize;
359
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000360 // Look at the value of the integer being passed by reference. Essentially
361 // we want to catch cases where the value passed in is not equal to the
362 // size of the type being created.
Ted Kremenek632e3b72012-01-06 22:09:28 +0000363 SVal TheValueExpr = state->getSVal(CE->getArg(2), LCtx);
Mike Stump11289f42009-09-09 15:08:12 +0000364
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000365 // FIXME: Eventually we should handle arbitrary locations. We can do this
366 // by having an enhanced memory model that does low-level typing.
David Blaikie05785d12013-02-20 22:23:23 +0000367 Optional<loc::MemRegionVal> LV = TheValueExpr.getAs<loc::MemRegionVal>();
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000368 if (!LV)
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000369 return;
Mike Stump11289f42009-09-09 15:08:12 +0000370
Ted Kremenek8df44b262011-08-12 20:02:48 +0000371 const TypedValueRegion* R = dyn_cast<TypedValueRegion>(LV->stripCasts());
Ted Kremenek87a7a452009-07-29 18:17:40 +0000372 if (!R)
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000373 return;
Ted Kremenek87a7a452009-07-29 18:17:40 +0000374
Zhongxing Xu8de0a3d2010-08-11 06:10:55 +0000375 QualType T = Ctx.getCanonicalType(R->getValueType());
Mike Stump11289f42009-09-09 15:08:12 +0000376
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000377 // FIXME: If the pointee isn't an integer type, should we flag a warning?
378 // People can do weird stuff with pointers.
Mike Stump11289f42009-09-09 15:08:12 +0000379
380 if (!T->isIntegerType())
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000381 return;
Mike Stump11289f42009-09-09 15:08:12 +0000382
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000383 uint64_t SourceSize = Ctx.getTypeSize(T);
Mike Stump11289f42009-09-09 15:08:12 +0000384
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000385 // CHECK: is SourceSize == TargetSize
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000386 if (SourceSize == TargetSize)
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000387 return;
Mike Stump11289f42009-09-09 15:08:12 +0000388
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000389 // Generate an error. Only generate a sink if 'SourceSize < TargetSize';
390 // otherwise generate a regular node.
391 //
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000392 // FIXME: We can actually create an abstract "CFNumber" object that has
393 // the bits initialized to the provided values.
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000394 //
Ted Kremenek750b7ac2010-12-20 21:19:09 +0000395 if (ExplodedNode *N = SourceSize < TargetSize ? C.generateSink()
Anna Zaksda4c8d62011-10-26 21:06:34 +0000396 : C.addTransition()) {
Dylan Noblesmith2c1dd272012-02-05 02:13:05 +0000397 SmallString<128> sbuf;
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000398 llvm::raw_svector_ostream os(sbuf);
399
400 os << (SourceSize == 8 ? "An " : "A ")
401 << SourceSize << " bit integer is used to initialize a CFNumber "
402 "object that represents "
403 << (TargetSize == 8 ? "an " : "a ")
404 << TargetSize << " bit integer. ";
405
406 if (SourceSize < TargetSize)
407 os << (TargetSize - SourceSize)
408 << " bits of the CFNumber value will be garbage." ;
409 else
410 os << (SourceSize - TargetSize)
411 << " bits of the input integer will be lost.";
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000412
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000413 if (!BT)
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000414 BT.reset(new APIMisuse("Bad use of CFNumberCreate"));
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000415
Anna Zaks3a6bdf82011-08-17 23:00:25 +0000416 BugReport *report = new BugReport(*BT, os.str(), N);
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000417 report->addRange(CE->getArg(2)->getSourceRange());
Jordan Rosee10d5a72012-11-02 01:53:40 +0000418 C.emitReport(report);
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000419 }
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000420}
421
Ted Kremenek1f352db2008-07-22 16:21:24 +0000422//===----------------------------------------------------------------------===//
Jordan Rose721567a2012-11-07 17:12:37 +0000423// CFRetain/CFRelease/CFMakeCollectable checking for null arguments.
Ted Kremenekc057f412009-07-14 00:43:42 +0000424//===----------------------------------------------------------------------===//
425
426namespace {
Argyrios Kyrtzidis6a5674f2011-03-01 01:16:21 +0000427class CFRetainReleaseChecker : public Checker< check::PreStmt<CallExpr> > {
Dylan Noblesmithe2778992012-02-05 02:12:40 +0000428 mutable OwningPtr<APIMisuse> BT;
Jordan Rose721567a2012-11-07 17:12:37 +0000429 mutable IdentifierInfo *Retain, *Release, *MakeCollectable;
Ted Kremenekc057f412009-07-14 00:43:42 +0000430public:
Jordan Rose721567a2012-11-07 17:12:37 +0000431 CFRetainReleaseChecker(): Retain(0), Release(0), MakeCollectable(0) {}
Ted Kremenek5ef32db2011-08-12 23:37:29 +0000432 void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
Ted Kremenekc057f412009-07-14 00:43:42 +0000433};
434} // end anonymous namespace
435
436
Ted Kremenek5ef32db2011-08-12 23:37:29 +0000437void CFRetainReleaseChecker::checkPreStmt(const CallExpr *CE,
438 CheckerContext &C) const {
Ted Kremenekc057f412009-07-14 00:43:42 +0000439 // If the CallExpr doesn't have exactly 1 argument just give up checking.
440 if (CE->getNumArgs() != 1)
Jordy Rose40c5c242010-07-06 02:34:42 +0000441 return;
Mike Stump11289f42009-09-09 15:08:12 +0000442
Ted Kremenek49b1e382012-01-26 21:29:00 +0000443 ProgramStateRef state = C.getState();
Anna Zaksc6aa5312011-12-01 05:57:37 +0000444 const FunctionDecl *FD = C.getCalleeDecl(CE);
Ted Kremenekc057f412009-07-14 00:43:42 +0000445 if (!FD)
Jordy Rose40c5c242010-07-06 02:34:42 +0000446 return;
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000447
448 if (!BT) {
449 ASTContext &Ctx = C.getASTContext();
450 Retain = &Ctx.Idents.get("CFRetain");
451 Release = &Ctx.Idents.get("CFRelease");
Jordan Rose721567a2012-11-07 17:12:37 +0000452 MakeCollectable = &Ctx.Idents.get("CFMakeCollectable");
453 BT.reset(
454 new APIMisuse("null passed to CFRetain/CFRelease/CFMakeCollectable"));
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000455 }
Mike Stump11289f42009-09-09 15:08:12 +0000456
Jordan Rose721567a2012-11-07 17:12:37 +0000457 // Check if we called CFRetain/CFRelease/CFMakeCollectable.
Mike Stump11289f42009-09-09 15:08:12 +0000458 const IdentifierInfo *FuncII = FD->getIdentifier();
Jordan Rose721567a2012-11-07 17:12:37 +0000459 if (!(FuncII == Retain || FuncII == Release || FuncII == MakeCollectable))
Jordy Rose40c5c242010-07-06 02:34:42 +0000460 return;
Mike Stump11289f42009-09-09 15:08:12 +0000461
Jordy Rose40c5c242010-07-06 02:34:42 +0000462 // FIXME: The rest of this just checks that the argument is non-null.
Anna Zaksef893392013-03-09 03:23:14 +0000463 // It should probably be refactored and combined with NonNullParamChecker.
Jordy Rose40c5c242010-07-06 02:34:42 +0000464
465 // Get the argument's value.
466 const Expr *Arg = CE->getArg(0);
Ted Kremenek632e3b72012-01-06 22:09:28 +0000467 SVal ArgVal = state->getSVal(Arg, C.getLocationContext());
David Blaikie05785d12013-02-20 22:23:23 +0000468 Optional<DefinedSVal> DefArgVal = ArgVal.getAs<DefinedSVal>();
Jordy Rose40c5c242010-07-06 02:34:42 +0000469 if (!DefArgVal)
470 return;
471
472 // Get a NULL value.
Ted Kremenek90af9092010-12-02 07:49:45 +0000473 SValBuilder &svalBuilder = C.getSValBuilder();
David Blaikie2fdacbc2013-02-20 05:52:05 +0000474 DefinedSVal zero =
475 svalBuilder.makeZeroVal(Arg->getType()).castAs<DefinedSVal>();
Jordy Rose40c5c242010-07-06 02:34:42 +0000476
477 // Make an expression asserting that they're equal.
Ted Kremenek90af9092010-12-02 07:49:45 +0000478 DefinedOrUnknownSVal ArgIsNull = svalBuilder.evalEQ(state, zero, *DefArgVal);
Jordy Rose40c5c242010-07-06 02:34:42 +0000479
480 // Are they equal?
Ted Kremenek49b1e382012-01-26 21:29:00 +0000481 ProgramStateRef stateTrue, stateFalse;
Ted Kremenekc5bea1e2010-12-01 22:16:56 +0000482 llvm::tie(stateTrue, stateFalse) = state->assume(ArgIsNull);
Jordy Rose40c5c242010-07-06 02:34:42 +0000483
484 if (stateTrue && !stateFalse) {
Ted Kremenek750b7ac2010-12-20 21:19:09 +0000485 ExplodedNode *N = C.generateSink(stateTrue);
Jordy Rose40c5c242010-07-06 02:34:42 +0000486 if (!N)
487 return;
488
Jordan Rose721567a2012-11-07 17:12:37 +0000489 const char *description;
490 if (FuncII == Retain)
491 description = "Null pointer argument in call to CFRetain";
492 else if (FuncII == Release)
493 description = "Null pointer argument in call to CFRelease";
494 else if (FuncII == MakeCollectable)
495 description = "Null pointer argument in call to CFMakeCollectable";
496 else
497 llvm_unreachable("impossible case");
Ted Kremenekc057f412009-07-14 00:43:42 +0000498
Anna Zaks3a6bdf82011-08-17 23:00:25 +0000499 BugReport *report = new BugReport(*BT, description, N);
Jordy Rose40c5c242010-07-06 02:34:42 +0000500 report->addRange(Arg->getSourceRange());
Jordan Rosea0f7d352012-08-28 00:50:51 +0000501 bugreporter::trackNullOrUndefValue(N, Arg, *report);
Jordan Rosee10d5a72012-11-02 01:53:40 +0000502 C.emitReport(report);
Jordy Rose40c5c242010-07-06 02:34:42 +0000503 return;
Ted Kremenekc057f412009-07-14 00:43:42 +0000504 }
505
Jordy Rose40c5c242010-07-06 02:34:42 +0000506 // From here on, we know the argument is non-null.
Anna Zaksda4c8d62011-10-26 21:06:34 +0000507 C.addTransition(stateFalse);
Ted Kremenekc057f412009-07-14 00:43:42 +0000508}
509
510//===----------------------------------------------------------------------===//
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000511// Check for sending 'retain', 'release', or 'autorelease' directly to a Class.
512//===----------------------------------------------------------------------===//
513
514namespace {
Argyrios Kyrtzidis6a5674f2011-03-01 01:16:21 +0000515class ClassReleaseChecker : public Checker<check::PreObjCMessage> {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000516 mutable Selector releaseS;
517 mutable Selector retainS;
518 mutable Selector autoreleaseS;
519 mutable Selector drainS;
Dylan Noblesmithe2778992012-02-05 02:12:40 +0000520 mutable OwningPtr<BugType> BT;
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000521
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000522public:
Jordan Rose547060b2012-07-02 19:28:04 +0000523 void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000524};
525}
526
Jordan Rose547060b2012-07-02 19:28:04 +0000527void ClassReleaseChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000528 CheckerContext &C) const {
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000529
530 if (!BT) {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000531 BT.reset(new APIMisuse("message incorrectly sent to class instead of class "
532 "instance"));
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000533
534 ASTContext &Ctx = C.getASTContext();
535 releaseS = GetNullarySelector("release", Ctx);
536 retainS = GetNullarySelector("retain", Ctx);
537 autoreleaseS = GetNullarySelector("autorelease", Ctx);
538 drainS = GetNullarySelector("drain", Ctx);
539 }
540
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +0000541 if (msg.isInstanceMessage())
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000542 return;
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +0000543 const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
544 assert(Class);
Douglas Gregor9a129192010-04-21 00:45:42 +0000545
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +0000546 Selector S = msg.getSelector();
Benjamin Kramer7d875c72009-11-20 10:03:00 +0000547 if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000548 return;
549
Anna Zaksda4c8d62011-10-26 21:06:34 +0000550 if (ExplodedNode *N = C.addTransition()) {
Dylan Noblesmith2c1dd272012-02-05 02:13:05 +0000551 SmallString<200> buf;
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000552 llvm::raw_svector_ostream os(buf);
Ted Kremenekf5735152009-11-23 22:22:01 +0000553
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000554 os << "The '" << S.getAsString() << "' message should be sent to instances "
555 "of class '" << Class->getName()
556 << "' and not the class directly";
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000557
Anna Zaks3a6bdf82011-08-17 23:00:25 +0000558 BugReport *report = new BugReport(*BT, os.str(), N);
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +0000559 report->addRange(msg.getSourceRange());
Jordan Rosee10d5a72012-11-02 01:53:40 +0000560 C.emitReport(report);
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000561 }
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000562}
563
564//===----------------------------------------------------------------------===//
Anders Carlssond91d5f12011-03-13 20:35:21 +0000565// Check for passing non-Objective-C types to variadic methods that expect
566// only Objective-C types.
567//===----------------------------------------------------------------------===//
568
569namespace {
570class VariadicMethodTypeChecker : public Checker<check::PreObjCMessage> {
571 mutable Selector arrayWithObjectsS;
572 mutable Selector dictionaryWithObjectsAndKeysS;
573 mutable Selector setWithObjectsS;
Jordy Rosec0230d72012-04-06 19:06:01 +0000574 mutable Selector orderedSetWithObjectsS;
Anders Carlssond91d5f12011-03-13 20:35:21 +0000575 mutable Selector initWithObjectsS;
576 mutable Selector initWithObjectsAndKeysS;
Dylan Noblesmithe2778992012-02-05 02:12:40 +0000577 mutable OwningPtr<BugType> BT;
Anders Carlssond91d5f12011-03-13 20:35:21 +0000578
Jordan Rose547060b2012-07-02 19:28:04 +0000579 bool isVariadicMessage(const ObjCMethodCall &msg) const;
Anders Carlssond91d5f12011-03-13 20:35:21 +0000580
581public:
Jordan Rose547060b2012-07-02 19:28:04 +0000582 void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
Anders Carlssond91d5f12011-03-13 20:35:21 +0000583};
584}
585
586/// isVariadicMessage - Returns whether the given message is a variadic message,
587/// where all arguments must be Objective-C types.
588bool
Jordan Rose547060b2012-07-02 19:28:04 +0000589VariadicMethodTypeChecker::isVariadicMessage(const ObjCMethodCall &msg) const {
590 const ObjCMethodDecl *MD = msg.getDecl();
Ted Kremenekced5fea2011-04-12 21:47:05 +0000591
592 if (!MD || !MD->isVariadic() || isa<ObjCProtocolDecl>(MD->getDeclContext()))
Anders Carlssond91d5f12011-03-13 20:35:21 +0000593 return false;
594
595 Selector S = msg.getSelector();
596
597 if (msg.isInstanceMessage()) {
598 // FIXME: Ideally we'd look at the receiver interface here, but that's not
599 // useful for init, because alloc returns 'id'. In theory, this could lead
600 // to false positives, for example if there existed a class that had an
601 // initWithObjects: implementation that does accept non-Objective-C pointer
602 // types, but the chance of that happening is pretty small compared to the
603 // gains that this analysis gives.
604 const ObjCInterfaceDecl *Class = MD->getClassInterface();
605
Jordan Rose3ba8ae32012-06-11 16:40:37 +0000606 switch (findKnownClass(Class)) {
607 case FC_NSArray:
608 case FC_NSOrderedSet:
609 case FC_NSSet:
610 return S == initWithObjectsS;
611 case FC_NSDictionary:
612 return S == initWithObjectsAndKeysS;
613 default:
614 return false;
615 }
Anders Carlssond91d5f12011-03-13 20:35:21 +0000616 } else {
617 const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
618
Jordan Rose3ba8ae32012-06-11 16:40:37 +0000619 switch (findKnownClass(Class)) {
620 case FC_NSArray:
621 return S == arrayWithObjectsS;
622 case FC_NSOrderedSet:
623 return S == orderedSetWithObjectsS;
624 case FC_NSSet:
625 return S == setWithObjectsS;
626 case FC_NSDictionary:
627 return S == dictionaryWithObjectsAndKeysS;
628 default:
629 return false;
630 }
Anders Carlssond91d5f12011-03-13 20:35:21 +0000631 }
Anders Carlssond91d5f12011-03-13 20:35:21 +0000632}
633
Jordan Rose547060b2012-07-02 19:28:04 +0000634void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
Anders Carlssond91d5f12011-03-13 20:35:21 +0000635 CheckerContext &C) const {
636 if (!BT) {
637 BT.reset(new APIMisuse("Arguments passed to variadic method aren't all "
638 "Objective-C pointer types"));
639
640 ASTContext &Ctx = C.getASTContext();
641 arrayWithObjectsS = GetUnarySelector("arrayWithObjects", Ctx);
642 dictionaryWithObjectsAndKeysS =
643 GetUnarySelector("dictionaryWithObjectsAndKeys", Ctx);
644 setWithObjectsS = GetUnarySelector("setWithObjects", Ctx);
Jordy Rosec0230d72012-04-06 19:06:01 +0000645 orderedSetWithObjectsS = GetUnarySelector("orderedSetWithObjects", Ctx);
Anders Carlssond91d5f12011-03-13 20:35:21 +0000646
647 initWithObjectsS = GetUnarySelector("initWithObjects", Ctx);
648 initWithObjectsAndKeysS = GetUnarySelector("initWithObjectsAndKeys", Ctx);
649 }
650
651 if (!isVariadicMessage(msg))
652 return;
653
654 // We are not interested in the selector arguments since they have
655 // well-defined types, so the compiler will issue a warning for them.
656 unsigned variadicArgsBegin = msg.getSelector().getNumArgs();
657
658 // We're not interested in the last argument since it has to be nil or the
659 // compiler would have issued a warning for it elsewhere.
660 unsigned variadicArgsEnd = msg.getNumArgs() - 1;
661
662 if (variadicArgsEnd <= variadicArgsBegin)
663 return;
664
665 // Verify that all arguments have Objective-C types.
David Blaikie05785d12013-02-20 22:23:23 +0000666 Optional<ExplodedNode*> errorNode;
Ted Kremenek49b1e382012-01-26 21:29:00 +0000667 ProgramStateRef state = C.getState();
Ted Kremenek066b2262011-03-14 19:50:37 +0000668
Anders Carlssond91d5f12011-03-13 20:35:21 +0000669 for (unsigned I = variadicArgsBegin; I != variadicArgsEnd; ++I) {
Jordan Rose547060b2012-07-02 19:28:04 +0000670 QualType ArgTy = msg.getArgExpr(I)->getType();
Anders Carlssond91d5f12011-03-13 20:35:21 +0000671 if (ArgTy->isObjCObjectPointerType())
672 continue;
673
Anders Carlssond1f65f62011-04-19 01:16:46 +0000674 // Block pointers are treaded as Objective-C pointers.
675 if (ArgTy->isBlockPointerType())
676 continue;
677
Ted Kremenek4ceebbf2011-03-16 00:22:51 +0000678 // Ignore pointer constants.
David Blaikie2fdacbc2013-02-20 05:52:05 +0000679 if (msg.getArgSVal(I).getAs<loc::ConcreteInt>())
Ted Kremenek4ceebbf2011-03-16 00:22:51 +0000680 continue;
Ted Kremenek6fa1dae2011-03-17 04:01:35 +0000681
Ted Kremenek70727342011-03-17 04:10:25 +0000682 // Ignore pointer types annotated with 'NSObject' attribute.
683 if (C.getASTContext().isObjCNSObjectType(ArgTy))
684 continue;
685
Ted Kremenek6fa1dae2011-03-17 04:01:35 +0000686 // Ignore CF references, which can be toll-free bridged.
Ted Kremenekc85964e2011-07-16 19:50:32 +0000687 if (coreFoundation::isCFObjectRef(ArgTy))
Ted Kremenek6fa1dae2011-03-17 04:01:35 +0000688 continue;
Ted Kremenek4ceebbf2011-03-16 00:22:51 +0000689
Ted Kremenek066b2262011-03-14 19:50:37 +0000690 // Generate only one error node to use for all bug reports.
Jordan Rose547060b2012-07-02 19:28:04 +0000691 if (!errorNode.hasValue())
Anna Zaksda4c8d62011-10-26 21:06:34 +0000692 errorNode = C.addTransition();
Ted Kremenek066b2262011-03-14 19:50:37 +0000693
694 if (!errorNode.getValue())
Anders Carlssond91d5f12011-03-13 20:35:21 +0000695 continue;
696
Dylan Noblesmith2c1dd272012-02-05 02:13:05 +0000697 SmallString<128> sbuf;
Anders Carlssond91d5f12011-03-13 20:35:21 +0000698 llvm::raw_svector_ostream os(sbuf);
699
Jordan Rose547060b2012-07-02 19:28:04 +0000700 StringRef TypeName = GetReceiverInterfaceName(msg);
701 if (!TypeName.empty())
Anders Carlssond91d5f12011-03-13 20:35:21 +0000702 os << "Argument to '" << TypeName << "' method '";
703 else
704 os << "Argument to method '";
705
706 os << msg.getSelector().getAsString()
Jordan Rose547060b2012-07-02 19:28:04 +0000707 << "' should be an Objective-C pointer type, not '";
708 ArgTy.print(os, C.getLangOpts());
709 os << "'";
Anders Carlssond91d5f12011-03-13 20:35:21 +0000710
Jordan Rose547060b2012-07-02 19:28:04 +0000711 BugReport *R = new BugReport(*BT, os.str(), errorNode.getValue());
Anders Carlssond91d5f12011-03-13 20:35:21 +0000712 R->addRange(msg.getArgSourceRange(I));
Jordan Rosee10d5a72012-11-02 01:53:40 +0000713 C.emitReport(R);
Anders Carlssond91d5f12011-03-13 20:35:21 +0000714 }
715}
716
717//===----------------------------------------------------------------------===//
Jordan Roseefef7602012-06-11 16:40:41 +0000718// Improves the modeling of loops over Cocoa collections.
719//===----------------------------------------------------------------------===//
720
721namespace {
722class ObjCLoopChecker
723 : public Checker<check::PostStmt<ObjCForCollectionStmt> > {
724
725public:
726 void checkPostStmt(const ObjCForCollectionStmt *FCS, CheckerContext &C) const;
727};
728}
729
730static bool isKnownNonNilCollectionType(QualType T) {
731 const ObjCObjectPointerType *PT = T->getAs<ObjCObjectPointerType>();
732 if (!PT)
733 return false;
734
735 const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();
736 if (!ID)
737 return false;
738
739 switch (findKnownClass(ID)) {
740 case FC_NSArray:
741 case FC_NSDictionary:
742 case FC_NSEnumerator:
743 case FC_NSOrderedSet:
744 case FC_NSSet:
745 return true;
746 default:
747 return false;
748 }
749}
750
751void ObjCLoopChecker::checkPostStmt(const ObjCForCollectionStmt *FCS,
752 CheckerContext &C) const {
753 ProgramStateRef State = C.getState();
754
755 // Check if this is the branch for the end of the loop.
756 SVal CollectionSentinel = State->getSVal(FCS, C.getLocationContext());
757 if (CollectionSentinel.isZeroConstant())
758 return;
759
760 // See if the collection is one where we /know/ the elements are non-nil.
761 const Expr *Collection = FCS->getCollection();
762 if (!isKnownNonNilCollectionType(Collection->getType()))
763 return;
764
765 // FIXME: Copied from ExprEngineObjC.
766 const Stmt *Element = FCS->getElement();
767 SVal ElementVar;
768 if (const DeclStmt *DS = dyn_cast<DeclStmt>(Element)) {
769 const VarDecl *ElemDecl = cast<VarDecl>(DS->getSingleDecl());
770 assert(ElemDecl->getInit() == 0);
771 ElementVar = State->getLValue(ElemDecl, C.getLocationContext());
772 } else {
773 ElementVar = State->getSVal(Element, C.getLocationContext());
774 }
775
David Blaikie2fdacbc2013-02-20 05:52:05 +0000776 if (!ElementVar.getAs<Loc>())
Jordan Roseefef7602012-06-11 16:40:41 +0000777 return;
778
779 // Go ahead and assume the value is non-nil.
David Blaikie2fdacbc2013-02-20 05:52:05 +0000780 SVal Val = State->getSVal(ElementVar.castAs<Loc>());
781 State = State->assume(Val.castAs<DefinedOrUnknownSVal>(), true);
Jordan Roseefef7602012-06-11 16:40:41 +0000782 C.addTransition(State);
783}
784
Anna Zaks5a5a1752012-08-22 21:19:56 +0000785namespace {
786/// \class ObjCNonNilReturnValueChecker
Anna Zaks4818bbe2012-08-30 19:40:52 +0000787/// \brief The checker restricts the return values of APIs known to
788/// never (or almost never) return 'nil'.
Anna Zaks5a5a1752012-08-22 21:19:56 +0000789class ObjCNonNilReturnValueChecker
790 : public Checker<check::PostObjCMessage> {
791 mutable bool Initialized;
792 mutable Selector ObjectAtIndex;
793 mutable Selector ObjectAtIndexedSubscript;
Anna Zaks9159e162012-08-22 22:47:58 +0000794
Anna Zaks5a5a1752012-08-22 21:19:56 +0000795public:
Anna Zaks9159e162012-08-22 22:47:58 +0000796 ObjCNonNilReturnValueChecker() : Initialized(false) {}
Anna Zaks5a5a1752012-08-22 21:19:56 +0000797 void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
798};
799}
800
Benjamin Kramer199f8da2012-09-10 11:57:16 +0000801static ProgramStateRef assumeExprIsNonNull(const Expr *NonNullExpr,
802 ProgramStateRef State,
803 CheckerContext &C) {
Anna Zaks4818bbe2012-08-30 19:40:52 +0000804 SVal Val = State->getSVal(NonNullExpr, C.getLocationContext());
David Blaikie05785d12013-02-20 22:23:23 +0000805 if (Optional<DefinedOrUnknownSVal> DV = Val.getAs<DefinedOrUnknownSVal>())
Anna Zaks830c48e2012-08-30 22:55:32 +0000806 return State->assume(*DV, true);
Anna Zaksb504f442012-08-30 22:42:41 +0000807 return State;
Anna Zaks4818bbe2012-08-30 19:40:52 +0000808}
809
Anna Zaks5a5a1752012-08-22 21:19:56 +0000810void ObjCNonNilReturnValueChecker::checkPostObjCMessage(const ObjCMethodCall &M,
811 CheckerContext &C)
Anna Zaks4818bbe2012-08-30 19:40:52 +0000812 const {
Anna Zaks5a5a1752012-08-22 21:19:56 +0000813 ProgramStateRef State = C.getState();
814
815 if (!Initialized) {
816 ASTContext &Ctx = C.getASTContext();
817 ObjectAtIndex = GetUnarySelector("objectAtIndex", Ctx);
818 ObjectAtIndexedSubscript = GetUnarySelector("objectAtIndexedSubscript", Ctx);
819 }
820
821 // Check the receiver type.
822 if (const ObjCInterfaceDecl *Interface = M.getReceiverInterface()) {
Anna Zaks4818bbe2012-08-30 19:40:52 +0000823
824 // Assume that object returned from '[self init]' or '[super init]' is not
825 // 'nil' if we are processing an inlined function/method.
826 //
827 // A defensive callee will (and should) check if the object returned by
828 // '[super init]' is 'nil' before doing it's own initialization. However,
829 // since 'nil' is rarely returned in practice, we should not warn when the
830 // caller to the defensive constructor uses the object in contexts where
831 // 'nil' is not accepted.
Anna Zaks49bb6502012-11-06 04:20:54 +0000832 if (!C.inTopFrame() && M.getDecl() &&
Anna Zaks4818bbe2012-08-30 19:40:52 +0000833 M.getDecl()->getMethodFamily() == OMF_init &&
834 M.isReceiverSelfOrSuper()) {
835 State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
836 }
837
838 // Objects returned from
839 // [NSArray|NSOrderedSet]::[ObjectAtIndex|ObjectAtIndexedSubscript]
840 // are never 'nil'.
Anna Zaks5a5a1752012-08-22 21:19:56 +0000841 FoundationClass Cl = findKnownClass(Interface);
842 if (Cl == FC_NSArray || Cl == FC_NSOrderedSet) {
843 Selector Sel = M.getSelector();
844 if (Sel == ObjectAtIndex || Sel == ObjectAtIndexedSubscript) {
845 // Go ahead and assume the value is non-nil.
Anna Zaks4818bbe2012-08-30 19:40:52 +0000846 State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
Anna Zaks5a5a1752012-08-22 21:19:56 +0000847 }
848 }
849 }
Anna Zaks4818bbe2012-08-30 19:40:52 +0000850 C.addTransition(State);
Anna Zaks5a5a1752012-08-22 21:19:56 +0000851}
Jordan Roseefef7602012-06-11 16:40:41 +0000852
853//===----------------------------------------------------------------------===//
Ted Kremenek1f352db2008-07-22 16:21:24 +0000854// Check registration.
Ted Kremenekc057f412009-07-14 00:43:42 +0000855//===----------------------------------------------------------------------===//
Argyrios Kyrtzidis9d4d4f92011-02-16 01:40:52 +0000856
Argyrios Kyrtzidis507ff532011-02-17 21:39:17 +0000857void ento::registerNilArgChecker(CheckerManager &mgr) {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000858 mgr.registerChecker<NilArgChecker>();
Argyrios Kyrtzidis9d4d4f92011-02-16 01:40:52 +0000859}
860
Argyrios Kyrtzidis507ff532011-02-17 21:39:17 +0000861void ento::registerCFNumberCreateChecker(CheckerManager &mgr) {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000862 mgr.registerChecker<CFNumberCreateChecker>();
Argyrios Kyrtzidis9d4d4f92011-02-16 01:40:52 +0000863}
864
Argyrios Kyrtzidis507ff532011-02-17 21:39:17 +0000865void ento::registerCFRetainReleaseChecker(CheckerManager &mgr) {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000866 mgr.registerChecker<CFRetainReleaseChecker>();
Ted Kremenek1f352db2008-07-22 16:21:24 +0000867}
Argyrios Kyrtzidis507ff532011-02-17 21:39:17 +0000868
869void ento::registerClassReleaseChecker(CheckerManager &mgr) {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000870 mgr.registerChecker<ClassReleaseChecker>();
Argyrios Kyrtzidis507ff532011-02-17 21:39:17 +0000871}
Anders Carlssond91d5f12011-03-13 20:35:21 +0000872
873void ento::registerVariadicMethodTypeChecker(CheckerManager &mgr) {
874 mgr.registerChecker<VariadicMethodTypeChecker>();
875}
Jordan Roseefef7602012-06-11 16:40:41 +0000876
877void ento::registerObjCLoopChecker(CheckerManager &mgr) {
878 mgr.registerChecker<ObjCLoopChecker>();
879}
Anna Zaks5a5a1752012-08-22 21:19:56 +0000880
881void ento::registerObjCNonNilReturnValueChecker(CheckerManager &mgr) {
882 mgr.registerChecker<ObjCNonNilReturnValueChecker>();
883}