blob: be729bee6c0aec73d6396145f1388b1203a97ff4 [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
Ted Kremeneka4d60b62008-03-27 17:17:22 +000016#include "BasicObjCFoundationChecks.h"
17
Ted Kremenekc0414922008-03-27 07:25:52 +000018#include "clang/Analysis/PathSensitive/ExplodedGraph.h"
19#include "clang/Analysis/PathSensitive/GRSimpleAPICheck.h"
Ted Kremenek1f352db2008-07-22 16:21:24 +000020#include "clang/Analysis/PathSensitive/GRExprEngine.h"
Ted Kremenek5ab5a1b2008-08-13 04:27:00 +000021#include "clang/Analysis/PathSensitive/GRState.h"
Ted Kremenekcb2dc8e2008-04-03 17:57:38 +000022#include "clang/Analysis/PathSensitive/BugReporter.h"
Ted Kremenek5ca90a22008-10-04 05:50:14 +000023#include "clang/Analysis/PathSensitive/MemRegion.h"
Ted Kremenekc0414922008-03-27 07:25:52 +000024#include "clang/Analysis/PathDiagnostic.h"
Ted Kremenek1f352db2008-07-22 16:21:24 +000025#include "clang/Analysis/LocalCheckers.h"
26
Daniel Dunbar6e8aa532008-08-11 05:35:13 +000027#include "clang/AST/DeclObjC.h"
Ted Kremenekc0414922008-03-27 07:25:52 +000028#include "clang/AST/Expr.h"
Steve Naroff021ca182008-05-29 21:12:08 +000029#include "clang/AST/ExprObjC.h"
Ted Kremenekc0414922008-03-27 07:25:52 +000030#include "clang/AST/ASTContext.h"
31#include "llvm/Support/Compiler.h"
32
Ted Kremenek276278e2008-03-27 22:05:32 +000033#include <sstream>
Ted Kremenekc0414922008-03-27 07:25:52 +000034
35using namespace clang;
Ted Kremeneka4d60b62008-03-27 17:17:22 +000036
Ted Kremenek276278e2008-03-27 22:05:32 +000037static ObjCInterfaceType* GetReceiverType(ObjCMessageExpr* ME) {
38 Expr* Receiver = ME->getReceiver();
39
40 if (!Receiver)
41 return NULL;
42
Ted Kremenekd1a2efa2008-04-03 21:44:24 +000043 QualType X = Receiver->getType();
Ted Kremenek575f24e2008-04-19 19:12:50 +000044
Ted Kremenekf20e2282008-04-30 22:48:21 +000045 if (X->isPointerType()) {
46 Type* TP = X.getTypePtr();
47 const PointerType* T = TP->getAsPointerType();
48 return dyn_cast<ObjCInterfaceType>(T->getPointeeType().getTypePtr());
49 }
50
51 // FIXME: Support ObjCQualifiedIdType?
52 return NULL;
Ted Kremenek276278e2008-03-27 22:05:32 +000053}
54
55static const char* GetReceiverNameType(ObjCMessageExpr* ME) {
56 ObjCInterfaceType* ReceiverType = GetReceiverType(ME);
57 return ReceiverType ? ReceiverType->getDecl()->getIdentifier()->getName()
58 : NULL;
59}
Ted Kremeneka4d60b62008-03-27 17:17:22 +000060
Ted Kremenekcb2dc8e2008-04-03 17:57:38 +000061namespace {
Ted Kremenek638e2802008-09-21 19:01:39 +000062
63class VISIBILITY_HIDDEN APIMisuse : public BugTypeCacheLocation {
64public:
65 const char* getCategory() const {
66 return "API Misuse (Apple)";
67 }
68};
Ted Kremenekcb2dc8e2008-04-03 17:57:38 +000069
Ted Kremenek638e2802008-09-21 19:01:39 +000070class VISIBILITY_HIDDEN NilArg : public APIMisuse {
Ted Kremenekcb2dc8e2008-04-03 17:57:38 +000071public:
Ted Kremenekcb2dc8e2008-04-03 17:57:38 +000072 virtual ~NilArg() {}
73
74 virtual const char* getName() const {
75 return "nil argument";
Ted Kremenek638e2802008-09-21 19:01:39 +000076 }
Ted Kremenekcb2dc8e2008-04-03 17:57:38 +000077
Ted Kremenek7acc3a32008-04-09 21:41:14 +000078 class Report : public BugReport {
79 std::string Msg;
80 const char* s;
81 SourceRange R;
82 public:
Ted Kremenekcb2dc8e2008-04-03 17:57:38 +000083
Ted Kremenek5ab5a1b2008-08-13 04:27:00 +000084 Report(NilArg& Desc, ExplodedNode<GRState>* N,
Ted Kremenek7e151302008-04-14 17:39:48 +000085 ObjCMessageExpr* ME, unsigned Arg)
86 : BugReport(Desc, N) {
Ted Kremenek7acc3a32008-04-09 21:41:14 +000087
88 Expr* E = ME->getArg(Arg);
89 R = E->getSourceRange();
90
91 std::ostringstream os;
92
93 os << "Argument to '" << GetReceiverNameType(ME) << "' method '"
Chris Lattnere4b95692008-11-24 03:33:13 +000094 << ME->getSelector().getAsString() << "' cannot be nil.";
Ted Kremenek7acc3a32008-04-09 21:41:14 +000095
96 Msg = os.str();
97 s = Msg.c_str();
98 }
99
100 virtual ~Report() {}
101
Ted Kremenek83744dd2008-04-10 16:05:13 +0000102 virtual const char* getDescription() const { return s; }
103
Ted Kremenekfabfb462008-05-01 22:50:36 +0000104 virtual void getRanges(BugReporter& BR,
105 const SourceRange*& B, const SourceRange*& E) {
Ted Kremenek83744dd2008-04-10 16:05:13 +0000106 B = &R;
107 E = B+1;
108 }
Ted Kremenek7acc3a32008-04-09 21:41:14 +0000109 };
Ted Kremenekcb2dc8e2008-04-03 17:57:38 +0000110};
Ted Kremenek7acc3a32008-04-09 21:41:14 +0000111
Ted Kremenekcb2dc8e2008-04-03 17:57:38 +0000112
113class VISIBILITY_HIDDEN BasicObjCFoundationChecks : public GRSimpleAPICheck {
Ted Kremenek7acc3a32008-04-09 21:41:14 +0000114 NilArg Desc;
Ted Kremenekcb2dc8e2008-04-03 17:57:38 +0000115 ASTContext &Ctx;
Ted Kremenek5ab5a1b2008-08-13 04:27:00 +0000116 GRStateManager* VMgr;
Ted Kremenekcb2dc8e2008-04-03 17:57:38 +0000117
Ted Kremenek7e151302008-04-14 17:39:48 +0000118 typedef std::vector<BugReport*> ErrorsTy;
Ted Kremenekcb2dc8e2008-04-03 17:57:38 +0000119 ErrorsTy Errors;
120
Zhongxing Xu27f17422008-10-17 05:57:07 +0000121 SVal GetSVal(const GRState* St, Expr* E) { return VMgr->GetSVal(St, E); }
Ted Kremenekcb2dc8e2008-04-03 17:57:38 +0000122
123 bool isNSString(ObjCInterfaceType* T, const char* suffix);
124 bool AuditNSString(NodeTy* N, ObjCMessageExpr* ME);
125
126 void Warn(NodeTy* N, Expr* E, const std::string& s);
127 void WarnNilArg(NodeTy* N, Expr* E);
128
129 bool CheckNilArg(NodeTy* N, unsigned Arg);
130
131public:
Ted Kremenek5ab5a1b2008-08-13 04:27:00 +0000132 BasicObjCFoundationChecks(ASTContext& ctx, GRStateManager* vmgr)
Ted Kremenekcb2dc8e2008-04-03 17:57:38 +0000133 : Ctx(ctx), VMgr(vmgr) {}
134
135 virtual ~BasicObjCFoundationChecks() {
136 for (ErrorsTy::iterator I = Errors.begin(), E = Errors.end(); I!=E; ++I)
Ted Kremenek7e151302008-04-14 17:39:48 +0000137 delete *I;
Ted Kremenekcb2dc8e2008-04-03 17:57:38 +0000138 }
139
Ted Kremenek5ab5a1b2008-08-13 04:27:00 +0000140 virtual bool Audit(ExplodedNode<GRState>* N, GRStateManager&);
Ted Kremenekcb2dc8e2008-04-03 17:57:38 +0000141
Ted Kremenek7acc3a32008-04-09 21:41:14 +0000142 virtual void EmitWarnings(BugReporter& BR);
Ted Kremenekcb2dc8e2008-04-03 17:57:38 +0000143
144private:
145
Ted Kremenek7e151302008-04-14 17:39:48 +0000146 void AddError(BugReport* R) {
147 Errors.push_back(R);
Ted Kremenekcb2dc8e2008-04-03 17:57:38 +0000148 }
149
150 void WarnNilArg(NodeTy* N, ObjCMessageExpr* ME, unsigned Arg) {
Ted Kremenek7e151302008-04-14 17:39:48 +0000151 AddError(new NilArg::Report(Desc, N, ME, Arg));
Ted Kremenekcb2dc8e2008-04-03 17:57:38 +0000152 }
153};
154
155} // end anonymous namespace
156
157
158GRSimpleAPICheck*
159clang::CreateBasicObjCFoundationChecks(ASTContext& Ctx,
Ted Kremenek5ab5a1b2008-08-13 04:27:00 +0000160 GRStateManager* VMgr) {
Ted Kremenekcb2dc8e2008-04-03 17:57:38 +0000161
162 return new BasicObjCFoundationChecks(Ctx, VMgr);
163}
164
165
166
Ted Kremenek5ab5a1b2008-08-13 04:27:00 +0000167bool BasicObjCFoundationChecks::Audit(ExplodedNode<GRState>* N,
168 GRStateManager&) {
Ted Kremenekc0414922008-03-27 07:25:52 +0000169
170 ObjCMessageExpr* ME =
171 cast<ObjCMessageExpr>(cast<PostStmt>(N->getLocation()).getStmt());
Ted Kremenekc0414922008-03-27 07:25:52 +0000172
Ted Kremenek276278e2008-03-27 22:05:32 +0000173 ObjCInterfaceType* ReceiverType = GetReceiverType(ME);
Ted Kremenekc0414922008-03-27 07:25:52 +0000174
175 if (!ReceiverType)
Nuno Lopes652eaab2008-05-20 17:33:56 +0000176 return false;
Ted Kremenekc0414922008-03-27 07:25:52 +0000177
Ted Kremenek276278e2008-03-27 22:05:32 +0000178 const char* name = ReceiverType->getDecl()->getIdentifier()->getName();
179
180 if (!name)
181 return false;
Ted Kremenekc0414922008-03-27 07:25:52 +0000182
183 if (name[0] != 'N' || name[1] != 'S')
184 return false;
185
186 name += 2;
187
188 // FIXME: Make all of this faster.
189
190 if (isNSString(ReceiverType, name))
191 return AuditNSString(N, ME);
192
Nuno Lopes652eaab2008-05-20 17:33:56 +0000193 return false;
Ted Kremenekc0414922008-03-27 07:25:52 +0000194}
195
Zhongxing Xu27f17422008-10-17 05:57:07 +0000196static inline bool isNil(SVal X) {
197 return isa<loc::ConcreteInt>(X);
Ted Kremenek27156c82008-03-27 21:15:17 +0000198}
199
Ted Kremenekc0414922008-03-27 07:25:52 +0000200//===----------------------------------------------------------------------===//
201// Error reporting.
202//===----------------------------------------------------------------------===//
203
204
Ted Kremenek7acc3a32008-04-09 21:41:14 +0000205void BasicObjCFoundationChecks::EmitWarnings(BugReporter& BR) {
206
Ted Kremenek7e151302008-04-14 17:39:48 +0000207 for (ErrorsTy::iterator I=Errors.begin(), E=Errors.end(); I!=E; ++I)
Ted Kremenekcffe6352008-04-18 01:56:37 +0000208 BR.EmitWarning(**I);
Ted Kremenek276278e2008-03-27 22:05:32 +0000209}
210
211bool BasicObjCFoundationChecks::CheckNilArg(NodeTy* N, unsigned Arg) {
212 ObjCMessageExpr* ME =
213 cast<ObjCMessageExpr>(cast<PostStmt>(N->getLocation()).getStmt());
214
215 Expr * E = ME->getArg(Arg);
216
Zhongxing Xu27f17422008-10-17 05:57:07 +0000217 if (isNil(GetSVal(N->getState(), E))) {
Ted Kremenekcb2dc8e2008-04-03 17:57:38 +0000218 WarnNilArg(N, ME, Arg);
Ted Kremenek276278e2008-03-27 22:05:32 +0000219 return true;
220 }
221
222 return false;
223}
224
Ted Kremenekc0414922008-03-27 07:25:52 +0000225//===----------------------------------------------------------------------===//
226// NSString checking.
227//===----------------------------------------------------------------------===//
228
229bool BasicObjCFoundationChecks::isNSString(ObjCInterfaceType* T,
230 const char* suffix) {
231
232 return !strcmp("String", suffix) || !strcmp("MutableString", suffix);
233}
234
235bool BasicObjCFoundationChecks::AuditNSString(NodeTy* N,
236 ObjCMessageExpr* ME) {
237
238 Selector S = ME->getSelector();
239
240 if (S.isUnarySelector())
241 return false;
242
243 // FIXME: This is going to be really slow doing these checks with
244 // lexical comparisons.
245
Chris Lattnere4b95692008-11-24 03:33:13 +0000246 std::string name = S.getAsString();
Ted Kremenek2e4e7cc2008-03-27 21:23:57 +0000247 assert (!name.empty());
248 const char* cstr = &name[0];
249 unsigned len = name.size();
Ted Kremenek276278e2008-03-27 22:05:32 +0000250
Ted Kremenek2e4e7cc2008-03-27 21:23:57 +0000251 switch (len) {
252 default:
253 break;
Ted Kremenekc7194242008-03-28 16:09:38 +0000254 case 8:
Ted Kremenek276278e2008-03-27 22:05:32 +0000255 if (!strcmp(cstr, "compare:"))
256 return CheckNilArg(N, 0);
257
258 break;
Ted Kremenekc7194242008-03-28 16:09:38 +0000259
260 case 15:
261 // FIXME: Checking for initWithFormat: will not work in most cases
262 // yet because [NSString alloc] returns id, not NSString*. We will
263 // need support for tracking expected-type information in the analyzer
264 // to find these errors.
265 if (!strcmp(cstr, "initWithFormat:"))
266 return CheckNilArg(N, 0);
267
268 break;
Ted Kremenekc0414922008-03-27 07:25:52 +0000269
Ted Kremenek276278e2008-03-27 22:05:32 +0000270 case 16:
271 if (!strcmp(cstr, "compare:options:"))
272 return CheckNilArg(N, 0);
Ted Kremenek2e4e7cc2008-03-27 21:23:57 +0000273
274 break;
Ted Kremenek276278e2008-03-27 22:05:32 +0000275
276 case 22:
277 if (!strcmp(cstr, "compare:options:range:"))
278 return CheckNilArg(N, 0);
279
280 break;
281
282 case 23:
283
284 if (!strcmp(cstr, "caseInsensitiveCompare:"))
285 return CheckNilArg(N, 0);
286
287 break;
Ted Kremenekc7194242008-03-28 16:09:38 +0000288
Ted Kremenek276278e2008-03-27 22:05:32 +0000289 case 29:
290 if (!strcmp(cstr, "compare:options:range:locale:"))
291 return CheckNilArg(N, 0);
292
293 break;
294
295 case 37:
296 if (!strcmp(cstr, "componentsSeparatedByCharactersInSet:"))
297 return CheckNilArg(N, 0);
298
299 break;
Ted Kremenekc0414922008-03-27 07:25:52 +0000300 }
301
302 return false;
303}
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000304
305//===----------------------------------------------------------------------===//
306// Error reporting.
307//===----------------------------------------------------------------------===//
308
309namespace {
310
Ted Kremenek638e2802008-09-21 19:01:39 +0000311class VISIBILITY_HIDDEN BadCFNumberCreate : public APIMisuse{
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000312public:
313 typedef std::vector<BugReport*> AllErrorsTy;
314 AllErrorsTy AllErrors;
315
316 virtual const char* getName() const {
317 return "Bad use of CFNumberCreate";
318 }
319
320 virtual void EmitWarnings(BugReporter& BR) {
321 // FIXME: Refactor this method.
322 for (AllErrorsTy::iterator I=AllErrors.begin(), E=AllErrors.end(); I!=E;++I)
323 BR.EmitWarning(**I);
324 }
325};
326
327 // FIXME: This entire class should be refactored into the common
328 // BugReporter classes.
329class VISIBILITY_HIDDEN StrBugReport : public RangedBugReport {
330 std::string str;
331 const char* cstr;
332public:
Ted Kremenek5ab5a1b2008-08-13 04:27:00 +0000333 StrBugReport(BugType& D, ExplodedNode<GRState>* N, std::string s)
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000334 : RangedBugReport(D, N), str(s) {
335 cstr = str.c_str();
336 }
337
338 virtual const char* getDescription() const { return cstr; }
339};
340
341
342class VISIBILITY_HIDDEN AuditCFNumberCreate : public GRSimpleAPICheck {
343 // FIXME: Who should own this?
344 BadCFNumberCreate Desc;
345
346 // FIXME: Either this should be refactored into GRSimpleAPICheck, or
347 // it should always be passed with a call to Audit. The latter
348 // approach makes this class more stateless.
349 ASTContext& Ctx;
350 IdentifierInfo* II;
Ted Kremenek5ab5a1b2008-08-13 04:27:00 +0000351 GRStateManager* VMgr;
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000352
Zhongxing Xu27f17422008-10-17 05:57:07 +0000353 SVal GetSVal(const GRState* St, Expr* E) { return VMgr->GetSVal(St, E); }
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000354
355public:
356
Ted Kremenek5ab5a1b2008-08-13 04:27:00 +0000357 AuditCFNumberCreate(ASTContext& ctx, GRStateManager* vmgr)
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000358 : Ctx(ctx), II(&Ctx.Idents.get("CFNumberCreate")), VMgr(vmgr) {}
359
360 virtual ~AuditCFNumberCreate() {}
361
Ted Kremenek5ab5a1b2008-08-13 04:27:00 +0000362 virtual bool Audit(ExplodedNode<GRState>* N, GRStateManager&);
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000363
364 virtual void EmitWarnings(BugReporter& BR) {
365 Desc.EmitWarnings(BR);
366 }
367
368private:
369
Ted Kremenek8b103c62008-10-17 20:28:54 +0000370 void AddError(const TypedRegion* R, Expr* Ex, ExplodedNode<GRState> *N,
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000371 uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind);
372};
373} // end anonymous namespace
374
375enum CFNumberType {
376 kCFNumberSInt8Type = 1,
377 kCFNumberSInt16Type = 2,
378 kCFNumberSInt32Type = 3,
379 kCFNumberSInt64Type = 4,
380 kCFNumberFloat32Type = 5,
381 kCFNumberFloat64Type = 6,
382 kCFNumberCharType = 7,
383 kCFNumberShortType = 8,
384 kCFNumberIntType = 9,
385 kCFNumberLongType = 10,
386 kCFNumberLongLongType = 11,
387 kCFNumberFloatType = 12,
388 kCFNumberDoubleType = 13,
389 kCFNumberCFIndexType = 14,
390 kCFNumberNSIntegerType = 15,
391 kCFNumberCGFloatType = 16
392};
393
394namespace {
395 template<typename T>
396 class Optional {
397 bool IsKnown;
398 T Val;
399 public:
400 Optional() : IsKnown(false), Val(0) {}
401 Optional(const T& val) : IsKnown(true), Val(val) {}
402
403 bool isKnown() const { return IsKnown; }
404
405 const T& getValue() const {
406 assert (isKnown());
407 return Val;
408 }
409
410 operator const T&() const {
411 return getValue();
412 }
413 };
414}
415
416static Optional<uint64_t> GetCFNumberSize(ASTContext& Ctx, uint64_t i) {
417 static unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 };
418
419 if (i < kCFNumberCharType)
420 return FixedSize[i-1];
421
422 QualType T;
423
424 switch (i) {
425 case kCFNumberCharType: T = Ctx.CharTy; break;
426 case kCFNumberShortType: T = Ctx.ShortTy; break;
427 case kCFNumberIntType: T = Ctx.IntTy; break;
428 case kCFNumberLongType: T = Ctx.LongTy; break;
429 case kCFNumberLongLongType: T = Ctx.LongLongTy; break;
430 case kCFNumberFloatType: T = Ctx.FloatTy; break;
431 case kCFNumberDoubleType: T = Ctx.DoubleTy; break;
432 case kCFNumberCFIndexType:
433 case kCFNumberNSIntegerType:
434 case kCFNumberCGFloatType:
435 // FIXME: We need a way to map from names to Type*.
436 default:
437 return Optional<uint64_t>();
438 }
439
440 return Ctx.getTypeSize(T);
441}
442
443#if 0
444static const char* GetCFNumberTypeStr(uint64_t i) {
445 static const char* Names[] = {
446 "kCFNumberSInt8Type",
447 "kCFNumberSInt16Type",
448 "kCFNumberSInt32Type",
449 "kCFNumberSInt64Type",
450 "kCFNumberFloat32Type",
451 "kCFNumberFloat64Type",
452 "kCFNumberCharType",
453 "kCFNumberShortType",
454 "kCFNumberIntType",
455 "kCFNumberLongType",
456 "kCFNumberLongLongType",
457 "kCFNumberFloatType",
458 "kCFNumberDoubleType",
459 "kCFNumberCFIndexType",
460 "kCFNumberNSIntegerType",
461 "kCFNumberCGFloatType"
462 };
463
464 return i <= kCFNumberCGFloatType ? Names[i-1] : "Invalid CFNumberType";
465}
466#endif
467
Ted Kremenek5ab5a1b2008-08-13 04:27:00 +0000468bool AuditCFNumberCreate::Audit(ExplodedNode<GRState>* N,GRStateManager&){
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000469 CallExpr* CE = cast<CallExpr>(cast<PostStmt>(N->getLocation()).getStmt());
470 Expr* Callee = CE->getCallee();
Zhongxing Xu27f17422008-10-17 05:57:07 +0000471 SVal CallV = GetSVal(N->getState(), Callee);
472 loc::FuncVal* FuncV = dyn_cast<loc::FuncVal>(&CallV);
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000473
474 if (!FuncV || FuncV->getDecl()->getIdentifier() != II || CE->getNumArgs()!=3)
475 return false;
476
477 // Get the value of the "theType" argument.
Zhongxing Xu27f17422008-10-17 05:57:07 +0000478 SVal TheTypeVal = GetSVal(N->getState(), CE->getArg(1));
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000479
480 // FIXME: We really should allow ranges of valid theType values, and
481 // bifurcate the state appropriately.
Zhongxing Xu27f17422008-10-17 05:57:07 +0000482 nonloc::ConcreteInt* V = dyn_cast<nonloc::ConcreteInt>(&TheTypeVal);
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000483
484 if (!V)
485 return false;
486
487 uint64_t NumberKind = V->getValue().getLimitedValue();
488 Optional<uint64_t> TargetSize = GetCFNumberSize(Ctx, NumberKind);
489
490 // FIXME: In some cases we can emit an error.
491 if (!TargetSize.isKnown())
492 return false;
493
494 // Look at the value of the integer being passed by reference. Essentially
495 // we want to catch cases where the value passed in is not equal to the
496 // size of the type being created.
Zhongxing Xu27f17422008-10-17 05:57:07 +0000497 SVal TheValueExpr = GetSVal(N->getState(), CE->getArg(2));
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000498
499 // FIXME: Eventually we should handle arbitrary locations. We can do this
500 // by having an enhanced memory model that does low-level typing.
Zhongxing Xu27f17422008-10-17 05:57:07 +0000501 loc::MemRegionVal* LV = dyn_cast<loc::MemRegionVal>(&TheValueExpr);
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000502
503 if (!LV)
504 return false;
505
Ted Kremenek8b103c62008-10-17 20:28:54 +0000506 const TypedRegion* R = dyn_cast<TypedRegion>(LV->getRegion());
Ted Kremenekb5670fd2008-12-13 21:49:13 +0000507 if (!R) return false;
Ted Kremenek5ca90a22008-10-04 05:50:14 +0000508
Ted Kremenekb5670fd2008-12-13 21:49:13 +0000509 while (const AnonTypedRegion* ATR = dyn_cast<AnonTypedRegion>(R)) {
510 R = dyn_cast<TypedRegion>(ATR->getSuperRegion());
511 if (!R) return false;
512 }
Ted Kremenek5ca90a22008-10-04 05:50:14 +0000513
Ted Kremenekb5670fd2008-12-13 21:49:13 +0000514 QualType T = Ctx.getCanonicalType(R->getRValueType(Ctx));
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000515
516 // FIXME: If the pointee isn't an integer type, should we flag a warning?
517 // People can do weird stuff with pointers.
518
519 if (!T->isIntegerType())
520 return false;
521
522 uint64_t SourceSize = Ctx.getTypeSize(T);
523
524 // CHECK: is SourceSize == TargetSize
525
526 if (SourceSize == TargetSize)
527 return false;
528
Ted Kremenek5ca90a22008-10-04 05:50:14 +0000529 AddError(R, CE->getArg(2), N, SourceSize, TargetSize, NumberKind);
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000530
531 // FIXME: We can actually create an abstract "CFNumber" object that has
532 // the bits initialized to the provided values.
533 return SourceSize < TargetSize;
534}
535
Ted Kremenek8b103c62008-10-17 20:28:54 +0000536void AuditCFNumberCreate::AddError(const TypedRegion* R, Expr* Ex,
Ted Kremenek5ab5a1b2008-08-13 04:27:00 +0000537 ExplodedNode<GRState> *N,
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000538 uint64_t SourceSize, uint64_t TargetSize,
539 uint64_t NumberKind) {
540
541 std::ostringstream os;
542
543 os << (SourceSize == 8 ? "An " : "A ")
544 << SourceSize << " bit integer is used to initialize a CFNumber "
545 "object that represents "
546 << (TargetSize == 8 ? "an " : "a ")
547 << TargetSize << " bit integer. ";
548
549 if (SourceSize < TargetSize)
550 os << (TargetSize - SourceSize)
551 << " bits of the CFNumber value will be garbage." ;
552 else
553 os << (SourceSize - TargetSize)
554 << " bits of the input integer will be lost.";
555
556 StrBugReport* B = new StrBugReport(Desc, N, os.str());
557 B->addRange(Ex->getSourceRange());
558 Desc.AllErrors.push_back(B);
559}
560
561GRSimpleAPICheck*
562clang::CreateAuditCFNumberCreate(ASTContext& Ctx,
Ted Kremenek5ab5a1b2008-08-13 04:27:00 +0000563 GRStateManager* VMgr) {
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000564
565 return new AuditCFNumberCreate(Ctx, VMgr);
566}
567
Ted Kremenek1f352db2008-07-22 16:21:24 +0000568//===----------------------------------------------------------------------===//
569// Check registration.
570
571void clang::RegisterAppleChecks(GRExprEngine& Eng) {
572 ASTContext& Ctx = Eng.getContext();
Ted Kremenek5ab5a1b2008-08-13 04:27:00 +0000573 GRStateManager* VMgr = &Eng.getStateManager();
Ted Kremenek1f352db2008-07-22 16:21:24 +0000574
575 Eng.AddCheck(CreateBasicObjCFoundationChecks(Ctx, VMgr),
576 Stmt::ObjCMessageExprClass);
577
Ted Kremenekf0673e42008-09-18 21:25:13 +0000578 Eng.AddCheck(CreateAuditCFNumberCreate(Ctx, VMgr),
579 Stmt::CallExprClass);
580
581 Eng.Register(CreateNSErrorCheck());
Ted Kremenek1f352db2008-07-22 16:21:24 +0000582}