blob: c723e4f29b023b433cbc428c75ba3d170b9ab115 [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 Rose3ba8ae32012-06-11 16:40:37 +000067static FoundationClass findKnownClass(const ObjCInterfaceDecl *ID) {
68 static llvm::StringMap<FoundationClass> Classes;
69 if (Classes.empty()) {
70 Classes["NSArray"] = FC_NSArray;
71 Classes["NSDictionary"] = FC_NSDictionary;
72 Classes["NSEnumerator"] = FC_NSEnumerator;
Anna Zaks4063fa12013-05-10 18:04:46 +000073 Classes["NSNull"] = FC_NSNull;
Jordan Rose3ba8ae32012-06-11 16:40:37 +000074 Classes["NSOrderedSet"] = FC_NSOrderedSet;
75 Classes["NSSet"] = FC_NSSet;
76 Classes["NSString"] = FC_NSString;
77 }
Anders Carlsson3c50aea2011-03-08 20:05:26 +000078
Jordan Rose3ba8ae32012-06-11 16:40:37 +000079 // FIXME: Should we cache this at all?
80 FoundationClass result = Classes.lookup(ID->getIdentifier()->getName());
81 if (result == FC_None)
82 if (const ObjCInterfaceDecl *Super = ID->getSuperClass())
83 return findKnownClass(Super);
84
85 return result;
Ted Kremenekc0414922008-03-27 07:25:52 +000086}
87
88//===----------------------------------------------------------------------===//
Ted Kremenekbd2c8002010-10-20 23:38:56 +000089// NilArgChecker - Check for prohibited nil arguments to ObjC method calls.
Ted Kremenekc0414922008-03-27 07:25:52 +000090//===----------------------------------------------------------------------===//
91
Benjamin Kramer2fc373e2010-10-22 16:33:16 +000092namespace {
Anna Zaksbb2a2c82013-05-13 21:48:20 +000093 class NilArgChecker : public Checker<check::PreObjCMessage,
94 check::PostStmt<ObjCDictionaryLiteral>,
95 check::PostStmt<ObjCArrayLiteral> > {
Dylan Noblesmithe2778992012-02-05 02:12:40 +000096 mutable OwningPtr<APIMisuse> BT;
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +000097
Anna Zaksbb2a2c82013-05-13 21:48:20 +000098 void warnIfNilExpr(const Expr *E,
99 const char *Msg,
100 CheckerContext &C) const;
101
102 void warnIfNilArg(CheckerContext &C,
103 const ObjCMethodCall &msg, unsigned Arg,
104 FoundationClass Class,
105 bool CanBeSubscript = false) const;
106
107 void generateBugReport(ExplodedNode *N,
108 llvm::raw_svector_ostream &os,
109 SourceRange Range,
110 const Expr *Expr,
111 CheckerContext &C) const;
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000112
Benjamin Kramer2fc373e2010-10-22 16:33:16 +0000113 public:
Jordan Rose547060b2012-07-02 19:28:04 +0000114 void checkPreObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000115 void checkPostStmt(const ObjCDictionaryLiteral *DL,
116 CheckerContext &C) const;
117 void checkPostStmt(const ObjCArrayLiteral *AL,
118 CheckerContext &C) const;
Benjamin Kramer2fc373e2010-10-22 16:33:16 +0000119 };
120}
Mike Stump11289f42009-09-09 15:08:12 +0000121
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000122void NilArgChecker::warnIfNilExpr(const Expr *E,
123 const char *Msg,
124 CheckerContext &C) const {
125 ProgramStateRef State = C.getState();
126 SVal SV = State->getSVal(E, C.getLocationContext());
127 if (State->isNull(SV).isConstrainedTrue()) {
128
129 if (ExplodedNode *N = C.generateSink()) {
130 SmallString<128> sbuf;
131 llvm::raw_svector_ostream os(sbuf);
132 os << Msg;
133 generateBugReport(N, os, E->getSourceRange(), E, C);
134 }
135
136 }
137}
138
139void NilArgChecker::warnIfNilArg(CheckerContext &C,
Anna Zaks130df4b2013-03-23 00:39:21 +0000140 const ObjCMethodCall &msg,
141 unsigned int Arg,
142 FoundationClass Class,
143 bool CanBeSubscript) const {
144 // Check if the argument is nil.
145 ProgramStateRef State = C.getState();
146 if (!State->isNull(msg.getArgSVal(Arg)).isConstrainedTrue())
147 return;
148
Ted Kremenek750b7ac2010-12-20 21:19:09 +0000149 if (ExplodedNode *N = C.generateSink()) {
Dylan Noblesmith2c1dd272012-02-05 02:13:05 +0000150 SmallString<128> sbuf;
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000151 llvm::raw_svector_ostream os(sbuf);
Anna Zaks130df4b2013-03-23 00:39:21 +0000152
153 if (CanBeSubscript && msg.getMessageKind() == OCM_Subscript) {
154
155 if (Class == FC_NSArray) {
156 os << "Array element cannot be nil";
157 } else if (Class == FC_NSDictionary) {
Anna Zaks4d1e3042013-04-05 23:50:18 +0000158 if (Arg == 0) {
Ted Kremeneke06df462013-04-08 18:09:16 +0000159 os << "Value stored into '";
Anna Zaks4d1e3042013-04-05 23:50:18 +0000160 os << GetReceiverInterfaceName(msg) << "' cannot be nil";
161 } else {
Anna Zaks130df4b2013-03-23 00:39:21 +0000162 assert(Arg == 1);
Anna Zaks4d1e3042013-04-05 23:50:18 +0000163 os << "'"<< GetReceiverInterfaceName(msg) << "' key cannot be nil";
Anna Zaks130df4b2013-03-23 00:39:21 +0000164 }
165 } else
166 llvm_unreachable("Missing foundation class for the subscript expr");
167
168 } else {
Anna Zaks4d1e3042013-04-05 23:50:18 +0000169 if (Class == FC_NSDictionary) {
170 if (Arg == 0)
171 os << "Value argument ";
172 else {
173 assert(Arg == 1);
174 os << "Key argument ";
175 }
176 os << "to '" << msg.getSelector().getAsString() << "' cannot be nil";
177 } else {
178 os << "Argument to '" << GetReceiverInterfaceName(msg) << "' method '"
179 << msg.getSelector().getAsString() << "' cannot be nil";
180 }
Anna Zaks130df4b2013-03-23 00:39:21 +0000181 }
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000182
183 generateBugReport(N, os, msg.getArgSourceRange(Arg),
184 msg.getArgExpr(Arg), C);
Ted Kremenek276278e2008-03-27 22:05:32 +0000185 }
Ted Kremenek276278e2008-03-27 22:05:32 +0000186}
187
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000188void NilArgChecker::generateBugReport(ExplodedNode *N,
189 llvm::raw_svector_ostream &os,
190 SourceRange Range,
191 const Expr *Expr,
192 CheckerContext &C) const {
193 if (!BT)
194 BT.reset(new APIMisuse("nil argument"));
195
196 BugReport *R = new BugReport(*BT, os.str(), N);
197 R->addRange(Range);
198 bugreporter::trackNullOrUndefValue(N, Expr, *R);
199 C.emitReport(R);
200}
201
Jordan Rose547060b2012-07-02 19:28:04 +0000202void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000203 CheckerContext &C) const {
Anders Carlsson3c50aea2011-03-08 20:05:26 +0000204 const ObjCInterfaceDecl *ID = msg.getReceiverInterface();
205 if (!ID)
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000206 return;
Anna Zaks6457ad22013-03-18 20:46:56 +0000207
208 FoundationClass Class = findKnownClass(ID);
209
210 static const unsigned InvalidArgIndex = UINT_MAX;
211 unsigned Arg = InvalidArgIndex;
Anna Zaks130df4b2013-03-23 00:39:21 +0000212 bool CanBeSubscript = false;
213
Anna Zaks6457ad22013-03-18 20:46:56 +0000214 if (Class == FC_NSString) {
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +0000215 Selector S = msg.getSelector();
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000216
217 if (S.isUnarySelector())
218 return;
219
220 // FIXME: This is going to be really slow doing these checks with
221 // lexical comparisons.
222
223 std::string NameStr = S.getAsString();
Chris Lattner0e62c1c2011-07-23 10:55:15 +0000224 StringRef Name(NameStr);
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000225 assert(!Name.empty());
226
227 // FIXME: Checking for initWithFormat: will not work in most cases
228 // yet because [NSString alloc] returns id, not NSString*. We will
229 // need support for tracking expected-type information in the analyzer
230 // to find these errors.
231 if (Name == "caseInsensitiveCompare:" ||
232 Name == "compare:" ||
233 Name == "compare:options:" ||
234 Name == "compare:options:range:" ||
235 Name == "compare:options:range:locale:" ||
236 Name == "componentsSeparatedByCharactersInSet:" ||
237 Name == "initWithFormat:") {
Anna Zaks6457ad22013-03-18 20:46:56 +0000238 Arg = 0;
239 }
240 } else if (Class == FC_NSArray) {
241 Selector S = msg.getSelector();
242
243 if (S.isUnarySelector())
244 return;
245
246 if (S.getNameForSlot(0).equals("addObject")) {
247 Arg = 0;
248 } else if (S.getNameForSlot(0).equals("insertObject") &&
249 S.getNameForSlot(1).equals("atIndex")) {
250 Arg = 0;
251 } else if (S.getNameForSlot(0).equals("replaceObjectAtIndex") &&
252 S.getNameForSlot(1).equals("withObject")) {
253 Arg = 1;
254 } else if (S.getNameForSlot(0).equals("setObject") &&
255 S.getNameForSlot(1).equals("atIndexedSubscript")) {
256 Arg = 0;
Anna Zaks130df4b2013-03-23 00:39:21 +0000257 CanBeSubscript = true;
Anna Zaks6457ad22013-03-18 20:46:56 +0000258 } else if (S.getNameForSlot(0).equals("arrayByAddingObject")) {
259 Arg = 0;
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000260 }
Anna Zaks130df4b2013-03-23 00:39:21 +0000261 } else if (Class == FC_NSDictionary) {
262 Selector S = msg.getSelector();
263
264 if (S.isUnarySelector())
265 return;
266
267 if (S.getNameForSlot(0).equals("dictionaryWithObject") &&
268 S.getNameForSlot(1).equals("forKey")) {
269 Arg = 0;
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000270 warnIfNilArg(C, msg, /* Arg */1, Class);
Anna Zaks130df4b2013-03-23 00:39:21 +0000271 } else if (S.getNameForSlot(0).equals("setObject") &&
272 S.getNameForSlot(1).equals("forKey")) {
273 Arg = 0;
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000274 warnIfNilArg(C, msg, /* Arg */1, Class);
Anna Zaks130df4b2013-03-23 00:39:21 +0000275 } else if (S.getNameForSlot(0).equals("setObject") &&
276 S.getNameForSlot(1).equals("forKeyedSubscript")) {
277 CanBeSubscript = true;
278 Arg = 0;
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000279 warnIfNilArg(C, msg, /* Arg */1, Class, CanBeSubscript);
Anna Zaks130df4b2013-03-23 00:39:21 +0000280 } else if (S.getNameForSlot(0).equals("removeObjectForKey")) {
281 Arg = 0;
282 }
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000283 }
Anna Zaks6457ad22013-03-18 20:46:56 +0000284
285 // If argument is '0', report a warning.
Anna Zaks130df4b2013-03-23 00:39:21 +0000286 if ((Arg != InvalidArgIndex))
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000287 warnIfNilArg(C, msg, Arg, Class, CanBeSubscript);
Anna Zaks6457ad22013-03-18 20:46:56 +0000288
Ted Kremenekc0414922008-03-27 07:25:52 +0000289}
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000290
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000291void NilArgChecker::checkPostStmt(const ObjCArrayLiteral *AL,
292 CheckerContext &C) const {
293 for (unsigned i = 0; i < AL->getNumElements(); ++i) {
294 warnIfNilExpr(AL->getElement(i), "Array element cannot be nil", C);
295 }
296}
297
298void NilArgChecker::checkPostStmt(const ObjCDictionaryLiteral *DL,
299 CheckerContext &C) const {
300 for (unsigned i = 0; i < DL->getNumElements(); ++i) {
301 ObjCDictionaryElement Element = DL->getKeyValueElement(i);
302 warnIfNilExpr(Element.Key, "Dictionary key cannot be nil", C);
303 warnIfNilExpr(Element.Value, "Dictionary value cannot be nil", C);
304 }
305}
306
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000307//===----------------------------------------------------------------------===//
308// Error reporting.
309//===----------------------------------------------------------------------===//
310
311namespace {
Argyrios Kyrtzidis6a5674f2011-03-01 01:16:21 +0000312class CFNumberCreateChecker : public Checker< check::PreStmt<CallExpr> > {
Dylan Noblesmithe2778992012-02-05 02:12:40 +0000313 mutable OwningPtr<APIMisuse> BT;
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000314 mutable IdentifierInfo* II;
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000315public:
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000316 CFNumberCreateChecker() : II(0) {}
317
318 void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
319
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000320private:
Ted Kremenek5ef32db2011-08-12 23:37:29 +0000321 void EmitError(const TypedRegion* R, const Expr *Ex,
Mike Stump11289f42009-09-09 15:08:12 +0000322 uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind);
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000323};
324} // end anonymous namespace
325
326enum CFNumberType {
327 kCFNumberSInt8Type = 1,
328 kCFNumberSInt16Type = 2,
329 kCFNumberSInt32Type = 3,
330 kCFNumberSInt64Type = 4,
331 kCFNumberFloat32Type = 5,
332 kCFNumberFloat64Type = 6,
333 kCFNumberCharType = 7,
334 kCFNumberShortType = 8,
335 kCFNumberIntType = 9,
336 kCFNumberLongType = 10,
337 kCFNumberLongLongType = 11,
338 kCFNumberFloatType = 12,
339 kCFNumberDoubleType = 13,
340 kCFNumberCFIndexType = 14,
341 kCFNumberNSIntegerType = 15,
342 kCFNumberCGFloatType = 16
343};
344
Ted Kremenek5ef32db2011-08-12 23:37:29 +0000345static Optional<uint64_t> GetCFNumberSize(ASTContext &Ctx, uint64_t i) {
Nuno Lopescfca1f02009-12-23 17:49:57 +0000346 static const unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 };
Mike Stump11289f42009-09-09 15:08:12 +0000347
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000348 if (i < kCFNumberCharType)
349 return FixedSize[i-1];
Mike Stump11289f42009-09-09 15:08:12 +0000350
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000351 QualType T;
Mike Stump11289f42009-09-09 15:08:12 +0000352
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000353 switch (i) {
354 case kCFNumberCharType: T = Ctx.CharTy; break;
355 case kCFNumberShortType: T = Ctx.ShortTy; break;
356 case kCFNumberIntType: T = Ctx.IntTy; break;
357 case kCFNumberLongType: T = Ctx.LongTy; break;
358 case kCFNumberLongLongType: T = Ctx.LongLongTy; break;
359 case kCFNumberFloatType: T = Ctx.FloatTy; break;
360 case kCFNumberDoubleType: T = Ctx.DoubleTy; break;
361 case kCFNumberCFIndexType:
362 case kCFNumberNSIntegerType:
363 case kCFNumberCGFloatType:
Mike Stump11289f42009-09-09 15:08:12 +0000364 // FIXME: We need a way to map from names to Type*.
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000365 default:
David Blaikie7a30dc52013-02-21 01:47:18 +0000366 return None;
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000367 }
Mike Stump11289f42009-09-09 15:08:12 +0000368
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000369 return Ctx.getTypeSize(T);
370}
371
372#if 0
373static const char* GetCFNumberTypeStr(uint64_t i) {
374 static const char* Names[] = {
375 "kCFNumberSInt8Type",
376 "kCFNumberSInt16Type",
377 "kCFNumberSInt32Type",
378 "kCFNumberSInt64Type",
379 "kCFNumberFloat32Type",
380 "kCFNumberFloat64Type",
381 "kCFNumberCharType",
382 "kCFNumberShortType",
383 "kCFNumberIntType",
384 "kCFNumberLongType",
385 "kCFNumberLongLongType",
386 "kCFNumberFloatType",
387 "kCFNumberDoubleType",
388 "kCFNumberCFIndexType",
389 "kCFNumberNSIntegerType",
390 "kCFNumberCGFloatType"
391 };
Mike Stump11289f42009-09-09 15:08:12 +0000392
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000393 return i <= kCFNumberCGFloatType ? Names[i-1] : "Invalid CFNumberType";
394}
395#endif
396
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000397void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE,
398 CheckerContext &C) const {
Ted Kremenek49b1e382012-01-26 21:29:00 +0000399 ProgramStateRef state = C.getState();
Anna Zaksc6aa5312011-12-01 05:57:37 +0000400 const FunctionDecl *FD = C.getCalleeDecl(CE);
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000401 if (!FD)
402 return;
403
404 ASTContext &Ctx = C.getASTContext();
405 if (!II)
406 II = &Ctx.Idents.get("CFNumberCreate");
407
408 if (FD->getIdentifier() != II || CE->getNumArgs() != 3)
409 return;
Mike Stump11289f42009-09-09 15:08:12 +0000410
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000411 // Get the value of the "theType" argument.
Ted Kremenek632e3b72012-01-06 22:09:28 +0000412 const LocationContext *LCtx = C.getLocationContext();
413 SVal TheTypeVal = state->getSVal(CE->getArg(1), LCtx);
Mike Stump11289f42009-09-09 15:08:12 +0000414
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000415 // FIXME: We really should allow ranges of valid theType values, and
416 // bifurcate the state appropriately.
David Blaikie05785d12013-02-20 22:23:23 +0000417 Optional<nonloc::ConcreteInt> V = TheTypeVal.getAs<nonloc::ConcreteInt>();
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000418 if (!V)
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000419 return;
Mike Stump11289f42009-09-09 15:08:12 +0000420
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000421 uint64_t NumberKind = V->getValue().getLimitedValue();
David Blaikie05785d12013-02-20 22:23:23 +0000422 Optional<uint64_t> OptTargetSize = GetCFNumberSize(Ctx, NumberKind);
Mike Stump11289f42009-09-09 15:08:12 +0000423
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000424 // FIXME: In some cases we can emit an error.
David Blaikiee359f3c2013-02-20 22:23:03 +0000425 if (!OptTargetSize)
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000426 return;
Mike Stump11289f42009-09-09 15:08:12 +0000427
David Blaikiee359f3c2013-02-20 22:23:03 +0000428 uint64_t TargetSize = *OptTargetSize;
429
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000430 // Look at the value of the integer being passed by reference. Essentially
431 // we want to catch cases where the value passed in is not equal to the
432 // size of the type being created.
Ted Kremenek632e3b72012-01-06 22:09:28 +0000433 SVal TheValueExpr = state->getSVal(CE->getArg(2), LCtx);
Mike Stump11289f42009-09-09 15:08:12 +0000434
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000435 // FIXME: Eventually we should handle arbitrary locations. We can do this
436 // by having an enhanced memory model that does low-level typing.
David Blaikie05785d12013-02-20 22:23:23 +0000437 Optional<loc::MemRegionVal> LV = TheValueExpr.getAs<loc::MemRegionVal>();
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000438 if (!LV)
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000439 return;
Mike Stump11289f42009-09-09 15:08:12 +0000440
Ted Kremenek8df44b262011-08-12 20:02:48 +0000441 const TypedValueRegion* R = dyn_cast<TypedValueRegion>(LV->stripCasts());
Ted Kremenek87a7a452009-07-29 18:17:40 +0000442 if (!R)
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000443 return;
Ted Kremenek87a7a452009-07-29 18:17:40 +0000444
Zhongxing Xu8de0a3d2010-08-11 06:10:55 +0000445 QualType T = Ctx.getCanonicalType(R->getValueType());
Mike Stump11289f42009-09-09 15:08:12 +0000446
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000447 // FIXME: If the pointee isn't an integer type, should we flag a warning?
448 // People can do weird stuff with pointers.
Mike Stump11289f42009-09-09 15:08:12 +0000449
Jordan Rose61e221f2013-04-09 02:30:33 +0000450 if (!T->isIntegralOrEnumerationType())
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000451 return;
Mike Stump11289f42009-09-09 15:08:12 +0000452
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000453 uint64_t SourceSize = Ctx.getTypeSize(T);
Mike Stump11289f42009-09-09 15:08:12 +0000454
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000455 // CHECK: is SourceSize == TargetSize
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000456 if (SourceSize == TargetSize)
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000457 return;
Mike Stump11289f42009-09-09 15:08:12 +0000458
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000459 // Generate an error. Only generate a sink if 'SourceSize < TargetSize';
460 // otherwise generate a regular node.
461 //
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000462 // FIXME: We can actually create an abstract "CFNumber" object that has
463 // the bits initialized to the provided values.
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000464 //
Ted Kremenek750b7ac2010-12-20 21:19:09 +0000465 if (ExplodedNode *N = SourceSize < TargetSize ? C.generateSink()
Anna Zaksda4c8d62011-10-26 21:06:34 +0000466 : C.addTransition()) {
Dylan Noblesmith2c1dd272012-02-05 02:13:05 +0000467 SmallString<128> sbuf;
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000468 llvm::raw_svector_ostream os(sbuf);
469
470 os << (SourceSize == 8 ? "An " : "A ")
471 << SourceSize << " bit integer is used to initialize a CFNumber "
472 "object that represents "
473 << (TargetSize == 8 ? "an " : "a ")
474 << TargetSize << " bit integer. ";
475
476 if (SourceSize < TargetSize)
477 os << (TargetSize - SourceSize)
478 << " bits of the CFNumber value will be garbage." ;
479 else
480 os << (SourceSize - TargetSize)
481 << " bits of the input integer will be lost.";
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000482
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000483 if (!BT)
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000484 BT.reset(new APIMisuse("Bad use of CFNumberCreate"));
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000485
Anna Zaks3a6bdf82011-08-17 23:00:25 +0000486 BugReport *report = new BugReport(*BT, os.str(), N);
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000487 report->addRange(CE->getArg(2)->getSourceRange());
Jordan Rosee10d5a72012-11-02 01:53:40 +0000488 C.emitReport(report);
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000489 }
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000490}
491
Ted Kremenek1f352db2008-07-22 16:21:24 +0000492//===----------------------------------------------------------------------===//
Jordan Rose721567a2012-11-07 17:12:37 +0000493// CFRetain/CFRelease/CFMakeCollectable checking for null arguments.
Ted Kremenekc057f412009-07-14 00:43:42 +0000494//===----------------------------------------------------------------------===//
495
496namespace {
Argyrios Kyrtzidis6a5674f2011-03-01 01:16:21 +0000497class CFRetainReleaseChecker : public Checker< check::PreStmt<CallExpr> > {
Dylan Noblesmithe2778992012-02-05 02:12:40 +0000498 mutable OwningPtr<APIMisuse> BT;
Jordan Rose721567a2012-11-07 17:12:37 +0000499 mutable IdentifierInfo *Retain, *Release, *MakeCollectable;
Ted Kremenekc057f412009-07-14 00:43:42 +0000500public:
Jordan Rose721567a2012-11-07 17:12:37 +0000501 CFRetainReleaseChecker(): Retain(0), Release(0), MakeCollectable(0) {}
Ted Kremenek5ef32db2011-08-12 23:37:29 +0000502 void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
Ted Kremenekc057f412009-07-14 00:43:42 +0000503};
504} // end anonymous namespace
505
506
Ted Kremenek5ef32db2011-08-12 23:37:29 +0000507void CFRetainReleaseChecker::checkPreStmt(const CallExpr *CE,
508 CheckerContext &C) const {
Ted Kremenekc057f412009-07-14 00:43:42 +0000509 // If the CallExpr doesn't have exactly 1 argument just give up checking.
510 if (CE->getNumArgs() != 1)
Jordy Rose40c5c242010-07-06 02:34:42 +0000511 return;
Mike Stump11289f42009-09-09 15:08:12 +0000512
Ted Kremenek49b1e382012-01-26 21:29:00 +0000513 ProgramStateRef state = C.getState();
Anna Zaksc6aa5312011-12-01 05:57:37 +0000514 const FunctionDecl *FD = C.getCalleeDecl(CE);
Ted Kremenekc057f412009-07-14 00:43:42 +0000515 if (!FD)
Jordy Rose40c5c242010-07-06 02:34:42 +0000516 return;
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000517
518 if (!BT) {
519 ASTContext &Ctx = C.getASTContext();
520 Retain = &Ctx.Idents.get("CFRetain");
521 Release = &Ctx.Idents.get("CFRelease");
Jordan Rose721567a2012-11-07 17:12:37 +0000522 MakeCollectable = &Ctx.Idents.get("CFMakeCollectable");
523 BT.reset(
524 new APIMisuse("null passed to CFRetain/CFRelease/CFMakeCollectable"));
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000525 }
Mike Stump11289f42009-09-09 15:08:12 +0000526
Jordan Rose721567a2012-11-07 17:12:37 +0000527 // Check if we called CFRetain/CFRelease/CFMakeCollectable.
Mike Stump11289f42009-09-09 15:08:12 +0000528 const IdentifierInfo *FuncII = FD->getIdentifier();
Jordan Rose721567a2012-11-07 17:12:37 +0000529 if (!(FuncII == Retain || FuncII == Release || FuncII == MakeCollectable))
Jordy Rose40c5c242010-07-06 02:34:42 +0000530 return;
Mike Stump11289f42009-09-09 15:08:12 +0000531
Jordy Rose40c5c242010-07-06 02:34:42 +0000532 // FIXME: The rest of this just checks that the argument is non-null.
Anna Zaksef893392013-03-09 03:23:14 +0000533 // It should probably be refactored and combined with NonNullParamChecker.
Jordy Rose40c5c242010-07-06 02:34:42 +0000534
535 // Get the argument's value.
536 const Expr *Arg = CE->getArg(0);
Ted Kremenek632e3b72012-01-06 22:09:28 +0000537 SVal ArgVal = state->getSVal(Arg, C.getLocationContext());
David Blaikie05785d12013-02-20 22:23:23 +0000538 Optional<DefinedSVal> DefArgVal = ArgVal.getAs<DefinedSVal>();
Jordy Rose40c5c242010-07-06 02:34:42 +0000539 if (!DefArgVal)
540 return;
541
542 // Get a NULL value.
Ted Kremenek90af9092010-12-02 07:49:45 +0000543 SValBuilder &svalBuilder = C.getSValBuilder();
David Blaikie2fdacbc2013-02-20 05:52:05 +0000544 DefinedSVal zero =
545 svalBuilder.makeZeroVal(Arg->getType()).castAs<DefinedSVal>();
Jordy Rose40c5c242010-07-06 02:34:42 +0000546
547 // Make an expression asserting that they're equal.
Ted Kremenek90af9092010-12-02 07:49:45 +0000548 DefinedOrUnknownSVal ArgIsNull = svalBuilder.evalEQ(state, zero, *DefArgVal);
Jordy Rose40c5c242010-07-06 02:34:42 +0000549
550 // Are they equal?
Ted Kremenek49b1e382012-01-26 21:29:00 +0000551 ProgramStateRef stateTrue, stateFalse;
Ted Kremenekc5bea1e2010-12-01 22:16:56 +0000552 llvm::tie(stateTrue, stateFalse) = state->assume(ArgIsNull);
Jordy Rose40c5c242010-07-06 02:34:42 +0000553
554 if (stateTrue && !stateFalse) {
Ted Kremenek750b7ac2010-12-20 21:19:09 +0000555 ExplodedNode *N = C.generateSink(stateTrue);
Jordy Rose40c5c242010-07-06 02:34:42 +0000556 if (!N)
557 return;
558
Jordan Rose721567a2012-11-07 17:12:37 +0000559 const char *description;
560 if (FuncII == Retain)
561 description = "Null pointer argument in call to CFRetain";
562 else if (FuncII == Release)
563 description = "Null pointer argument in call to CFRelease";
564 else if (FuncII == MakeCollectable)
565 description = "Null pointer argument in call to CFMakeCollectable";
566 else
567 llvm_unreachable("impossible case");
Ted Kremenekc057f412009-07-14 00:43:42 +0000568
Anna Zaks3a6bdf82011-08-17 23:00:25 +0000569 BugReport *report = new BugReport(*BT, description, N);
Jordy Rose40c5c242010-07-06 02:34:42 +0000570 report->addRange(Arg->getSourceRange());
Jordan Rosea0f7d352012-08-28 00:50:51 +0000571 bugreporter::trackNullOrUndefValue(N, Arg, *report);
Jordan Rosee10d5a72012-11-02 01:53:40 +0000572 C.emitReport(report);
Jordy Rose40c5c242010-07-06 02:34:42 +0000573 return;
Ted Kremenekc057f412009-07-14 00:43:42 +0000574 }
575
Jordy Rose40c5c242010-07-06 02:34:42 +0000576 // From here on, we know the argument is non-null.
Anna Zaksda4c8d62011-10-26 21:06:34 +0000577 C.addTransition(stateFalse);
Ted Kremenekc057f412009-07-14 00:43:42 +0000578}
579
580//===----------------------------------------------------------------------===//
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000581// Check for sending 'retain', 'release', or 'autorelease' directly to a Class.
582//===----------------------------------------------------------------------===//
583
584namespace {
Argyrios Kyrtzidis6a5674f2011-03-01 01:16:21 +0000585class ClassReleaseChecker : public Checker<check::PreObjCMessage> {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000586 mutable Selector releaseS;
587 mutable Selector retainS;
588 mutable Selector autoreleaseS;
589 mutable Selector drainS;
Dylan Noblesmithe2778992012-02-05 02:12:40 +0000590 mutable OwningPtr<BugType> BT;
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000591
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000592public:
Jordan Rose547060b2012-07-02 19:28:04 +0000593 void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000594};
595}
596
Jordan Rose547060b2012-07-02 19:28:04 +0000597void ClassReleaseChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000598 CheckerContext &C) const {
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000599
600 if (!BT) {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000601 BT.reset(new APIMisuse("message incorrectly sent to class instead of class "
602 "instance"));
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000603
604 ASTContext &Ctx = C.getASTContext();
605 releaseS = GetNullarySelector("release", Ctx);
606 retainS = GetNullarySelector("retain", Ctx);
607 autoreleaseS = GetNullarySelector("autorelease", Ctx);
608 drainS = GetNullarySelector("drain", Ctx);
609 }
610
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +0000611 if (msg.isInstanceMessage())
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000612 return;
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +0000613 const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
614 assert(Class);
Douglas Gregor9a129192010-04-21 00:45:42 +0000615
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +0000616 Selector S = msg.getSelector();
Benjamin Kramer7d875c72009-11-20 10:03:00 +0000617 if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000618 return;
619
Anna Zaksda4c8d62011-10-26 21:06:34 +0000620 if (ExplodedNode *N = C.addTransition()) {
Dylan Noblesmith2c1dd272012-02-05 02:13:05 +0000621 SmallString<200> buf;
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000622 llvm::raw_svector_ostream os(buf);
Ted Kremenekf5735152009-11-23 22:22:01 +0000623
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000624 os << "The '" << S.getAsString() << "' message should be sent to instances "
625 "of class '" << Class->getName()
626 << "' and not the class directly";
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000627
Anna Zaks3a6bdf82011-08-17 23:00:25 +0000628 BugReport *report = new BugReport(*BT, os.str(), N);
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +0000629 report->addRange(msg.getSourceRange());
Jordan Rosee10d5a72012-11-02 01:53:40 +0000630 C.emitReport(report);
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000631 }
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000632}
633
634//===----------------------------------------------------------------------===//
Anders Carlssond91d5f12011-03-13 20:35:21 +0000635// Check for passing non-Objective-C types to variadic methods that expect
636// only Objective-C types.
637//===----------------------------------------------------------------------===//
638
639namespace {
640class VariadicMethodTypeChecker : public Checker<check::PreObjCMessage> {
641 mutable Selector arrayWithObjectsS;
642 mutable Selector dictionaryWithObjectsAndKeysS;
643 mutable Selector setWithObjectsS;
Jordy Rosec0230d72012-04-06 19:06:01 +0000644 mutable Selector orderedSetWithObjectsS;
Anders Carlssond91d5f12011-03-13 20:35:21 +0000645 mutable Selector initWithObjectsS;
646 mutable Selector initWithObjectsAndKeysS;
Dylan Noblesmithe2778992012-02-05 02:12:40 +0000647 mutable OwningPtr<BugType> BT;
Anders Carlssond91d5f12011-03-13 20:35:21 +0000648
Jordan Rose547060b2012-07-02 19:28:04 +0000649 bool isVariadicMessage(const ObjCMethodCall &msg) const;
Anders Carlssond91d5f12011-03-13 20:35:21 +0000650
651public:
Jordan Rose547060b2012-07-02 19:28:04 +0000652 void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
Anders Carlssond91d5f12011-03-13 20:35:21 +0000653};
654}
655
656/// isVariadicMessage - Returns whether the given message is a variadic message,
657/// where all arguments must be Objective-C types.
658bool
Jordan Rose547060b2012-07-02 19:28:04 +0000659VariadicMethodTypeChecker::isVariadicMessage(const ObjCMethodCall &msg) const {
660 const ObjCMethodDecl *MD = msg.getDecl();
Ted Kremenekced5fea2011-04-12 21:47:05 +0000661
662 if (!MD || !MD->isVariadic() || isa<ObjCProtocolDecl>(MD->getDeclContext()))
Anders Carlssond91d5f12011-03-13 20:35:21 +0000663 return false;
664
665 Selector S = msg.getSelector();
666
667 if (msg.isInstanceMessage()) {
668 // FIXME: Ideally we'd look at the receiver interface here, but that's not
669 // useful for init, because alloc returns 'id'. In theory, this could lead
670 // to false positives, for example if there existed a class that had an
671 // initWithObjects: implementation that does accept non-Objective-C pointer
672 // types, but the chance of that happening is pretty small compared to the
673 // gains that this analysis gives.
674 const ObjCInterfaceDecl *Class = MD->getClassInterface();
675
Jordan Rose3ba8ae32012-06-11 16:40:37 +0000676 switch (findKnownClass(Class)) {
677 case FC_NSArray:
678 case FC_NSOrderedSet:
679 case FC_NSSet:
680 return S == initWithObjectsS;
681 case FC_NSDictionary:
682 return S == initWithObjectsAndKeysS;
683 default:
684 return false;
685 }
Anders Carlssond91d5f12011-03-13 20:35:21 +0000686 } else {
687 const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
688
Jordan Rose3ba8ae32012-06-11 16:40:37 +0000689 switch (findKnownClass(Class)) {
690 case FC_NSArray:
691 return S == arrayWithObjectsS;
692 case FC_NSOrderedSet:
693 return S == orderedSetWithObjectsS;
694 case FC_NSSet:
695 return S == setWithObjectsS;
696 case FC_NSDictionary:
697 return S == dictionaryWithObjectsAndKeysS;
698 default:
699 return false;
700 }
Anders Carlssond91d5f12011-03-13 20:35:21 +0000701 }
Anders Carlssond91d5f12011-03-13 20:35:21 +0000702}
703
Jordan Rose547060b2012-07-02 19:28:04 +0000704void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
Anders Carlssond91d5f12011-03-13 20:35:21 +0000705 CheckerContext &C) const {
706 if (!BT) {
707 BT.reset(new APIMisuse("Arguments passed to variadic method aren't all "
708 "Objective-C pointer types"));
709
710 ASTContext &Ctx = C.getASTContext();
711 arrayWithObjectsS = GetUnarySelector("arrayWithObjects", Ctx);
712 dictionaryWithObjectsAndKeysS =
713 GetUnarySelector("dictionaryWithObjectsAndKeys", Ctx);
714 setWithObjectsS = GetUnarySelector("setWithObjects", Ctx);
Jordy Rosec0230d72012-04-06 19:06:01 +0000715 orderedSetWithObjectsS = GetUnarySelector("orderedSetWithObjects", Ctx);
Anders Carlssond91d5f12011-03-13 20:35:21 +0000716
717 initWithObjectsS = GetUnarySelector("initWithObjects", Ctx);
718 initWithObjectsAndKeysS = GetUnarySelector("initWithObjectsAndKeys", Ctx);
719 }
720
721 if (!isVariadicMessage(msg))
722 return;
723
724 // We are not interested in the selector arguments since they have
725 // well-defined types, so the compiler will issue a warning for them.
726 unsigned variadicArgsBegin = msg.getSelector().getNumArgs();
727
728 // We're not interested in the last argument since it has to be nil or the
729 // compiler would have issued a warning for it elsewhere.
730 unsigned variadicArgsEnd = msg.getNumArgs() - 1;
731
732 if (variadicArgsEnd <= variadicArgsBegin)
733 return;
734
735 // Verify that all arguments have Objective-C types.
David Blaikie05785d12013-02-20 22:23:23 +0000736 Optional<ExplodedNode*> errorNode;
Ted Kremenek49b1e382012-01-26 21:29:00 +0000737 ProgramStateRef state = C.getState();
Ted Kremenek066b2262011-03-14 19:50:37 +0000738
Anders Carlssond91d5f12011-03-13 20:35:21 +0000739 for (unsigned I = variadicArgsBegin; I != variadicArgsEnd; ++I) {
Jordan Rose547060b2012-07-02 19:28:04 +0000740 QualType ArgTy = msg.getArgExpr(I)->getType();
Anders Carlssond91d5f12011-03-13 20:35:21 +0000741 if (ArgTy->isObjCObjectPointerType())
742 continue;
743
Anders Carlssond1f65f62011-04-19 01:16:46 +0000744 // Block pointers are treaded as Objective-C pointers.
745 if (ArgTy->isBlockPointerType())
746 continue;
747
Ted Kremenek4ceebbf2011-03-16 00:22:51 +0000748 // Ignore pointer constants.
David Blaikie2fdacbc2013-02-20 05:52:05 +0000749 if (msg.getArgSVal(I).getAs<loc::ConcreteInt>())
Ted Kremenek4ceebbf2011-03-16 00:22:51 +0000750 continue;
Ted Kremenek6fa1dae2011-03-17 04:01:35 +0000751
Ted Kremenek70727342011-03-17 04:10:25 +0000752 // Ignore pointer types annotated with 'NSObject' attribute.
753 if (C.getASTContext().isObjCNSObjectType(ArgTy))
754 continue;
755
Ted Kremenek6fa1dae2011-03-17 04:01:35 +0000756 // Ignore CF references, which can be toll-free bridged.
Ted Kremenekc85964e2011-07-16 19:50:32 +0000757 if (coreFoundation::isCFObjectRef(ArgTy))
Ted Kremenek6fa1dae2011-03-17 04:01:35 +0000758 continue;
Ted Kremenek4ceebbf2011-03-16 00:22:51 +0000759
Ted Kremenek066b2262011-03-14 19:50:37 +0000760 // Generate only one error node to use for all bug reports.
Jordan Rose547060b2012-07-02 19:28:04 +0000761 if (!errorNode.hasValue())
Anna Zaksda4c8d62011-10-26 21:06:34 +0000762 errorNode = C.addTransition();
Ted Kremenek066b2262011-03-14 19:50:37 +0000763
764 if (!errorNode.getValue())
Anders Carlssond91d5f12011-03-13 20:35:21 +0000765 continue;
766
Dylan Noblesmith2c1dd272012-02-05 02:13:05 +0000767 SmallString<128> sbuf;
Anders Carlssond91d5f12011-03-13 20:35:21 +0000768 llvm::raw_svector_ostream os(sbuf);
769
Jordan Rose547060b2012-07-02 19:28:04 +0000770 StringRef TypeName = GetReceiverInterfaceName(msg);
771 if (!TypeName.empty())
Anders Carlssond91d5f12011-03-13 20:35:21 +0000772 os << "Argument to '" << TypeName << "' method '";
773 else
774 os << "Argument to method '";
775
776 os << msg.getSelector().getAsString()
Jordan Rose547060b2012-07-02 19:28:04 +0000777 << "' should be an Objective-C pointer type, not '";
778 ArgTy.print(os, C.getLangOpts());
779 os << "'";
Anders Carlssond91d5f12011-03-13 20:35:21 +0000780
Jordan Rose547060b2012-07-02 19:28:04 +0000781 BugReport *R = new BugReport(*BT, os.str(), errorNode.getValue());
Anders Carlssond91d5f12011-03-13 20:35:21 +0000782 R->addRange(msg.getArgSourceRange(I));
Jordan Rosee10d5a72012-11-02 01:53:40 +0000783 C.emitReport(R);
Anders Carlssond91d5f12011-03-13 20:35:21 +0000784 }
785}
786
787//===----------------------------------------------------------------------===//
Jordan Roseefef7602012-06-11 16:40:41 +0000788// Improves the modeling of loops over Cocoa collections.
789//===----------------------------------------------------------------------===//
790
791namespace {
792class ObjCLoopChecker
793 : public Checker<check::PostStmt<ObjCForCollectionStmt> > {
794
795public:
796 void checkPostStmt(const ObjCForCollectionStmt *FCS, CheckerContext &C) const;
797};
798}
799
800static bool isKnownNonNilCollectionType(QualType T) {
801 const ObjCObjectPointerType *PT = T->getAs<ObjCObjectPointerType>();
802 if (!PT)
803 return false;
804
805 const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();
806 if (!ID)
807 return false;
808
809 switch (findKnownClass(ID)) {
810 case FC_NSArray:
811 case FC_NSDictionary:
812 case FC_NSEnumerator:
813 case FC_NSOrderedSet:
814 case FC_NSSet:
815 return true;
816 default:
817 return false;
818 }
819}
820
Jordan Rose9de821e2013-04-26 21:43:01 +0000821/// Assumes that the collection is non-nil.
822///
823/// If the collection is known to be nil, returns NULL to indicate an infeasible
824/// path.
825static ProgramStateRef checkCollectionNonNil(CheckerContext &C,
826 ProgramStateRef State,
827 const ObjCForCollectionStmt *FCS) {
828 if (!State)
829 return NULL;
830
831 SVal CollectionVal = C.getSVal(FCS->getCollection());
832 Optional<DefinedSVal> KnownCollection = CollectionVal.getAs<DefinedSVal>();
833 if (!KnownCollection)
834 return State;
835
836 ProgramStateRef StNonNil, StNil;
837 llvm::tie(StNonNil, StNil) = State->assume(*KnownCollection);
838 if (StNil && !StNonNil) {
839 // The collection is nil. This path is infeasible.
840 return NULL;
841 }
842
843 return StNonNil;
844}
845
846/// Assumes that the collection elements are non-nil.
847///
848/// This only applies if the collection is one of those known not to contain
849/// nil values.
850static ProgramStateRef checkElementNonNil(CheckerContext &C,
851 ProgramStateRef State,
852 const ObjCForCollectionStmt *FCS) {
853 if (!State)
854 return NULL;
855
Jordan Roseefef7602012-06-11 16:40:41 +0000856 // See if the collection is one where we /know/ the elements are non-nil.
Jordan Rose9de821e2013-04-26 21:43:01 +0000857 if (!isKnownNonNilCollectionType(FCS->getCollection()->getType()))
858 return State;
859
860 const LocationContext *LCtx = C.getLocationContext();
Jordan Roseefef7602012-06-11 16:40:41 +0000861 const Stmt *Element = FCS->getElement();
Jordan Rose9de821e2013-04-26 21:43:01 +0000862
863 // FIXME: Copied from ExprEngineObjC.
864 Optional<Loc> ElementLoc;
Jordan Roseefef7602012-06-11 16:40:41 +0000865 if (const DeclStmt *DS = dyn_cast<DeclStmt>(Element)) {
866 const VarDecl *ElemDecl = cast<VarDecl>(DS->getSingleDecl());
867 assert(ElemDecl->getInit() == 0);
Jordan Rose9de821e2013-04-26 21:43:01 +0000868 ElementLoc = State->getLValue(ElemDecl, LCtx);
Jordan Roseefef7602012-06-11 16:40:41 +0000869 } else {
Jordan Rose9de821e2013-04-26 21:43:01 +0000870 ElementLoc = State->getSVal(Element, LCtx).getAs<Loc>();
Jordan Roseefef7602012-06-11 16:40:41 +0000871 }
872
Jordan Rose9de821e2013-04-26 21:43:01 +0000873 if (!ElementLoc)
874 return State;
Jordan Roseefef7602012-06-11 16:40:41 +0000875
876 // Go ahead and assume the value is non-nil.
Jordan Rose9de821e2013-04-26 21:43:01 +0000877 SVal Val = State->getSVal(*ElementLoc);
878 return State->assume(Val.castAs<DefinedOrUnknownSVal>(), true);
879}
880
881void ObjCLoopChecker::checkPostStmt(const ObjCForCollectionStmt *FCS,
882 CheckerContext &C) const {
883 // Check if this is the branch for the end of the loop.
884 SVal CollectionSentinel = C.getSVal(FCS);
885 if (CollectionSentinel.isZeroConstant())
886 return;
887
888 ProgramStateRef State = C.getState();
889 State = checkCollectionNonNil(C, State, FCS);
890 State = checkElementNonNil(C, State, FCS);
891
892 if (!State)
893 C.generateSink();
894 else if (State != C.getState())
895 C.addTransition(State);
Jordan Roseefef7602012-06-11 16:40:41 +0000896}
897
Anna Zaks5a5a1752012-08-22 21:19:56 +0000898namespace {
899/// \class ObjCNonNilReturnValueChecker
Anna Zaks4818bbe2012-08-30 19:40:52 +0000900/// \brief The checker restricts the return values of APIs known to
901/// never (or almost never) return 'nil'.
Anna Zaks5a5a1752012-08-22 21:19:56 +0000902class ObjCNonNilReturnValueChecker
903 : public Checker<check::PostObjCMessage> {
904 mutable bool Initialized;
905 mutable Selector ObjectAtIndex;
906 mutable Selector ObjectAtIndexedSubscript;
Anna Zaks4063fa12013-05-10 18:04:46 +0000907 mutable Selector NullSelector;
Anna Zaks9159e162012-08-22 22:47:58 +0000908
Anna Zaks5a5a1752012-08-22 21:19:56 +0000909public:
Anna Zaks9159e162012-08-22 22:47:58 +0000910 ObjCNonNilReturnValueChecker() : Initialized(false) {}
Anna Zaks5a5a1752012-08-22 21:19:56 +0000911 void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
912};
913}
914
Benjamin Kramer199f8da2012-09-10 11:57:16 +0000915static ProgramStateRef assumeExprIsNonNull(const Expr *NonNullExpr,
916 ProgramStateRef State,
917 CheckerContext &C) {
Anna Zaks4818bbe2012-08-30 19:40:52 +0000918 SVal Val = State->getSVal(NonNullExpr, C.getLocationContext());
David Blaikie05785d12013-02-20 22:23:23 +0000919 if (Optional<DefinedOrUnknownSVal> DV = Val.getAs<DefinedOrUnknownSVal>())
Anna Zaks830c48e2012-08-30 22:55:32 +0000920 return State->assume(*DV, true);
Anna Zaksb504f442012-08-30 22:42:41 +0000921 return State;
Anna Zaks4818bbe2012-08-30 19:40:52 +0000922}
923
Anna Zaks5a5a1752012-08-22 21:19:56 +0000924void ObjCNonNilReturnValueChecker::checkPostObjCMessage(const ObjCMethodCall &M,
925 CheckerContext &C)
Anna Zaks4818bbe2012-08-30 19:40:52 +0000926 const {
Anna Zaks5a5a1752012-08-22 21:19:56 +0000927 ProgramStateRef State = C.getState();
928
929 if (!Initialized) {
930 ASTContext &Ctx = C.getASTContext();
931 ObjectAtIndex = GetUnarySelector("objectAtIndex", Ctx);
932 ObjectAtIndexedSubscript = GetUnarySelector("objectAtIndexedSubscript", Ctx);
Anna Zaks4063fa12013-05-10 18:04:46 +0000933 NullSelector = GetNullarySelector("null", Ctx);
Anna Zaks5a5a1752012-08-22 21:19:56 +0000934 }
935
936 // Check the receiver type.
937 if (const ObjCInterfaceDecl *Interface = M.getReceiverInterface()) {
Anna Zaks4818bbe2012-08-30 19:40:52 +0000938
939 // Assume that object returned from '[self init]' or '[super init]' is not
940 // 'nil' if we are processing an inlined function/method.
941 //
942 // A defensive callee will (and should) check if the object returned by
943 // '[super init]' is 'nil' before doing it's own initialization. However,
944 // since 'nil' is rarely returned in practice, we should not warn when the
945 // caller to the defensive constructor uses the object in contexts where
946 // 'nil' is not accepted.
Anna Zaks49bb6502012-11-06 04:20:54 +0000947 if (!C.inTopFrame() && M.getDecl() &&
Anna Zaks4818bbe2012-08-30 19:40:52 +0000948 M.getDecl()->getMethodFamily() == OMF_init &&
949 M.isReceiverSelfOrSuper()) {
950 State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
951 }
952
Anna Zaks4063fa12013-05-10 18:04:46 +0000953 FoundationClass Cl = findKnownClass(Interface);
954
Anna Zaks4818bbe2012-08-30 19:40:52 +0000955 // Objects returned from
956 // [NSArray|NSOrderedSet]::[ObjectAtIndex|ObjectAtIndexedSubscript]
957 // are never 'nil'.
Anna Zaks5a5a1752012-08-22 21:19:56 +0000958 if (Cl == FC_NSArray || Cl == FC_NSOrderedSet) {
959 Selector Sel = M.getSelector();
960 if (Sel == ObjectAtIndex || Sel == ObjectAtIndexedSubscript) {
961 // Go ahead and assume the value is non-nil.
Anna Zaks4818bbe2012-08-30 19:40:52 +0000962 State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
Anna Zaks5a5a1752012-08-22 21:19:56 +0000963 }
964 }
Anna Zaks4063fa12013-05-10 18:04:46 +0000965
966 // Objects returned from [NSNull null] are not nil.
967 if (Cl == FC_NSNull) {
968 if (M.getSelector() == NullSelector) {
969 // Go ahead and assume the value is non-nil.
970 State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
971 }
972 }
Anna Zaks5a5a1752012-08-22 21:19:56 +0000973 }
Anna Zaks4818bbe2012-08-30 19:40:52 +0000974 C.addTransition(State);
Anna Zaks5a5a1752012-08-22 21:19:56 +0000975}
Jordan Roseefef7602012-06-11 16:40:41 +0000976
977//===----------------------------------------------------------------------===//
Ted Kremenek1f352db2008-07-22 16:21:24 +0000978// Check registration.
Ted Kremenekc057f412009-07-14 00:43:42 +0000979//===----------------------------------------------------------------------===//
Argyrios Kyrtzidis9d4d4f92011-02-16 01:40:52 +0000980
Argyrios Kyrtzidis507ff532011-02-17 21:39:17 +0000981void ento::registerNilArgChecker(CheckerManager &mgr) {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000982 mgr.registerChecker<NilArgChecker>();
Argyrios Kyrtzidis9d4d4f92011-02-16 01:40:52 +0000983}
984
Argyrios Kyrtzidis507ff532011-02-17 21:39:17 +0000985void ento::registerCFNumberCreateChecker(CheckerManager &mgr) {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000986 mgr.registerChecker<CFNumberCreateChecker>();
Argyrios Kyrtzidis9d4d4f92011-02-16 01:40:52 +0000987}
988
Argyrios Kyrtzidis507ff532011-02-17 21:39:17 +0000989void ento::registerCFRetainReleaseChecker(CheckerManager &mgr) {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000990 mgr.registerChecker<CFRetainReleaseChecker>();
Ted Kremenek1f352db2008-07-22 16:21:24 +0000991}
Argyrios Kyrtzidis507ff532011-02-17 21:39:17 +0000992
993void ento::registerClassReleaseChecker(CheckerManager &mgr) {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000994 mgr.registerChecker<ClassReleaseChecker>();
Argyrios Kyrtzidis507ff532011-02-17 21:39:17 +0000995}
Anders Carlssond91d5f12011-03-13 20:35:21 +0000996
997void ento::registerVariadicMethodTypeChecker(CheckerManager &mgr) {
998 mgr.registerChecker<VariadicMethodTypeChecker>();
999}
Jordan Roseefef7602012-06-11 16:40:41 +00001000
1001void ento::registerObjCLoopChecker(CheckerManager &mgr) {
1002 mgr.registerChecker<ObjCLoopChecker>();
1003}
Anna Zaks5a5a1752012-08-22 21:19:56 +00001004
1005void ento::registerObjCNonNilReturnValueChecker(CheckerManager &mgr) {
1006 mgr.registerChecker<ObjCNonNilReturnValueChecker>();
1007}