blob: ba779ff191ce37b81101e7b44ed92a2d7ad61f96 [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,
Anna Zaks6afa8f12013-05-13 23:49:51 +0000108 StringRef Msg,
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000109 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();
Anna Zaks6afa8f12013-05-13 23:49:51 +0000126 if (State->isNull(C.getSVal(E)).isConstrainedTrue()) {
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000127
128 if (ExplodedNode *N = C.generateSink()) {
Anna Zaks6afa8f12013-05-13 23:49:51 +0000129 generateBugReport(N, Msg, E->getSourceRange(), E, C);
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000130 }
131
132 }
133}
134
135void NilArgChecker::warnIfNilArg(CheckerContext &C,
Anna Zaks130df4b2013-03-23 00:39:21 +0000136 const ObjCMethodCall &msg,
137 unsigned int Arg,
138 FoundationClass Class,
139 bool CanBeSubscript) const {
140 // Check if the argument is nil.
141 ProgramStateRef State = C.getState();
142 if (!State->isNull(msg.getArgSVal(Arg)).isConstrainedTrue())
143 return;
144
Ted Kremenek750b7ac2010-12-20 21:19:09 +0000145 if (ExplodedNode *N = C.generateSink()) {
Dylan Noblesmith2c1dd272012-02-05 02:13:05 +0000146 SmallString<128> sbuf;
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000147 llvm::raw_svector_ostream os(sbuf);
Anna Zaks130df4b2013-03-23 00:39:21 +0000148
149 if (CanBeSubscript && msg.getMessageKind() == OCM_Subscript) {
150
151 if (Class == FC_NSArray) {
152 os << "Array element cannot be nil";
153 } else if (Class == FC_NSDictionary) {
Anna Zaks4d1e3042013-04-05 23:50:18 +0000154 if (Arg == 0) {
Ted Kremeneke06df462013-04-08 18:09:16 +0000155 os << "Value stored into '";
Anna Zaks4d1e3042013-04-05 23:50:18 +0000156 os << GetReceiverInterfaceName(msg) << "' cannot be nil";
157 } else {
Anna Zaks130df4b2013-03-23 00:39:21 +0000158 assert(Arg == 1);
Anna Zaks4d1e3042013-04-05 23:50:18 +0000159 os << "'"<< GetReceiverInterfaceName(msg) << "' key cannot be nil";
Anna Zaks130df4b2013-03-23 00:39:21 +0000160 }
161 } else
162 llvm_unreachable("Missing foundation class for the subscript expr");
163
164 } else {
Anna Zaks4d1e3042013-04-05 23:50:18 +0000165 if (Class == FC_NSDictionary) {
166 if (Arg == 0)
167 os << "Value argument ";
168 else {
169 assert(Arg == 1);
170 os << "Key argument ";
171 }
172 os << "to '" << msg.getSelector().getAsString() << "' cannot be nil";
173 } else {
174 os << "Argument to '" << GetReceiverInterfaceName(msg) << "' method '"
175 << msg.getSelector().getAsString() << "' cannot be nil";
176 }
Anna Zaks130df4b2013-03-23 00:39:21 +0000177 }
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000178
Anna Zaks6afa8f12013-05-13 23:49:51 +0000179 generateBugReport(N, os.str(), msg.getArgSourceRange(Arg),
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000180 msg.getArgExpr(Arg), C);
Ted Kremenek276278e2008-03-27 22:05:32 +0000181 }
Ted Kremenek276278e2008-03-27 22:05:32 +0000182}
183
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000184void NilArgChecker::generateBugReport(ExplodedNode *N,
Anna Zaks6afa8f12013-05-13 23:49:51 +0000185 StringRef Msg,
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000186 SourceRange Range,
Anna Zaks6afa8f12013-05-13 23:49:51 +0000187 const Expr *E,
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000188 CheckerContext &C) const {
189 if (!BT)
190 BT.reset(new APIMisuse("nil argument"));
191
Anna Zaks6afa8f12013-05-13 23:49:51 +0000192 BugReport *R = new BugReport(*BT, Msg, N);
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000193 R->addRange(Range);
Anna Zaks6afa8f12013-05-13 23:49:51 +0000194 bugreporter::trackNullOrUndefValue(N, E, *R);
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000195 C.emitReport(R);
196}
197
Jordan Rose547060b2012-07-02 19:28:04 +0000198void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000199 CheckerContext &C) const {
Anders Carlsson3c50aea2011-03-08 20:05:26 +0000200 const ObjCInterfaceDecl *ID = msg.getReceiverInterface();
201 if (!ID)
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000202 return;
Anna Zaks6457ad22013-03-18 20:46:56 +0000203
204 FoundationClass Class = findKnownClass(ID);
205
206 static const unsigned InvalidArgIndex = UINT_MAX;
207 unsigned Arg = InvalidArgIndex;
Anna Zaks130df4b2013-03-23 00:39:21 +0000208 bool CanBeSubscript = false;
209
Anna Zaks6457ad22013-03-18 20:46:56 +0000210 if (Class == FC_NSString) {
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +0000211 Selector S = msg.getSelector();
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000212
213 if (S.isUnarySelector())
214 return;
215
216 // FIXME: This is going to be really slow doing these checks with
217 // lexical comparisons.
218
219 std::string NameStr = S.getAsString();
Chris Lattner0e62c1c2011-07-23 10:55:15 +0000220 StringRef Name(NameStr);
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000221 assert(!Name.empty());
222
223 // FIXME: Checking for initWithFormat: will not work in most cases
224 // yet because [NSString alloc] returns id, not NSString*. We will
225 // need support for tracking expected-type information in the analyzer
226 // to find these errors.
227 if (Name == "caseInsensitiveCompare:" ||
228 Name == "compare:" ||
229 Name == "compare:options:" ||
230 Name == "compare:options:range:" ||
231 Name == "compare:options:range:locale:" ||
232 Name == "componentsSeparatedByCharactersInSet:" ||
233 Name == "initWithFormat:") {
Anna Zaks6457ad22013-03-18 20:46:56 +0000234 Arg = 0;
235 }
236 } else if (Class == FC_NSArray) {
237 Selector S = msg.getSelector();
238
239 if (S.isUnarySelector())
240 return;
241
242 if (S.getNameForSlot(0).equals("addObject")) {
243 Arg = 0;
244 } else if (S.getNameForSlot(0).equals("insertObject") &&
245 S.getNameForSlot(1).equals("atIndex")) {
246 Arg = 0;
247 } else if (S.getNameForSlot(0).equals("replaceObjectAtIndex") &&
248 S.getNameForSlot(1).equals("withObject")) {
249 Arg = 1;
250 } else if (S.getNameForSlot(0).equals("setObject") &&
251 S.getNameForSlot(1).equals("atIndexedSubscript")) {
252 Arg = 0;
Anna Zaks130df4b2013-03-23 00:39:21 +0000253 CanBeSubscript = true;
Anna Zaks6457ad22013-03-18 20:46:56 +0000254 } else if (S.getNameForSlot(0).equals("arrayByAddingObject")) {
255 Arg = 0;
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000256 }
Anna Zaks130df4b2013-03-23 00:39:21 +0000257 } else if (Class == FC_NSDictionary) {
258 Selector S = msg.getSelector();
259
260 if (S.isUnarySelector())
261 return;
262
263 if (S.getNameForSlot(0).equals("dictionaryWithObject") &&
264 S.getNameForSlot(1).equals("forKey")) {
265 Arg = 0;
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000266 warnIfNilArg(C, msg, /* Arg */1, Class);
Anna Zaks130df4b2013-03-23 00:39:21 +0000267 } else if (S.getNameForSlot(0).equals("setObject") &&
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("forKeyedSubscript")) {
273 CanBeSubscript = true;
274 Arg = 0;
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000275 warnIfNilArg(C, msg, /* Arg */1, Class, CanBeSubscript);
Anna Zaks130df4b2013-03-23 00:39:21 +0000276 } else if (S.getNameForSlot(0).equals("removeObjectForKey")) {
277 Arg = 0;
278 }
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000279 }
Anna Zaks6457ad22013-03-18 20:46:56 +0000280
281 // If argument is '0', report a warning.
Anna Zaks130df4b2013-03-23 00:39:21 +0000282 if ((Arg != InvalidArgIndex))
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000283 warnIfNilArg(C, msg, Arg, Class, CanBeSubscript);
Anna Zaks6457ad22013-03-18 20:46:56 +0000284
Ted Kremenekc0414922008-03-27 07:25:52 +0000285}
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000286
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000287void NilArgChecker::checkPostStmt(const ObjCArrayLiteral *AL,
288 CheckerContext &C) const {
Anna Zaks6afa8f12013-05-13 23:49:51 +0000289 unsigned NumOfElements = AL->getNumElements();
290 for (unsigned i = 0; i < NumOfElements; ++i) {
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000291 warnIfNilExpr(AL->getElement(i), "Array element cannot be nil", C);
292 }
293}
294
295void NilArgChecker::checkPostStmt(const ObjCDictionaryLiteral *DL,
296 CheckerContext &C) const {
Anna Zaks6afa8f12013-05-13 23:49:51 +0000297 unsigned NumOfElements = DL->getNumElements();
298 for (unsigned i = 0; i < NumOfElements; ++i) {
Anna Zaksbb2a2c82013-05-13 21:48:20 +0000299 ObjCDictionaryElement Element = DL->getKeyValueElement(i);
300 warnIfNilExpr(Element.Key, "Dictionary key cannot be nil", C);
301 warnIfNilExpr(Element.Value, "Dictionary value cannot be nil", C);
302 }
303}
304
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000305//===----------------------------------------------------------------------===//
306// Error reporting.
307//===----------------------------------------------------------------------===//
308
309namespace {
Argyrios Kyrtzidis6a5674f2011-03-01 01:16:21 +0000310class CFNumberCreateChecker : public Checker< check::PreStmt<CallExpr> > {
Dylan Noblesmithe2778992012-02-05 02:12:40 +0000311 mutable OwningPtr<APIMisuse> BT;
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000312 mutable IdentifierInfo* II;
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000313public:
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000314 CFNumberCreateChecker() : II(0) {}
315
316 void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
317
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000318private:
Ted Kremenek5ef32db2011-08-12 23:37:29 +0000319 void EmitError(const TypedRegion* R, const Expr *Ex,
Mike Stump11289f42009-09-09 15:08:12 +0000320 uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind);
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000321};
322} // end anonymous namespace
323
324enum CFNumberType {
325 kCFNumberSInt8Type = 1,
326 kCFNumberSInt16Type = 2,
327 kCFNumberSInt32Type = 3,
328 kCFNumberSInt64Type = 4,
329 kCFNumberFloat32Type = 5,
330 kCFNumberFloat64Type = 6,
331 kCFNumberCharType = 7,
332 kCFNumberShortType = 8,
333 kCFNumberIntType = 9,
334 kCFNumberLongType = 10,
335 kCFNumberLongLongType = 11,
336 kCFNumberFloatType = 12,
337 kCFNumberDoubleType = 13,
338 kCFNumberCFIndexType = 14,
339 kCFNumberNSIntegerType = 15,
340 kCFNumberCGFloatType = 16
341};
342
Ted Kremenek5ef32db2011-08-12 23:37:29 +0000343static Optional<uint64_t> GetCFNumberSize(ASTContext &Ctx, uint64_t i) {
Nuno Lopescfca1f02009-12-23 17:49:57 +0000344 static const unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 };
Mike Stump11289f42009-09-09 15:08:12 +0000345
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000346 if (i < kCFNumberCharType)
347 return FixedSize[i-1];
Mike Stump11289f42009-09-09 15:08:12 +0000348
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000349 QualType T;
Mike Stump11289f42009-09-09 15:08:12 +0000350
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000351 switch (i) {
352 case kCFNumberCharType: T = Ctx.CharTy; break;
353 case kCFNumberShortType: T = Ctx.ShortTy; break;
354 case kCFNumberIntType: T = Ctx.IntTy; break;
355 case kCFNumberLongType: T = Ctx.LongTy; break;
356 case kCFNumberLongLongType: T = Ctx.LongLongTy; break;
357 case kCFNumberFloatType: T = Ctx.FloatTy; break;
358 case kCFNumberDoubleType: T = Ctx.DoubleTy; break;
359 case kCFNumberCFIndexType:
360 case kCFNumberNSIntegerType:
361 case kCFNumberCGFloatType:
Mike Stump11289f42009-09-09 15:08:12 +0000362 // FIXME: We need a way to map from names to Type*.
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000363 default:
David Blaikie7a30dc52013-02-21 01:47:18 +0000364 return None;
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000365 }
Mike Stump11289f42009-09-09 15:08:12 +0000366
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000367 return Ctx.getTypeSize(T);
368}
369
370#if 0
371static const char* GetCFNumberTypeStr(uint64_t i) {
372 static const char* Names[] = {
373 "kCFNumberSInt8Type",
374 "kCFNumberSInt16Type",
375 "kCFNumberSInt32Type",
376 "kCFNumberSInt64Type",
377 "kCFNumberFloat32Type",
378 "kCFNumberFloat64Type",
379 "kCFNumberCharType",
380 "kCFNumberShortType",
381 "kCFNumberIntType",
382 "kCFNumberLongType",
383 "kCFNumberLongLongType",
384 "kCFNumberFloatType",
385 "kCFNumberDoubleType",
386 "kCFNumberCFIndexType",
387 "kCFNumberNSIntegerType",
388 "kCFNumberCGFloatType"
389 };
Mike Stump11289f42009-09-09 15:08:12 +0000390
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000391 return i <= kCFNumberCGFloatType ? Names[i-1] : "Invalid CFNumberType";
392}
393#endif
394
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000395void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE,
396 CheckerContext &C) const {
Ted Kremenek49b1e382012-01-26 21:29:00 +0000397 ProgramStateRef state = C.getState();
Anna Zaksc6aa5312011-12-01 05:57:37 +0000398 const FunctionDecl *FD = C.getCalleeDecl(CE);
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000399 if (!FD)
400 return;
401
402 ASTContext &Ctx = C.getASTContext();
403 if (!II)
404 II = &Ctx.Idents.get("CFNumberCreate");
405
406 if (FD->getIdentifier() != II || CE->getNumArgs() != 3)
407 return;
Mike Stump11289f42009-09-09 15:08:12 +0000408
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000409 // Get the value of the "theType" argument.
Ted Kremenek632e3b72012-01-06 22:09:28 +0000410 const LocationContext *LCtx = C.getLocationContext();
411 SVal TheTypeVal = state->getSVal(CE->getArg(1), LCtx);
Mike Stump11289f42009-09-09 15:08:12 +0000412
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000413 // FIXME: We really should allow ranges of valid theType values, and
414 // bifurcate the state appropriately.
David Blaikie05785d12013-02-20 22:23:23 +0000415 Optional<nonloc::ConcreteInt> V = TheTypeVal.getAs<nonloc::ConcreteInt>();
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000416 if (!V)
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000417 return;
Mike Stump11289f42009-09-09 15:08:12 +0000418
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000419 uint64_t NumberKind = V->getValue().getLimitedValue();
David Blaikie05785d12013-02-20 22:23:23 +0000420 Optional<uint64_t> OptTargetSize = GetCFNumberSize(Ctx, NumberKind);
Mike Stump11289f42009-09-09 15:08:12 +0000421
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000422 // FIXME: In some cases we can emit an error.
David Blaikiee359f3c2013-02-20 22:23:03 +0000423 if (!OptTargetSize)
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000424 return;
Mike Stump11289f42009-09-09 15:08:12 +0000425
David Blaikiee359f3c2013-02-20 22:23:03 +0000426 uint64_t TargetSize = *OptTargetSize;
427
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000428 // Look at the value of the integer being passed by reference. Essentially
429 // we want to catch cases where the value passed in is not equal to the
430 // size of the type being created.
Ted Kremenek632e3b72012-01-06 22:09:28 +0000431 SVal TheValueExpr = state->getSVal(CE->getArg(2), LCtx);
Mike Stump11289f42009-09-09 15:08:12 +0000432
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000433 // FIXME: Eventually we should handle arbitrary locations. We can do this
434 // by having an enhanced memory model that does low-level typing.
David Blaikie05785d12013-02-20 22:23:23 +0000435 Optional<loc::MemRegionVal> LV = TheValueExpr.getAs<loc::MemRegionVal>();
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000436 if (!LV)
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000437 return;
Mike Stump11289f42009-09-09 15:08:12 +0000438
Ted Kremenek8df44b262011-08-12 20:02:48 +0000439 const TypedValueRegion* R = dyn_cast<TypedValueRegion>(LV->stripCasts());
Ted Kremenek87a7a452009-07-29 18:17:40 +0000440 if (!R)
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000441 return;
Ted Kremenek87a7a452009-07-29 18:17:40 +0000442
Zhongxing Xu8de0a3d2010-08-11 06:10:55 +0000443 QualType T = Ctx.getCanonicalType(R->getValueType());
Mike Stump11289f42009-09-09 15:08:12 +0000444
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000445 // FIXME: If the pointee isn't an integer type, should we flag a warning?
446 // People can do weird stuff with pointers.
Mike Stump11289f42009-09-09 15:08:12 +0000447
Jordan Rose61e221f2013-04-09 02:30:33 +0000448 if (!T->isIntegralOrEnumerationType())
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000449 return;
Mike Stump11289f42009-09-09 15:08:12 +0000450
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000451 uint64_t SourceSize = Ctx.getTypeSize(T);
Mike Stump11289f42009-09-09 15:08:12 +0000452
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000453 // CHECK: is SourceSize == TargetSize
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000454 if (SourceSize == TargetSize)
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000455 return;
Mike Stump11289f42009-09-09 15:08:12 +0000456
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000457 // Generate an error. Only generate a sink if 'SourceSize < TargetSize';
458 // otherwise generate a regular node.
459 //
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000460 // FIXME: We can actually create an abstract "CFNumber" object that has
461 // the bits initialized to the provided values.
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000462 //
Ted Kremenek750b7ac2010-12-20 21:19:09 +0000463 if (ExplodedNode *N = SourceSize < TargetSize ? C.generateSink()
Anna Zaksda4c8d62011-10-26 21:06:34 +0000464 : C.addTransition()) {
Dylan Noblesmith2c1dd272012-02-05 02:13:05 +0000465 SmallString<128> sbuf;
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000466 llvm::raw_svector_ostream os(sbuf);
467
468 os << (SourceSize == 8 ? "An " : "A ")
469 << SourceSize << " bit integer is used to initialize a CFNumber "
470 "object that represents "
471 << (TargetSize == 8 ? "an " : "a ")
472 << TargetSize << " bit integer. ";
473
474 if (SourceSize < TargetSize)
475 os << (TargetSize - SourceSize)
476 << " bits of the CFNumber value will be garbage." ;
477 else
478 os << (SourceSize - TargetSize)
479 << " bits of the input integer will be lost.";
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000480
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000481 if (!BT)
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000482 BT.reset(new APIMisuse("Bad use of CFNumberCreate"));
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000483
Anna Zaks3a6bdf82011-08-17 23:00:25 +0000484 BugReport *report = new BugReport(*BT, os.str(), N);
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000485 report->addRange(CE->getArg(2)->getSourceRange());
Jordan Rosee10d5a72012-11-02 01:53:40 +0000486 C.emitReport(report);
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000487 }
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000488}
489
Ted Kremenek1f352db2008-07-22 16:21:24 +0000490//===----------------------------------------------------------------------===//
Jordan Rose721567a2012-11-07 17:12:37 +0000491// CFRetain/CFRelease/CFMakeCollectable checking for null arguments.
Ted Kremenekc057f412009-07-14 00:43:42 +0000492//===----------------------------------------------------------------------===//
493
494namespace {
Argyrios Kyrtzidis6a5674f2011-03-01 01:16:21 +0000495class CFRetainReleaseChecker : public Checker< check::PreStmt<CallExpr> > {
Dylan Noblesmithe2778992012-02-05 02:12:40 +0000496 mutable OwningPtr<APIMisuse> BT;
Jordan Rose721567a2012-11-07 17:12:37 +0000497 mutable IdentifierInfo *Retain, *Release, *MakeCollectable;
Ted Kremenekc057f412009-07-14 00:43:42 +0000498public:
Jordan Rose721567a2012-11-07 17:12:37 +0000499 CFRetainReleaseChecker(): Retain(0), Release(0), MakeCollectable(0) {}
Ted Kremenek5ef32db2011-08-12 23:37:29 +0000500 void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
Ted Kremenekc057f412009-07-14 00:43:42 +0000501};
502} // end anonymous namespace
503
504
Ted Kremenek5ef32db2011-08-12 23:37:29 +0000505void CFRetainReleaseChecker::checkPreStmt(const CallExpr *CE,
506 CheckerContext &C) const {
Ted Kremenekc057f412009-07-14 00:43:42 +0000507 // If the CallExpr doesn't have exactly 1 argument just give up checking.
508 if (CE->getNumArgs() != 1)
Jordy Rose40c5c242010-07-06 02:34:42 +0000509 return;
Mike Stump11289f42009-09-09 15:08:12 +0000510
Ted Kremenek49b1e382012-01-26 21:29:00 +0000511 ProgramStateRef state = C.getState();
Anna Zaksc6aa5312011-12-01 05:57:37 +0000512 const FunctionDecl *FD = C.getCalleeDecl(CE);
Ted Kremenekc057f412009-07-14 00:43:42 +0000513 if (!FD)
Jordy Rose40c5c242010-07-06 02:34:42 +0000514 return;
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000515
516 if (!BT) {
517 ASTContext &Ctx = C.getASTContext();
518 Retain = &Ctx.Idents.get("CFRetain");
519 Release = &Ctx.Idents.get("CFRelease");
Jordan Rose721567a2012-11-07 17:12:37 +0000520 MakeCollectable = &Ctx.Idents.get("CFMakeCollectable");
521 BT.reset(
522 new APIMisuse("null passed to CFRetain/CFRelease/CFMakeCollectable"));
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000523 }
Mike Stump11289f42009-09-09 15:08:12 +0000524
Jordan Rose721567a2012-11-07 17:12:37 +0000525 // Check if we called CFRetain/CFRelease/CFMakeCollectable.
Mike Stump11289f42009-09-09 15:08:12 +0000526 const IdentifierInfo *FuncII = FD->getIdentifier();
Jordan Rose721567a2012-11-07 17:12:37 +0000527 if (!(FuncII == Retain || FuncII == Release || FuncII == MakeCollectable))
Jordy Rose40c5c242010-07-06 02:34:42 +0000528 return;
Mike Stump11289f42009-09-09 15:08:12 +0000529
Jordy Rose40c5c242010-07-06 02:34:42 +0000530 // FIXME: The rest of this just checks that the argument is non-null.
Anna Zaksef893392013-03-09 03:23:14 +0000531 // It should probably be refactored and combined with NonNullParamChecker.
Jordy Rose40c5c242010-07-06 02:34:42 +0000532
533 // Get the argument's value.
534 const Expr *Arg = CE->getArg(0);
Ted Kremenek632e3b72012-01-06 22:09:28 +0000535 SVal ArgVal = state->getSVal(Arg, C.getLocationContext());
David Blaikie05785d12013-02-20 22:23:23 +0000536 Optional<DefinedSVal> DefArgVal = ArgVal.getAs<DefinedSVal>();
Jordy Rose40c5c242010-07-06 02:34:42 +0000537 if (!DefArgVal)
538 return;
539
540 // Get a NULL value.
Ted Kremenek90af9092010-12-02 07:49:45 +0000541 SValBuilder &svalBuilder = C.getSValBuilder();
David Blaikie2fdacbc2013-02-20 05:52:05 +0000542 DefinedSVal zero =
543 svalBuilder.makeZeroVal(Arg->getType()).castAs<DefinedSVal>();
Jordy Rose40c5c242010-07-06 02:34:42 +0000544
545 // Make an expression asserting that they're equal.
Ted Kremenek90af9092010-12-02 07:49:45 +0000546 DefinedOrUnknownSVal ArgIsNull = svalBuilder.evalEQ(state, zero, *DefArgVal);
Jordy Rose40c5c242010-07-06 02:34:42 +0000547
548 // Are they equal?
Ted Kremenek49b1e382012-01-26 21:29:00 +0000549 ProgramStateRef stateTrue, stateFalse;
Ted Kremenekc5bea1e2010-12-01 22:16:56 +0000550 llvm::tie(stateTrue, stateFalse) = state->assume(ArgIsNull);
Jordy Rose40c5c242010-07-06 02:34:42 +0000551
552 if (stateTrue && !stateFalse) {
Ted Kremenek750b7ac2010-12-20 21:19:09 +0000553 ExplodedNode *N = C.generateSink(stateTrue);
Jordy Rose40c5c242010-07-06 02:34:42 +0000554 if (!N)
555 return;
556
Jordan Rose721567a2012-11-07 17:12:37 +0000557 const char *description;
558 if (FuncII == Retain)
559 description = "Null pointer argument in call to CFRetain";
560 else if (FuncII == Release)
561 description = "Null pointer argument in call to CFRelease";
562 else if (FuncII == MakeCollectable)
563 description = "Null pointer argument in call to CFMakeCollectable";
564 else
565 llvm_unreachable("impossible case");
Ted Kremenekc057f412009-07-14 00:43:42 +0000566
Anna Zaks3a6bdf82011-08-17 23:00:25 +0000567 BugReport *report = new BugReport(*BT, description, N);
Jordy Rose40c5c242010-07-06 02:34:42 +0000568 report->addRange(Arg->getSourceRange());
Jordan Rosea0f7d352012-08-28 00:50:51 +0000569 bugreporter::trackNullOrUndefValue(N, Arg, *report);
Jordan Rosee10d5a72012-11-02 01:53:40 +0000570 C.emitReport(report);
Jordy Rose40c5c242010-07-06 02:34:42 +0000571 return;
Ted Kremenekc057f412009-07-14 00:43:42 +0000572 }
573
Jordy Rose40c5c242010-07-06 02:34:42 +0000574 // From here on, we know the argument is non-null.
Anna Zaksda4c8d62011-10-26 21:06:34 +0000575 C.addTransition(stateFalse);
Ted Kremenekc057f412009-07-14 00:43:42 +0000576}
577
578//===----------------------------------------------------------------------===//
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000579// Check for sending 'retain', 'release', or 'autorelease' directly to a Class.
580//===----------------------------------------------------------------------===//
581
582namespace {
Argyrios Kyrtzidis6a5674f2011-03-01 01:16:21 +0000583class ClassReleaseChecker : public Checker<check::PreObjCMessage> {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000584 mutable Selector releaseS;
585 mutable Selector retainS;
586 mutable Selector autoreleaseS;
587 mutable Selector drainS;
Dylan Noblesmithe2778992012-02-05 02:12:40 +0000588 mutable OwningPtr<BugType> BT;
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000589
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000590public:
Jordan Rose547060b2012-07-02 19:28:04 +0000591 void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000592};
593}
594
Jordan Rose547060b2012-07-02 19:28:04 +0000595void ClassReleaseChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000596 CheckerContext &C) const {
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000597
598 if (!BT) {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000599 BT.reset(new APIMisuse("message incorrectly sent to class instead of class "
600 "instance"));
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000601
602 ASTContext &Ctx = C.getASTContext();
603 releaseS = GetNullarySelector("release", Ctx);
604 retainS = GetNullarySelector("retain", Ctx);
605 autoreleaseS = GetNullarySelector("autorelease", Ctx);
606 drainS = GetNullarySelector("drain", Ctx);
607 }
608
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +0000609 if (msg.isInstanceMessage())
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000610 return;
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +0000611 const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
612 assert(Class);
Douglas Gregor9a129192010-04-21 00:45:42 +0000613
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +0000614 Selector S = msg.getSelector();
Benjamin Kramer7d875c72009-11-20 10:03:00 +0000615 if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000616 return;
617
Anna Zaksda4c8d62011-10-26 21:06:34 +0000618 if (ExplodedNode *N = C.addTransition()) {
Dylan Noblesmith2c1dd272012-02-05 02:13:05 +0000619 SmallString<200> buf;
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000620 llvm::raw_svector_ostream os(buf);
Ted Kremenekf5735152009-11-23 22:22:01 +0000621
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000622 os << "The '" << S.getAsString() << "' message should be sent to instances "
623 "of class '" << Class->getName()
624 << "' and not the class directly";
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000625
Anna Zaks3a6bdf82011-08-17 23:00:25 +0000626 BugReport *report = new BugReport(*BT, os.str(), N);
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +0000627 report->addRange(msg.getSourceRange());
Jordan Rosee10d5a72012-11-02 01:53:40 +0000628 C.emitReport(report);
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000629 }
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000630}
631
632//===----------------------------------------------------------------------===//
Anders Carlssond91d5f12011-03-13 20:35:21 +0000633// Check for passing non-Objective-C types to variadic methods that expect
634// only Objective-C types.
635//===----------------------------------------------------------------------===//
636
637namespace {
638class VariadicMethodTypeChecker : public Checker<check::PreObjCMessage> {
639 mutable Selector arrayWithObjectsS;
640 mutable Selector dictionaryWithObjectsAndKeysS;
641 mutable Selector setWithObjectsS;
Jordy Rosec0230d72012-04-06 19:06:01 +0000642 mutable Selector orderedSetWithObjectsS;
Anders Carlssond91d5f12011-03-13 20:35:21 +0000643 mutable Selector initWithObjectsS;
644 mutable Selector initWithObjectsAndKeysS;
Dylan Noblesmithe2778992012-02-05 02:12:40 +0000645 mutable OwningPtr<BugType> BT;
Anders Carlssond91d5f12011-03-13 20:35:21 +0000646
Jordan Rose547060b2012-07-02 19:28:04 +0000647 bool isVariadicMessage(const ObjCMethodCall &msg) const;
Anders Carlssond91d5f12011-03-13 20:35:21 +0000648
649public:
Jordan Rose547060b2012-07-02 19:28:04 +0000650 void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
Anders Carlssond91d5f12011-03-13 20:35:21 +0000651};
652}
653
654/// isVariadicMessage - Returns whether the given message is a variadic message,
655/// where all arguments must be Objective-C types.
656bool
Jordan Rose547060b2012-07-02 19:28:04 +0000657VariadicMethodTypeChecker::isVariadicMessage(const ObjCMethodCall &msg) const {
658 const ObjCMethodDecl *MD = msg.getDecl();
Ted Kremenekced5fea2011-04-12 21:47:05 +0000659
660 if (!MD || !MD->isVariadic() || isa<ObjCProtocolDecl>(MD->getDeclContext()))
Anders Carlssond91d5f12011-03-13 20:35:21 +0000661 return false;
662
663 Selector S = msg.getSelector();
664
665 if (msg.isInstanceMessage()) {
666 // FIXME: Ideally we'd look at the receiver interface here, but that's not
667 // useful for init, because alloc returns 'id'. In theory, this could lead
668 // to false positives, for example if there existed a class that had an
669 // initWithObjects: implementation that does accept non-Objective-C pointer
670 // types, but the chance of that happening is pretty small compared to the
671 // gains that this analysis gives.
672 const ObjCInterfaceDecl *Class = MD->getClassInterface();
673
Jordan Rose3ba8ae32012-06-11 16:40:37 +0000674 switch (findKnownClass(Class)) {
675 case FC_NSArray:
676 case FC_NSOrderedSet:
677 case FC_NSSet:
678 return S == initWithObjectsS;
679 case FC_NSDictionary:
680 return S == initWithObjectsAndKeysS;
681 default:
682 return false;
683 }
Anders Carlssond91d5f12011-03-13 20:35:21 +0000684 } else {
685 const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
686
Jordan Rose3ba8ae32012-06-11 16:40:37 +0000687 switch (findKnownClass(Class)) {
688 case FC_NSArray:
689 return S == arrayWithObjectsS;
690 case FC_NSOrderedSet:
691 return S == orderedSetWithObjectsS;
692 case FC_NSSet:
693 return S == setWithObjectsS;
694 case FC_NSDictionary:
695 return S == dictionaryWithObjectsAndKeysS;
696 default:
697 return false;
698 }
Anders Carlssond91d5f12011-03-13 20:35:21 +0000699 }
Anders Carlssond91d5f12011-03-13 20:35:21 +0000700}
701
Jordan Rose547060b2012-07-02 19:28:04 +0000702void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
Anders Carlssond91d5f12011-03-13 20:35:21 +0000703 CheckerContext &C) const {
704 if (!BT) {
705 BT.reset(new APIMisuse("Arguments passed to variadic method aren't all "
706 "Objective-C pointer types"));
707
708 ASTContext &Ctx = C.getASTContext();
709 arrayWithObjectsS = GetUnarySelector("arrayWithObjects", Ctx);
710 dictionaryWithObjectsAndKeysS =
711 GetUnarySelector("dictionaryWithObjectsAndKeys", Ctx);
712 setWithObjectsS = GetUnarySelector("setWithObjects", Ctx);
Jordy Rosec0230d72012-04-06 19:06:01 +0000713 orderedSetWithObjectsS = GetUnarySelector("orderedSetWithObjects", Ctx);
Anders Carlssond91d5f12011-03-13 20:35:21 +0000714
715 initWithObjectsS = GetUnarySelector("initWithObjects", Ctx);
716 initWithObjectsAndKeysS = GetUnarySelector("initWithObjectsAndKeys", Ctx);
717 }
718
719 if (!isVariadicMessage(msg))
720 return;
721
722 // We are not interested in the selector arguments since they have
723 // well-defined types, so the compiler will issue a warning for them.
724 unsigned variadicArgsBegin = msg.getSelector().getNumArgs();
725
726 // We're not interested in the last argument since it has to be nil or the
727 // compiler would have issued a warning for it elsewhere.
728 unsigned variadicArgsEnd = msg.getNumArgs() - 1;
729
730 if (variadicArgsEnd <= variadicArgsBegin)
731 return;
732
733 // Verify that all arguments have Objective-C types.
David Blaikie05785d12013-02-20 22:23:23 +0000734 Optional<ExplodedNode*> errorNode;
Ted Kremenek49b1e382012-01-26 21:29:00 +0000735 ProgramStateRef state = C.getState();
Ted Kremenek066b2262011-03-14 19:50:37 +0000736
Anders Carlssond91d5f12011-03-13 20:35:21 +0000737 for (unsigned I = variadicArgsBegin; I != variadicArgsEnd; ++I) {
Jordan Rose547060b2012-07-02 19:28:04 +0000738 QualType ArgTy = msg.getArgExpr(I)->getType();
Anders Carlssond91d5f12011-03-13 20:35:21 +0000739 if (ArgTy->isObjCObjectPointerType())
740 continue;
741
Anders Carlssond1f65f62011-04-19 01:16:46 +0000742 // Block pointers are treaded as Objective-C pointers.
743 if (ArgTy->isBlockPointerType())
744 continue;
745
Ted Kremenek4ceebbf2011-03-16 00:22:51 +0000746 // Ignore pointer constants.
David Blaikie2fdacbc2013-02-20 05:52:05 +0000747 if (msg.getArgSVal(I).getAs<loc::ConcreteInt>())
Ted Kremenek4ceebbf2011-03-16 00:22:51 +0000748 continue;
Ted Kremenek6fa1dae2011-03-17 04:01:35 +0000749
Ted Kremenek70727342011-03-17 04:10:25 +0000750 // Ignore pointer types annotated with 'NSObject' attribute.
751 if (C.getASTContext().isObjCNSObjectType(ArgTy))
752 continue;
753
Ted Kremenek6fa1dae2011-03-17 04:01:35 +0000754 // Ignore CF references, which can be toll-free bridged.
Ted Kremenekc85964e2011-07-16 19:50:32 +0000755 if (coreFoundation::isCFObjectRef(ArgTy))
Ted Kremenek6fa1dae2011-03-17 04:01:35 +0000756 continue;
Ted Kremenek4ceebbf2011-03-16 00:22:51 +0000757
Ted Kremenek066b2262011-03-14 19:50:37 +0000758 // Generate only one error node to use for all bug reports.
Jordan Rose547060b2012-07-02 19:28:04 +0000759 if (!errorNode.hasValue())
Anna Zaksda4c8d62011-10-26 21:06:34 +0000760 errorNode = C.addTransition();
Ted Kremenek066b2262011-03-14 19:50:37 +0000761
762 if (!errorNode.getValue())
Anders Carlssond91d5f12011-03-13 20:35:21 +0000763 continue;
764
Dylan Noblesmith2c1dd272012-02-05 02:13:05 +0000765 SmallString<128> sbuf;
Anders Carlssond91d5f12011-03-13 20:35:21 +0000766 llvm::raw_svector_ostream os(sbuf);
767
Jordan Rose547060b2012-07-02 19:28:04 +0000768 StringRef TypeName = GetReceiverInterfaceName(msg);
769 if (!TypeName.empty())
Anders Carlssond91d5f12011-03-13 20:35:21 +0000770 os << "Argument to '" << TypeName << "' method '";
771 else
772 os << "Argument to method '";
773
774 os << msg.getSelector().getAsString()
Jordan Rose547060b2012-07-02 19:28:04 +0000775 << "' should be an Objective-C pointer type, not '";
776 ArgTy.print(os, C.getLangOpts());
777 os << "'";
Anders Carlssond91d5f12011-03-13 20:35:21 +0000778
Jordan Rose547060b2012-07-02 19:28:04 +0000779 BugReport *R = new BugReport(*BT, os.str(), errorNode.getValue());
Anders Carlssond91d5f12011-03-13 20:35:21 +0000780 R->addRange(msg.getArgSourceRange(I));
Jordan Rosee10d5a72012-11-02 01:53:40 +0000781 C.emitReport(R);
Anders Carlssond91d5f12011-03-13 20:35:21 +0000782 }
783}
784
785//===----------------------------------------------------------------------===//
Jordan Roseefef7602012-06-11 16:40:41 +0000786// Improves the modeling of loops over Cocoa collections.
787//===----------------------------------------------------------------------===//
788
789namespace {
790class ObjCLoopChecker
791 : public Checker<check::PostStmt<ObjCForCollectionStmt> > {
792
793public:
794 void checkPostStmt(const ObjCForCollectionStmt *FCS, CheckerContext &C) const;
795};
796}
797
798static bool isKnownNonNilCollectionType(QualType T) {
799 const ObjCObjectPointerType *PT = T->getAs<ObjCObjectPointerType>();
800 if (!PT)
801 return false;
802
803 const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();
804 if (!ID)
805 return false;
806
807 switch (findKnownClass(ID)) {
808 case FC_NSArray:
809 case FC_NSDictionary:
810 case FC_NSEnumerator:
811 case FC_NSOrderedSet:
812 case FC_NSSet:
813 return true;
814 default:
815 return false;
816 }
817}
818
Jordan Rose9de821e2013-04-26 21:43:01 +0000819/// Assumes that the collection is non-nil.
820///
821/// If the collection is known to be nil, returns NULL to indicate an infeasible
822/// path.
823static ProgramStateRef checkCollectionNonNil(CheckerContext &C,
824 ProgramStateRef State,
825 const ObjCForCollectionStmt *FCS) {
826 if (!State)
827 return NULL;
828
829 SVal CollectionVal = C.getSVal(FCS->getCollection());
830 Optional<DefinedSVal> KnownCollection = CollectionVal.getAs<DefinedSVal>();
831 if (!KnownCollection)
832 return State;
833
834 ProgramStateRef StNonNil, StNil;
835 llvm::tie(StNonNil, StNil) = State->assume(*KnownCollection);
836 if (StNil && !StNonNil) {
837 // The collection is nil. This path is infeasible.
838 return NULL;
839 }
840
841 return StNonNil;
842}
843
844/// Assumes that the collection elements are non-nil.
845///
846/// This only applies if the collection is one of those known not to contain
847/// nil values.
848static ProgramStateRef checkElementNonNil(CheckerContext &C,
849 ProgramStateRef State,
850 const ObjCForCollectionStmt *FCS) {
851 if (!State)
852 return NULL;
853
Jordan Roseefef7602012-06-11 16:40:41 +0000854 // See if the collection is one where we /know/ the elements are non-nil.
Jordan Rose9de821e2013-04-26 21:43:01 +0000855 if (!isKnownNonNilCollectionType(FCS->getCollection()->getType()))
856 return State;
857
858 const LocationContext *LCtx = C.getLocationContext();
Jordan Roseefef7602012-06-11 16:40:41 +0000859 const Stmt *Element = FCS->getElement();
Jordan Rose9de821e2013-04-26 21:43:01 +0000860
861 // FIXME: Copied from ExprEngineObjC.
862 Optional<Loc> ElementLoc;
Jordan Roseefef7602012-06-11 16:40:41 +0000863 if (const DeclStmt *DS = dyn_cast<DeclStmt>(Element)) {
864 const VarDecl *ElemDecl = cast<VarDecl>(DS->getSingleDecl());
865 assert(ElemDecl->getInit() == 0);
Jordan Rose9de821e2013-04-26 21:43:01 +0000866 ElementLoc = State->getLValue(ElemDecl, LCtx);
Jordan Roseefef7602012-06-11 16:40:41 +0000867 } else {
Jordan Rose9de821e2013-04-26 21:43:01 +0000868 ElementLoc = State->getSVal(Element, LCtx).getAs<Loc>();
Jordan Roseefef7602012-06-11 16:40:41 +0000869 }
870
Jordan Rose9de821e2013-04-26 21:43:01 +0000871 if (!ElementLoc)
872 return State;
Jordan Roseefef7602012-06-11 16:40:41 +0000873
874 // Go ahead and assume the value is non-nil.
Jordan Rose9de821e2013-04-26 21:43:01 +0000875 SVal Val = State->getSVal(*ElementLoc);
876 return State->assume(Val.castAs<DefinedOrUnknownSVal>(), true);
877}
878
879void ObjCLoopChecker::checkPostStmt(const ObjCForCollectionStmt *FCS,
880 CheckerContext &C) const {
881 // Check if this is the branch for the end of the loop.
882 SVal CollectionSentinel = C.getSVal(FCS);
883 if (CollectionSentinel.isZeroConstant())
884 return;
885
886 ProgramStateRef State = C.getState();
887 State = checkCollectionNonNil(C, State, FCS);
888 State = checkElementNonNil(C, State, FCS);
889
890 if (!State)
891 C.generateSink();
892 else if (State != C.getState())
893 C.addTransition(State);
Jordan Roseefef7602012-06-11 16:40:41 +0000894}
895
Anna Zaks5a5a1752012-08-22 21:19:56 +0000896namespace {
897/// \class ObjCNonNilReturnValueChecker
Anna Zaks4818bbe2012-08-30 19:40:52 +0000898/// \brief The checker restricts the return values of APIs known to
899/// never (or almost never) return 'nil'.
Anna Zaks5a5a1752012-08-22 21:19:56 +0000900class ObjCNonNilReturnValueChecker
901 : public Checker<check::PostObjCMessage> {
902 mutable bool Initialized;
903 mutable Selector ObjectAtIndex;
904 mutable Selector ObjectAtIndexedSubscript;
Anna Zaks4063fa12013-05-10 18:04:46 +0000905 mutable Selector NullSelector;
Anna Zaks9159e162012-08-22 22:47:58 +0000906
Anna Zaks5a5a1752012-08-22 21:19:56 +0000907public:
Anna Zaks9159e162012-08-22 22:47:58 +0000908 ObjCNonNilReturnValueChecker() : Initialized(false) {}
Anna Zaks5a5a1752012-08-22 21:19:56 +0000909 void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
910};
911}
912
Benjamin Kramer199f8da2012-09-10 11:57:16 +0000913static ProgramStateRef assumeExprIsNonNull(const Expr *NonNullExpr,
914 ProgramStateRef State,
915 CheckerContext &C) {
Anna Zaks4818bbe2012-08-30 19:40:52 +0000916 SVal Val = State->getSVal(NonNullExpr, C.getLocationContext());
David Blaikie05785d12013-02-20 22:23:23 +0000917 if (Optional<DefinedOrUnknownSVal> DV = Val.getAs<DefinedOrUnknownSVal>())
Anna Zaks830c48e2012-08-30 22:55:32 +0000918 return State->assume(*DV, true);
Anna Zaksb504f442012-08-30 22:42:41 +0000919 return State;
Anna Zaks4818bbe2012-08-30 19:40:52 +0000920}
921
Anna Zaks5a5a1752012-08-22 21:19:56 +0000922void ObjCNonNilReturnValueChecker::checkPostObjCMessage(const ObjCMethodCall &M,
923 CheckerContext &C)
Anna Zaks4818bbe2012-08-30 19:40:52 +0000924 const {
Anna Zaks5a5a1752012-08-22 21:19:56 +0000925 ProgramStateRef State = C.getState();
926
927 if (!Initialized) {
928 ASTContext &Ctx = C.getASTContext();
929 ObjectAtIndex = GetUnarySelector("objectAtIndex", Ctx);
930 ObjectAtIndexedSubscript = GetUnarySelector("objectAtIndexedSubscript", Ctx);
Anna Zaks4063fa12013-05-10 18:04:46 +0000931 NullSelector = GetNullarySelector("null", Ctx);
Anna Zaks5a5a1752012-08-22 21:19:56 +0000932 }
933
934 // Check the receiver type.
935 if (const ObjCInterfaceDecl *Interface = M.getReceiverInterface()) {
Anna Zaks4818bbe2012-08-30 19:40:52 +0000936
937 // Assume that object returned from '[self init]' or '[super init]' is not
938 // 'nil' if we are processing an inlined function/method.
939 //
940 // A defensive callee will (and should) check if the object returned by
941 // '[super init]' is 'nil' before doing it's own initialization. However,
942 // since 'nil' is rarely returned in practice, we should not warn when the
943 // caller to the defensive constructor uses the object in contexts where
944 // 'nil' is not accepted.
Anna Zaks49bb6502012-11-06 04:20:54 +0000945 if (!C.inTopFrame() && M.getDecl() &&
Anna Zaks4818bbe2012-08-30 19:40:52 +0000946 M.getDecl()->getMethodFamily() == OMF_init &&
947 M.isReceiverSelfOrSuper()) {
948 State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
949 }
950
Anna Zaks4063fa12013-05-10 18:04:46 +0000951 FoundationClass Cl = findKnownClass(Interface);
952
Anna Zaks4818bbe2012-08-30 19:40:52 +0000953 // Objects returned from
954 // [NSArray|NSOrderedSet]::[ObjectAtIndex|ObjectAtIndexedSubscript]
955 // are never 'nil'.
Anna Zaks5a5a1752012-08-22 21:19:56 +0000956 if (Cl == FC_NSArray || Cl == FC_NSOrderedSet) {
957 Selector Sel = M.getSelector();
958 if (Sel == ObjectAtIndex || Sel == ObjectAtIndexedSubscript) {
959 // Go ahead and assume the value is non-nil.
Anna Zaks4818bbe2012-08-30 19:40:52 +0000960 State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
Anna Zaks5a5a1752012-08-22 21:19:56 +0000961 }
962 }
Anna Zaks4063fa12013-05-10 18:04:46 +0000963
964 // Objects returned from [NSNull null] are not nil.
965 if (Cl == FC_NSNull) {
966 if (M.getSelector() == NullSelector) {
967 // Go ahead and assume the value is non-nil.
968 State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
969 }
970 }
Anna Zaks5a5a1752012-08-22 21:19:56 +0000971 }
Anna Zaks4818bbe2012-08-30 19:40:52 +0000972 C.addTransition(State);
Anna Zaks5a5a1752012-08-22 21:19:56 +0000973}
Jordan Roseefef7602012-06-11 16:40:41 +0000974
975//===----------------------------------------------------------------------===//
Ted Kremenek1f352db2008-07-22 16:21:24 +0000976// Check registration.
Ted Kremenekc057f412009-07-14 00:43:42 +0000977//===----------------------------------------------------------------------===//
Argyrios Kyrtzidis9d4d4f92011-02-16 01:40:52 +0000978
Argyrios Kyrtzidis507ff532011-02-17 21:39:17 +0000979void ento::registerNilArgChecker(CheckerManager &mgr) {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000980 mgr.registerChecker<NilArgChecker>();
Argyrios Kyrtzidis9d4d4f92011-02-16 01:40:52 +0000981}
982
Argyrios Kyrtzidis507ff532011-02-17 21:39:17 +0000983void ento::registerCFNumberCreateChecker(CheckerManager &mgr) {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000984 mgr.registerChecker<CFNumberCreateChecker>();
Argyrios Kyrtzidis9d4d4f92011-02-16 01:40:52 +0000985}
986
Argyrios Kyrtzidis507ff532011-02-17 21:39:17 +0000987void ento::registerCFRetainReleaseChecker(CheckerManager &mgr) {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000988 mgr.registerChecker<CFRetainReleaseChecker>();
Ted Kremenek1f352db2008-07-22 16:21:24 +0000989}
Argyrios Kyrtzidis507ff532011-02-17 21:39:17 +0000990
991void ento::registerClassReleaseChecker(CheckerManager &mgr) {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000992 mgr.registerChecker<ClassReleaseChecker>();
Argyrios Kyrtzidis507ff532011-02-17 21:39:17 +0000993}
Anders Carlssond91d5f12011-03-13 20:35:21 +0000994
995void ento::registerVariadicMethodTypeChecker(CheckerManager &mgr) {
996 mgr.registerChecker<VariadicMethodTypeChecker>();
997}
Jordan Roseefef7602012-06-11 16:40:41 +0000998
999void ento::registerObjCLoopChecker(CheckerManager &mgr) {
1000 mgr.registerChecker<ObjCLoopChecker>();
1001}
Anna Zaks5a5a1752012-08-22 21:19:56 +00001002
1003void ento::registerObjCNonNilReturnValueChecker(CheckerManager &mgr) {
1004 mgr.registerChecker<ObjCNonNilReturnValueChecker>();
1005}