blob: f66f8b75ed383cab5a72bab75c55f8a6965015c3 [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 }
173 os << "to '" << msg.getSelector().getAsString() << "' cannot be nil";
174 } else {
175 os << "Argument to '" << GetReceiverInterfaceName(msg) << "' method '"
176 << msg.getSelector().getAsString() << "' cannot be nil";
177 }
Anna Zaks130df4b2013-03-23 00:39:21 +0000178 }
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000179
Anna Zaks6afa8f12013-05-13 23:49:51 +0000180 generateBugReport(N, os.str(), msg.getArgSourceRange(Arg),
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000181 msg.getArgExpr(Arg), C);
Ted Kremenek276278e2008-03-27 22:05:32 +0000182 }
Ted Kremenek276278e2008-03-27 22:05:32 +0000183}
184
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000185void NilArgChecker::generateBugReport(ExplodedNode *N,
Anna Zaks6afa8f12013-05-13 23:49:51 +0000186 StringRef Msg,
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000187 SourceRange Range,
Anna Zaks6afa8f12013-05-13 23:49:51 +0000188 const Expr *E,
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000189 CheckerContext &C) const {
190 if (!BT)
191 BT.reset(new APIMisuse("nil argument"));
192
Anna Zaks6afa8f12013-05-13 23:49:51 +0000193 BugReport *R = new BugReport(*BT, Msg, N);
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000194 R->addRange(Range);
Anna Zaks6afa8f12013-05-13 23:49:51 +0000195 bugreporter::trackNullOrUndefValue(N, E, *R);
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000196 C.emitReport(R);
197}
198
Jordan Rose547060b2012-07-02 19:28:04 +0000199void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000200 CheckerContext &C) const {
Anders Carlsson3c50aea2011-03-08 20:05:26 +0000201 const ObjCInterfaceDecl *ID = msg.getReceiverInterface();
202 if (!ID)
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000203 return;
Anna Zaks6457ad22013-03-18 20:46:56 +0000204
205 FoundationClass Class = findKnownClass(ID);
206
207 static const unsigned InvalidArgIndex = UINT_MAX;
208 unsigned Arg = InvalidArgIndex;
Anna Zaks130df4b2013-03-23 00:39:21 +0000209 bool CanBeSubscript = false;
210
Anna Zaks6457ad22013-03-18 20:46:56 +0000211 if (Class == FC_NSString) {
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +0000212 Selector S = msg.getSelector();
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000213
214 if (S.isUnarySelector())
215 return;
216
217 // FIXME: This is going to be really slow doing these checks with
218 // lexical comparisons.
219
220 std::string NameStr = S.getAsString();
Chris Lattner0e62c1c2011-07-23 10:55:15 +0000221 StringRef Name(NameStr);
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000222 assert(!Name.empty());
223
224 // FIXME: Checking for initWithFormat: will not work in most cases
225 // yet because [NSString alloc] returns id, not NSString*. We will
226 // need support for tracking expected-type information in the analyzer
227 // to find these errors.
228 if (Name == "caseInsensitiveCompare:" ||
229 Name == "compare:" ||
230 Name == "compare:options:" ||
231 Name == "compare:options:range:" ||
232 Name == "compare:options:range:locale:" ||
233 Name == "componentsSeparatedByCharactersInSet:" ||
234 Name == "initWithFormat:") {
Anna Zaks6457ad22013-03-18 20:46:56 +0000235 Arg = 0;
236 }
237 } else if (Class == FC_NSArray) {
238 Selector S = msg.getSelector();
239
240 if (S.isUnarySelector())
241 return;
242
243 if (S.getNameForSlot(0).equals("addObject")) {
244 Arg = 0;
245 } else if (S.getNameForSlot(0).equals("insertObject") &&
246 S.getNameForSlot(1).equals("atIndex")) {
247 Arg = 0;
248 } else if (S.getNameForSlot(0).equals("replaceObjectAtIndex") &&
249 S.getNameForSlot(1).equals("withObject")) {
250 Arg = 1;
251 } else if (S.getNameForSlot(0).equals("setObject") &&
252 S.getNameForSlot(1).equals("atIndexedSubscript")) {
253 Arg = 0;
Anna Zaks130df4b2013-03-23 00:39:21 +0000254 CanBeSubscript = true;
Anna Zaks6457ad22013-03-18 20:46:56 +0000255 } else if (S.getNameForSlot(0).equals("arrayByAddingObject")) {
256 Arg = 0;
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000257 }
Anna Zaks130df4b2013-03-23 00:39:21 +0000258 } else if (Class == FC_NSDictionary) {
259 Selector S = msg.getSelector();
260
261 if (S.isUnarySelector())
262 return;
263
264 if (S.getNameForSlot(0).equals("dictionaryWithObject") &&
265 S.getNameForSlot(1).equals("forKey")) {
266 Arg = 0;
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000267 warnIfNilArg(C, msg, /* Arg */1, Class);
Anna Zaks130df4b2013-03-23 00:39:21 +0000268 } else if (S.getNameForSlot(0).equals("setObject") &&
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("forKeyedSubscript")) {
274 CanBeSubscript = true;
275 Arg = 0;
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000276 warnIfNilArg(C, msg, /* Arg */1, Class, CanBeSubscript);
Anna Zaks130df4b2013-03-23 00:39:21 +0000277 } else if (S.getNameForSlot(0).equals("removeObjectForKey")) {
278 Arg = 0;
279 }
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000280 }
Anna Zaks6457ad22013-03-18 20:46:56 +0000281
282 // If argument is '0', report a warning.
Anna Zaks130df4b2013-03-23 00:39:21 +0000283 if ((Arg != InvalidArgIndex))
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000284 warnIfNilArg(C, msg, Arg, Class, CanBeSubscript);
Anna Zaks6457ad22013-03-18 20:46:56 +0000285
Ted Kremenekc0414922008-03-27 07:25:52 +0000286}
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000287
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000288void NilArgChecker::checkPostStmt(const ObjCArrayLiteral *AL,
289 CheckerContext &C) const {
Anna Zaks6afa8f12013-05-13 23:49:51 +0000290 unsigned NumOfElements = AL->getNumElements();
291 for (unsigned i = 0; i < NumOfElements; ++i) {
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000292 warnIfNilExpr(AL->getElement(i), "Array element cannot be nil", C);
293 }
294}
295
296void NilArgChecker::checkPostStmt(const ObjCDictionaryLiteral *DL,
297 CheckerContext &C) const {
Anna Zaks6afa8f12013-05-13 23:49:51 +0000298 unsigned NumOfElements = DL->getNumElements();
299 for (unsigned i = 0; i < NumOfElements; ++i) {
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000300 ObjCDictionaryElement Element = DL->getKeyValueElement(i);
301 warnIfNilExpr(Element.Key, "Dictionary key cannot be nil", C);
302 warnIfNilExpr(Element.Value, "Dictionary value cannot be nil", C);
303 }
304}
305
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000306//===----------------------------------------------------------------------===//
307// Error reporting.
308//===----------------------------------------------------------------------===//
309
310namespace {
Argyrios Kyrtzidis6a5674f2011-03-01 01:16:21 +0000311class CFNumberCreateChecker : public Checker< check::PreStmt<CallExpr> > {
Dylan Noblesmithe2778992012-02-05 02:12:40 +0000312 mutable OwningPtr<APIMisuse> BT;
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000313 mutable IdentifierInfo* II;
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000314public:
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000315 CFNumberCreateChecker() : II(0) {}
316
317 void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
318
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000319private:
Ted Kremenek5ef32db2011-08-12 23:37:29 +0000320 void EmitError(const TypedRegion* R, const Expr *Ex,
Mike Stump11289f42009-09-09 15:08:12 +0000321 uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind);
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000322};
323} // end anonymous namespace
324
325enum CFNumberType {
326 kCFNumberSInt8Type = 1,
327 kCFNumberSInt16Type = 2,
328 kCFNumberSInt32Type = 3,
329 kCFNumberSInt64Type = 4,
330 kCFNumberFloat32Type = 5,
331 kCFNumberFloat64Type = 6,
332 kCFNumberCharType = 7,
333 kCFNumberShortType = 8,
334 kCFNumberIntType = 9,
335 kCFNumberLongType = 10,
336 kCFNumberLongLongType = 11,
337 kCFNumberFloatType = 12,
338 kCFNumberDoubleType = 13,
339 kCFNumberCFIndexType = 14,
340 kCFNumberNSIntegerType = 15,
341 kCFNumberCGFloatType = 16
342};
343
Ted Kremenek5ef32db2011-08-12 23:37:29 +0000344static Optional<uint64_t> GetCFNumberSize(ASTContext &Ctx, uint64_t i) {
Nuno Lopescfca1f02009-12-23 17:49:57 +0000345 static const unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 };
Mike Stump11289f42009-09-09 15:08:12 +0000346
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000347 if (i < kCFNumberCharType)
348 return FixedSize[i-1];
Mike Stump11289f42009-09-09 15:08:12 +0000349
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000350 QualType T;
Mike Stump11289f42009-09-09 15:08:12 +0000351
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000352 switch (i) {
353 case kCFNumberCharType: T = Ctx.CharTy; break;
354 case kCFNumberShortType: T = Ctx.ShortTy; break;
355 case kCFNumberIntType: T = Ctx.IntTy; break;
356 case kCFNumberLongType: T = Ctx.LongTy; break;
357 case kCFNumberLongLongType: T = Ctx.LongLongTy; break;
358 case kCFNumberFloatType: T = Ctx.FloatTy; break;
359 case kCFNumberDoubleType: T = Ctx.DoubleTy; break;
360 case kCFNumberCFIndexType:
361 case kCFNumberNSIntegerType:
362 case kCFNumberCGFloatType:
Mike Stump11289f42009-09-09 15:08:12 +0000363 // FIXME: We need a way to map from names to Type*.
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000364 default:
David Blaikie7a30dc52013-02-21 01:47:18 +0000365 return None;
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000366 }
Mike Stump11289f42009-09-09 15:08:12 +0000367
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000368 return Ctx.getTypeSize(T);
369}
370
371#if 0
372static const char* GetCFNumberTypeStr(uint64_t i) {
373 static const char* Names[] = {
374 "kCFNumberSInt8Type",
375 "kCFNumberSInt16Type",
376 "kCFNumberSInt32Type",
377 "kCFNumberSInt64Type",
378 "kCFNumberFloat32Type",
379 "kCFNumberFloat64Type",
380 "kCFNumberCharType",
381 "kCFNumberShortType",
382 "kCFNumberIntType",
383 "kCFNumberLongType",
384 "kCFNumberLongLongType",
385 "kCFNumberFloatType",
386 "kCFNumberDoubleType",
387 "kCFNumberCFIndexType",
388 "kCFNumberNSIntegerType",
389 "kCFNumberCGFloatType"
390 };
Mike Stump11289f42009-09-09 15:08:12 +0000391
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000392 return i <= kCFNumberCGFloatType ? Names[i-1] : "Invalid CFNumberType";
393}
394#endif
395
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000396void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE,
397 CheckerContext &C) const {
Ted Kremenek49b1e382012-01-26 21:29:00 +0000398 ProgramStateRef state = C.getState();
Anna Zaksc6aa5312011-12-01 05:57:37 +0000399 const FunctionDecl *FD = C.getCalleeDecl(CE);
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000400 if (!FD)
401 return;
402
403 ASTContext &Ctx = C.getASTContext();
404 if (!II)
405 II = &Ctx.Idents.get("CFNumberCreate");
406
407 if (FD->getIdentifier() != II || CE->getNumArgs() != 3)
408 return;
Mike Stump11289f42009-09-09 15:08:12 +0000409
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000410 // Get the value of the "theType" argument.
Ted Kremenek632e3b72012-01-06 22:09:28 +0000411 const LocationContext *LCtx = C.getLocationContext();
412 SVal TheTypeVal = state->getSVal(CE->getArg(1), LCtx);
Mike Stump11289f42009-09-09 15:08:12 +0000413
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000414 // FIXME: We really should allow ranges of valid theType values, and
415 // bifurcate the state appropriately.
David Blaikie05785d12013-02-20 22:23:23 +0000416 Optional<nonloc::ConcreteInt> V = TheTypeVal.getAs<nonloc::ConcreteInt>();
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000417 if (!V)
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000418 return;
Mike Stump11289f42009-09-09 15:08:12 +0000419
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000420 uint64_t NumberKind = V->getValue().getLimitedValue();
David Blaikie05785d12013-02-20 22:23:23 +0000421 Optional<uint64_t> OptTargetSize = GetCFNumberSize(Ctx, NumberKind);
Mike Stump11289f42009-09-09 15:08:12 +0000422
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000423 // FIXME: In some cases we can emit an error.
David Blaikiee359f3c2013-02-20 22:23:03 +0000424 if (!OptTargetSize)
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000425 return;
Mike Stump11289f42009-09-09 15:08:12 +0000426
David Blaikiee359f3c2013-02-20 22:23:03 +0000427 uint64_t TargetSize = *OptTargetSize;
428
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000429 // Look at the value of the integer being passed by reference. Essentially
430 // we want to catch cases where the value passed in is not equal to the
431 // size of the type being created.
Ted Kremenek632e3b72012-01-06 22:09:28 +0000432 SVal TheValueExpr = state->getSVal(CE->getArg(2), LCtx);
Mike Stump11289f42009-09-09 15:08:12 +0000433
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000434 // FIXME: Eventually we should handle arbitrary locations. We can do this
435 // by having an enhanced memory model that does low-level typing.
David Blaikie05785d12013-02-20 22:23:23 +0000436 Optional<loc::MemRegionVal> LV = TheValueExpr.getAs<loc::MemRegionVal>();
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000437 if (!LV)
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000438 return;
Mike Stump11289f42009-09-09 15:08:12 +0000439
Ted Kremenek8df44b262011-08-12 20:02:48 +0000440 const TypedValueRegion* R = dyn_cast<TypedValueRegion>(LV->stripCasts());
Ted Kremenek87a7a452009-07-29 18:17:40 +0000441 if (!R)
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000442 return;
Ted Kremenek87a7a452009-07-29 18:17:40 +0000443
Zhongxing Xu8de0a3d2010-08-11 06:10:55 +0000444 QualType T = Ctx.getCanonicalType(R->getValueType());
Mike Stump11289f42009-09-09 15:08:12 +0000445
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000446 // FIXME: If the pointee isn't an integer type, should we flag a warning?
447 // People can do weird stuff with pointers.
Mike Stump11289f42009-09-09 15:08:12 +0000448
Jordan Rose61e221f2013-04-09 02:30:33 +0000449 if (!T->isIntegralOrEnumerationType())
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000450 return;
Mike Stump11289f42009-09-09 15:08:12 +0000451
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000452 uint64_t SourceSize = Ctx.getTypeSize(T);
Mike Stump11289f42009-09-09 15:08:12 +0000453
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000454 // CHECK: is SourceSize == TargetSize
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000455 if (SourceSize == TargetSize)
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000456 return;
Mike Stump11289f42009-09-09 15:08:12 +0000457
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000458 // Generate an error. Only generate a sink if 'SourceSize < TargetSize';
459 // otherwise generate a regular node.
460 //
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000461 // FIXME: We can actually create an abstract "CFNumber" object that has
462 // the bits initialized to the provided values.
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000463 //
Ted Kremenek750b7ac2010-12-20 21:19:09 +0000464 if (ExplodedNode *N = SourceSize < TargetSize ? C.generateSink()
Anna Zaksda4c8d62011-10-26 21:06:34 +0000465 : C.addTransition()) {
Dylan Noblesmith2c1dd272012-02-05 02:13:05 +0000466 SmallString<128> sbuf;
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000467 llvm::raw_svector_ostream os(sbuf);
468
469 os << (SourceSize == 8 ? "An " : "A ")
470 << SourceSize << " bit integer is used to initialize a CFNumber "
471 "object that represents "
472 << (TargetSize == 8 ? "an " : "a ")
473 << TargetSize << " bit integer. ";
474
475 if (SourceSize < TargetSize)
476 os << (TargetSize - SourceSize)
477 << " bits of the CFNumber value will be garbage." ;
478 else
479 os << (SourceSize - TargetSize)
480 << " bits of the input integer will be lost.";
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000481
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000482 if (!BT)
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000483 BT.reset(new APIMisuse("Bad use of CFNumberCreate"));
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000484
Anna Zaks3a6bdf82011-08-17 23:00:25 +0000485 BugReport *report = new BugReport(*BT, os.str(), N);
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000486 report->addRange(CE->getArg(2)->getSourceRange());
Jordan Rosee10d5a72012-11-02 01:53:40 +0000487 C.emitReport(report);
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000488 }
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000489}
490
Ted Kremenek1f352db2008-07-22 16:21:24 +0000491//===----------------------------------------------------------------------===//
Jordan Rose721567a2012-11-07 17:12:37 +0000492// CFRetain/CFRelease/CFMakeCollectable checking for null arguments.
Ted Kremenekc057f412009-07-14 00:43:42 +0000493//===----------------------------------------------------------------------===//
494
495namespace {
Argyrios Kyrtzidis6a5674f2011-03-01 01:16:21 +0000496class CFRetainReleaseChecker : public Checker< check::PreStmt<CallExpr> > {
Dylan Noblesmithe2778992012-02-05 02:12:40 +0000497 mutable OwningPtr<APIMisuse> BT;
Jordan Rose721567a2012-11-07 17:12:37 +0000498 mutable IdentifierInfo *Retain, *Release, *MakeCollectable;
Ted Kremenekc057f412009-07-14 00:43:42 +0000499public:
Jordan Rose721567a2012-11-07 17:12:37 +0000500 CFRetainReleaseChecker(): Retain(0), Release(0), MakeCollectable(0) {}
Ted Kremenek5ef32db2011-08-12 23:37:29 +0000501 void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
Ted Kremenekc057f412009-07-14 00:43:42 +0000502};
503} // end anonymous namespace
504
505
Ted Kremenek5ef32db2011-08-12 23:37:29 +0000506void CFRetainReleaseChecker::checkPreStmt(const CallExpr *CE,
507 CheckerContext &C) const {
Ted Kremenekc057f412009-07-14 00:43:42 +0000508 // If the CallExpr doesn't have exactly 1 argument just give up checking.
509 if (CE->getNumArgs() != 1)
Jordy Rose40c5c242010-07-06 02:34:42 +0000510 return;
Mike Stump11289f42009-09-09 15:08:12 +0000511
Ted Kremenek49b1e382012-01-26 21:29:00 +0000512 ProgramStateRef state = C.getState();
Anna Zaksc6aa5312011-12-01 05:57:37 +0000513 const FunctionDecl *FD = C.getCalleeDecl(CE);
Ted Kremenekc057f412009-07-14 00:43:42 +0000514 if (!FD)
Jordy Rose40c5c242010-07-06 02:34:42 +0000515 return;
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000516
517 if (!BT) {
518 ASTContext &Ctx = C.getASTContext();
519 Retain = &Ctx.Idents.get("CFRetain");
520 Release = &Ctx.Idents.get("CFRelease");
Jordan Rose721567a2012-11-07 17:12:37 +0000521 MakeCollectable = &Ctx.Idents.get("CFMakeCollectable");
522 BT.reset(
523 new APIMisuse("null passed to CFRetain/CFRelease/CFMakeCollectable"));
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000524 }
Mike Stump11289f42009-09-09 15:08:12 +0000525
Jordan Rose721567a2012-11-07 17:12:37 +0000526 // Check if we called CFRetain/CFRelease/CFMakeCollectable.
Mike Stump11289f42009-09-09 15:08:12 +0000527 const IdentifierInfo *FuncII = FD->getIdentifier();
Jordan Rose721567a2012-11-07 17:12:37 +0000528 if (!(FuncII == Retain || FuncII == Release || FuncII == MakeCollectable))
Jordy Rose40c5c242010-07-06 02:34:42 +0000529 return;
Mike Stump11289f42009-09-09 15:08:12 +0000530
Jordy Rose40c5c242010-07-06 02:34:42 +0000531 // FIXME: The rest of this just checks that the argument is non-null.
Anna Zaksef893392013-03-09 03:23:14 +0000532 // It should probably be refactored and combined with NonNullParamChecker.
Jordy Rose40c5c242010-07-06 02:34:42 +0000533
534 // Get the argument's value.
535 const Expr *Arg = CE->getArg(0);
Ted Kremenek632e3b72012-01-06 22:09:28 +0000536 SVal ArgVal = state->getSVal(Arg, C.getLocationContext());
David Blaikie05785d12013-02-20 22:23:23 +0000537 Optional<DefinedSVal> DefArgVal = ArgVal.getAs<DefinedSVal>();
Jordy Rose40c5c242010-07-06 02:34:42 +0000538 if (!DefArgVal)
539 return;
540
541 // Get a NULL value.
Ted Kremenek90af9092010-12-02 07:49:45 +0000542 SValBuilder &svalBuilder = C.getSValBuilder();
David Blaikie2fdacbc2013-02-20 05:52:05 +0000543 DefinedSVal zero =
544 svalBuilder.makeZeroVal(Arg->getType()).castAs<DefinedSVal>();
Jordy Rose40c5c242010-07-06 02:34:42 +0000545
546 // Make an expression asserting that they're equal.
Ted Kremenek90af9092010-12-02 07:49:45 +0000547 DefinedOrUnknownSVal ArgIsNull = svalBuilder.evalEQ(state, zero, *DefArgVal);
Jordy Rose40c5c242010-07-06 02:34:42 +0000548
549 // Are they equal?
Ted Kremenek49b1e382012-01-26 21:29:00 +0000550 ProgramStateRef stateTrue, stateFalse;
Ted Kremenekc5bea1e2010-12-01 22:16:56 +0000551 llvm::tie(stateTrue, stateFalse) = state->assume(ArgIsNull);
Jordy Rose40c5c242010-07-06 02:34:42 +0000552
553 if (stateTrue && !stateFalse) {
Ted Kremenek750b7ac2010-12-20 21:19:09 +0000554 ExplodedNode *N = C.generateSink(stateTrue);
Jordy Rose40c5c242010-07-06 02:34:42 +0000555 if (!N)
556 return;
557
Jordan Rose721567a2012-11-07 17:12:37 +0000558 const char *description;
559 if (FuncII == Retain)
560 description = "Null pointer argument in call to CFRetain";
561 else if (FuncII == Release)
562 description = "Null pointer argument in call to CFRelease";
563 else if (FuncII == MakeCollectable)
564 description = "Null pointer argument in call to CFMakeCollectable";
565 else
566 llvm_unreachable("impossible case");
Ted Kremenekc057f412009-07-14 00:43:42 +0000567
Anna Zaks3a6bdf82011-08-17 23:00:25 +0000568 BugReport *report = new BugReport(*BT, description, N);
Jordy Rose40c5c242010-07-06 02:34:42 +0000569 report->addRange(Arg->getSourceRange());
Jordan Rosea0f7d352012-08-28 00:50:51 +0000570 bugreporter::trackNullOrUndefValue(N, Arg, *report);
Jordan Rosee10d5a72012-11-02 01:53:40 +0000571 C.emitReport(report);
Jordy Rose40c5c242010-07-06 02:34:42 +0000572 return;
Ted Kremenekc057f412009-07-14 00:43:42 +0000573 }
574
Jordy Rose40c5c242010-07-06 02:34:42 +0000575 // From here on, we know the argument is non-null.
Anna Zaksda4c8d62011-10-26 21:06:34 +0000576 C.addTransition(stateFalse);
Ted Kremenekc057f412009-07-14 00:43:42 +0000577}
578
579//===----------------------------------------------------------------------===//
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000580// Check for sending 'retain', 'release', or 'autorelease' directly to a Class.
581//===----------------------------------------------------------------------===//
582
583namespace {
Argyrios Kyrtzidis6a5674f2011-03-01 01:16:21 +0000584class ClassReleaseChecker : public Checker<check::PreObjCMessage> {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000585 mutable Selector releaseS;
586 mutable Selector retainS;
587 mutable Selector autoreleaseS;
588 mutable Selector drainS;
Dylan Noblesmithe2778992012-02-05 02:12:40 +0000589 mutable OwningPtr<BugType> BT;
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000590
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000591public:
Jordan Rose547060b2012-07-02 19:28:04 +0000592 void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000593};
594}
595
Jordan Rose547060b2012-07-02 19:28:04 +0000596void ClassReleaseChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000597 CheckerContext &C) const {
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000598
599 if (!BT) {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000600 BT.reset(new APIMisuse("message incorrectly sent to class instead of class "
601 "instance"));
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000602
603 ASTContext &Ctx = C.getASTContext();
604 releaseS = GetNullarySelector("release", Ctx);
605 retainS = GetNullarySelector("retain", Ctx);
606 autoreleaseS = GetNullarySelector("autorelease", Ctx);
607 drainS = GetNullarySelector("drain", Ctx);
608 }
609
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +0000610 if (msg.isInstanceMessage())
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000611 return;
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +0000612 const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
613 assert(Class);
Douglas Gregor9a129192010-04-21 00:45:42 +0000614
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +0000615 Selector S = msg.getSelector();
Benjamin Kramer7d875c72009-11-20 10:03:00 +0000616 if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000617 return;
618
Anna Zaksda4c8d62011-10-26 21:06:34 +0000619 if (ExplodedNode *N = C.addTransition()) {
Dylan Noblesmith2c1dd272012-02-05 02:13:05 +0000620 SmallString<200> buf;
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000621 llvm::raw_svector_ostream os(buf);
Ted Kremenekf5735152009-11-23 22:22:01 +0000622
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000623 os << "The '" << S.getAsString() << "' message should be sent to instances "
624 "of class '" << Class->getName()
625 << "' and not the class directly";
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000626
Anna Zaks3a6bdf82011-08-17 23:00:25 +0000627 BugReport *report = new BugReport(*BT, os.str(), N);
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +0000628 report->addRange(msg.getSourceRange());
Jordan Rosee10d5a72012-11-02 01:53:40 +0000629 C.emitReport(report);
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000630 }
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000631}
632
633//===----------------------------------------------------------------------===//
Anders Carlssond91d5f12011-03-13 20:35:21 +0000634// Check for passing non-Objective-C types to variadic methods that expect
635// only Objective-C types.
636//===----------------------------------------------------------------------===//
637
638namespace {
639class VariadicMethodTypeChecker : public Checker<check::PreObjCMessage> {
640 mutable Selector arrayWithObjectsS;
641 mutable Selector dictionaryWithObjectsAndKeysS;
642 mutable Selector setWithObjectsS;
Jordy Rosec0230d72012-04-06 19:06:01 +0000643 mutable Selector orderedSetWithObjectsS;
Anders Carlssond91d5f12011-03-13 20:35:21 +0000644 mutable Selector initWithObjectsS;
645 mutable Selector initWithObjectsAndKeysS;
Dylan Noblesmithe2778992012-02-05 02:12:40 +0000646 mutable OwningPtr<BugType> BT;
Anders Carlssond91d5f12011-03-13 20:35:21 +0000647
Jordan Rose547060b2012-07-02 19:28:04 +0000648 bool isVariadicMessage(const ObjCMethodCall &msg) const;
Anders Carlssond91d5f12011-03-13 20:35:21 +0000649
650public:
Jordan Rose547060b2012-07-02 19:28:04 +0000651 void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
Anders Carlssond91d5f12011-03-13 20:35:21 +0000652};
653}
654
655/// isVariadicMessage - Returns whether the given message is a variadic message,
656/// where all arguments must be Objective-C types.
657bool
Jordan Rose547060b2012-07-02 19:28:04 +0000658VariadicMethodTypeChecker::isVariadicMessage(const ObjCMethodCall &msg) const {
659 const ObjCMethodDecl *MD = msg.getDecl();
Ted Kremenekced5fea2011-04-12 21:47:05 +0000660
661 if (!MD || !MD->isVariadic() || isa<ObjCProtocolDecl>(MD->getDeclContext()))
Anders Carlssond91d5f12011-03-13 20:35:21 +0000662 return false;
663
664 Selector S = msg.getSelector();
665
666 if (msg.isInstanceMessage()) {
667 // FIXME: Ideally we'd look at the receiver interface here, but that's not
668 // useful for init, because alloc returns 'id'. In theory, this could lead
669 // to false positives, for example if there existed a class that had an
670 // initWithObjects: implementation that does accept non-Objective-C pointer
671 // types, but the chance of that happening is pretty small compared to the
672 // gains that this analysis gives.
673 const ObjCInterfaceDecl *Class = MD->getClassInterface();
674
Jordan Rose3ba8ae32012-06-11 16:40:37 +0000675 switch (findKnownClass(Class)) {
676 case FC_NSArray:
677 case FC_NSOrderedSet:
678 case FC_NSSet:
679 return S == initWithObjectsS;
680 case FC_NSDictionary:
681 return S == initWithObjectsAndKeysS;
682 default:
683 return false;
684 }
Anders Carlssond91d5f12011-03-13 20:35:21 +0000685 } else {
686 const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
687
Jordan Rose3ba8ae32012-06-11 16:40:37 +0000688 switch (findKnownClass(Class)) {
689 case FC_NSArray:
690 return S == arrayWithObjectsS;
691 case FC_NSOrderedSet:
692 return S == orderedSetWithObjectsS;
693 case FC_NSSet:
694 return S == setWithObjectsS;
695 case FC_NSDictionary:
696 return S == dictionaryWithObjectsAndKeysS;
697 default:
698 return false;
699 }
Anders Carlssond91d5f12011-03-13 20:35:21 +0000700 }
Anders Carlssond91d5f12011-03-13 20:35:21 +0000701}
702
Jordan Rose547060b2012-07-02 19:28:04 +0000703void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
Anders Carlssond91d5f12011-03-13 20:35:21 +0000704 CheckerContext &C) const {
705 if (!BT) {
706 BT.reset(new APIMisuse("Arguments passed to variadic method aren't all "
707 "Objective-C pointer types"));
708
709 ASTContext &Ctx = C.getASTContext();
710 arrayWithObjectsS = GetUnarySelector("arrayWithObjects", Ctx);
711 dictionaryWithObjectsAndKeysS =
712 GetUnarySelector("dictionaryWithObjectsAndKeys", Ctx);
713 setWithObjectsS = GetUnarySelector("setWithObjects", Ctx);
Jordy Rosec0230d72012-04-06 19:06:01 +0000714 orderedSetWithObjectsS = GetUnarySelector("orderedSetWithObjects", Ctx);
Anders Carlssond91d5f12011-03-13 20:35:21 +0000715
716 initWithObjectsS = GetUnarySelector("initWithObjects", Ctx);
717 initWithObjectsAndKeysS = GetUnarySelector("initWithObjectsAndKeys", Ctx);
718 }
719
720 if (!isVariadicMessage(msg))
721 return;
722
723 // We are not interested in the selector arguments since they have
724 // well-defined types, so the compiler will issue a warning for them.
725 unsigned variadicArgsBegin = msg.getSelector().getNumArgs();
726
727 // We're not interested in the last argument since it has to be nil or the
728 // compiler would have issued a warning for it elsewhere.
729 unsigned variadicArgsEnd = msg.getNumArgs() - 1;
730
731 if (variadicArgsEnd <= variadicArgsBegin)
732 return;
733
734 // Verify that all arguments have Objective-C types.
David Blaikie05785d12013-02-20 22:23:23 +0000735 Optional<ExplodedNode*> errorNode;
Ted Kremenek49b1e382012-01-26 21:29:00 +0000736 ProgramStateRef state = C.getState();
Ted Kremenek066b2262011-03-14 19:50:37 +0000737
Anders Carlssond91d5f12011-03-13 20:35:21 +0000738 for (unsigned I = variadicArgsBegin; I != variadicArgsEnd; ++I) {
Jordan Rose547060b2012-07-02 19:28:04 +0000739 QualType ArgTy = msg.getArgExpr(I)->getType();
Anders Carlssond91d5f12011-03-13 20:35:21 +0000740 if (ArgTy->isObjCObjectPointerType())
741 continue;
742
Anders Carlssond1f65f62011-04-19 01:16:46 +0000743 // Block pointers are treaded as Objective-C pointers.
744 if (ArgTy->isBlockPointerType())
745 continue;
746
Ted Kremenek4ceebbf2011-03-16 00:22:51 +0000747 // Ignore pointer constants.
David Blaikie2fdacbc2013-02-20 05:52:05 +0000748 if (msg.getArgSVal(I).getAs<loc::ConcreteInt>())
Ted Kremenek4ceebbf2011-03-16 00:22:51 +0000749 continue;
Ted Kremenek6fa1dae2011-03-17 04:01:35 +0000750
Ted Kremenek70727342011-03-17 04:10:25 +0000751 // Ignore pointer types annotated with 'NSObject' attribute.
752 if (C.getASTContext().isObjCNSObjectType(ArgTy))
753 continue;
754
Ted Kremenek6fa1dae2011-03-17 04:01:35 +0000755 // Ignore CF references, which can be toll-free bridged.
Ted Kremenekc85964e2011-07-16 19:50:32 +0000756 if (coreFoundation::isCFObjectRef(ArgTy))
Ted Kremenek6fa1dae2011-03-17 04:01:35 +0000757 continue;
Ted Kremenek4ceebbf2011-03-16 00:22:51 +0000758
Ted Kremenek066b2262011-03-14 19:50:37 +0000759 // Generate only one error node to use for all bug reports.
Jordan Rose547060b2012-07-02 19:28:04 +0000760 if (!errorNode.hasValue())
Anna Zaksda4c8d62011-10-26 21:06:34 +0000761 errorNode = C.addTransition();
Ted Kremenek066b2262011-03-14 19:50:37 +0000762
763 if (!errorNode.getValue())
Anders Carlssond91d5f12011-03-13 20:35:21 +0000764 continue;
765
Dylan Noblesmith2c1dd272012-02-05 02:13:05 +0000766 SmallString<128> sbuf;
Anders Carlssond91d5f12011-03-13 20:35:21 +0000767 llvm::raw_svector_ostream os(sbuf);
768
Jordan Rose547060b2012-07-02 19:28:04 +0000769 StringRef TypeName = GetReceiverInterfaceName(msg);
770 if (!TypeName.empty())
Anders Carlssond91d5f12011-03-13 20:35:21 +0000771 os << "Argument to '" << TypeName << "' method '";
772 else
773 os << "Argument to method '";
774
775 os << msg.getSelector().getAsString()
Jordan Rose547060b2012-07-02 19:28:04 +0000776 << "' should be an Objective-C pointer type, not '";
777 ArgTy.print(os, C.getLangOpts());
778 os << "'";
Anders Carlssond91d5f12011-03-13 20:35:21 +0000779
Jordan Rose547060b2012-07-02 19:28:04 +0000780 BugReport *R = new BugReport(*BT, os.str(), errorNode.getValue());
Anders Carlssond91d5f12011-03-13 20:35:21 +0000781 R->addRange(msg.getArgSourceRange(I));
Jordan Rosee10d5a72012-11-02 01:53:40 +0000782 C.emitReport(R);
Anders Carlssond91d5f12011-03-13 20:35:21 +0000783 }
784}
785
786//===----------------------------------------------------------------------===//
Jordan Roseefef7602012-06-11 16:40:41 +0000787// Improves the modeling of loops over Cocoa collections.
788//===----------------------------------------------------------------------===//
789
Anna Zaks27982c72013-06-22 00:23:26 +0000790// The map from container symbol to the container count symbol.
791// We currently will remember the last countainer count symbol encountered.
792REGISTER_MAP_WITH_PROGRAMSTATE(ContainerCountMap, SymbolRef, SymbolRef)
Jordan Rose1a4ae202013-11-08 01:15:35 +0000793REGISTER_MAP_WITH_PROGRAMSTATE(ContainerNonEmptyMap, SymbolRef, bool)
Anna Zaks27982c72013-06-22 00:23:26 +0000794
Jordan Roseefef7602012-06-11 16:40:41 +0000795namespace {
796class ObjCLoopChecker
Anna Zaks27982c72013-06-22 00:23:26 +0000797 : public Checker<check::PostStmt<ObjCForCollectionStmt>,
798 check::PostObjCMessage,
799 check::DeadSymbols,
800 check::PointerEscape > {
801 mutable IdentifierInfo *CountSelectorII;
802
803 bool isCollectionCountMethod(const ObjCMethodCall &M,
804 CheckerContext &C) const;
805
Jordan Roseefef7602012-06-11 16:40:41 +0000806public:
Anna Zaks27982c72013-06-22 00:23:26 +0000807 ObjCLoopChecker() : CountSelectorII(0) {}
Jordan Roseefef7602012-06-11 16:40:41 +0000808 void checkPostStmt(const ObjCForCollectionStmt *FCS, CheckerContext &C) const;
Anna Zaks27982c72013-06-22 00:23:26 +0000809 void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
810 void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
811 ProgramStateRef checkPointerEscape(ProgramStateRef State,
812 const InvalidatedSymbols &Escaped,
813 const CallEvent *Call,
814 PointerEscapeKind Kind) const;
Jordan Roseefef7602012-06-11 16:40:41 +0000815};
816}
817
818static bool isKnownNonNilCollectionType(QualType T) {
819 const ObjCObjectPointerType *PT = T->getAs<ObjCObjectPointerType>();
820 if (!PT)
821 return false;
822
823 const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();
824 if (!ID)
825 return false;
826
827 switch (findKnownClass(ID)) {
828 case FC_NSArray:
829 case FC_NSDictionary:
830 case FC_NSEnumerator:
831 case FC_NSOrderedSet:
832 case FC_NSSet:
833 return true;
834 default:
835 return false;
836 }
837}
838
Jordan Rose9de821e2013-04-26 21:43:01 +0000839/// Assumes that the collection is non-nil.
840///
841/// If the collection is known to be nil, returns NULL to indicate an infeasible
842/// path.
843static ProgramStateRef checkCollectionNonNil(CheckerContext &C,
844 ProgramStateRef State,
845 const ObjCForCollectionStmt *FCS) {
846 if (!State)
847 return NULL;
848
849 SVal CollectionVal = C.getSVal(FCS->getCollection());
850 Optional<DefinedSVal> KnownCollection = CollectionVal.getAs<DefinedSVal>();
851 if (!KnownCollection)
852 return State;
853
854 ProgramStateRef StNonNil, StNil;
855 llvm::tie(StNonNil, StNil) = State->assume(*KnownCollection);
856 if (StNil && !StNonNil) {
857 // The collection is nil. This path is infeasible.
858 return NULL;
859 }
860
861 return StNonNil;
862}
863
864/// Assumes that the collection elements are non-nil.
865///
866/// This only applies if the collection is one of those known not to contain
867/// nil values.
868static ProgramStateRef checkElementNonNil(CheckerContext &C,
869 ProgramStateRef State,
870 const ObjCForCollectionStmt *FCS) {
871 if (!State)
872 return NULL;
873
Jordan Roseefef7602012-06-11 16:40:41 +0000874 // See if the collection is one where we /know/ the elements are non-nil.
Jordan Rose9de821e2013-04-26 21:43:01 +0000875 if (!isKnownNonNilCollectionType(FCS->getCollection()->getType()))
876 return State;
877
878 const LocationContext *LCtx = C.getLocationContext();
Jordan Roseefef7602012-06-11 16:40:41 +0000879 const Stmt *Element = FCS->getElement();
Jordan Rose9de821e2013-04-26 21:43:01 +0000880
881 // FIXME: Copied from ExprEngineObjC.
882 Optional<Loc> ElementLoc;
Jordan Roseefef7602012-06-11 16:40:41 +0000883 if (const DeclStmt *DS = dyn_cast<DeclStmt>(Element)) {
884 const VarDecl *ElemDecl = cast<VarDecl>(DS->getSingleDecl());
885 assert(ElemDecl->getInit() == 0);
Jordan Rose9de821e2013-04-26 21:43:01 +0000886 ElementLoc = State->getLValue(ElemDecl, LCtx);
Jordan Roseefef7602012-06-11 16:40:41 +0000887 } else {
Jordan Rose9de821e2013-04-26 21:43:01 +0000888 ElementLoc = State->getSVal(Element, LCtx).getAs<Loc>();
Jordan Roseefef7602012-06-11 16:40:41 +0000889 }
890
Jordan Rose9de821e2013-04-26 21:43:01 +0000891 if (!ElementLoc)
892 return State;
Jordan Roseefef7602012-06-11 16:40:41 +0000893
894 // Go ahead and assume the value is non-nil.
Jordan Rose9de821e2013-04-26 21:43:01 +0000895 SVal Val = State->getSVal(*ElementLoc);
896 return State->assume(Val.castAs<DefinedOrUnknownSVal>(), true);
897}
898
Anna Zaks27982c72013-06-22 00:23:26 +0000899/// Returns NULL state if the collection is known to contain elements
900/// (or is known not to contain elements if the Assumption parameter is false.)
Jordan Rose1a4ae202013-11-08 01:15:35 +0000901static ProgramStateRef
902assumeCollectionNonEmpty(CheckerContext &C, ProgramStateRef State,
903 SymbolRef CollectionS, bool Assumption) {
904 if (!State || !CollectionS)
905 return State;
Anna Zaks27982c72013-06-22 00:23:26 +0000906
Anna Zaks27982c72013-06-22 00:23:26 +0000907 const SymbolRef *CountS = State->get<ContainerCountMap>(CollectionS);
Jordan Rose1a4ae202013-11-08 01:15:35 +0000908 if (!CountS) {
909 const bool *KnownNonEmpty = State->get<ContainerNonEmptyMap>(CollectionS);
910 if (!KnownNonEmpty)
911 return State->set<ContainerNonEmptyMap>(CollectionS, Assumption);
912 return (Assumption == *KnownNonEmpty) ? State : NULL;
913 }
Anna Zaks27982c72013-06-22 00:23:26 +0000914
915 SValBuilder &SvalBuilder = C.getSValBuilder();
916 SVal CountGreaterThanZeroVal =
917 SvalBuilder.evalBinOp(State, BO_GT,
918 nonloc::SymbolVal(*CountS),
919 SvalBuilder.makeIntVal(0, (*CountS)->getType()),
920 SvalBuilder.getConditionType());
921 Optional<DefinedSVal> CountGreaterThanZero =
922 CountGreaterThanZeroVal.getAs<DefinedSVal>();
923 if (!CountGreaterThanZero) {
924 // The SValBuilder cannot construct a valid SVal for this condition.
925 // This means we cannot properly reason about it.
926 return State;
927 }
928
929 return State->assume(*CountGreaterThanZero, Assumption);
930}
931
Jordan Rose1a4ae202013-11-08 01:15:35 +0000932static ProgramStateRef
933assumeCollectionNonEmpty(CheckerContext &C, ProgramStateRef State,
934 const ObjCForCollectionStmt *FCS,
935 bool Assumption) {
936 if (!State)
937 return NULL;
938
939 SymbolRef CollectionS =
940 State->getSVal(FCS->getCollection(), C.getLocationContext()).getAsSymbol();
941 return assumeCollectionNonEmpty(C, State, CollectionS, Assumption);
942}
943
944
Anna Zaks27982c72013-06-22 00:23:26 +0000945/// If the fist block edge is a back edge, we are reentering the loop.
946static bool alreadyExecutedAtLeastOneLoopIteration(const ExplodedNode *N,
947 const ObjCForCollectionStmt *FCS) {
948 if (!N)
949 return false;
950
951 ProgramPoint P = N->getLocation();
952 if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) {
953 if (BE->getSrc()->getLoopTarget() == FCS)
954 return true;
955 return false;
956 }
957
958 // Keep looking for a block edge.
959 for (ExplodedNode::const_pred_iterator I = N->pred_begin(),
960 E = N->pred_end(); I != E; ++I) {
961 if (alreadyExecutedAtLeastOneLoopIteration(*I, FCS))
962 return true;
963 }
964
965 return false;
966}
967
Jordan Rose9de821e2013-04-26 21:43:01 +0000968void ObjCLoopChecker::checkPostStmt(const ObjCForCollectionStmt *FCS,
969 CheckerContext &C) const {
Anna Zaks27982c72013-06-22 00:23:26 +0000970 ProgramStateRef State = C.getState();
971
Jordan Rose9de821e2013-04-26 21:43:01 +0000972 // Check if this is the branch for the end of the loop.
973 SVal CollectionSentinel = C.getSVal(FCS);
Anna Zaks27982c72013-06-22 00:23:26 +0000974 if (CollectionSentinel.isZeroConstant()) {
975 if (!alreadyExecutedAtLeastOneLoopIteration(C.getPredecessor(), FCS))
976 State = assumeCollectionNonEmpty(C, State, FCS, /*Assumption*/false);
Jordan Rose9de821e2013-04-26 21:43:01 +0000977
Anna Zaks27982c72013-06-22 00:23:26 +0000978 // Otherwise, this is a branch that goes through the loop body.
979 } else {
980 State = checkCollectionNonNil(C, State, FCS);
981 State = checkElementNonNil(C, State, FCS);
982 State = assumeCollectionNonEmpty(C, State, FCS, /*Assumption*/true);
983 }
984
Jordan Rose9de821e2013-04-26 21:43:01 +0000985 if (!State)
986 C.generateSink();
987 else if (State != C.getState())
988 C.addTransition(State);
Jordan Roseefef7602012-06-11 16:40:41 +0000989}
990
Anna Zaks27982c72013-06-22 00:23:26 +0000991bool ObjCLoopChecker::isCollectionCountMethod(const ObjCMethodCall &M,
992 CheckerContext &C) const {
993 Selector S = M.getSelector();
994 // Initialize the identifiers on first use.
995 if (!CountSelectorII)
996 CountSelectorII = &C.getASTContext().Idents.get("count");
997
998 // If the method returns collection count, record the value.
999 if (S.isUnarySelector() &&
1000 (S.getIdentifierInfoForSlot(0) == CountSelectorII))
1001 return true;
1002
1003 return false;
1004}
1005
1006void ObjCLoopChecker::checkPostObjCMessage(const ObjCMethodCall &M,
1007 CheckerContext &C) const {
1008 if (!M.isInstanceMessage())
1009 return;
1010
1011 const ObjCInterfaceDecl *ClassID = M.getReceiverInterface();
1012 if (!ClassID)
1013 return;
1014
1015 FoundationClass Class = findKnownClass(ClassID);
1016 if (Class != FC_NSDictionary &&
1017 Class != FC_NSArray &&
Anna Zaks3d46ac62013-11-04 19:13:08 +00001018 Class != FC_NSSet &&
1019 Class != FC_NSOrderedSet)
Anna Zaks27982c72013-06-22 00:23:26 +00001020 return;
1021
1022 SymbolRef ContainerS = M.getReceiverSVal().getAsSymbol();
1023 if (!ContainerS)
1024 return;
1025
1026 // If we are processing a call to "count", get the symbolic value returned by
1027 // a call to "count" and add it to the map.
1028 if (!isCollectionCountMethod(M, C))
1029 return;
1030
1031 const Expr *MsgExpr = M.getOriginExpr();
1032 SymbolRef CountS = C.getSVal(MsgExpr).getAsSymbol();
1033 if (CountS) {
1034 ProgramStateRef State = C.getState();
Jordan Rose1a4ae202013-11-08 01:15:35 +00001035
Anna Zaks27982c72013-06-22 00:23:26 +00001036 C.getSymbolManager().addSymbolDependency(ContainerS, CountS);
1037 State = State->set<ContainerCountMap>(ContainerS, CountS);
Jordan Rose1a4ae202013-11-08 01:15:35 +00001038
1039 if (const bool *NonEmpty = State->get<ContainerNonEmptyMap>(ContainerS)) {
1040 State = State->remove<ContainerNonEmptyMap>(ContainerS);
1041 State = assumeCollectionNonEmpty(C, State, ContainerS, *NonEmpty);
1042 }
1043
Anna Zaks27982c72013-06-22 00:23:26 +00001044 C.addTransition(State);
1045 }
1046 return;
1047}
1048
Jordan Rose1a4ae202013-11-08 01:15:35 +00001049static SymbolRef getMethodReceiverIfKnownImmutable(const CallEvent *Call) {
1050 const ObjCMethodCall *Message = dyn_cast_or_null<ObjCMethodCall>(Call);
1051 if (!Message)
1052 return 0;
1053
1054 const ObjCMethodDecl *MD = Message->getDecl();
1055 if (!MD)
1056 return 0;
1057
1058 const ObjCInterfaceDecl *StaticClass;
1059 if (isa<ObjCProtocolDecl>(MD->getDeclContext())) {
1060 // We can't find out where the method was declared without doing more work.
1061 // Instead, see if the receiver is statically typed as a known immutable
1062 // collection.
1063 StaticClass = Message->getOriginExpr()->getReceiverInterface();
1064 } else {
1065 StaticClass = MD->getClassInterface();
1066 }
1067
1068 if (!StaticClass)
1069 return 0;
1070
1071 switch (findKnownClass(StaticClass, /*IncludeSuper=*/false)) {
1072 case FC_None:
1073 return 0;
1074 case FC_NSArray:
1075 case FC_NSDictionary:
1076 case FC_NSEnumerator:
1077 case FC_NSNull:
1078 case FC_NSOrderedSet:
1079 case FC_NSSet:
1080 case FC_NSString:
1081 break;
1082 }
1083
1084 return Message->getReceiverSVal().getAsSymbol();
1085}
1086
Anna Zaks27982c72013-06-22 00:23:26 +00001087ProgramStateRef
1088ObjCLoopChecker::checkPointerEscape(ProgramStateRef State,
1089 const InvalidatedSymbols &Escaped,
1090 const CallEvent *Call,
1091 PointerEscapeKind Kind) const {
Jordan Rose1a4ae202013-11-08 01:15:35 +00001092 SymbolRef ImmutableReceiver = getMethodReceiverIfKnownImmutable(Call);
Anna Zaks27982c72013-06-22 00:23:26 +00001093
1094 // Remove the invalidated symbols form the collection count map.
1095 for (InvalidatedSymbols::const_iterator I = Escaped.begin(),
1096 E = Escaped.end();
1097 I != E; ++I) {
1098 SymbolRef Sym = *I;
1099
Jordan Rose1a4ae202013-11-08 01:15:35 +00001100 // Don't invalidate this symbol's count if we know the method being called
1101 // is declared on an immutable class. This isn't completely correct if the
1102 // receiver is also passed as an argument, but in most uses of NSArray,
1103 // NSDictionary, etc. this isn't likely to happen in a dangerous way.
1104 if (Sym == ImmutableReceiver)
1105 continue;
1106
Anna Zaks27982c72013-06-22 00:23:26 +00001107 // The symbol escaped. Pessimistically, assume that the count could have
1108 // changed.
1109 State = State->remove<ContainerCountMap>(Sym);
Jordan Rose1a4ae202013-11-08 01:15:35 +00001110 State = State->remove<ContainerNonEmptyMap>(Sym);
Anna Zaks27982c72013-06-22 00:23:26 +00001111 }
1112 return State;
1113}
1114
1115void ObjCLoopChecker::checkDeadSymbols(SymbolReaper &SymReaper,
1116 CheckerContext &C) const {
1117 ProgramStateRef State = C.getState();
1118
1119 // Remove the dead symbols from the collection count map.
1120 ContainerCountMapTy Tracked = State->get<ContainerCountMap>();
1121 for (ContainerCountMapTy::iterator I = Tracked.begin(),
1122 E = Tracked.end(); I != E; ++I) {
1123 SymbolRef Sym = I->first;
Jordan Rose1a4ae202013-11-08 01:15:35 +00001124 if (SymReaper.isDead(Sym)) {
Anna Zaks27982c72013-06-22 00:23:26 +00001125 State = State->remove<ContainerCountMap>(Sym);
Jordan Rose1a4ae202013-11-08 01:15:35 +00001126 State = State->remove<ContainerNonEmptyMap>(Sym);
1127 }
Anna Zaks27982c72013-06-22 00:23:26 +00001128 }
1129
1130 C.addTransition(State);
1131}
1132
Anna Zaks5a5a1752012-08-22 21:19:56 +00001133namespace {
1134/// \class ObjCNonNilReturnValueChecker
Anna Zaks4818bbe2012-08-30 19:40:52 +00001135/// \brief The checker restricts the return values of APIs known to
1136/// never (or almost never) return 'nil'.
Anna Zaks5a5a1752012-08-22 21:19:56 +00001137class ObjCNonNilReturnValueChecker
1138 : public Checker<check::PostObjCMessage> {
1139 mutable bool Initialized;
1140 mutable Selector ObjectAtIndex;
1141 mutable Selector ObjectAtIndexedSubscript;
Anna Zaks4063fa12013-05-10 18:04:46 +00001142 mutable Selector NullSelector;
Anna Zaks9159e162012-08-22 22:47:58 +00001143
Anna Zaks5a5a1752012-08-22 21:19:56 +00001144public:
Anna Zaks9159e162012-08-22 22:47:58 +00001145 ObjCNonNilReturnValueChecker() : Initialized(false) {}
Anna Zaks5a5a1752012-08-22 21:19:56 +00001146 void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
1147};
1148}
1149
Benjamin Kramer199f8da2012-09-10 11:57:16 +00001150static ProgramStateRef assumeExprIsNonNull(const Expr *NonNullExpr,
1151 ProgramStateRef State,
1152 CheckerContext &C) {
Anna Zaks4818bbe2012-08-30 19:40:52 +00001153 SVal Val = State->getSVal(NonNullExpr, C.getLocationContext());
David Blaikie05785d12013-02-20 22:23:23 +00001154 if (Optional<DefinedOrUnknownSVal> DV = Val.getAs<DefinedOrUnknownSVal>())
Anna Zaks830c48e2012-08-30 22:55:32 +00001155 return State->assume(*DV, true);
Anna Zaksb504f442012-08-30 22:42:41 +00001156 return State;
Anna Zaks4818bbe2012-08-30 19:40:52 +00001157}
1158
Anna Zaks5a5a1752012-08-22 21:19:56 +00001159void ObjCNonNilReturnValueChecker::checkPostObjCMessage(const ObjCMethodCall &M,
1160 CheckerContext &C)
Anna Zaks4818bbe2012-08-30 19:40:52 +00001161 const {
Anna Zaks5a5a1752012-08-22 21:19:56 +00001162 ProgramStateRef State = C.getState();
1163
1164 if (!Initialized) {
1165 ASTContext &Ctx = C.getASTContext();
1166 ObjectAtIndex = GetUnarySelector("objectAtIndex", Ctx);
1167 ObjectAtIndexedSubscript = GetUnarySelector("objectAtIndexedSubscript", Ctx);
Anna Zaks4063fa12013-05-10 18:04:46 +00001168 NullSelector = GetNullarySelector("null", Ctx);
Anna Zaks5a5a1752012-08-22 21:19:56 +00001169 }
1170
1171 // Check the receiver type.
1172 if (const ObjCInterfaceDecl *Interface = M.getReceiverInterface()) {
Anna Zaks4818bbe2012-08-30 19:40:52 +00001173
1174 // Assume that object returned from '[self init]' or '[super init]' is not
1175 // 'nil' if we are processing an inlined function/method.
1176 //
1177 // A defensive callee will (and should) check if the object returned by
1178 // '[super init]' is 'nil' before doing it's own initialization. However,
1179 // since 'nil' is rarely returned in practice, we should not warn when the
1180 // caller to the defensive constructor uses the object in contexts where
1181 // 'nil' is not accepted.
Anna Zaks49bb6502012-11-06 04:20:54 +00001182 if (!C.inTopFrame() && M.getDecl() &&
Anna Zaks4818bbe2012-08-30 19:40:52 +00001183 M.getDecl()->getMethodFamily() == OMF_init &&
1184 M.isReceiverSelfOrSuper()) {
1185 State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
1186 }
1187
Anna Zaks4063fa12013-05-10 18:04:46 +00001188 FoundationClass Cl = findKnownClass(Interface);
1189
Anna Zaks4818bbe2012-08-30 19:40:52 +00001190 // Objects returned from
1191 // [NSArray|NSOrderedSet]::[ObjectAtIndex|ObjectAtIndexedSubscript]
1192 // are never 'nil'.
Anna Zaks5a5a1752012-08-22 21:19:56 +00001193 if (Cl == FC_NSArray || Cl == FC_NSOrderedSet) {
1194 Selector Sel = M.getSelector();
1195 if (Sel == ObjectAtIndex || Sel == ObjectAtIndexedSubscript) {
1196 // Go ahead and assume the value is non-nil.
Anna Zaks4818bbe2012-08-30 19:40:52 +00001197 State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
Anna Zaks5a5a1752012-08-22 21:19:56 +00001198 }
1199 }
Anna Zaks4063fa12013-05-10 18:04:46 +00001200
1201 // Objects returned from [NSNull null] are not nil.
1202 if (Cl == FC_NSNull) {
1203 if (M.getSelector() == NullSelector) {
1204 // Go ahead and assume the value is non-nil.
1205 State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
1206 }
1207 }
Anna Zaks5a5a1752012-08-22 21:19:56 +00001208 }
Anna Zaks4818bbe2012-08-30 19:40:52 +00001209 C.addTransition(State);
Anna Zaks5a5a1752012-08-22 21:19:56 +00001210}
Jordan Roseefef7602012-06-11 16:40:41 +00001211
1212//===----------------------------------------------------------------------===//
Ted Kremenek1f352db2008-07-22 16:21:24 +00001213// Check registration.
Ted Kremenekc057f412009-07-14 00:43:42 +00001214//===----------------------------------------------------------------------===//
Argyrios Kyrtzidis9d4d4f92011-02-16 01:40:52 +00001215
Argyrios Kyrtzidis507ff532011-02-17 21:39:17 +00001216void ento::registerNilArgChecker(CheckerManager &mgr) {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +00001217 mgr.registerChecker<NilArgChecker>();
Argyrios Kyrtzidis9d4d4f92011-02-16 01:40:52 +00001218}
1219
Argyrios Kyrtzidis507ff532011-02-17 21:39:17 +00001220void ento::registerCFNumberCreateChecker(CheckerManager &mgr) {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +00001221 mgr.registerChecker<CFNumberCreateChecker>();
Argyrios Kyrtzidis9d4d4f92011-02-16 01:40:52 +00001222}
1223
Argyrios Kyrtzidis507ff532011-02-17 21:39:17 +00001224void ento::registerCFRetainReleaseChecker(CheckerManager &mgr) {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +00001225 mgr.registerChecker<CFRetainReleaseChecker>();
Ted Kremenek1f352db2008-07-22 16:21:24 +00001226}
Argyrios Kyrtzidis507ff532011-02-17 21:39:17 +00001227
1228void ento::registerClassReleaseChecker(CheckerManager &mgr) {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +00001229 mgr.registerChecker<ClassReleaseChecker>();
Argyrios Kyrtzidis507ff532011-02-17 21:39:17 +00001230}
Anders Carlssond91d5f12011-03-13 20:35:21 +00001231
1232void ento::registerVariadicMethodTypeChecker(CheckerManager &mgr) {
1233 mgr.registerChecker<VariadicMethodTypeChecker>();
1234}
Jordan Roseefef7602012-06-11 16:40:41 +00001235
1236void ento::registerObjCLoopChecker(CheckerManager &mgr) {
1237 mgr.registerChecker<ObjCLoopChecker>();
1238}
Anna Zaks5a5a1752012-08-22 21:19:56 +00001239
1240void ento::registerObjCNonNilReturnValueChecker(CheckerManager &mgr) {
1241 mgr.registerChecker<ObjCNonNilReturnValueChecker>();
1242}