blob: 4b2ccd43aa396f9dbd1a0ac5dbffe760ff9642aa [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:
Alexander Kornienko4aca9b12014-02-11 21:49:21 +000042 APIMisuse(const CheckerBase *checker, const char *name)
43 : BugType(checker, name, "API Misuse (Apple)") {}
Ted Kremenekbd2c8002010-10-20 23:38:56 +000044};
45} // end anonymous namespace
46
47//===----------------------------------------------------------------------===//
48// Utility functions.
49//===----------------------------------------------------------------------===//
50
Jordan Rose547060b2012-07-02 19:28:04 +000051static StringRef GetReceiverInterfaceName(const ObjCMethodCall &msg) {
Anders Carlsson3c50aea2011-03-08 20:05:26 +000052 if (const ObjCInterfaceDecl *ID = msg.getReceiverInterface())
Jordan Rose547060b2012-07-02 19:28:04 +000053 return ID->getIdentifier()->getName();
54 return StringRef();
Ted Kremenek276278e2008-03-27 22:05:32 +000055}
Ted Kremeneka4d60b62008-03-27 17:17:22 +000056
Jordan Rose3ba8ae32012-06-11 16:40:37 +000057enum FoundationClass {
58 FC_None,
59 FC_NSArray,
60 FC_NSDictionary,
61 FC_NSEnumerator,
Anna Zaks4063fa12013-05-10 18:04:46 +000062 FC_NSNull,
Jordan Rose3ba8ae32012-06-11 16:40:37 +000063 FC_NSOrderedSet,
64 FC_NSSet,
65 FC_NSString
66};
Anders Carlsson3c50aea2011-03-08 20:05:26 +000067
Jordan Rose1a4ae202013-11-08 01:15:35 +000068static FoundationClass findKnownClass(const ObjCInterfaceDecl *ID,
69 bool IncludeSuperclasses = true) {
Jordan Rose3ba8ae32012-06-11 16:40:37 +000070 static llvm::StringMap<FoundationClass> Classes;
71 if (Classes.empty()) {
72 Classes["NSArray"] = FC_NSArray;
73 Classes["NSDictionary"] = FC_NSDictionary;
74 Classes["NSEnumerator"] = FC_NSEnumerator;
Anna Zaks4063fa12013-05-10 18:04:46 +000075 Classes["NSNull"] = FC_NSNull;
Jordan Rose3ba8ae32012-06-11 16:40:37 +000076 Classes["NSOrderedSet"] = FC_NSOrderedSet;
77 Classes["NSSet"] = FC_NSSet;
78 Classes["NSString"] = FC_NSString;
79 }
Anders Carlsson3c50aea2011-03-08 20:05:26 +000080
Jordan Rose3ba8ae32012-06-11 16:40:37 +000081 // FIXME: Should we cache this at all?
82 FoundationClass result = Classes.lookup(ID->getIdentifier()->getName());
Jordan Rose1a4ae202013-11-08 01:15:35 +000083 if (result == FC_None && IncludeSuperclasses)
Jordan Rose3ba8ae32012-06-11 16:40:37 +000084 if (const ObjCInterfaceDecl *Super = ID->getSuperClass())
85 return findKnownClass(Super);
86
87 return result;
Ted Kremenekc0414922008-03-27 07:25:52 +000088}
89
90//===----------------------------------------------------------------------===//
Ted Kremenekbd2c8002010-10-20 23:38:56 +000091// NilArgChecker - Check for prohibited nil arguments to ObjC method calls.
Ted Kremenekc0414922008-03-27 07:25:52 +000092//===----------------------------------------------------------------------===//
93
Benjamin Kramer2fc373e2010-10-22 16:33:16 +000094namespace {
Anna Zaksbb2a2c82013-05-13 21:48:20 +000095 class NilArgChecker : public Checker<check::PreObjCMessage,
96 check::PostStmt<ObjCDictionaryLiteral>,
97 check::PostStmt<ObjCArrayLiteral> > {
Ahmed Charlesb8984322014-03-07 20:03:18 +000098 mutable std::unique_ptr<APIMisuse> BT;
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +000099
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000100 void warnIfNilExpr(const Expr *E,
101 const char *Msg,
102 CheckerContext &C) const;
103
104 void warnIfNilArg(CheckerContext &C,
105 const ObjCMethodCall &msg, unsigned Arg,
106 FoundationClass Class,
107 bool CanBeSubscript = false) const;
108
109 void generateBugReport(ExplodedNode *N,
Anna Zaks6afa8f12013-05-13 23:49:51 +0000110 StringRef Msg,
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000111 SourceRange Range,
112 const Expr *Expr,
113 CheckerContext &C) const;
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000114
Benjamin Kramer2fc373e2010-10-22 16:33:16 +0000115 public:
Jordan Rose547060b2012-07-02 19:28:04 +0000116 void checkPreObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000117 void checkPostStmt(const ObjCDictionaryLiteral *DL,
118 CheckerContext &C) const;
119 void checkPostStmt(const ObjCArrayLiteral *AL,
120 CheckerContext &C) const;
Benjamin Kramer2fc373e2010-10-22 16:33:16 +0000121 };
122}
Mike Stump11289f42009-09-09 15:08:12 +0000123
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000124void NilArgChecker::warnIfNilExpr(const Expr *E,
125 const char *Msg,
126 CheckerContext &C) const {
127 ProgramStateRef State = C.getState();
Anna Zaks6afa8f12013-05-13 23:49:51 +0000128 if (State->isNull(C.getSVal(E)).isConstrainedTrue()) {
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000129
130 if (ExplodedNode *N = C.generateSink()) {
Anna Zaks6afa8f12013-05-13 23:49:51 +0000131 generateBugReport(N, Msg, E->getSourceRange(), E, C);
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000132 }
133
134 }
135}
136
137void NilArgChecker::warnIfNilArg(CheckerContext &C,
Anna Zaks130df4b2013-03-23 00:39:21 +0000138 const ObjCMethodCall &msg,
139 unsigned int Arg,
140 FoundationClass Class,
141 bool CanBeSubscript) const {
142 // Check if the argument is nil.
143 ProgramStateRef State = C.getState();
144 if (!State->isNull(msg.getArgSVal(Arg)).isConstrainedTrue())
145 return;
146
Ted Kremenek750b7ac2010-12-20 21:19:09 +0000147 if (ExplodedNode *N = C.generateSink()) {
Dylan Noblesmith2c1dd272012-02-05 02:13:05 +0000148 SmallString<128> sbuf;
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000149 llvm::raw_svector_ostream os(sbuf);
Anna Zaks130df4b2013-03-23 00:39:21 +0000150
151 if (CanBeSubscript && msg.getMessageKind() == OCM_Subscript) {
152
153 if (Class == FC_NSArray) {
154 os << "Array element cannot be nil";
155 } else if (Class == FC_NSDictionary) {
Anna Zaks4d1e3042013-04-05 23:50:18 +0000156 if (Arg == 0) {
Ted Kremeneke06df462013-04-08 18:09:16 +0000157 os << "Value stored into '";
Anna Zaks4d1e3042013-04-05 23:50:18 +0000158 os << GetReceiverInterfaceName(msg) << "' cannot be nil";
159 } else {
Anna Zaks130df4b2013-03-23 00:39:21 +0000160 assert(Arg == 1);
Anna Zaks4d1e3042013-04-05 23:50:18 +0000161 os << "'"<< GetReceiverInterfaceName(msg) << "' key cannot be nil";
Anna Zaks130df4b2013-03-23 00:39:21 +0000162 }
163 } else
164 llvm_unreachable("Missing foundation class for the subscript expr");
165
166 } else {
Anna Zaks4d1e3042013-04-05 23:50:18 +0000167 if (Class == FC_NSDictionary) {
168 if (Arg == 0)
169 os << "Value argument ";
170 else {
171 assert(Arg == 1);
172 os << "Key argument ";
173 }
Aaron Ballmanb190f972014-01-03 17:59:55 +0000174 os << "to '";
175 msg.getSelector().print(os);
176 os << "' cannot be nil";
Anna Zaks4d1e3042013-04-05 23:50:18 +0000177 } else {
Aaron Ballmanb190f972014-01-03 17:59:55 +0000178 os << "Argument to '" << GetReceiverInterfaceName(msg) << "' method '";
179 msg.getSelector().print(os);
180 os << "' cannot be nil";
Anna Zaks4d1e3042013-04-05 23:50:18 +0000181 }
Anna Zaks130df4b2013-03-23 00:39:21 +0000182 }
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000183
Anna Zaks6afa8f12013-05-13 23:49:51 +0000184 generateBugReport(N, os.str(), msg.getArgSourceRange(Arg),
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000185 msg.getArgExpr(Arg), C);
Ted Kremenek276278e2008-03-27 22:05:32 +0000186 }
Ted Kremenek276278e2008-03-27 22:05:32 +0000187}
188
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000189void NilArgChecker::generateBugReport(ExplodedNode *N,
Anna Zaks6afa8f12013-05-13 23:49:51 +0000190 StringRef Msg,
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000191 SourceRange Range,
Anna Zaks6afa8f12013-05-13 23:49:51 +0000192 const Expr *E,
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000193 CheckerContext &C) const {
194 if (!BT)
Alexander Kornienko4aca9b12014-02-11 21:49:21 +0000195 BT.reset(new APIMisuse(this, "nil argument"));
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000196
Anna Zaks6afa8f12013-05-13 23:49:51 +0000197 BugReport *R = new BugReport(*BT, Msg, N);
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000198 R->addRange(Range);
Anna Zaks6afa8f12013-05-13 23:49:51 +0000199 bugreporter::trackNullOrUndefValue(N, E, *R);
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000200 C.emitReport(R);
201}
202
Jordan Rose547060b2012-07-02 19:28:04 +0000203void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000204 CheckerContext &C) const {
Anders Carlsson3c50aea2011-03-08 20:05:26 +0000205 const ObjCInterfaceDecl *ID = msg.getReceiverInterface();
206 if (!ID)
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000207 return;
Anna Zaks6457ad22013-03-18 20:46:56 +0000208
209 FoundationClass Class = findKnownClass(ID);
210
211 static const unsigned InvalidArgIndex = UINT_MAX;
212 unsigned Arg = InvalidArgIndex;
Anna Zaks130df4b2013-03-23 00:39:21 +0000213 bool CanBeSubscript = false;
214
Anna Zaks6457ad22013-03-18 20:46:56 +0000215 if (Class == FC_NSString) {
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +0000216 Selector S = msg.getSelector();
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000217
218 if (S.isUnarySelector())
219 return;
220
221 // FIXME: This is going to be really slow doing these checks with
222 // lexical comparisons.
223
224 std::string NameStr = S.getAsString();
Chris Lattner0e62c1c2011-07-23 10:55:15 +0000225 StringRef Name(NameStr);
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000226 assert(!Name.empty());
227
228 // FIXME: Checking for initWithFormat: will not work in most cases
229 // yet because [NSString alloc] returns id, not NSString*. We will
230 // need support for tracking expected-type information in the analyzer
231 // to find these errors.
232 if (Name == "caseInsensitiveCompare:" ||
233 Name == "compare:" ||
234 Name == "compare:options:" ||
235 Name == "compare:options:range:" ||
236 Name == "compare:options:range:locale:" ||
237 Name == "componentsSeparatedByCharactersInSet:" ||
238 Name == "initWithFormat:") {
Anna Zaks6457ad22013-03-18 20:46:56 +0000239 Arg = 0;
240 }
241 } else if (Class == FC_NSArray) {
242 Selector S = msg.getSelector();
243
244 if (S.isUnarySelector())
245 return;
246
247 if (S.getNameForSlot(0).equals("addObject")) {
248 Arg = 0;
249 } else if (S.getNameForSlot(0).equals("insertObject") &&
250 S.getNameForSlot(1).equals("atIndex")) {
251 Arg = 0;
252 } else if (S.getNameForSlot(0).equals("replaceObjectAtIndex") &&
253 S.getNameForSlot(1).equals("withObject")) {
254 Arg = 1;
255 } else if (S.getNameForSlot(0).equals("setObject") &&
256 S.getNameForSlot(1).equals("atIndexedSubscript")) {
257 Arg = 0;
Anna Zaks130df4b2013-03-23 00:39:21 +0000258 CanBeSubscript = true;
Anna Zaks6457ad22013-03-18 20:46:56 +0000259 } else if (S.getNameForSlot(0).equals("arrayByAddingObject")) {
260 Arg = 0;
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000261 }
Anna Zaks130df4b2013-03-23 00:39:21 +0000262 } else if (Class == FC_NSDictionary) {
263 Selector S = msg.getSelector();
264
265 if (S.isUnarySelector())
266 return;
267
268 if (S.getNameForSlot(0).equals("dictionaryWithObject") &&
269 S.getNameForSlot(1).equals("forKey")) {
270 Arg = 0;
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000271 warnIfNilArg(C, msg, /* Arg */1, Class);
Anna Zaks130df4b2013-03-23 00:39:21 +0000272 } else if (S.getNameForSlot(0).equals("setObject") &&
273 S.getNameForSlot(1).equals("forKey")) {
274 Arg = 0;
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000275 warnIfNilArg(C, msg, /* Arg */1, Class);
Anna Zaks130df4b2013-03-23 00:39:21 +0000276 } else if (S.getNameForSlot(0).equals("setObject") &&
277 S.getNameForSlot(1).equals("forKeyedSubscript")) {
278 CanBeSubscript = true;
279 Arg = 0;
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000280 warnIfNilArg(C, msg, /* Arg */1, Class, CanBeSubscript);
Anna Zaks130df4b2013-03-23 00:39:21 +0000281 } else if (S.getNameForSlot(0).equals("removeObjectForKey")) {
282 Arg = 0;
283 }
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000284 }
Anna Zaks6457ad22013-03-18 20:46:56 +0000285
286 // If argument is '0', report a warning.
Anna Zaks130df4b2013-03-23 00:39:21 +0000287 if ((Arg != InvalidArgIndex))
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000288 warnIfNilArg(C, msg, Arg, Class, CanBeSubscript);
Anna Zaks6457ad22013-03-18 20:46:56 +0000289
Ted Kremenekc0414922008-03-27 07:25:52 +0000290}
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000291
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000292void NilArgChecker::checkPostStmt(const ObjCArrayLiteral *AL,
293 CheckerContext &C) const {
Anna Zaks6afa8f12013-05-13 23:49:51 +0000294 unsigned NumOfElements = AL->getNumElements();
295 for (unsigned i = 0; i < NumOfElements; ++i) {
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000296 warnIfNilExpr(AL->getElement(i), "Array element cannot be nil", C);
297 }
298}
299
300void NilArgChecker::checkPostStmt(const ObjCDictionaryLiteral *DL,
301 CheckerContext &C) const {
Anna Zaks6afa8f12013-05-13 23:49:51 +0000302 unsigned NumOfElements = DL->getNumElements();
303 for (unsigned i = 0; i < NumOfElements; ++i) {
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000304 ObjCDictionaryElement Element = DL->getKeyValueElement(i);
305 warnIfNilExpr(Element.Key, "Dictionary key cannot be nil", C);
306 warnIfNilExpr(Element.Value, "Dictionary value cannot be nil", C);
307 }
308}
309
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000310//===----------------------------------------------------------------------===//
311// Error reporting.
312//===----------------------------------------------------------------------===//
313
314namespace {
Argyrios Kyrtzidis6a5674f2011-03-01 01:16:21 +0000315class CFNumberCreateChecker : public Checker< check::PreStmt<CallExpr> > {
Ahmed Charlesb8984322014-03-07 20:03:18 +0000316 mutable std::unique_ptr<APIMisuse> BT;
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000317 mutable IdentifierInfo* II;
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000318public:
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000319 CFNumberCreateChecker() : II(0) {}
320
321 void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
322
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000323private:
Ted Kremenek5ef32db2011-08-12 23:37:29 +0000324 void EmitError(const TypedRegion* R, const Expr *Ex,
Mike Stump11289f42009-09-09 15:08:12 +0000325 uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind);
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000326};
327} // end anonymous namespace
328
329enum CFNumberType {
330 kCFNumberSInt8Type = 1,
331 kCFNumberSInt16Type = 2,
332 kCFNumberSInt32Type = 3,
333 kCFNumberSInt64Type = 4,
334 kCFNumberFloat32Type = 5,
335 kCFNumberFloat64Type = 6,
336 kCFNumberCharType = 7,
337 kCFNumberShortType = 8,
338 kCFNumberIntType = 9,
339 kCFNumberLongType = 10,
340 kCFNumberLongLongType = 11,
341 kCFNumberFloatType = 12,
342 kCFNumberDoubleType = 13,
343 kCFNumberCFIndexType = 14,
344 kCFNumberNSIntegerType = 15,
345 kCFNumberCGFloatType = 16
346};
347
Ted Kremenek5ef32db2011-08-12 23:37:29 +0000348static Optional<uint64_t> GetCFNumberSize(ASTContext &Ctx, uint64_t i) {
Nuno Lopescfca1f02009-12-23 17:49:57 +0000349 static const unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 };
Mike Stump11289f42009-09-09 15:08:12 +0000350
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000351 if (i < kCFNumberCharType)
352 return FixedSize[i-1];
Mike Stump11289f42009-09-09 15:08:12 +0000353
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000354 QualType T;
Mike Stump11289f42009-09-09 15:08:12 +0000355
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000356 switch (i) {
357 case kCFNumberCharType: T = Ctx.CharTy; break;
358 case kCFNumberShortType: T = Ctx.ShortTy; break;
359 case kCFNumberIntType: T = Ctx.IntTy; break;
360 case kCFNumberLongType: T = Ctx.LongTy; break;
361 case kCFNumberLongLongType: T = Ctx.LongLongTy; break;
362 case kCFNumberFloatType: T = Ctx.FloatTy; break;
363 case kCFNumberDoubleType: T = Ctx.DoubleTy; break;
364 case kCFNumberCFIndexType:
365 case kCFNumberNSIntegerType:
366 case kCFNumberCGFloatType:
Mike Stump11289f42009-09-09 15:08:12 +0000367 // FIXME: We need a way to map from names to Type*.
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000368 default:
David Blaikie7a30dc52013-02-21 01:47:18 +0000369 return None;
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000370 }
Mike Stump11289f42009-09-09 15:08:12 +0000371
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000372 return Ctx.getTypeSize(T);
373}
374
375#if 0
376static const char* GetCFNumberTypeStr(uint64_t i) {
377 static const char* Names[] = {
378 "kCFNumberSInt8Type",
379 "kCFNumberSInt16Type",
380 "kCFNumberSInt32Type",
381 "kCFNumberSInt64Type",
382 "kCFNumberFloat32Type",
383 "kCFNumberFloat64Type",
384 "kCFNumberCharType",
385 "kCFNumberShortType",
386 "kCFNumberIntType",
387 "kCFNumberLongType",
388 "kCFNumberLongLongType",
389 "kCFNumberFloatType",
390 "kCFNumberDoubleType",
391 "kCFNumberCFIndexType",
392 "kCFNumberNSIntegerType",
393 "kCFNumberCGFloatType"
394 };
Mike Stump11289f42009-09-09 15:08:12 +0000395
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000396 return i <= kCFNumberCGFloatType ? Names[i-1] : "Invalid CFNumberType";
397}
398#endif
399
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000400void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE,
401 CheckerContext &C) const {
Ted Kremenek49b1e382012-01-26 21:29:00 +0000402 ProgramStateRef state = C.getState();
Anna Zaksc6aa5312011-12-01 05:57:37 +0000403 const FunctionDecl *FD = C.getCalleeDecl(CE);
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000404 if (!FD)
405 return;
406
407 ASTContext &Ctx = C.getASTContext();
408 if (!II)
409 II = &Ctx.Idents.get("CFNumberCreate");
410
411 if (FD->getIdentifier() != II || CE->getNumArgs() != 3)
412 return;
Mike Stump11289f42009-09-09 15:08:12 +0000413
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000414 // Get the value of the "theType" argument.
Ted Kremenek632e3b72012-01-06 22:09:28 +0000415 const LocationContext *LCtx = C.getLocationContext();
416 SVal TheTypeVal = state->getSVal(CE->getArg(1), LCtx);
Mike Stump11289f42009-09-09 15:08:12 +0000417
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000418 // FIXME: We really should allow ranges of valid theType values, and
419 // bifurcate the state appropriately.
David Blaikie05785d12013-02-20 22:23:23 +0000420 Optional<nonloc::ConcreteInt> V = TheTypeVal.getAs<nonloc::ConcreteInt>();
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000421 if (!V)
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000422 return;
Mike Stump11289f42009-09-09 15:08:12 +0000423
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000424 uint64_t NumberKind = V->getValue().getLimitedValue();
David Blaikie05785d12013-02-20 22:23:23 +0000425 Optional<uint64_t> OptTargetSize = GetCFNumberSize(Ctx, NumberKind);
Mike Stump11289f42009-09-09 15:08:12 +0000426
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000427 // FIXME: In some cases we can emit an error.
David Blaikiee359f3c2013-02-20 22:23:03 +0000428 if (!OptTargetSize)
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000429 return;
Mike Stump11289f42009-09-09 15:08:12 +0000430
David Blaikiee359f3c2013-02-20 22:23:03 +0000431 uint64_t TargetSize = *OptTargetSize;
432
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000433 // Look at the value of the integer being passed by reference. Essentially
434 // we want to catch cases where the value passed in is not equal to the
435 // size of the type being created.
Ted Kremenek632e3b72012-01-06 22:09:28 +0000436 SVal TheValueExpr = state->getSVal(CE->getArg(2), LCtx);
Mike Stump11289f42009-09-09 15:08:12 +0000437
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000438 // FIXME: Eventually we should handle arbitrary locations. We can do this
439 // by having an enhanced memory model that does low-level typing.
David Blaikie05785d12013-02-20 22:23:23 +0000440 Optional<loc::MemRegionVal> LV = TheValueExpr.getAs<loc::MemRegionVal>();
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000441 if (!LV)
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000442 return;
Mike Stump11289f42009-09-09 15:08:12 +0000443
Ted Kremenek8df44b262011-08-12 20:02:48 +0000444 const TypedValueRegion* R = dyn_cast<TypedValueRegion>(LV->stripCasts());
Ted Kremenek87a7a452009-07-29 18:17:40 +0000445 if (!R)
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000446 return;
Ted Kremenek87a7a452009-07-29 18:17:40 +0000447
Zhongxing Xu8de0a3d2010-08-11 06:10:55 +0000448 QualType T = Ctx.getCanonicalType(R->getValueType());
Mike Stump11289f42009-09-09 15:08:12 +0000449
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000450 // FIXME: If the pointee isn't an integer type, should we flag a warning?
451 // People can do weird stuff with pointers.
Mike Stump11289f42009-09-09 15:08:12 +0000452
Jordan Rose61e221f2013-04-09 02:30:33 +0000453 if (!T->isIntegralOrEnumerationType())
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000454 return;
Mike Stump11289f42009-09-09 15:08:12 +0000455
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000456 uint64_t SourceSize = Ctx.getTypeSize(T);
Mike Stump11289f42009-09-09 15:08:12 +0000457
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000458 // CHECK: is SourceSize == TargetSize
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000459 if (SourceSize == TargetSize)
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000460 return;
Mike Stump11289f42009-09-09 15:08:12 +0000461
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000462 // Generate an error. Only generate a sink if 'SourceSize < TargetSize';
463 // otherwise generate a regular node.
464 //
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000465 // FIXME: We can actually create an abstract "CFNumber" object that has
466 // the bits initialized to the provided values.
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000467 //
Ted Kremenek750b7ac2010-12-20 21:19:09 +0000468 if (ExplodedNode *N = SourceSize < TargetSize ? C.generateSink()
Anna Zaksda4c8d62011-10-26 21:06:34 +0000469 : C.addTransition()) {
Dylan Noblesmith2c1dd272012-02-05 02:13:05 +0000470 SmallString<128> sbuf;
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000471 llvm::raw_svector_ostream os(sbuf);
472
473 os << (SourceSize == 8 ? "An " : "A ")
474 << SourceSize << " bit integer is used to initialize a CFNumber "
475 "object that represents "
476 << (TargetSize == 8 ? "an " : "a ")
477 << TargetSize << " bit integer. ";
478
479 if (SourceSize < TargetSize)
480 os << (TargetSize - SourceSize)
481 << " bits of the CFNumber value will be garbage." ;
482 else
483 os << (SourceSize - TargetSize)
484 << " bits of the input integer will be lost.";
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000485
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000486 if (!BT)
Alexander Kornienko4aca9b12014-02-11 21:49:21 +0000487 BT.reset(new APIMisuse(this, "Bad use of CFNumberCreate"));
488
Anna Zaks3a6bdf82011-08-17 23:00:25 +0000489 BugReport *report = new BugReport(*BT, os.str(), N);
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000490 report->addRange(CE->getArg(2)->getSourceRange());
Jordan Rosee10d5a72012-11-02 01:53:40 +0000491 C.emitReport(report);
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000492 }
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000493}
494
Ted Kremenek1f352db2008-07-22 16:21:24 +0000495//===----------------------------------------------------------------------===//
Jordan Rose721567a2012-11-07 17:12:37 +0000496// CFRetain/CFRelease/CFMakeCollectable checking for null arguments.
Ted Kremenekc057f412009-07-14 00:43:42 +0000497//===----------------------------------------------------------------------===//
498
499namespace {
Argyrios Kyrtzidis6a5674f2011-03-01 01:16:21 +0000500class CFRetainReleaseChecker : public Checker< check::PreStmt<CallExpr> > {
Ahmed Charlesb8984322014-03-07 20:03:18 +0000501 mutable std::unique_ptr<APIMisuse> BT;
Jordan Rose721567a2012-11-07 17:12:37 +0000502 mutable IdentifierInfo *Retain, *Release, *MakeCollectable;
Ted Kremenekc057f412009-07-14 00:43:42 +0000503public:
Jordan Rose721567a2012-11-07 17:12:37 +0000504 CFRetainReleaseChecker(): Retain(0), Release(0), MakeCollectable(0) {}
Ted Kremenek5ef32db2011-08-12 23:37:29 +0000505 void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
Ted Kremenekc057f412009-07-14 00:43:42 +0000506};
507} // end anonymous namespace
508
509
Ted Kremenek5ef32db2011-08-12 23:37:29 +0000510void CFRetainReleaseChecker::checkPreStmt(const CallExpr *CE,
511 CheckerContext &C) const {
Ted Kremenekc057f412009-07-14 00:43:42 +0000512 // If the CallExpr doesn't have exactly 1 argument just give up checking.
513 if (CE->getNumArgs() != 1)
Jordy Rose40c5c242010-07-06 02:34:42 +0000514 return;
Mike Stump11289f42009-09-09 15:08:12 +0000515
Ted Kremenek49b1e382012-01-26 21:29:00 +0000516 ProgramStateRef state = C.getState();
Anna Zaksc6aa5312011-12-01 05:57:37 +0000517 const FunctionDecl *FD = C.getCalleeDecl(CE);
Ted Kremenekc057f412009-07-14 00:43:42 +0000518 if (!FD)
Jordy Rose40c5c242010-07-06 02:34:42 +0000519 return;
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000520
521 if (!BT) {
522 ASTContext &Ctx = C.getASTContext();
523 Retain = &Ctx.Idents.get("CFRetain");
524 Release = &Ctx.Idents.get("CFRelease");
Jordan Rose721567a2012-11-07 17:12:37 +0000525 MakeCollectable = &Ctx.Idents.get("CFMakeCollectable");
Alexander Kornienko4aca9b12014-02-11 21:49:21 +0000526 BT.reset(new APIMisuse(
527 this, "null passed to CFRetain/CFRelease/CFMakeCollectable"));
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000528 }
Mike Stump11289f42009-09-09 15:08:12 +0000529
Jordan Rose721567a2012-11-07 17:12:37 +0000530 // Check if we called CFRetain/CFRelease/CFMakeCollectable.
Mike Stump11289f42009-09-09 15:08:12 +0000531 const IdentifierInfo *FuncII = FD->getIdentifier();
Jordan Rose721567a2012-11-07 17:12:37 +0000532 if (!(FuncII == Retain || FuncII == Release || FuncII == MakeCollectable))
Jordy Rose40c5c242010-07-06 02:34:42 +0000533 return;
Mike Stump11289f42009-09-09 15:08:12 +0000534
Jordy Rose40c5c242010-07-06 02:34:42 +0000535 // FIXME: The rest of this just checks that the argument is non-null.
Anna Zaksef893392013-03-09 03:23:14 +0000536 // It should probably be refactored and combined with NonNullParamChecker.
Jordy Rose40c5c242010-07-06 02:34:42 +0000537
538 // Get the argument's value.
539 const Expr *Arg = CE->getArg(0);
Ted Kremenek632e3b72012-01-06 22:09:28 +0000540 SVal ArgVal = state->getSVal(Arg, C.getLocationContext());
David Blaikie05785d12013-02-20 22:23:23 +0000541 Optional<DefinedSVal> DefArgVal = ArgVal.getAs<DefinedSVal>();
Jordy Rose40c5c242010-07-06 02:34:42 +0000542 if (!DefArgVal)
543 return;
544
545 // Get a NULL value.
Ted Kremenek90af9092010-12-02 07:49:45 +0000546 SValBuilder &svalBuilder = C.getSValBuilder();
David Blaikie2fdacbc2013-02-20 05:52:05 +0000547 DefinedSVal zero =
548 svalBuilder.makeZeroVal(Arg->getType()).castAs<DefinedSVal>();
Jordy Rose40c5c242010-07-06 02:34:42 +0000549
550 // Make an expression asserting that they're equal.
Ted Kremenek90af9092010-12-02 07:49:45 +0000551 DefinedOrUnknownSVal ArgIsNull = svalBuilder.evalEQ(state, zero, *DefArgVal);
Jordy Rose40c5c242010-07-06 02:34:42 +0000552
553 // Are they equal?
Ted Kremenek49b1e382012-01-26 21:29:00 +0000554 ProgramStateRef stateTrue, stateFalse;
Benjamin Kramer867ea1d2014-03-02 13:01:17 +0000555 std::tie(stateTrue, stateFalse) = state->assume(ArgIsNull);
Jordy Rose40c5c242010-07-06 02:34:42 +0000556
557 if (stateTrue && !stateFalse) {
Ted Kremenek750b7ac2010-12-20 21:19:09 +0000558 ExplodedNode *N = C.generateSink(stateTrue);
Jordy Rose40c5c242010-07-06 02:34:42 +0000559 if (!N)
560 return;
561
Jordan Rose721567a2012-11-07 17:12:37 +0000562 const char *description;
563 if (FuncII == Retain)
564 description = "Null pointer argument in call to CFRetain";
565 else if (FuncII == Release)
566 description = "Null pointer argument in call to CFRelease";
567 else if (FuncII == MakeCollectable)
568 description = "Null pointer argument in call to CFMakeCollectable";
569 else
570 llvm_unreachable("impossible case");
Ted Kremenekc057f412009-07-14 00:43:42 +0000571
Anna Zaks3a6bdf82011-08-17 23:00:25 +0000572 BugReport *report = new BugReport(*BT, description, N);
Jordy Rose40c5c242010-07-06 02:34:42 +0000573 report->addRange(Arg->getSourceRange());
Jordan Rosea0f7d352012-08-28 00:50:51 +0000574 bugreporter::trackNullOrUndefValue(N, Arg, *report);
Jordan Rosee10d5a72012-11-02 01:53:40 +0000575 C.emitReport(report);
Jordy Rose40c5c242010-07-06 02:34:42 +0000576 return;
Ted Kremenekc057f412009-07-14 00:43:42 +0000577 }
578
Jordy Rose40c5c242010-07-06 02:34:42 +0000579 // From here on, we know the argument is non-null.
Anna Zaksda4c8d62011-10-26 21:06:34 +0000580 C.addTransition(stateFalse);
Ted Kremenekc057f412009-07-14 00:43:42 +0000581}
582
583//===----------------------------------------------------------------------===//
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000584// Check for sending 'retain', 'release', or 'autorelease' directly to a Class.
585//===----------------------------------------------------------------------===//
586
587namespace {
Argyrios Kyrtzidis6a5674f2011-03-01 01:16:21 +0000588class ClassReleaseChecker : public Checker<check::PreObjCMessage> {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000589 mutable Selector releaseS;
590 mutable Selector retainS;
591 mutable Selector autoreleaseS;
592 mutable Selector drainS;
Ahmed Charlesb8984322014-03-07 20:03:18 +0000593 mutable std::unique_ptr<BugType> BT;
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000594
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000595public:
Jordan Rose547060b2012-07-02 19:28:04 +0000596 void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000597};
598}
599
Jordan Rose547060b2012-07-02 19:28:04 +0000600void ClassReleaseChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000601 CheckerContext &C) const {
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000602
603 if (!BT) {
Alexander Kornienko4aca9b12014-02-11 21:49:21 +0000604 BT.reset(new APIMisuse(
605 this, "message incorrectly sent to class instead of class instance"));
606
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000607 ASTContext &Ctx = C.getASTContext();
608 releaseS = GetNullarySelector("release", Ctx);
609 retainS = GetNullarySelector("retain", Ctx);
610 autoreleaseS = GetNullarySelector("autorelease", Ctx);
611 drainS = GetNullarySelector("drain", Ctx);
612 }
613
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +0000614 if (msg.isInstanceMessage())
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000615 return;
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +0000616 const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
617 assert(Class);
Douglas Gregor9a129192010-04-21 00:45:42 +0000618
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +0000619 Selector S = msg.getSelector();
Benjamin Kramer7d875c72009-11-20 10:03:00 +0000620 if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000621 return;
622
Anna Zaksda4c8d62011-10-26 21:06:34 +0000623 if (ExplodedNode *N = C.addTransition()) {
Dylan Noblesmith2c1dd272012-02-05 02:13:05 +0000624 SmallString<200> buf;
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000625 llvm::raw_svector_ostream os(buf);
Ted Kremenekf5735152009-11-23 22:22:01 +0000626
Aaron Ballmanb190f972014-01-03 17:59:55 +0000627 os << "The '";
628 S.print(os);
629 os << "' message should be sent to instances "
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000630 "of class '" << Class->getName()
631 << "' and not the class directly";
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000632
Anna Zaks3a6bdf82011-08-17 23:00:25 +0000633 BugReport *report = new BugReport(*BT, os.str(), N);
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +0000634 report->addRange(msg.getSourceRange());
Jordan Rosee10d5a72012-11-02 01:53:40 +0000635 C.emitReport(report);
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000636 }
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000637}
638
639//===----------------------------------------------------------------------===//
Anders Carlssond91d5f12011-03-13 20:35:21 +0000640// Check for passing non-Objective-C types to variadic methods that expect
641// only Objective-C types.
642//===----------------------------------------------------------------------===//
643
644namespace {
645class VariadicMethodTypeChecker : public Checker<check::PreObjCMessage> {
646 mutable Selector arrayWithObjectsS;
647 mutable Selector dictionaryWithObjectsAndKeysS;
648 mutable Selector setWithObjectsS;
Jordy Rosec0230d72012-04-06 19:06:01 +0000649 mutable Selector orderedSetWithObjectsS;
Anders Carlssond91d5f12011-03-13 20:35:21 +0000650 mutable Selector initWithObjectsS;
651 mutable Selector initWithObjectsAndKeysS;
Ahmed Charlesb8984322014-03-07 20:03:18 +0000652 mutable std::unique_ptr<BugType> BT;
Anders Carlssond91d5f12011-03-13 20:35:21 +0000653
Jordan Rose547060b2012-07-02 19:28:04 +0000654 bool isVariadicMessage(const ObjCMethodCall &msg) const;
Anders Carlssond91d5f12011-03-13 20:35:21 +0000655
656public:
Jordan Rose547060b2012-07-02 19:28:04 +0000657 void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
Anders Carlssond91d5f12011-03-13 20:35:21 +0000658};
659}
660
661/// isVariadicMessage - Returns whether the given message is a variadic message,
662/// where all arguments must be Objective-C types.
663bool
Jordan Rose547060b2012-07-02 19:28:04 +0000664VariadicMethodTypeChecker::isVariadicMessage(const ObjCMethodCall &msg) const {
665 const ObjCMethodDecl *MD = msg.getDecl();
Ted Kremenekced5fea2011-04-12 21:47:05 +0000666
667 if (!MD || !MD->isVariadic() || isa<ObjCProtocolDecl>(MD->getDeclContext()))
Anders Carlssond91d5f12011-03-13 20:35:21 +0000668 return false;
669
670 Selector S = msg.getSelector();
671
672 if (msg.isInstanceMessage()) {
673 // FIXME: Ideally we'd look at the receiver interface here, but that's not
674 // useful for init, because alloc returns 'id'. In theory, this could lead
675 // to false positives, for example if there existed a class that had an
676 // initWithObjects: implementation that does accept non-Objective-C pointer
677 // types, but the chance of that happening is pretty small compared to the
678 // gains that this analysis gives.
679 const ObjCInterfaceDecl *Class = MD->getClassInterface();
680
Jordan Rose3ba8ae32012-06-11 16:40:37 +0000681 switch (findKnownClass(Class)) {
682 case FC_NSArray:
683 case FC_NSOrderedSet:
684 case FC_NSSet:
685 return S == initWithObjectsS;
686 case FC_NSDictionary:
687 return S == initWithObjectsAndKeysS;
688 default:
689 return false;
690 }
Anders Carlssond91d5f12011-03-13 20:35:21 +0000691 } else {
692 const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
693
Jordan Rose3ba8ae32012-06-11 16:40:37 +0000694 switch (findKnownClass(Class)) {
695 case FC_NSArray:
696 return S == arrayWithObjectsS;
697 case FC_NSOrderedSet:
698 return S == orderedSetWithObjectsS;
699 case FC_NSSet:
700 return S == setWithObjectsS;
701 case FC_NSDictionary:
702 return S == dictionaryWithObjectsAndKeysS;
703 default:
704 return false;
705 }
Anders Carlssond91d5f12011-03-13 20:35:21 +0000706 }
Anders Carlssond91d5f12011-03-13 20:35:21 +0000707}
708
Jordan Rose547060b2012-07-02 19:28:04 +0000709void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
Anders Carlssond91d5f12011-03-13 20:35:21 +0000710 CheckerContext &C) const {
711 if (!BT) {
Alexander Kornienko4aca9b12014-02-11 21:49:21 +0000712 BT.reset(new APIMisuse(this,
713 "Arguments passed to variadic method aren't all "
Anders Carlssond91d5f12011-03-13 20:35:21 +0000714 "Objective-C pointer types"));
715
716 ASTContext &Ctx = C.getASTContext();
717 arrayWithObjectsS = GetUnarySelector("arrayWithObjects", Ctx);
718 dictionaryWithObjectsAndKeysS =
719 GetUnarySelector("dictionaryWithObjectsAndKeys", Ctx);
720 setWithObjectsS = GetUnarySelector("setWithObjects", Ctx);
Jordy Rosec0230d72012-04-06 19:06:01 +0000721 orderedSetWithObjectsS = GetUnarySelector("orderedSetWithObjects", Ctx);
Anders Carlssond91d5f12011-03-13 20:35:21 +0000722
723 initWithObjectsS = GetUnarySelector("initWithObjects", Ctx);
724 initWithObjectsAndKeysS = GetUnarySelector("initWithObjectsAndKeys", Ctx);
725 }
726
727 if (!isVariadicMessage(msg))
728 return;
729
730 // We are not interested in the selector arguments since they have
731 // well-defined types, so the compiler will issue a warning for them.
732 unsigned variadicArgsBegin = msg.getSelector().getNumArgs();
733
734 // We're not interested in the last argument since it has to be nil or the
735 // compiler would have issued a warning for it elsewhere.
736 unsigned variadicArgsEnd = msg.getNumArgs() - 1;
737
738 if (variadicArgsEnd <= variadicArgsBegin)
739 return;
740
741 // Verify that all arguments have Objective-C types.
David Blaikie05785d12013-02-20 22:23:23 +0000742 Optional<ExplodedNode*> errorNode;
Alp Toker965f8822013-11-27 05:22:15 +0000743
Anders Carlssond91d5f12011-03-13 20:35:21 +0000744 for (unsigned I = variadicArgsBegin; I != variadicArgsEnd; ++I) {
Jordan Rose547060b2012-07-02 19:28:04 +0000745 QualType ArgTy = msg.getArgExpr(I)->getType();
Anders Carlssond91d5f12011-03-13 20:35:21 +0000746 if (ArgTy->isObjCObjectPointerType())
747 continue;
748
Anders Carlssond1f65f62011-04-19 01:16:46 +0000749 // Block pointers are treaded as Objective-C pointers.
750 if (ArgTy->isBlockPointerType())
751 continue;
752
Ted Kremenek4ceebbf2011-03-16 00:22:51 +0000753 // Ignore pointer constants.
David Blaikie2fdacbc2013-02-20 05:52:05 +0000754 if (msg.getArgSVal(I).getAs<loc::ConcreteInt>())
Ted Kremenek4ceebbf2011-03-16 00:22:51 +0000755 continue;
Ted Kremenek6fa1dae2011-03-17 04:01:35 +0000756
Ted Kremenek70727342011-03-17 04:10:25 +0000757 // Ignore pointer types annotated with 'NSObject' attribute.
758 if (C.getASTContext().isObjCNSObjectType(ArgTy))
759 continue;
760
Ted Kremenek6fa1dae2011-03-17 04:01:35 +0000761 // Ignore CF references, which can be toll-free bridged.
Ted Kremenekc85964e2011-07-16 19:50:32 +0000762 if (coreFoundation::isCFObjectRef(ArgTy))
Ted Kremenek6fa1dae2011-03-17 04:01:35 +0000763 continue;
Ted Kremenek4ceebbf2011-03-16 00:22:51 +0000764
Ted Kremenek066b2262011-03-14 19:50:37 +0000765 // Generate only one error node to use for all bug reports.
Jordan Rose547060b2012-07-02 19:28:04 +0000766 if (!errorNode.hasValue())
Anna Zaksda4c8d62011-10-26 21:06:34 +0000767 errorNode = C.addTransition();
Ted Kremenek066b2262011-03-14 19:50:37 +0000768
769 if (!errorNode.getValue())
Anders Carlssond91d5f12011-03-13 20:35:21 +0000770 continue;
771
Dylan Noblesmith2c1dd272012-02-05 02:13:05 +0000772 SmallString<128> sbuf;
Anders Carlssond91d5f12011-03-13 20:35:21 +0000773 llvm::raw_svector_ostream os(sbuf);
774
Jordan Rose547060b2012-07-02 19:28:04 +0000775 StringRef TypeName = GetReceiverInterfaceName(msg);
776 if (!TypeName.empty())
Anders Carlssond91d5f12011-03-13 20:35:21 +0000777 os << "Argument to '" << TypeName << "' method '";
778 else
779 os << "Argument to method '";
780
Aaron Ballmanb190f972014-01-03 17:59:55 +0000781 msg.getSelector().print(os);
782 os << "' should be an Objective-C pointer type, not '";
Jordan Rose547060b2012-07-02 19:28:04 +0000783 ArgTy.print(os, C.getLangOpts());
784 os << "'";
Anders Carlssond91d5f12011-03-13 20:35:21 +0000785
Jordan Rose547060b2012-07-02 19:28:04 +0000786 BugReport *R = new BugReport(*BT, os.str(), errorNode.getValue());
Anders Carlssond91d5f12011-03-13 20:35:21 +0000787 R->addRange(msg.getArgSourceRange(I));
Jordan Rosee10d5a72012-11-02 01:53:40 +0000788 C.emitReport(R);
Anders Carlssond91d5f12011-03-13 20:35:21 +0000789 }
790}
791
792//===----------------------------------------------------------------------===//
Jordan Roseefef7602012-06-11 16:40:41 +0000793// Improves the modeling of loops over Cocoa collections.
794//===----------------------------------------------------------------------===//
795
Anna Zaks27982c72013-06-22 00:23:26 +0000796// The map from container symbol to the container count symbol.
797// We currently will remember the last countainer count symbol encountered.
798REGISTER_MAP_WITH_PROGRAMSTATE(ContainerCountMap, SymbolRef, SymbolRef)
Jordan Rose5650bcb2013-11-08 17:23:33 +0000799REGISTER_MAP_WITH_PROGRAMSTATE(ContainerNonEmptyMap, SymbolRef, bool)
Anna Zaks27982c72013-06-22 00:23:26 +0000800
Jordan Roseefef7602012-06-11 16:40:41 +0000801namespace {
802class ObjCLoopChecker
Anna Zaks27982c72013-06-22 00:23:26 +0000803 : public Checker<check::PostStmt<ObjCForCollectionStmt>,
804 check::PostObjCMessage,
805 check::DeadSymbols,
806 check::PointerEscape > {
807 mutable IdentifierInfo *CountSelectorII;
808
809 bool isCollectionCountMethod(const ObjCMethodCall &M,
810 CheckerContext &C) const;
811
Jordan Roseefef7602012-06-11 16:40:41 +0000812public:
Anna Zaks27982c72013-06-22 00:23:26 +0000813 ObjCLoopChecker() : CountSelectorII(0) {}
Jordan Roseefef7602012-06-11 16:40:41 +0000814 void checkPostStmt(const ObjCForCollectionStmt *FCS, CheckerContext &C) const;
Anna Zaks27982c72013-06-22 00:23:26 +0000815 void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
816 void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
817 ProgramStateRef checkPointerEscape(ProgramStateRef State,
818 const InvalidatedSymbols &Escaped,
819 const CallEvent *Call,
820 PointerEscapeKind Kind) const;
Jordan Roseefef7602012-06-11 16:40:41 +0000821};
822}
823
824static bool isKnownNonNilCollectionType(QualType T) {
825 const ObjCObjectPointerType *PT = T->getAs<ObjCObjectPointerType>();
826 if (!PT)
827 return false;
828
829 const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();
830 if (!ID)
831 return false;
832
833 switch (findKnownClass(ID)) {
834 case FC_NSArray:
835 case FC_NSDictionary:
836 case FC_NSEnumerator:
837 case FC_NSOrderedSet:
838 case FC_NSSet:
839 return true;
840 default:
841 return false;
842 }
843}
844
Jordan Rose9de821e2013-04-26 21:43:01 +0000845/// Assumes that the collection is non-nil.
846///
847/// If the collection is known to be nil, returns NULL to indicate an infeasible
848/// path.
849static ProgramStateRef checkCollectionNonNil(CheckerContext &C,
850 ProgramStateRef State,
851 const ObjCForCollectionStmt *FCS) {
852 if (!State)
853 return NULL;
854
855 SVal CollectionVal = C.getSVal(FCS->getCollection());
856 Optional<DefinedSVal> KnownCollection = CollectionVal.getAs<DefinedSVal>();
857 if (!KnownCollection)
858 return State;
859
860 ProgramStateRef StNonNil, StNil;
Benjamin Kramer867ea1d2014-03-02 13:01:17 +0000861 std::tie(StNonNil, StNil) = State->assume(*KnownCollection);
Jordan Rose9de821e2013-04-26 21:43:01 +0000862 if (StNil && !StNonNil) {
863 // The collection is nil. This path is infeasible.
864 return NULL;
865 }
866
867 return StNonNil;
868}
869
870/// Assumes that the collection elements are non-nil.
871///
872/// This only applies if the collection is one of those known not to contain
873/// nil values.
874static ProgramStateRef checkElementNonNil(CheckerContext &C,
875 ProgramStateRef State,
876 const ObjCForCollectionStmt *FCS) {
877 if (!State)
878 return NULL;
879
Jordan Roseefef7602012-06-11 16:40:41 +0000880 // See if the collection is one where we /know/ the elements are non-nil.
Jordan Rose9de821e2013-04-26 21:43:01 +0000881 if (!isKnownNonNilCollectionType(FCS->getCollection()->getType()))
882 return State;
883
884 const LocationContext *LCtx = C.getLocationContext();
Jordan Roseefef7602012-06-11 16:40:41 +0000885 const Stmt *Element = FCS->getElement();
Jordan Rose9de821e2013-04-26 21:43:01 +0000886
887 // FIXME: Copied from ExprEngineObjC.
888 Optional<Loc> ElementLoc;
Jordan Roseefef7602012-06-11 16:40:41 +0000889 if (const DeclStmt *DS = dyn_cast<DeclStmt>(Element)) {
890 const VarDecl *ElemDecl = cast<VarDecl>(DS->getSingleDecl());
891 assert(ElemDecl->getInit() == 0);
Jordan Rose9de821e2013-04-26 21:43:01 +0000892 ElementLoc = State->getLValue(ElemDecl, LCtx);
Jordan Roseefef7602012-06-11 16:40:41 +0000893 } else {
Jordan Rose9de821e2013-04-26 21:43:01 +0000894 ElementLoc = State->getSVal(Element, LCtx).getAs<Loc>();
Jordan Roseefef7602012-06-11 16:40:41 +0000895 }
896
Jordan Rose9de821e2013-04-26 21:43:01 +0000897 if (!ElementLoc)
898 return State;
Jordan Roseefef7602012-06-11 16:40:41 +0000899
900 // Go ahead and assume the value is non-nil.
Jordan Rose9de821e2013-04-26 21:43:01 +0000901 SVal Val = State->getSVal(*ElementLoc);
902 return State->assume(Val.castAs<DefinedOrUnknownSVal>(), true);
903}
904
Anna Zaks27982c72013-06-22 00:23:26 +0000905/// Returns NULL state if the collection is known to contain elements
906/// (or is known not to contain elements if the Assumption parameter is false.)
Jordan Rose1a4ae202013-11-08 01:15:35 +0000907static ProgramStateRef
908assumeCollectionNonEmpty(CheckerContext &C, ProgramStateRef State,
909 SymbolRef CollectionS, bool Assumption) {
910 if (!State || !CollectionS)
911 return State;
Anna Zaks27982c72013-06-22 00:23:26 +0000912
Anna Zaks27982c72013-06-22 00:23:26 +0000913 const SymbolRef *CountS = State->get<ContainerCountMap>(CollectionS);
Jordan Rose1a4ae202013-11-08 01:15:35 +0000914 if (!CountS) {
Jordan Rose5650bcb2013-11-08 17:23:33 +0000915 const bool *KnownNonEmpty = State->get<ContainerNonEmptyMap>(CollectionS);
Jordan Rose1a4ae202013-11-08 01:15:35 +0000916 if (!KnownNonEmpty)
917 return State->set<ContainerNonEmptyMap>(CollectionS, Assumption);
918 return (Assumption == *KnownNonEmpty) ? State : NULL;
919 }
Anna Zaks27982c72013-06-22 00:23:26 +0000920
921 SValBuilder &SvalBuilder = C.getSValBuilder();
922 SVal CountGreaterThanZeroVal =
923 SvalBuilder.evalBinOp(State, BO_GT,
924 nonloc::SymbolVal(*CountS),
925 SvalBuilder.makeIntVal(0, (*CountS)->getType()),
926 SvalBuilder.getConditionType());
927 Optional<DefinedSVal> CountGreaterThanZero =
928 CountGreaterThanZeroVal.getAs<DefinedSVal>();
929 if (!CountGreaterThanZero) {
930 // The SValBuilder cannot construct a valid SVal for this condition.
931 // This means we cannot properly reason about it.
932 return State;
933 }
934
935 return State->assume(*CountGreaterThanZero, Assumption);
936}
937
Jordan Rose1a4ae202013-11-08 01:15:35 +0000938static ProgramStateRef
939assumeCollectionNonEmpty(CheckerContext &C, ProgramStateRef State,
940 const ObjCForCollectionStmt *FCS,
941 bool Assumption) {
942 if (!State)
943 return NULL;
944
945 SymbolRef CollectionS =
946 State->getSVal(FCS->getCollection(), C.getLocationContext()).getAsSymbol();
947 return assumeCollectionNonEmpty(C, State, CollectionS, Assumption);
948}
949
950
Anna Zaks27982c72013-06-22 00:23:26 +0000951/// If the fist block edge is a back edge, we are reentering the loop.
952static bool alreadyExecutedAtLeastOneLoopIteration(const ExplodedNode *N,
953 const ObjCForCollectionStmt *FCS) {
954 if (!N)
955 return false;
956
957 ProgramPoint P = N->getLocation();
958 if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) {
959 if (BE->getSrc()->getLoopTarget() == FCS)
960 return true;
961 return false;
962 }
963
964 // Keep looking for a block edge.
965 for (ExplodedNode::const_pred_iterator I = N->pred_begin(),
966 E = N->pred_end(); I != E; ++I) {
967 if (alreadyExecutedAtLeastOneLoopIteration(*I, FCS))
968 return true;
969 }
970
971 return false;
972}
973
Jordan Rose9de821e2013-04-26 21:43:01 +0000974void ObjCLoopChecker::checkPostStmt(const ObjCForCollectionStmt *FCS,
975 CheckerContext &C) const {
Anna Zaks27982c72013-06-22 00:23:26 +0000976 ProgramStateRef State = C.getState();
977
Jordan Rose9de821e2013-04-26 21:43:01 +0000978 // Check if this is the branch for the end of the loop.
979 SVal CollectionSentinel = C.getSVal(FCS);
Anna Zaks27982c72013-06-22 00:23:26 +0000980 if (CollectionSentinel.isZeroConstant()) {
981 if (!alreadyExecutedAtLeastOneLoopIteration(C.getPredecessor(), FCS))
982 State = assumeCollectionNonEmpty(C, State, FCS, /*Assumption*/false);
Jordan Rose9de821e2013-04-26 21:43:01 +0000983
Anna Zaks27982c72013-06-22 00:23:26 +0000984 // Otherwise, this is a branch that goes through the loop body.
985 } else {
986 State = checkCollectionNonNil(C, State, FCS);
987 State = checkElementNonNil(C, State, FCS);
988 State = assumeCollectionNonEmpty(C, State, FCS, /*Assumption*/true);
989 }
990
Jordan Rose9de821e2013-04-26 21:43:01 +0000991 if (!State)
992 C.generateSink();
993 else if (State != C.getState())
994 C.addTransition(State);
Jordan Roseefef7602012-06-11 16:40:41 +0000995}
996
Anna Zaks27982c72013-06-22 00:23:26 +0000997bool ObjCLoopChecker::isCollectionCountMethod(const ObjCMethodCall &M,
998 CheckerContext &C) const {
999 Selector S = M.getSelector();
1000 // Initialize the identifiers on first use.
1001 if (!CountSelectorII)
1002 CountSelectorII = &C.getASTContext().Idents.get("count");
1003
1004 // If the method returns collection count, record the value.
1005 if (S.isUnarySelector() &&
1006 (S.getIdentifierInfoForSlot(0) == CountSelectorII))
1007 return true;
1008
1009 return false;
1010}
1011
1012void ObjCLoopChecker::checkPostObjCMessage(const ObjCMethodCall &M,
1013 CheckerContext &C) const {
1014 if (!M.isInstanceMessage())
1015 return;
1016
1017 const ObjCInterfaceDecl *ClassID = M.getReceiverInterface();
1018 if (!ClassID)
1019 return;
1020
1021 FoundationClass Class = findKnownClass(ClassID);
1022 if (Class != FC_NSDictionary &&
1023 Class != FC_NSArray &&
Anna Zaks3d46ac62013-11-04 19:13:08 +00001024 Class != FC_NSSet &&
1025 Class != FC_NSOrderedSet)
Anna Zaks27982c72013-06-22 00:23:26 +00001026 return;
1027
1028 SymbolRef ContainerS = M.getReceiverSVal().getAsSymbol();
1029 if (!ContainerS)
1030 return;
1031
1032 // If we are processing a call to "count", get the symbolic value returned by
1033 // a call to "count" and add it to the map.
1034 if (!isCollectionCountMethod(M, C))
1035 return;
1036
1037 const Expr *MsgExpr = M.getOriginExpr();
1038 SymbolRef CountS = C.getSVal(MsgExpr).getAsSymbol();
1039 if (CountS) {
1040 ProgramStateRef State = C.getState();
Jordan Rose1a4ae202013-11-08 01:15:35 +00001041
Anna Zaks27982c72013-06-22 00:23:26 +00001042 C.getSymbolManager().addSymbolDependency(ContainerS, CountS);
1043 State = State->set<ContainerCountMap>(ContainerS, CountS);
Jordan Rose1a4ae202013-11-08 01:15:35 +00001044
Jordan Rose5650bcb2013-11-08 17:23:33 +00001045 if (const bool *NonEmpty = State->get<ContainerNonEmptyMap>(ContainerS)) {
Jordan Rose1a4ae202013-11-08 01:15:35 +00001046 State = State->remove<ContainerNonEmptyMap>(ContainerS);
1047 State = assumeCollectionNonEmpty(C, State, ContainerS, *NonEmpty);
1048 }
1049
Anna Zaks27982c72013-06-22 00:23:26 +00001050 C.addTransition(State);
1051 }
1052 return;
1053}
1054
Jordan Rose1a4ae202013-11-08 01:15:35 +00001055static SymbolRef getMethodReceiverIfKnownImmutable(const CallEvent *Call) {
1056 const ObjCMethodCall *Message = dyn_cast_or_null<ObjCMethodCall>(Call);
1057 if (!Message)
1058 return 0;
1059
1060 const ObjCMethodDecl *MD = Message->getDecl();
1061 if (!MD)
1062 return 0;
1063
1064 const ObjCInterfaceDecl *StaticClass;
1065 if (isa<ObjCProtocolDecl>(MD->getDeclContext())) {
1066 // We can't find out where the method was declared without doing more work.
1067 // Instead, see if the receiver is statically typed as a known immutable
1068 // collection.
1069 StaticClass = Message->getOriginExpr()->getReceiverInterface();
1070 } else {
1071 StaticClass = MD->getClassInterface();
1072 }
1073
1074 if (!StaticClass)
1075 return 0;
1076
1077 switch (findKnownClass(StaticClass, /*IncludeSuper=*/false)) {
1078 case FC_None:
1079 return 0;
1080 case FC_NSArray:
1081 case FC_NSDictionary:
1082 case FC_NSEnumerator:
1083 case FC_NSNull:
1084 case FC_NSOrderedSet:
1085 case FC_NSSet:
1086 case FC_NSString:
1087 break;
1088 }
1089
1090 return Message->getReceiverSVal().getAsSymbol();
1091}
1092
Anna Zaks27982c72013-06-22 00:23:26 +00001093ProgramStateRef
1094ObjCLoopChecker::checkPointerEscape(ProgramStateRef State,
1095 const InvalidatedSymbols &Escaped,
1096 const CallEvent *Call,
1097 PointerEscapeKind Kind) const {
Jordan Rose1a4ae202013-11-08 01:15:35 +00001098 SymbolRef ImmutableReceiver = getMethodReceiverIfKnownImmutable(Call);
Anna Zaks27982c72013-06-22 00:23:26 +00001099
1100 // Remove the invalidated symbols form the collection count map.
1101 for (InvalidatedSymbols::const_iterator I = Escaped.begin(),
1102 E = Escaped.end();
1103 I != E; ++I) {
1104 SymbolRef Sym = *I;
1105
Jordan Rose1a4ae202013-11-08 01:15:35 +00001106 // Don't invalidate this symbol's count if we know the method being called
1107 // is declared on an immutable class. This isn't completely correct if the
1108 // receiver is also passed as an argument, but in most uses of NSArray,
1109 // NSDictionary, etc. this isn't likely to happen in a dangerous way.
1110 if (Sym == ImmutableReceiver)
1111 continue;
1112
Anna Zaks27982c72013-06-22 00:23:26 +00001113 // The symbol escaped. Pessimistically, assume that the count could have
1114 // changed.
1115 State = State->remove<ContainerCountMap>(Sym);
Jordan Rose1a4ae202013-11-08 01:15:35 +00001116 State = State->remove<ContainerNonEmptyMap>(Sym);
Anna Zaks27982c72013-06-22 00:23:26 +00001117 }
1118 return State;
1119}
1120
1121void ObjCLoopChecker::checkDeadSymbols(SymbolReaper &SymReaper,
1122 CheckerContext &C) const {
1123 ProgramStateRef State = C.getState();
1124
1125 // Remove the dead symbols from the collection count map.
1126 ContainerCountMapTy Tracked = State->get<ContainerCountMap>();
1127 for (ContainerCountMapTy::iterator I = Tracked.begin(),
1128 E = Tracked.end(); I != E; ++I) {
1129 SymbolRef Sym = I->first;
Jordan Rose1a4ae202013-11-08 01:15:35 +00001130 if (SymReaper.isDead(Sym)) {
Anna Zaks27982c72013-06-22 00:23:26 +00001131 State = State->remove<ContainerCountMap>(Sym);
Jordan Rose1a4ae202013-11-08 01:15:35 +00001132 State = State->remove<ContainerNonEmptyMap>(Sym);
1133 }
Anna Zaks27982c72013-06-22 00:23:26 +00001134 }
1135
1136 C.addTransition(State);
1137}
1138
Anna Zaks5a5a1752012-08-22 21:19:56 +00001139namespace {
1140/// \class ObjCNonNilReturnValueChecker
Anna Zaks4818bbe2012-08-30 19:40:52 +00001141/// \brief The checker restricts the return values of APIs known to
1142/// never (or almost never) return 'nil'.
Anna Zaks5a5a1752012-08-22 21:19:56 +00001143class ObjCNonNilReturnValueChecker
Jordan Rose4393aa72014-02-08 00:04:14 +00001144 : public Checker<check::PostObjCMessage,
1145 check::PostStmt<ObjCArrayLiteral>,
1146 check::PostStmt<ObjCDictionaryLiteral>,
1147 check::PostStmt<ObjCBoxedExpr> > {
Anna Zaks5a5a1752012-08-22 21:19:56 +00001148 mutable bool Initialized;
1149 mutable Selector ObjectAtIndex;
1150 mutable Selector ObjectAtIndexedSubscript;
Anna Zaks4063fa12013-05-10 18:04:46 +00001151 mutable Selector NullSelector;
Anna Zaks9159e162012-08-22 22:47:58 +00001152
Anna Zaks5a5a1752012-08-22 21:19:56 +00001153public:
Anna Zaks9159e162012-08-22 22:47:58 +00001154 ObjCNonNilReturnValueChecker() : Initialized(false) {}
Jordan Rose4393aa72014-02-08 00:04:14 +00001155
1156 ProgramStateRef assumeExprIsNonNull(const Expr *NonNullExpr,
1157 ProgramStateRef State,
1158 CheckerContext &C) const;
1159 void assumeExprIsNonNull(const Expr *E, CheckerContext &C) const {
1160 C.addTransition(assumeExprIsNonNull(E, C.getState(), C));
1161 }
1162
1163 void checkPostStmt(const ObjCArrayLiteral *E, CheckerContext &C) const {
1164 assumeExprIsNonNull(E, C);
1165 }
1166 void checkPostStmt(const ObjCDictionaryLiteral *E, CheckerContext &C) const {
1167 assumeExprIsNonNull(E, C);
1168 }
1169 void checkPostStmt(const ObjCBoxedExpr *E, CheckerContext &C) const {
1170 assumeExprIsNonNull(E, C);
1171 }
1172
Anna Zaks5a5a1752012-08-22 21:19:56 +00001173 void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
1174};
1175}
1176
Jordan Rose4393aa72014-02-08 00:04:14 +00001177ProgramStateRef
1178ObjCNonNilReturnValueChecker::assumeExprIsNonNull(const Expr *NonNullExpr,
1179 ProgramStateRef State,
1180 CheckerContext &C) const {
Anna Zaks4818bbe2012-08-30 19:40:52 +00001181 SVal Val = State->getSVal(NonNullExpr, C.getLocationContext());
David Blaikie05785d12013-02-20 22:23:23 +00001182 if (Optional<DefinedOrUnknownSVal> DV = Val.getAs<DefinedOrUnknownSVal>())
Anna Zaks830c48e2012-08-30 22:55:32 +00001183 return State->assume(*DV, true);
Anna Zaksb504f442012-08-30 22:42:41 +00001184 return State;
Anna Zaks4818bbe2012-08-30 19:40:52 +00001185}
1186
Anna Zaks5a5a1752012-08-22 21:19:56 +00001187void ObjCNonNilReturnValueChecker::checkPostObjCMessage(const ObjCMethodCall &M,
1188 CheckerContext &C)
Anna Zaks4818bbe2012-08-30 19:40:52 +00001189 const {
Anna Zaks5a5a1752012-08-22 21:19:56 +00001190 ProgramStateRef State = C.getState();
1191
1192 if (!Initialized) {
1193 ASTContext &Ctx = C.getASTContext();
1194 ObjectAtIndex = GetUnarySelector("objectAtIndex", Ctx);
1195 ObjectAtIndexedSubscript = GetUnarySelector("objectAtIndexedSubscript", Ctx);
Anna Zaks4063fa12013-05-10 18:04:46 +00001196 NullSelector = GetNullarySelector("null", Ctx);
Anna Zaks5a5a1752012-08-22 21:19:56 +00001197 }
1198
1199 // Check the receiver type.
1200 if (const ObjCInterfaceDecl *Interface = M.getReceiverInterface()) {
Anna Zaks4818bbe2012-08-30 19:40:52 +00001201
1202 // Assume that object returned from '[self init]' or '[super init]' is not
1203 // 'nil' if we are processing an inlined function/method.
1204 //
1205 // A defensive callee will (and should) check if the object returned by
1206 // '[super init]' is 'nil' before doing it's own initialization. However,
1207 // since 'nil' is rarely returned in practice, we should not warn when the
1208 // caller to the defensive constructor uses the object in contexts where
1209 // 'nil' is not accepted.
Anna Zaks49bb6502012-11-06 04:20:54 +00001210 if (!C.inTopFrame() && M.getDecl() &&
Anna Zaks4818bbe2012-08-30 19:40:52 +00001211 M.getDecl()->getMethodFamily() == OMF_init &&
1212 M.isReceiverSelfOrSuper()) {
1213 State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
1214 }
1215
Anna Zaks4063fa12013-05-10 18:04:46 +00001216 FoundationClass Cl = findKnownClass(Interface);
1217
Anna Zaks4818bbe2012-08-30 19:40:52 +00001218 // Objects returned from
1219 // [NSArray|NSOrderedSet]::[ObjectAtIndex|ObjectAtIndexedSubscript]
1220 // are never 'nil'.
Anna Zaks5a5a1752012-08-22 21:19:56 +00001221 if (Cl == FC_NSArray || Cl == FC_NSOrderedSet) {
1222 Selector Sel = M.getSelector();
1223 if (Sel == ObjectAtIndex || Sel == ObjectAtIndexedSubscript) {
1224 // Go ahead and assume the value is non-nil.
Anna Zaks4818bbe2012-08-30 19:40:52 +00001225 State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
Anna Zaks5a5a1752012-08-22 21:19:56 +00001226 }
1227 }
Anna Zaks4063fa12013-05-10 18:04:46 +00001228
1229 // Objects returned from [NSNull null] are not nil.
1230 if (Cl == FC_NSNull) {
1231 if (M.getSelector() == NullSelector) {
1232 // Go ahead and assume the value is non-nil.
1233 State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
1234 }
1235 }
Anna Zaks5a5a1752012-08-22 21:19:56 +00001236 }
Anna Zaks4818bbe2012-08-30 19:40:52 +00001237 C.addTransition(State);
Anna Zaks5a5a1752012-08-22 21:19:56 +00001238}
Jordan Roseefef7602012-06-11 16:40:41 +00001239
1240//===----------------------------------------------------------------------===//
Ted Kremenek1f352db2008-07-22 16:21:24 +00001241// Check registration.
Ted Kremenekc057f412009-07-14 00:43:42 +00001242//===----------------------------------------------------------------------===//
Argyrios Kyrtzidis9d4d4f92011-02-16 01:40:52 +00001243
Argyrios Kyrtzidis507ff532011-02-17 21:39:17 +00001244void ento::registerNilArgChecker(CheckerManager &mgr) {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +00001245 mgr.registerChecker<NilArgChecker>();
Argyrios Kyrtzidis9d4d4f92011-02-16 01:40:52 +00001246}
1247
Argyrios Kyrtzidis507ff532011-02-17 21:39:17 +00001248void ento::registerCFNumberCreateChecker(CheckerManager &mgr) {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +00001249 mgr.registerChecker<CFNumberCreateChecker>();
Argyrios Kyrtzidis9d4d4f92011-02-16 01:40:52 +00001250}
1251
Argyrios Kyrtzidis507ff532011-02-17 21:39:17 +00001252void ento::registerCFRetainReleaseChecker(CheckerManager &mgr) {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +00001253 mgr.registerChecker<CFRetainReleaseChecker>();
Ted Kremenek1f352db2008-07-22 16:21:24 +00001254}
Argyrios Kyrtzidis507ff532011-02-17 21:39:17 +00001255
1256void ento::registerClassReleaseChecker(CheckerManager &mgr) {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +00001257 mgr.registerChecker<ClassReleaseChecker>();
Argyrios Kyrtzidis507ff532011-02-17 21:39:17 +00001258}
Anders Carlssond91d5f12011-03-13 20:35:21 +00001259
1260void ento::registerVariadicMethodTypeChecker(CheckerManager &mgr) {
1261 mgr.registerChecker<VariadicMethodTypeChecker>();
1262}
Jordan Roseefef7602012-06-11 16:40:41 +00001263
1264void ento::registerObjCLoopChecker(CheckerManager &mgr) {
1265 mgr.registerChecker<ObjCLoopChecker>();
1266}
Anna Zaks5a5a1752012-08-22 21:19:56 +00001267
Alexander Kornienko4aca9b12014-02-11 21:49:21 +00001268void
1269ento::registerObjCNonNilReturnValueChecker(CheckerManager &mgr) {
Anna Zaks5a5a1752012-08-22 21:19:56 +00001270 mgr.registerChecker<ObjCNonNilReturnValueChecker>();
1271}