blob: adf1b239421f61bb8be680de8e09c37b3bfaf7cb [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,
Anna Zaks4063fa12013-05-10 18:04:46 +000061 FC_NSNull,
Jordan Rose3ba8ae32012-06-11 16:40:37 +000062 FC_NSOrderedSet,
63 FC_NSSet,
64 FC_NSString
65};
Anders Carlsson3c50aea2011-03-08 20:05:26 +000066
Jordan Rose1a4ae202013-11-08 01:15:35 +000067static FoundationClass findKnownClass(const ObjCInterfaceDecl *ID,
68 bool IncludeSuperclasses = true) {
Jordan Rose3ba8ae32012-06-11 16:40:37 +000069 static llvm::StringMap<FoundationClass> Classes;
70 if (Classes.empty()) {
71 Classes["NSArray"] = FC_NSArray;
72 Classes["NSDictionary"] = FC_NSDictionary;
73 Classes["NSEnumerator"] = FC_NSEnumerator;
Anna Zaks4063fa12013-05-10 18:04:46 +000074 Classes["NSNull"] = FC_NSNull;
Jordan Rose3ba8ae32012-06-11 16:40:37 +000075 Classes["NSOrderedSet"] = FC_NSOrderedSet;
76 Classes["NSSet"] = FC_NSSet;
77 Classes["NSString"] = FC_NSString;
78 }
Anders Carlsson3c50aea2011-03-08 20:05:26 +000079
Jordan Rose3ba8ae32012-06-11 16:40:37 +000080 // FIXME: Should we cache this at all?
81 FoundationClass result = Classes.lookup(ID->getIdentifier()->getName());
Jordan Rose1a4ae202013-11-08 01:15:35 +000082 if (result == FC_None && IncludeSuperclasses)
Jordan Rose3ba8ae32012-06-11 16:40:37 +000083 if (const ObjCInterfaceDecl *Super = ID->getSuperClass())
84 return findKnownClass(Super);
85
86 return result;
Ted Kremenekc0414922008-03-27 07:25:52 +000087}
88
89//===----------------------------------------------------------------------===//
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 {
Anna Zaksbb2a2c82013-05-13 21:48:20 +000094 class NilArgChecker : public Checker<check::PreObjCMessage,
95 check::PostStmt<ObjCDictionaryLiteral>,
96 check::PostStmt<ObjCArrayLiteral> > {
Dylan Noblesmithe2778992012-02-05 02:12:40 +000097 mutable OwningPtr<APIMisuse> BT;
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +000098
Anna Zaksbb2a2c82013-05-13 21:48:20 +000099 void warnIfNilExpr(const Expr *E,
100 const char *Msg,
101 CheckerContext &C) const;
102
103 void warnIfNilArg(CheckerContext &C,
104 const ObjCMethodCall &msg, unsigned Arg,
105 FoundationClass Class,
106 bool CanBeSubscript = false) const;
107
108 void generateBugReport(ExplodedNode *N,
Anna Zaks6afa8f12013-05-13 23:49:51 +0000109 StringRef Msg,
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000110 SourceRange Range,
111 const Expr *Expr,
112 CheckerContext &C) const;
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000113
Benjamin Kramer2fc373e2010-10-22 16:33:16 +0000114 public:
Jordan Rose547060b2012-07-02 19:28:04 +0000115 void checkPreObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000116 void checkPostStmt(const ObjCDictionaryLiteral *DL,
117 CheckerContext &C) const;
118 void checkPostStmt(const ObjCArrayLiteral *AL,
119 CheckerContext &C) const;
Benjamin Kramer2fc373e2010-10-22 16:33:16 +0000120 };
121}
Mike Stump11289f42009-09-09 15:08:12 +0000122
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000123void NilArgChecker::warnIfNilExpr(const Expr *E,
124 const char *Msg,
125 CheckerContext &C) const {
126 ProgramStateRef State = C.getState();
Anna Zaks6afa8f12013-05-13 23:49:51 +0000127 if (State->isNull(C.getSVal(E)).isConstrainedTrue()) {
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000128
129 if (ExplodedNode *N = C.generateSink()) {
Anna Zaks6afa8f12013-05-13 23:49:51 +0000130 generateBugReport(N, Msg, E->getSourceRange(), E, C);
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000131 }
132
133 }
134}
135
136void NilArgChecker::warnIfNilArg(CheckerContext &C,
Anna Zaks130df4b2013-03-23 00:39:21 +0000137 const ObjCMethodCall &msg,
138 unsigned int Arg,
139 FoundationClass Class,
140 bool CanBeSubscript) const {
141 // Check if the argument is nil.
142 ProgramStateRef State = C.getState();
143 if (!State->isNull(msg.getArgSVal(Arg)).isConstrainedTrue())
144 return;
145
Ted Kremenek750b7ac2010-12-20 21:19:09 +0000146 if (ExplodedNode *N = C.generateSink()) {
Dylan Noblesmith2c1dd272012-02-05 02:13:05 +0000147 SmallString<128> sbuf;
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000148 llvm::raw_svector_ostream os(sbuf);
Anna Zaks130df4b2013-03-23 00:39:21 +0000149
150 if (CanBeSubscript && msg.getMessageKind() == OCM_Subscript) {
151
152 if (Class == FC_NSArray) {
153 os << "Array element cannot be nil";
154 } else if (Class == FC_NSDictionary) {
Anna Zaks4d1e3042013-04-05 23:50:18 +0000155 if (Arg == 0) {
Ted Kremeneke06df462013-04-08 18:09:16 +0000156 os << "Value stored into '";
Anna Zaks4d1e3042013-04-05 23:50:18 +0000157 os << GetReceiverInterfaceName(msg) << "' cannot be nil";
158 } else {
Anna Zaks130df4b2013-03-23 00:39:21 +0000159 assert(Arg == 1);
Anna Zaks4d1e3042013-04-05 23:50:18 +0000160 os << "'"<< GetReceiverInterfaceName(msg) << "' key cannot be nil";
Anna Zaks130df4b2013-03-23 00:39:21 +0000161 }
162 } else
163 llvm_unreachable("Missing foundation class for the subscript expr");
164
165 } else {
Anna Zaks4d1e3042013-04-05 23:50:18 +0000166 if (Class == FC_NSDictionary) {
167 if (Arg == 0)
168 os << "Value argument ";
169 else {
170 assert(Arg == 1);
171 os << "Key argument ";
172 }
Aaron Ballmanb190f972014-01-03 17:59:55 +0000173 os << "to '";
174 msg.getSelector().print(os);
175 os << "' cannot be nil";
Anna Zaks4d1e3042013-04-05 23:50:18 +0000176 } else {
Aaron Ballmanb190f972014-01-03 17:59:55 +0000177 os << "Argument to '" << GetReceiverInterfaceName(msg) << "' method '";
178 msg.getSelector().print(os);
179 os << "' cannot be nil";
Anna Zaks4d1e3042013-04-05 23:50:18 +0000180 }
Anna Zaks130df4b2013-03-23 00:39:21 +0000181 }
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000182
Anna Zaks6afa8f12013-05-13 23:49:51 +0000183 generateBugReport(N, os.str(), msg.getArgSourceRange(Arg),
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000184 msg.getArgExpr(Arg), C);
Ted Kremenek276278e2008-03-27 22:05:32 +0000185 }
Ted Kremenek276278e2008-03-27 22:05:32 +0000186}
187
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000188void NilArgChecker::generateBugReport(ExplodedNode *N,
Anna Zaks6afa8f12013-05-13 23:49:51 +0000189 StringRef Msg,
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000190 SourceRange Range,
Anna Zaks6afa8f12013-05-13 23:49:51 +0000191 const Expr *E,
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000192 CheckerContext &C) const {
193 if (!BT)
194 BT.reset(new APIMisuse("nil argument"));
195
Anna Zaks6afa8f12013-05-13 23:49:51 +0000196 BugReport *R = new BugReport(*BT, Msg, N);
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000197 R->addRange(Range);
Anna Zaks6afa8f12013-05-13 23:49:51 +0000198 bugreporter::trackNullOrUndefValue(N, E, *R);
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000199 C.emitReport(R);
200}
201
Jordan Rose547060b2012-07-02 19:28:04 +0000202void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000203 CheckerContext &C) const {
Anders Carlsson3c50aea2011-03-08 20:05:26 +0000204 const ObjCInterfaceDecl *ID = msg.getReceiverInterface();
205 if (!ID)
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000206 return;
Anna Zaks6457ad22013-03-18 20:46:56 +0000207
208 FoundationClass Class = findKnownClass(ID);
209
210 static const unsigned InvalidArgIndex = UINT_MAX;
211 unsigned Arg = InvalidArgIndex;
Anna Zaks130df4b2013-03-23 00:39:21 +0000212 bool CanBeSubscript = false;
213
Anna Zaks6457ad22013-03-18 20:46:56 +0000214 if (Class == FC_NSString) {
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +0000215 Selector S = msg.getSelector();
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000216
217 if (S.isUnarySelector())
218 return;
219
220 // FIXME: This is going to be really slow doing these checks with
221 // lexical comparisons.
222
223 std::string NameStr = S.getAsString();
Chris Lattner0e62c1c2011-07-23 10:55:15 +0000224 StringRef Name(NameStr);
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000225 assert(!Name.empty());
226
227 // FIXME: Checking for initWithFormat: will not work in most cases
228 // yet because [NSString alloc] returns id, not NSString*. We will
229 // need support for tracking expected-type information in the analyzer
230 // to find these errors.
231 if (Name == "caseInsensitiveCompare:" ||
232 Name == "compare:" ||
233 Name == "compare:options:" ||
234 Name == "compare:options:range:" ||
235 Name == "compare:options:range:locale:" ||
236 Name == "componentsSeparatedByCharactersInSet:" ||
237 Name == "initWithFormat:") {
Anna Zaks6457ad22013-03-18 20:46:56 +0000238 Arg = 0;
239 }
240 } else if (Class == FC_NSArray) {
241 Selector S = msg.getSelector();
242
243 if (S.isUnarySelector())
244 return;
245
246 if (S.getNameForSlot(0).equals("addObject")) {
247 Arg = 0;
248 } else if (S.getNameForSlot(0).equals("insertObject") &&
249 S.getNameForSlot(1).equals("atIndex")) {
250 Arg = 0;
251 } else if (S.getNameForSlot(0).equals("replaceObjectAtIndex") &&
252 S.getNameForSlot(1).equals("withObject")) {
253 Arg = 1;
254 } else if (S.getNameForSlot(0).equals("setObject") &&
255 S.getNameForSlot(1).equals("atIndexedSubscript")) {
256 Arg = 0;
Anna Zaks130df4b2013-03-23 00:39:21 +0000257 CanBeSubscript = true;
Anna Zaks6457ad22013-03-18 20:46:56 +0000258 } else if (S.getNameForSlot(0).equals("arrayByAddingObject")) {
259 Arg = 0;
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000260 }
Anna Zaks130df4b2013-03-23 00:39:21 +0000261 } else if (Class == FC_NSDictionary) {
262 Selector S = msg.getSelector();
263
264 if (S.isUnarySelector())
265 return;
266
267 if (S.getNameForSlot(0).equals("dictionaryWithObject") &&
268 S.getNameForSlot(1).equals("forKey")) {
269 Arg = 0;
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000270 warnIfNilArg(C, msg, /* Arg */1, Class);
Anna Zaks130df4b2013-03-23 00:39:21 +0000271 } else if (S.getNameForSlot(0).equals("setObject") &&
272 S.getNameForSlot(1).equals("forKey")) {
273 Arg = 0;
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000274 warnIfNilArg(C, msg, /* Arg */1, Class);
Anna Zaks130df4b2013-03-23 00:39:21 +0000275 } else if (S.getNameForSlot(0).equals("setObject") &&
276 S.getNameForSlot(1).equals("forKeyedSubscript")) {
277 CanBeSubscript = true;
278 Arg = 0;
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000279 warnIfNilArg(C, msg, /* Arg */1, Class, CanBeSubscript);
Anna Zaks130df4b2013-03-23 00:39:21 +0000280 } else if (S.getNameForSlot(0).equals("removeObjectForKey")) {
281 Arg = 0;
282 }
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000283 }
Anna Zaks6457ad22013-03-18 20:46:56 +0000284
285 // If argument is '0', report a warning.
Anna Zaks130df4b2013-03-23 00:39:21 +0000286 if ((Arg != InvalidArgIndex))
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000287 warnIfNilArg(C, msg, Arg, Class, CanBeSubscript);
Anna Zaks6457ad22013-03-18 20:46:56 +0000288
Ted Kremenekc0414922008-03-27 07:25:52 +0000289}
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000290
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000291void NilArgChecker::checkPostStmt(const ObjCArrayLiteral *AL,
292 CheckerContext &C) const {
Anna Zaks6afa8f12013-05-13 23:49:51 +0000293 unsigned NumOfElements = AL->getNumElements();
294 for (unsigned i = 0; i < NumOfElements; ++i) {
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000295 warnIfNilExpr(AL->getElement(i), "Array element cannot be nil", C);
296 }
297}
298
299void NilArgChecker::checkPostStmt(const ObjCDictionaryLiteral *DL,
300 CheckerContext &C) const {
Anna Zaks6afa8f12013-05-13 23:49:51 +0000301 unsigned NumOfElements = DL->getNumElements();
302 for (unsigned i = 0; i < NumOfElements; ++i) {
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000303 ObjCDictionaryElement Element = DL->getKeyValueElement(i);
304 warnIfNilExpr(Element.Key, "Dictionary key cannot be nil", C);
305 warnIfNilExpr(Element.Value, "Dictionary value cannot be nil", C);
306 }
307}
308
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000309//===----------------------------------------------------------------------===//
310// Error reporting.
311//===----------------------------------------------------------------------===//
312
313namespace {
Argyrios Kyrtzidis6a5674f2011-03-01 01:16:21 +0000314class CFNumberCreateChecker : public Checker< check::PreStmt<CallExpr> > {
Dylan Noblesmithe2778992012-02-05 02:12:40 +0000315 mutable OwningPtr<APIMisuse> BT;
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000316 mutable IdentifierInfo* II;
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000317public:
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000318 CFNumberCreateChecker() : II(0) {}
319
320 void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
321
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000322private:
Ted Kremenek5ef32db2011-08-12 23:37:29 +0000323 void EmitError(const TypedRegion* R, const Expr *Ex,
Mike Stump11289f42009-09-09 15:08:12 +0000324 uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind);
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000325};
326} // end anonymous namespace
327
328enum CFNumberType {
329 kCFNumberSInt8Type = 1,
330 kCFNumberSInt16Type = 2,
331 kCFNumberSInt32Type = 3,
332 kCFNumberSInt64Type = 4,
333 kCFNumberFloat32Type = 5,
334 kCFNumberFloat64Type = 6,
335 kCFNumberCharType = 7,
336 kCFNumberShortType = 8,
337 kCFNumberIntType = 9,
338 kCFNumberLongType = 10,
339 kCFNumberLongLongType = 11,
340 kCFNumberFloatType = 12,
341 kCFNumberDoubleType = 13,
342 kCFNumberCFIndexType = 14,
343 kCFNumberNSIntegerType = 15,
344 kCFNumberCGFloatType = 16
345};
346
Ted Kremenek5ef32db2011-08-12 23:37:29 +0000347static Optional<uint64_t> GetCFNumberSize(ASTContext &Ctx, uint64_t i) {
Nuno Lopescfca1f02009-12-23 17:49:57 +0000348 static const unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 };
Mike Stump11289f42009-09-09 15:08:12 +0000349
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000350 if (i < kCFNumberCharType)
351 return FixedSize[i-1];
Mike Stump11289f42009-09-09 15:08:12 +0000352
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000353 QualType T;
Mike Stump11289f42009-09-09 15:08:12 +0000354
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000355 switch (i) {
356 case kCFNumberCharType: T = Ctx.CharTy; break;
357 case kCFNumberShortType: T = Ctx.ShortTy; break;
358 case kCFNumberIntType: T = Ctx.IntTy; break;
359 case kCFNumberLongType: T = Ctx.LongTy; break;
360 case kCFNumberLongLongType: T = Ctx.LongLongTy; break;
361 case kCFNumberFloatType: T = Ctx.FloatTy; break;
362 case kCFNumberDoubleType: T = Ctx.DoubleTy; break;
363 case kCFNumberCFIndexType:
364 case kCFNumberNSIntegerType:
365 case kCFNumberCGFloatType:
Mike Stump11289f42009-09-09 15:08:12 +0000366 // FIXME: We need a way to map from names to Type*.
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000367 default:
David Blaikie7a30dc52013-02-21 01:47:18 +0000368 return None;
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000369 }
Mike Stump11289f42009-09-09 15:08:12 +0000370
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000371 return Ctx.getTypeSize(T);
372}
373
374#if 0
375static const char* GetCFNumberTypeStr(uint64_t i) {
376 static const char* Names[] = {
377 "kCFNumberSInt8Type",
378 "kCFNumberSInt16Type",
379 "kCFNumberSInt32Type",
380 "kCFNumberSInt64Type",
381 "kCFNumberFloat32Type",
382 "kCFNumberFloat64Type",
383 "kCFNumberCharType",
384 "kCFNumberShortType",
385 "kCFNumberIntType",
386 "kCFNumberLongType",
387 "kCFNumberLongLongType",
388 "kCFNumberFloatType",
389 "kCFNumberDoubleType",
390 "kCFNumberCFIndexType",
391 "kCFNumberNSIntegerType",
392 "kCFNumberCGFloatType"
393 };
Mike Stump11289f42009-09-09 15:08:12 +0000394
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000395 return i <= kCFNumberCGFloatType ? Names[i-1] : "Invalid CFNumberType";
396}
397#endif
398
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000399void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE,
400 CheckerContext &C) const {
Ted Kremenek49b1e382012-01-26 21:29:00 +0000401 ProgramStateRef state = C.getState();
Anna Zaksc6aa5312011-12-01 05:57:37 +0000402 const FunctionDecl *FD = C.getCalleeDecl(CE);
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000403 if (!FD)
404 return;
405
406 ASTContext &Ctx = C.getASTContext();
407 if (!II)
408 II = &Ctx.Idents.get("CFNumberCreate");
409
410 if (FD->getIdentifier() != II || CE->getNumArgs() != 3)
411 return;
Mike Stump11289f42009-09-09 15:08:12 +0000412
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000413 // Get the value of the "theType" argument.
Ted Kremenek632e3b72012-01-06 22:09:28 +0000414 const LocationContext *LCtx = C.getLocationContext();
415 SVal TheTypeVal = state->getSVal(CE->getArg(1), LCtx);
Mike Stump11289f42009-09-09 15:08:12 +0000416
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000417 // FIXME: We really should allow ranges of valid theType values, and
418 // bifurcate the state appropriately.
David Blaikie05785d12013-02-20 22:23:23 +0000419 Optional<nonloc::ConcreteInt> V = TheTypeVal.getAs<nonloc::ConcreteInt>();
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000420 if (!V)
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000421 return;
Mike Stump11289f42009-09-09 15:08:12 +0000422
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000423 uint64_t NumberKind = V->getValue().getLimitedValue();
David Blaikie05785d12013-02-20 22:23:23 +0000424 Optional<uint64_t> OptTargetSize = GetCFNumberSize(Ctx, NumberKind);
Mike Stump11289f42009-09-09 15:08:12 +0000425
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000426 // FIXME: In some cases we can emit an error.
David Blaikiee359f3c2013-02-20 22:23:03 +0000427 if (!OptTargetSize)
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000428 return;
Mike Stump11289f42009-09-09 15:08:12 +0000429
David Blaikiee359f3c2013-02-20 22:23:03 +0000430 uint64_t TargetSize = *OptTargetSize;
431
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000432 // Look at the value of the integer being passed by reference. Essentially
433 // we want to catch cases where the value passed in is not equal to the
434 // size of the type being created.
Ted Kremenek632e3b72012-01-06 22:09:28 +0000435 SVal TheValueExpr = state->getSVal(CE->getArg(2), LCtx);
Mike Stump11289f42009-09-09 15:08:12 +0000436
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000437 // FIXME: Eventually we should handle arbitrary locations. We can do this
438 // by having an enhanced memory model that does low-level typing.
David Blaikie05785d12013-02-20 22:23:23 +0000439 Optional<loc::MemRegionVal> LV = TheValueExpr.getAs<loc::MemRegionVal>();
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000440 if (!LV)
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000441 return;
Mike Stump11289f42009-09-09 15:08:12 +0000442
Ted Kremenek8df44b262011-08-12 20:02:48 +0000443 const TypedValueRegion* R = dyn_cast<TypedValueRegion>(LV->stripCasts());
Ted Kremenek87a7a452009-07-29 18:17:40 +0000444 if (!R)
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000445 return;
Ted Kremenek87a7a452009-07-29 18:17:40 +0000446
Zhongxing Xu8de0a3d2010-08-11 06:10:55 +0000447 QualType T = Ctx.getCanonicalType(R->getValueType());
Mike Stump11289f42009-09-09 15:08:12 +0000448
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000449 // FIXME: If the pointee isn't an integer type, should we flag a warning?
450 // People can do weird stuff with pointers.
Mike Stump11289f42009-09-09 15:08:12 +0000451
Jordan Rose61e221f2013-04-09 02:30:33 +0000452 if (!T->isIntegralOrEnumerationType())
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000453 return;
Mike Stump11289f42009-09-09 15:08:12 +0000454
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000455 uint64_t SourceSize = Ctx.getTypeSize(T);
Mike Stump11289f42009-09-09 15:08:12 +0000456
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000457 // CHECK: is SourceSize == TargetSize
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000458 if (SourceSize == TargetSize)
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000459 return;
Mike Stump11289f42009-09-09 15:08:12 +0000460
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000461 // Generate an error. Only generate a sink if 'SourceSize < TargetSize';
462 // otherwise generate a regular node.
463 //
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000464 // FIXME: We can actually create an abstract "CFNumber" object that has
465 // the bits initialized to the provided values.
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000466 //
Ted Kremenek750b7ac2010-12-20 21:19:09 +0000467 if (ExplodedNode *N = SourceSize < TargetSize ? C.generateSink()
Anna Zaksda4c8d62011-10-26 21:06:34 +0000468 : C.addTransition()) {
Dylan Noblesmith2c1dd272012-02-05 02:13:05 +0000469 SmallString<128> sbuf;
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000470 llvm::raw_svector_ostream os(sbuf);
471
472 os << (SourceSize == 8 ? "An " : "A ")
473 << SourceSize << " bit integer is used to initialize a CFNumber "
474 "object that represents "
475 << (TargetSize == 8 ? "an " : "a ")
476 << TargetSize << " bit integer. ";
477
478 if (SourceSize < TargetSize)
479 os << (TargetSize - SourceSize)
480 << " bits of the CFNumber value will be garbage." ;
481 else
482 os << (SourceSize - TargetSize)
483 << " bits of the input integer will be lost.";
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000484
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000485 if (!BT)
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000486 BT.reset(new APIMisuse("Bad use of CFNumberCreate"));
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000487
Anna Zaks3a6bdf82011-08-17 23:00:25 +0000488 BugReport *report = new BugReport(*BT, os.str(), N);
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000489 report->addRange(CE->getArg(2)->getSourceRange());
Jordan Rosee10d5a72012-11-02 01:53:40 +0000490 C.emitReport(report);
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000491 }
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000492}
493
Ted Kremenek1f352db2008-07-22 16:21:24 +0000494//===----------------------------------------------------------------------===//
Jordan Rose721567a2012-11-07 17:12:37 +0000495// CFRetain/CFRelease/CFMakeCollectable checking for null arguments.
Ted Kremenekc057f412009-07-14 00:43:42 +0000496//===----------------------------------------------------------------------===//
497
498namespace {
Argyrios Kyrtzidis6a5674f2011-03-01 01:16:21 +0000499class CFRetainReleaseChecker : public Checker< check::PreStmt<CallExpr> > {
Dylan Noblesmithe2778992012-02-05 02:12:40 +0000500 mutable OwningPtr<APIMisuse> BT;
Jordan Rose721567a2012-11-07 17:12:37 +0000501 mutable IdentifierInfo *Retain, *Release, *MakeCollectable;
Ted Kremenekc057f412009-07-14 00:43:42 +0000502public:
Jordan Rose721567a2012-11-07 17:12:37 +0000503 CFRetainReleaseChecker(): Retain(0), Release(0), MakeCollectable(0) {}
Ted Kremenek5ef32db2011-08-12 23:37:29 +0000504 void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
Ted Kremenekc057f412009-07-14 00:43:42 +0000505};
506} // end anonymous namespace
507
508
Ted Kremenek5ef32db2011-08-12 23:37:29 +0000509void CFRetainReleaseChecker::checkPreStmt(const CallExpr *CE,
510 CheckerContext &C) const {
Ted Kremenekc057f412009-07-14 00:43:42 +0000511 // If the CallExpr doesn't have exactly 1 argument just give up checking.
512 if (CE->getNumArgs() != 1)
Jordy Rose40c5c242010-07-06 02:34:42 +0000513 return;
Mike Stump11289f42009-09-09 15:08:12 +0000514
Ted Kremenek49b1e382012-01-26 21:29:00 +0000515 ProgramStateRef state = C.getState();
Anna Zaksc6aa5312011-12-01 05:57:37 +0000516 const FunctionDecl *FD = C.getCalleeDecl(CE);
Ted Kremenekc057f412009-07-14 00:43:42 +0000517 if (!FD)
Jordy Rose40c5c242010-07-06 02:34:42 +0000518 return;
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000519
520 if (!BT) {
521 ASTContext &Ctx = C.getASTContext();
522 Retain = &Ctx.Idents.get("CFRetain");
523 Release = &Ctx.Idents.get("CFRelease");
Jordan Rose721567a2012-11-07 17:12:37 +0000524 MakeCollectable = &Ctx.Idents.get("CFMakeCollectable");
525 BT.reset(
526 new APIMisuse("null passed to CFRetain/CFRelease/CFMakeCollectable"));
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000527 }
Mike Stump11289f42009-09-09 15:08:12 +0000528
Jordan Rose721567a2012-11-07 17:12:37 +0000529 // Check if we called CFRetain/CFRelease/CFMakeCollectable.
Mike Stump11289f42009-09-09 15:08:12 +0000530 const IdentifierInfo *FuncII = FD->getIdentifier();
Jordan Rose721567a2012-11-07 17:12:37 +0000531 if (!(FuncII == Retain || FuncII == Release || FuncII == MakeCollectable))
Jordy Rose40c5c242010-07-06 02:34:42 +0000532 return;
Mike Stump11289f42009-09-09 15:08:12 +0000533
Jordy Rose40c5c242010-07-06 02:34:42 +0000534 // FIXME: The rest of this just checks that the argument is non-null.
Anna Zaksef893392013-03-09 03:23:14 +0000535 // It should probably be refactored and combined with NonNullParamChecker.
Jordy Rose40c5c242010-07-06 02:34:42 +0000536
537 // Get the argument's value.
538 const Expr *Arg = CE->getArg(0);
Ted Kremenek632e3b72012-01-06 22:09:28 +0000539 SVal ArgVal = state->getSVal(Arg, C.getLocationContext());
David Blaikie05785d12013-02-20 22:23:23 +0000540 Optional<DefinedSVal> DefArgVal = ArgVal.getAs<DefinedSVal>();
Jordy Rose40c5c242010-07-06 02:34:42 +0000541 if (!DefArgVal)
542 return;
543
544 // Get a NULL value.
Ted Kremenek90af9092010-12-02 07:49:45 +0000545 SValBuilder &svalBuilder = C.getSValBuilder();
David Blaikie2fdacbc2013-02-20 05:52:05 +0000546 DefinedSVal zero =
547 svalBuilder.makeZeroVal(Arg->getType()).castAs<DefinedSVal>();
Jordy Rose40c5c242010-07-06 02:34:42 +0000548
549 // Make an expression asserting that they're equal.
Ted Kremenek90af9092010-12-02 07:49:45 +0000550 DefinedOrUnknownSVal ArgIsNull = svalBuilder.evalEQ(state, zero, *DefArgVal);
Jordy Rose40c5c242010-07-06 02:34:42 +0000551
552 // Are they equal?
Ted Kremenek49b1e382012-01-26 21:29:00 +0000553 ProgramStateRef stateTrue, stateFalse;
Ted Kremenekc5bea1e2010-12-01 22:16:56 +0000554 llvm::tie(stateTrue, stateFalse) = state->assume(ArgIsNull);
Jordy Rose40c5c242010-07-06 02:34:42 +0000555
556 if (stateTrue && !stateFalse) {
Ted Kremenek750b7ac2010-12-20 21:19:09 +0000557 ExplodedNode *N = C.generateSink(stateTrue);
Jordy Rose40c5c242010-07-06 02:34:42 +0000558 if (!N)
559 return;
560
Jordan Rose721567a2012-11-07 17:12:37 +0000561 const char *description;
562 if (FuncII == Retain)
563 description = "Null pointer argument in call to CFRetain";
564 else if (FuncII == Release)
565 description = "Null pointer argument in call to CFRelease";
566 else if (FuncII == MakeCollectable)
567 description = "Null pointer argument in call to CFMakeCollectable";
568 else
569 llvm_unreachable("impossible case");
Ted Kremenekc057f412009-07-14 00:43:42 +0000570
Anna Zaks3a6bdf82011-08-17 23:00:25 +0000571 BugReport *report = new BugReport(*BT, description, N);
Jordy Rose40c5c242010-07-06 02:34:42 +0000572 report->addRange(Arg->getSourceRange());
Jordan Rosea0f7d352012-08-28 00:50:51 +0000573 bugreporter::trackNullOrUndefValue(N, Arg, *report);
Jordan Rosee10d5a72012-11-02 01:53:40 +0000574 C.emitReport(report);
Jordy Rose40c5c242010-07-06 02:34:42 +0000575 return;
Ted Kremenekc057f412009-07-14 00:43:42 +0000576 }
577
Jordy Rose40c5c242010-07-06 02:34:42 +0000578 // From here on, we know the argument is non-null.
Anna Zaksda4c8d62011-10-26 21:06:34 +0000579 C.addTransition(stateFalse);
Ted Kremenekc057f412009-07-14 00:43:42 +0000580}
581
582//===----------------------------------------------------------------------===//
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000583// Check for sending 'retain', 'release', or 'autorelease' directly to a Class.
584//===----------------------------------------------------------------------===//
585
586namespace {
Argyrios Kyrtzidis6a5674f2011-03-01 01:16:21 +0000587class ClassReleaseChecker : public Checker<check::PreObjCMessage> {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000588 mutable Selector releaseS;
589 mutable Selector retainS;
590 mutable Selector autoreleaseS;
591 mutable Selector drainS;
Dylan Noblesmithe2778992012-02-05 02:12:40 +0000592 mutable OwningPtr<BugType> BT;
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000593
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000594public:
Jordan Rose547060b2012-07-02 19:28:04 +0000595 void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000596};
597}
598
Jordan Rose547060b2012-07-02 19:28:04 +0000599void ClassReleaseChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000600 CheckerContext &C) const {
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000601
602 if (!BT) {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000603 BT.reset(new APIMisuse("message incorrectly sent to class instead of class "
604 "instance"));
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000605
606 ASTContext &Ctx = C.getASTContext();
607 releaseS = GetNullarySelector("release", Ctx);
608 retainS = GetNullarySelector("retain", Ctx);
609 autoreleaseS = GetNullarySelector("autorelease", Ctx);
610 drainS = GetNullarySelector("drain", Ctx);
611 }
612
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +0000613 if (msg.isInstanceMessage())
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000614 return;
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +0000615 const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
616 assert(Class);
Douglas Gregor9a129192010-04-21 00:45:42 +0000617
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +0000618 Selector S = msg.getSelector();
Benjamin Kramer7d875c72009-11-20 10:03:00 +0000619 if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000620 return;
621
Anna Zaksda4c8d62011-10-26 21:06:34 +0000622 if (ExplodedNode *N = C.addTransition()) {
Dylan Noblesmith2c1dd272012-02-05 02:13:05 +0000623 SmallString<200> buf;
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000624 llvm::raw_svector_ostream os(buf);
Ted Kremenekf5735152009-11-23 22:22:01 +0000625
Aaron Ballmanb190f972014-01-03 17:59:55 +0000626 os << "The '";
627 S.print(os);
628 os << "' message should be sent to instances "
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000629 "of class '" << Class->getName()
630 << "' and not the class directly";
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000631
Anna Zaks3a6bdf82011-08-17 23:00:25 +0000632 BugReport *report = new BugReport(*BT, os.str(), N);
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +0000633 report->addRange(msg.getSourceRange());
Jordan Rosee10d5a72012-11-02 01:53:40 +0000634 C.emitReport(report);
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000635 }
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000636}
637
638//===----------------------------------------------------------------------===//
Anders Carlssond91d5f12011-03-13 20:35:21 +0000639// Check for passing non-Objective-C types to variadic methods that expect
640// only Objective-C types.
641//===----------------------------------------------------------------------===//
642
643namespace {
644class VariadicMethodTypeChecker : public Checker<check::PreObjCMessage> {
645 mutable Selector arrayWithObjectsS;
646 mutable Selector dictionaryWithObjectsAndKeysS;
647 mutable Selector setWithObjectsS;
Jordy Rosec0230d72012-04-06 19:06:01 +0000648 mutable Selector orderedSetWithObjectsS;
Anders Carlssond91d5f12011-03-13 20:35:21 +0000649 mutable Selector initWithObjectsS;
650 mutable Selector initWithObjectsAndKeysS;
Dylan Noblesmithe2778992012-02-05 02:12:40 +0000651 mutable OwningPtr<BugType> BT;
Anders Carlssond91d5f12011-03-13 20:35:21 +0000652
Jordan Rose547060b2012-07-02 19:28:04 +0000653 bool isVariadicMessage(const ObjCMethodCall &msg) const;
Anders Carlssond91d5f12011-03-13 20:35:21 +0000654
655public:
Jordan Rose547060b2012-07-02 19:28:04 +0000656 void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
Anders Carlssond91d5f12011-03-13 20:35:21 +0000657};
658}
659
660/// isVariadicMessage - Returns whether the given message is a variadic message,
661/// where all arguments must be Objective-C types.
662bool
Jordan Rose547060b2012-07-02 19:28:04 +0000663VariadicMethodTypeChecker::isVariadicMessage(const ObjCMethodCall &msg) const {
664 const ObjCMethodDecl *MD = msg.getDecl();
Ted Kremenekced5fea2011-04-12 21:47:05 +0000665
666 if (!MD || !MD->isVariadic() || isa<ObjCProtocolDecl>(MD->getDeclContext()))
Anders Carlssond91d5f12011-03-13 20:35:21 +0000667 return false;
668
669 Selector S = msg.getSelector();
670
671 if (msg.isInstanceMessage()) {
672 // FIXME: Ideally we'd look at the receiver interface here, but that's not
673 // useful for init, because alloc returns 'id'. In theory, this could lead
674 // to false positives, for example if there existed a class that had an
675 // initWithObjects: implementation that does accept non-Objective-C pointer
676 // types, but the chance of that happening is pretty small compared to the
677 // gains that this analysis gives.
678 const ObjCInterfaceDecl *Class = MD->getClassInterface();
679
Jordan Rose3ba8ae32012-06-11 16:40:37 +0000680 switch (findKnownClass(Class)) {
681 case FC_NSArray:
682 case FC_NSOrderedSet:
683 case FC_NSSet:
684 return S == initWithObjectsS;
685 case FC_NSDictionary:
686 return S == initWithObjectsAndKeysS;
687 default:
688 return false;
689 }
Anders Carlssond91d5f12011-03-13 20:35:21 +0000690 } else {
691 const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
692
Jordan Rose3ba8ae32012-06-11 16:40:37 +0000693 switch (findKnownClass(Class)) {
694 case FC_NSArray:
695 return S == arrayWithObjectsS;
696 case FC_NSOrderedSet:
697 return S == orderedSetWithObjectsS;
698 case FC_NSSet:
699 return S == setWithObjectsS;
700 case FC_NSDictionary:
701 return S == dictionaryWithObjectsAndKeysS;
702 default:
703 return false;
704 }
Anders Carlssond91d5f12011-03-13 20:35:21 +0000705 }
Anders Carlssond91d5f12011-03-13 20:35:21 +0000706}
707
Jordan Rose547060b2012-07-02 19:28:04 +0000708void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
Anders Carlssond91d5f12011-03-13 20:35:21 +0000709 CheckerContext &C) const {
710 if (!BT) {
711 BT.reset(new APIMisuse("Arguments passed to variadic method aren't all "
712 "Objective-C pointer types"));
713
714 ASTContext &Ctx = C.getASTContext();
715 arrayWithObjectsS = GetUnarySelector("arrayWithObjects", Ctx);
716 dictionaryWithObjectsAndKeysS =
717 GetUnarySelector("dictionaryWithObjectsAndKeys", Ctx);
718 setWithObjectsS = GetUnarySelector("setWithObjects", Ctx);
Jordy Rosec0230d72012-04-06 19:06:01 +0000719 orderedSetWithObjectsS = GetUnarySelector("orderedSetWithObjects", Ctx);
Anders Carlssond91d5f12011-03-13 20:35:21 +0000720
721 initWithObjectsS = GetUnarySelector("initWithObjects", Ctx);
722 initWithObjectsAndKeysS = GetUnarySelector("initWithObjectsAndKeys", Ctx);
723 }
724
725 if (!isVariadicMessage(msg))
726 return;
727
728 // We are not interested in the selector arguments since they have
729 // well-defined types, so the compiler will issue a warning for them.
730 unsigned variadicArgsBegin = msg.getSelector().getNumArgs();
731
732 // We're not interested in the last argument since it has to be nil or the
733 // compiler would have issued a warning for it elsewhere.
734 unsigned variadicArgsEnd = msg.getNumArgs() - 1;
735
736 if (variadicArgsEnd <= variadicArgsBegin)
737 return;
738
739 // Verify that all arguments have Objective-C types.
David Blaikie05785d12013-02-20 22:23:23 +0000740 Optional<ExplodedNode*> errorNode;
Alp Toker965f8822013-11-27 05:22:15 +0000741
Anders Carlssond91d5f12011-03-13 20:35:21 +0000742 for (unsigned I = variadicArgsBegin; I != variadicArgsEnd; ++I) {
Jordan Rose547060b2012-07-02 19:28:04 +0000743 QualType ArgTy = msg.getArgExpr(I)->getType();
Anders Carlssond91d5f12011-03-13 20:35:21 +0000744 if (ArgTy->isObjCObjectPointerType())
745 continue;
746
Anders Carlssond1f65f62011-04-19 01:16:46 +0000747 // Block pointers are treaded as Objective-C pointers.
748 if (ArgTy->isBlockPointerType())
749 continue;
750
Ted Kremenek4ceebbf2011-03-16 00:22:51 +0000751 // Ignore pointer constants.
David Blaikie2fdacbc2013-02-20 05:52:05 +0000752 if (msg.getArgSVal(I).getAs<loc::ConcreteInt>())
Ted Kremenek4ceebbf2011-03-16 00:22:51 +0000753 continue;
Ted Kremenek6fa1dae2011-03-17 04:01:35 +0000754
Ted Kremenek70727342011-03-17 04:10:25 +0000755 // Ignore pointer types annotated with 'NSObject' attribute.
756 if (C.getASTContext().isObjCNSObjectType(ArgTy))
757 continue;
758
Ted Kremenek6fa1dae2011-03-17 04:01:35 +0000759 // Ignore CF references, which can be toll-free bridged.
Ted Kremenekc85964e2011-07-16 19:50:32 +0000760 if (coreFoundation::isCFObjectRef(ArgTy))
Ted Kremenek6fa1dae2011-03-17 04:01:35 +0000761 continue;
Ted Kremenek4ceebbf2011-03-16 00:22:51 +0000762
Ted Kremenek066b2262011-03-14 19:50:37 +0000763 // Generate only one error node to use for all bug reports.
Jordan Rose547060b2012-07-02 19:28:04 +0000764 if (!errorNode.hasValue())
Anna Zaksda4c8d62011-10-26 21:06:34 +0000765 errorNode = C.addTransition();
Ted Kremenek066b2262011-03-14 19:50:37 +0000766
767 if (!errorNode.getValue())
Anders Carlssond91d5f12011-03-13 20:35:21 +0000768 continue;
769
Dylan Noblesmith2c1dd272012-02-05 02:13:05 +0000770 SmallString<128> sbuf;
Anders Carlssond91d5f12011-03-13 20:35:21 +0000771 llvm::raw_svector_ostream os(sbuf);
772
Jordan Rose547060b2012-07-02 19:28:04 +0000773 StringRef TypeName = GetReceiverInterfaceName(msg);
774 if (!TypeName.empty())
Anders Carlssond91d5f12011-03-13 20:35:21 +0000775 os << "Argument to '" << TypeName << "' method '";
776 else
777 os << "Argument to method '";
778
Aaron Ballmanb190f972014-01-03 17:59:55 +0000779 msg.getSelector().print(os);
780 os << "' should be an Objective-C pointer type, not '";
Jordan Rose547060b2012-07-02 19:28:04 +0000781 ArgTy.print(os, C.getLangOpts());
782 os << "'";
Anders Carlssond91d5f12011-03-13 20:35:21 +0000783
Jordan Rose547060b2012-07-02 19:28:04 +0000784 BugReport *R = new BugReport(*BT, os.str(), errorNode.getValue());
Anders Carlssond91d5f12011-03-13 20:35:21 +0000785 R->addRange(msg.getArgSourceRange(I));
Jordan Rosee10d5a72012-11-02 01:53:40 +0000786 C.emitReport(R);
Anders Carlssond91d5f12011-03-13 20:35:21 +0000787 }
788}
789
790//===----------------------------------------------------------------------===//
Jordan Roseefef7602012-06-11 16:40:41 +0000791// Improves the modeling of loops over Cocoa collections.
792//===----------------------------------------------------------------------===//
793
Anna Zaks27982c72013-06-22 00:23:26 +0000794// The map from container symbol to the container count symbol.
795// We currently will remember the last countainer count symbol encountered.
796REGISTER_MAP_WITH_PROGRAMSTATE(ContainerCountMap, SymbolRef, SymbolRef)
Jordan Rose5650bcb2013-11-08 17:23:33 +0000797REGISTER_MAP_WITH_PROGRAMSTATE(ContainerNonEmptyMap, SymbolRef, bool)
Anna Zaks27982c72013-06-22 00:23:26 +0000798
Jordan Roseefef7602012-06-11 16:40:41 +0000799namespace {
800class ObjCLoopChecker
Anna Zaks27982c72013-06-22 00:23:26 +0000801 : public Checker<check::PostStmt<ObjCForCollectionStmt>,
802 check::PostObjCMessage,
803 check::DeadSymbols,
804 check::PointerEscape > {
805 mutable IdentifierInfo *CountSelectorII;
806
807 bool isCollectionCountMethod(const ObjCMethodCall &M,
808 CheckerContext &C) const;
809
Jordan Roseefef7602012-06-11 16:40:41 +0000810public:
Anna Zaks27982c72013-06-22 00:23:26 +0000811 ObjCLoopChecker() : CountSelectorII(0) {}
Jordan Roseefef7602012-06-11 16:40:41 +0000812 void checkPostStmt(const ObjCForCollectionStmt *FCS, CheckerContext &C) const;
Anna Zaks27982c72013-06-22 00:23:26 +0000813 void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
814 void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
815 ProgramStateRef checkPointerEscape(ProgramStateRef State,
816 const InvalidatedSymbols &Escaped,
817 const CallEvent *Call,
818 PointerEscapeKind Kind) const;
Jordan Roseefef7602012-06-11 16:40:41 +0000819};
820}
821
822static bool isKnownNonNilCollectionType(QualType T) {
823 const ObjCObjectPointerType *PT = T->getAs<ObjCObjectPointerType>();
824 if (!PT)
825 return false;
826
827 const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();
828 if (!ID)
829 return false;
830
831 switch (findKnownClass(ID)) {
832 case FC_NSArray:
833 case FC_NSDictionary:
834 case FC_NSEnumerator:
835 case FC_NSOrderedSet:
836 case FC_NSSet:
837 return true;
838 default:
839 return false;
840 }
841}
842
Jordan Rose9de821e2013-04-26 21:43:01 +0000843/// Assumes that the collection is non-nil.
844///
845/// If the collection is known to be nil, returns NULL to indicate an infeasible
846/// path.
847static ProgramStateRef checkCollectionNonNil(CheckerContext &C,
848 ProgramStateRef State,
849 const ObjCForCollectionStmt *FCS) {
850 if (!State)
851 return NULL;
852
853 SVal CollectionVal = C.getSVal(FCS->getCollection());
854 Optional<DefinedSVal> KnownCollection = CollectionVal.getAs<DefinedSVal>();
855 if (!KnownCollection)
856 return State;
857
858 ProgramStateRef StNonNil, StNil;
859 llvm::tie(StNonNil, StNil) = State->assume(*KnownCollection);
860 if (StNil && !StNonNil) {
861 // The collection is nil. This path is infeasible.
862 return NULL;
863 }
864
865 return StNonNil;
866}
867
868/// Assumes that the collection elements are non-nil.
869///
870/// This only applies if the collection is one of those known not to contain
871/// nil values.
872static ProgramStateRef checkElementNonNil(CheckerContext &C,
873 ProgramStateRef State,
874 const ObjCForCollectionStmt *FCS) {
875 if (!State)
876 return NULL;
877
Jordan Roseefef7602012-06-11 16:40:41 +0000878 // See if the collection is one where we /know/ the elements are non-nil.
Jordan Rose9de821e2013-04-26 21:43:01 +0000879 if (!isKnownNonNilCollectionType(FCS->getCollection()->getType()))
880 return State;
881
882 const LocationContext *LCtx = C.getLocationContext();
Jordan Roseefef7602012-06-11 16:40:41 +0000883 const Stmt *Element = FCS->getElement();
Jordan Rose9de821e2013-04-26 21:43:01 +0000884
885 // FIXME: Copied from ExprEngineObjC.
886 Optional<Loc> ElementLoc;
Jordan Roseefef7602012-06-11 16:40:41 +0000887 if (const DeclStmt *DS = dyn_cast<DeclStmt>(Element)) {
888 const VarDecl *ElemDecl = cast<VarDecl>(DS->getSingleDecl());
889 assert(ElemDecl->getInit() == 0);
Jordan Rose9de821e2013-04-26 21:43:01 +0000890 ElementLoc = State->getLValue(ElemDecl, LCtx);
Jordan Roseefef7602012-06-11 16:40:41 +0000891 } else {
Jordan Rose9de821e2013-04-26 21:43:01 +0000892 ElementLoc = State->getSVal(Element, LCtx).getAs<Loc>();
Jordan Roseefef7602012-06-11 16:40:41 +0000893 }
894
Jordan Rose9de821e2013-04-26 21:43:01 +0000895 if (!ElementLoc)
896 return State;
Jordan Roseefef7602012-06-11 16:40:41 +0000897
898 // Go ahead and assume the value is non-nil.
Jordan Rose9de821e2013-04-26 21:43:01 +0000899 SVal Val = State->getSVal(*ElementLoc);
900 return State->assume(Val.castAs<DefinedOrUnknownSVal>(), true);
901}
902
Anna Zaks27982c72013-06-22 00:23:26 +0000903/// Returns NULL state if the collection is known to contain elements
904/// (or is known not to contain elements if the Assumption parameter is false.)
Jordan Rose1a4ae202013-11-08 01:15:35 +0000905static ProgramStateRef
906assumeCollectionNonEmpty(CheckerContext &C, ProgramStateRef State,
907 SymbolRef CollectionS, bool Assumption) {
908 if (!State || !CollectionS)
909 return State;
Anna Zaks27982c72013-06-22 00:23:26 +0000910
Anna Zaks27982c72013-06-22 00:23:26 +0000911 const SymbolRef *CountS = State->get<ContainerCountMap>(CollectionS);
Jordan Rose1a4ae202013-11-08 01:15:35 +0000912 if (!CountS) {
Jordan Rose5650bcb2013-11-08 17:23:33 +0000913 const bool *KnownNonEmpty = State->get<ContainerNonEmptyMap>(CollectionS);
Jordan Rose1a4ae202013-11-08 01:15:35 +0000914 if (!KnownNonEmpty)
915 return State->set<ContainerNonEmptyMap>(CollectionS, Assumption);
916 return (Assumption == *KnownNonEmpty) ? State : NULL;
917 }
Anna Zaks27982c72013-06-22 00:23:26 +0000918
919 SValBuilder &SvalBuilder = C.getSValBuilder();
920 SVal CountGreaterThanZeroVal =
921 SvalBuilder.evalBinOp(State, BO_GT,
922 nonloc::SymbolVal(*CountS),
923 SvalBuilder.makeIntVal(0, (*CountS)->getType()),
924 SvalBuilder.getConditionType());
925 Optional<DefinedSVal> CountGreaterThanZero =
926 CountGreaterThanZeroVal.getAs<DefinedSVal>();
927 if (!CountGreaterThanZero) {
928 // The SValBuilder cannot construct a valid SVal for this condition.
929 // This means we cannot properly reason about it.
930 return State;
931 }
932
933 return State->assume(*CountGreaterThanZero, Assumption);
934}
935
Jordan Rose1a4ae202013-11-08 01:15:35 +0000936static ProgramStateRef
937assumeCollectionNonEmpty(CheckerContext &C, ProgramStateRef State,
938 const ObjCForCollectionStmt *FCS,
939 bool Assumption) {
940 if (!State)
941 return NULL;
942
943 SymbolRef CollectionS =
944 State->getSVal(FCS->getCollection(), C.getLocationContext()).getAsSymbol();
945 return assumeCollectionNonEmpty(C, State, CollectionS, Assumption);
946}
947
948
Anna Zaks27982c72013-06-22 00:23:26 +0000949/// If the fist block edge is a back edge, we are reentering the loop.
950static bool alreadyExecutedAtLeastOneLoopIteration(const ExplodedNode *N,
951 const ObjCForCollectionStmt *FCS) {
952 if (!N)
953 return false;
954
955 ProgramPoint P = N->getLocation();
956 if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) {
957 if (BE->getSrc()->getLoopTarget() == FCS)
958 return true;
959 return false;
960 }
961
962 // Keep looking for a block edge.
963 for (ExplodedNode::const_pred_iterator I = N->pred_begin(),
964 E = N->pred_end(); I != E; ++I) {
965 if (alreadyExecutedAtLeastOneLoopIteration(*I, FCS))
966 return true;
967 }
968
969 return false;
970}
971
Jordan Rose9de821e2013-04-26 21:43:01 +0000972void ObjCLoopChecker::checkPostStmt(const ObjCForCollectionStmt *FCS,
973 CheckerContext &C) const {
Anna Zaks27982c72013-06-22 00:23:26 +0000974 ProgramStateRef State = C.getState();
975
Jordan Rose9de821e2013-04-26 21:43:01 +0000976 // Check if this is the branch for the end of the loop.
977 SVal CollectionSentinel = C.getSVal(FCS);
Anna Zaks27982c72013-06-22 00:23:26 +0000978 if (CollectionSentinel.isZeroConstant()) {
979 if (!alreadyExecutedAtLeastOneLoopIteration(C.getPredecessor(), FCS))
980 State = assumeCollectionNonEmpty(C, State, FCS, /*Assumption*/false);
Jordan Rose9de821e2013-04-26 21:43:01 +0000981
Anna Zaks27982c72013-06-22 00:23:26 +0000982 // Otherwise, this is a branch that goes through the loop body.
983 } else {
984 State = checkCollectionNonNil(C, State, FCS);
985 State = checkElementNonNil(C, State, FCS);
986 State = assumeCollectionNonEmpty(C, State, FCS, /*Assumption*/true);
987 }
988
Jordan Rose9de821e2013-04-26 21:43:01 +0000989 if (!State)
990 C.generateSink();
991 else if (State != C.getState())
992 C.addTransition(State);
Jordan Roseefef7602012-06-11 16:40:41 +0000993}
994
Anna Zaks27982c72013-06-22 00:23:26 +0000995bool ObjCLoopChecker::isCollectionCountMethod(const ObjCMethodCall &M,
996 CheckerContext &C) const {
997 Selector S = M.getSelector();
998 // Initialize the identifiers on first use.
999 if (!CountSelectorII)
1000 CountSelectorII = &C.getASTContext().Idents.get("count");
1001
1002 // If the method returns collection count, record the value.
1003 if (S.isUnarySelector() &&
1004 (S.getIdentifierInfoForSlot(0) == CountSelectorII))
1005 return true;
1006
1007 return false;
1008}
1009
1010void ObjCLoopChecker::checkPostObjCMessage(const ObjCMethodCall &M,
1011 CheckerContext &C) const {
1012 if (!M.isInstanceMessage())
1013 return;
1014
1015 const ObjCInterfaceDecl *ClassID = M.getReceiverInterface();
1016 if (!ClassID)
1017 return;
1018
1019 FoundationClass Class = findKnownClass(ClassID);
1020 if (Class != FC_NSDictionary &&
1021 Class != FC_NSArray &&
Anna Zaks3d46ac62013-11-04 19:13:08 +00001022 Class != FC_NSSet &&
1023 Class != FC_NSOrderedSet)
Anna Zaks27982c72013-06-22 00:23:26 +00001024 return;
1025
1026 SymbolRef ContainerS = M.getReceiverSVal().getAsSymbol();
1027 if (!ContainerS)
1028 return;
1029
1030 // If we are processing a call to "count", get the symbolic value returned by
1031 // a call to "count" and add it to the map.
1032 if (!isCollectionCountMethod(M, C))
1033 return;
1034
1035 const Expr *MsgExpr = M.getOriginExpr();
1036 SymbolRef CountS = C.getSVal(MsgExpr).getAsSymbol();
1037 if (CountS) {
1038 ProgramStateRef State = C.getState();
Jordan Rose1a4ae202013-11-08 01:15:35 +00001039
Anna Zaks27982c72013-06-22 00:23:26 +00001040 C.getSymbolManager().addSymbolDependency(ContainerS, CountS);
1041 State = State->set<ContainerCountMap>(ContainerS, CountS);
Jordan Rose1a4ae202013-11-08 01:15:35 +00001042
Jordan Rose5650bcb2013-11-08 17:23:33 +00001043 if (const bool *NonEmpty = State->get<ContainerNonEmptyMap>(ContainerS)) {
Jordan Rose1a4ae202013-11-08 01:15:35 +00001044 State = State->remove<ContainerNonEmptyMap>(ContainerS);
1045 State = assumeCollectionNonEmpty(C, State, ContainerS, *NonEmpty);
1046 }
1047
Anna Zaks27982c72013-06-22 00:23:26 +00001048 C.addTransition(State);
1049 }
1050 return;
1051}
1052
Jordan Rose1a4ae202013-11-08 01:15:35 +00001053static SymbolRef getMethodReceiverIfKnownImmutable(const CallEvent *Call) {
1054 const ObjCMethodCall *Message = dyn_cast_or_null<ObjCMethodCall>(Call);
1055 if (!Message)
1056 return 0;
1057
1058 const ObjCMethodDecl *MD = Message->getDecl();
1059 if (!MD)
1060 return 0;
1061
1062 const ObjCInterfaceDecl *StaticClass;
1063 if (isa<ObjCProtocolDecl>(MD->getDeclContext())) {
1064 // We can't find out where the method was declared without doing more work.
1065 // Instead, see if the receiver is statically typed as a known immutable
1066 // collection.
1067 StaticClass = Message->getOriginExpr()->getReceiverInterface();
1068 } else {
1069 StaticClass = MD->getClassInterface();
1070 }
1071
1072 if (!StaticClass)
1073 return 0;
1074
1075 switch (findKnownClass(StaticClass, /*IncludeSuper=*/false)) {
1076 case FC_None:
1077 return 0;
1078 case FC_NSArray:
1079 case FC_NSDictionary:
1080 case FC_NSEnumerator:
1081 case FC_NSNull:
1082 case FC_NSOrderedSet:
1083 case FC_NSSet:
1084 case FC_NSString:
1085 break;
1086 }
1087
1088 return Message->getReceiverSVal().getAsSymbol();
1089}
1090
Anna Zaks27982c72013-06-22 00:23:26 +00001091ProgramStateRef
1092ObjCLoopChecker::checkPointerEscape(ProgramStateRef State,
1093 const InvalidatedSymbols &Escaped,
1094 const CallEvent *Call,
1095 PointerEscapeKind Kind) const {
Jordan Rose1a4ae202013-11-08 01:15:35 +00001096 SymbolRef ImmutableReceiver = getMethodReceiverIfKnownImmutable(Call);
Anna Zaks27982c72013-06-22 00:23:26 +00001097
1098 // Remove the invalidated symbols form the collection count map.
1099 for (InvalidatedSymbols::const_iterator I = Escaped.begin(),
1100 E = Escaped.end();
1101 I != E; ++I) {
1102 SymbolRef Sym = *I;
1103
Jordan Rose1a4ae202013-11-08 01:15:35 +00001104 // Don't invalidate this symbol's count if we know the method being called
1105 // is declared on an immutable class. This isn't completely correct if the
1106 // receiver is also passed as an argument, but in most uses of NSArray,
1107 // NSDictionary, etc. this isn't likely to happen in a dangerous way.
1108 if (Sym == ImmutableReceiver)
1109 continue;
1110
Anna Zaks27982c72013-06-22 00:23:26 +00001111 // The symbol escaped. Pessimistically, assume that the count could have
1112 // changed.
1113 State = State->remove<ContainerCountMap>(Sym);
Jordan Rose1a4ae202013-11-08 01:15:35 +00001114 State = State->remove<ContainerNonEmptyMap>(Sym);
Anna Zaks27982c72013-06-22 00:23:26 +00001115 }
1116 return State;
1117}
1118
1119void ObjCLoopChecker::checkDeadSymbols(SymbolReaper &SymReaper,
1120 CheckerContext &C) const {
1121 ProgramStateRef State = C.getState();
1122
1123 // Remove the dead symbols from the collection count map.
1124 ContainerCountMapTy Tracked = State->get<ContainerCountMap>();
1125 for (ContainerCountMapTy::iterator I = Tracked.begin(),
1126 E = Tracked.end(); I != E; ++I) {
1127 SymbolRef Sym = I->first;
Jordan Rose1a4ae202013-11-08 01:15:35 +00001128 if (SymReaper.isDead(Sym)) {
Anna Zaks27982c72013-06-22 00:23:26 +00001129 State = State->remove<ContainerCountMap>(Sym);
Jordan Rose1a4ae202013-11-08 01:15:35 +00001130 State = State->remove<ContainerNonEmptyMap>(Sym);
1131 }
Anna Zaks27982c72013-06-22 00:23:26 +00001132 }
1133
1134 C.addTransition(State);
1135}
1136
Anna Zaks5a5a1752012-08-22 21:19:56 +00001137namespace {
1138/// \class ObjCNonNilReturnValueChecker
Anna Zaks4818bbe2012-08-30 19:40:52 +00001139/// \brief The checker restricts the return values of APIs known to
1140/// never (or almost never) return 'nil'.
Anna Zaks5a5a1752012-08-22 21:19:56 +00001141class ObjCNonNilReturnValueChecker
Jordan Rose4393aa72014-02-08 00:04:14 +00001142 : public Checker<check::PostObjCMessage,
1143 check::PostStmt<ObjCArrayLiteral>,
1144 check::PostStmt<ObjCDictionaryLiteral>,
1145 check::PostStmt<ObjCBoxedExpr> > {
Anna Zaks5a5a1752012-08-22 21:19:56 +00001146 mutable bool Initialized;
1147 mutable Selector ObjectAtIndex;
1148 mutable Selector ObjectAtIndexedSubscript;
Anna Zaks4063fa12013-05-10 18:04:46 +00001149 mutable Selector NullSelector;
Anna Zaks9159e162012-08-22 22:47:58 +00001150
Anna Zaks5a5a1752012-08-22 21:19:56 +00001151public:
Anna Zaks9159e162012-08-22 22:47:58 +00001152 ObjCNonNilReturnValueChecker() : Initialized(false) {}
Jordan Rose4393aa72014-02-08 00:04:14 +00001153
1154 ProgramStateRef assumeExprIsNonNull(const Expr *NonNullExpr,
1155 ProgramStateRef State,
1156 CheckerContext &C) const;
1157 void assumeExprIsNonNull(const Expr *E, CheckerContext &C) const {
1158 C.addTransition(assumeExprIsNonNull(E, C.getState(), C));
1159 }
1160
1161 void checkPostStmt(const ObjCArrayLiteral *E, CheckerContext &C) const {
1162 assumeExprIsNonNull(E, C);
1163 }
1164 void checkPostStmt(const ObjCDictionaryLiteral *E, CheckerContext &C) const {
1165 assumeExprIsNonNull(E, C);
1166 }
1167 void checkPostStmt(const ObjCBoxedExpr *E, CheckerContext &C) const {
1168 assumeExprIsNonNull(E, C);
1169 }
1170
Anna Zaks5a5a1752012-08-22 21:19:56 +00001171 void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
1172};
1173}
1174
Jordan Rose4393aa72014-02-08 00:04:14 +00001175ProgramStateRef
1176ObjCNonNilReturnValueChecker::assumeExprIsNonNull(const Expr *NonNullExpr,
1177 ProgramStateRef State,
1178 CheckerContext &C) const {
Anna Zaks4818bbe2012-08-30 19:40:52 +00001179 SVal Val = State->getSVal(NonNullExpr, C.getLocationContext());
David Blaikie05785d12013-02-20 22:23:23 +00001180 if (Optional<DefinedOrUnknownSVal> DV = Val.getAs<DefinedOrUnknownSVal>())
Anna Zaks830c48e2012-08-30 22:55:32 +00001181 return State->assume(*DV, true);
Anna Zaksb504f442012-08-30 22:42:41 +00001182 return State;
Anna Zaks4818bbe2012-08-30 19:40:52 +00001183}
1184
Anna Zaks5a5a1752012-08-22 21:19:56 +00001185void ObjCNonNilReturnValueChecker::checkPostObjCMessage(const ObjCMethodCall &M,
1186 CheckerContext &C)
Anna Zaks4818bbe2012-08-30 19:40:52 +00001187 const {
Anna Zaks5a5a1752012-08-22 21:19:56 +00001188 ProgramStateRef State = C.getState();
1189
1190 if (!Initialized) {
1191 ASTContext &Ctx = C.getASTContext();
1192 ObjectAtIndex = GetUnarySelector("objectAtIndex", Ctx);
1193 ObjectAtIndexedSubscript = GetUnarySelector("objectAtIndexedSubscript", Ctx);
Anna Zaks4063fa12013-05-10 18:04:46 +00001194 NullSelector = GetNullarySelector("null", Ctx);
Anna Zaks5a5a1752012-08-22 21:19:56 +00001195 }
1196
1197 // Check the receiver type.
1198 if (const ObjCInterfaceDecl *Interface = M.getReceiverInterface()) {
Anna Zaks4818bbe2012-08-30 19:40:52 +00001199
1200 // Assume that object returned from '[self init]' or '[super init]' is not
1201 // 'nil' if we are processing an inlined function/method.
1202 //
1203 // A defensive callee will (and should) check if the object returned by
1204 // '[super init]' is 'nil' before doing it's own initialization. However,
1205 // since 'nil' is rarely returned in practice, we should not warn when the
1206 // caller to the defensive constructor uses the object in contexts where
1207 // 'nil' is not accepted.
Anna Zaks49bb6502012-11-06 04:20:54 +00001208 if (!C.inTopFrame() && M.getDecl() &&
Anna Zaks4818bbe2012-08-30 19:40:52 +00001209 M.getDecl()->getMethodFamily() == OMF_init &&
1210 M.isReceiverSelfOrSuper()) {
1211 State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
1212 }
1213
Anna Zaks4063fa12013-05-10 18:04:46 +00001214 FoundationClass Cl = findKnownClass(Interface);
1215
Anna Zaks4818bbe2012-08-30 19:40:52 +00001216 // Objects returned from
1217 // [NSArray|NSOrderedSet]::[ObjectAtIndex|ObjectAtIndexedSubscript]
1218 // are never 'nil'.
Anna Zaks5a5a1752012-08-22 21:19:56 +00001219 if (Cl == FC_NSArray || Cl == FC_NSOrderedSet) {
1220 Selector Sel = M.getSelector();
1221 if (Sel == ObjectAtIndex || Sel == ObjectAtIndexedSubscript) {
1222 // Go ahead and assume the value is non-nil.
Anna Zaks4818bbe2012-08-30 19:40:52 +00001223 State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
Anna Zaks5a5a1752012-08-22 21:19:56 +00001224 }
1225 }
Anna Zaks4063fa12013-05-10 18:04:46 +00001226
1227 // Objects returned from [NSNull null] are not nil.
1228 if (Cl == FC_NSNull) {
1229 if (M.getSelector() == NullSelector) {
1230 // Go ahead and assume the value is non-nil.
1231 State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
1232 }
1233 }
Anna Zaks5a5a1752012-08-22 21:19:56 +00001234 }
Anna Zaks4818bbe2012-08-30 19:40:52 +00001235 C.addTransition(State);
Anna Zaks5a5a1752012-08-22 21:19:56 +00001236}
Jordan Roseefef7602012-06-11 16:40:41 +00001237
1238//===----------------------------------------------------------------------===//
Ted Kremenek1f352db2008-07-22 16:21:24 +00001239// Check registration.
Ted Kremenekc057f412009-07-14 00:43:42 +00001240//===----------------------------------------------------------------------===//
Argyrios Kyrtzidis9d4d4f92011-02-16 01:40:52 +00001241
Argyrios Kyrtzidis507ff532011-02-17 21:39:17 +00001242void ento::registerNilArgChecker(CheckerManager &mgr) {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +00001243 mgr.registerChecker<NilArgChecker>();
Argyrios Kyrtzidis9d4d4f92011-02-16 01:40:52 +00001244}
1245
Argyrios Kyrtzidis507ff532011-02-17 21:39:17 +00001246void ento::registerCFNumberCreateChecker(CheckerManager &mgr) {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +00001247 mgr.registerChecker<CFNumberCreateChecker>();
Argyrios Kyrtzidis9d4d4f92011-02-16 01:40:52 +00001248}
1249
Argyrios Kyrtzidis507ff532011-02-17 21:39:17 +00001250void ento::registerCFRetainReleaseChecker(CheckerManager &mgr) {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +00001251 mgr.registerChecker<CFRetainReleaseChecker>();
Ted Kremenek1f352db2008-07-22 16:21:24 +00001252}
Argyrios Kyrtzidis507ff532011-02-17 21:39:17 +00001253
1254void ento::registerClassReleaseChecker(CheckerManager &mgr) {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +00001255 mgr.registerChecker<ClassReleaseChecker>();
Argyrios Kyrtzidis507ff532011-02-17 21:39:17 +00001256}
Anders Carlssond91d5f12011-03-13 20:35:21 +00001257
1258void ento::registerVariadicMethodTypeChecker(CheckerManager &mgr) {
1259 mgr.registerChecker<VariadicMethodTypeChecker>();
1260}
Jordan Roseefef7602012-06-11 16:40:41 +00001261
1262void ento::registerObjCLoopChecker(CheckerManager &mgr) {
1263 mgr.registerChecker<ObjCLoopChecker>();
1264}
Anna Zaks5a5a1752012-08-22 21:19:56 +00001265
1266void ento::registerObjCNonNilReturnValueChecker(CheckerManager &mgr) {
1267 mgr.registerChecker<ObjCNonNilReturnValueChecker>();
1268}