blob: b3f534d1af01dfbea23dc7d2bf1211b84fc8ec99 [file] [log] [blame]
Ted Kremenekb0a2e472008-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 Kremenek7a681942008-03-27 17:17:22 +000016#include "BasicObjCFoundationChecks.h"
17
Ted Kremenekb0a2e472008-03-27 07:25:52 +000018#include "clang/Analysis/PathSensitive/ExplodedGraph.h"
19#include "clang/Analysis/PathSensitive/GRSimpleAPICheck.h"
Ted Kremenek9f20c7c2008-07-22 16:21:24 +000020#include "clang/Analysis/PathSensitive/GRExprEngine.h"
Ted Kremenekabd89ac2008-08-13 04:27:00 +000021#include "clang/Analysis/PathSensitive/GRState.h"
Ted Kremenekf00daf02008-04-03 17:57:38 +000022#include "clang/Analysis/PathSensitive/BugReporter.h"
Ted Kremenekb15eba42008-10-04 05:50:14 +000023#include "clang/Analysis/PathSensitive/MemRegion.h"
Ted Kremenekb0a2e472008-03-27 07:25:52 +000024#include "clang/Analysis/PathDiagnostic.h"
Ted Kremenek9f20c7c2008-07-22 16:21:24 +000025#include "clang/Analysis/LocalCheckers.h"
26
Daniel Dunbar64789f82008-08-11 05:35:13 +000027#include "clang/AST/DeclObjC.h"
Ted Kremenekb0a2e472008-03-27 07:25:52 +000028#include "clang/AST/Expr.h"
Steve Naroff9ed3e772008-05-29 21:12:08 +000029#include "clang/AST/ExprObjC.h"
Ted Kremenekb0a2e472008-03-27 07:25:52 +000030#include "clang/AST/ASTContext.h"
31#include "llvm/Support/Compiler.h"
32
Ted Kremenek639247a2008-03-27 22:05:32 +000033#include <sstream>
Ted Kremenekb0a2e472008-03-27 07:25:52 +000034
35using namespace clang;
Ted Kremenek7a681942008-03-27 17:17:22 +000036
Ted Kremenek639247a2008-03-27 22:05:32 +000037static ObjCInterfaceType* GetReceiverType(ObjCMessageExpr* ME) {
38 Expr* Receiver = ME->getReceiver();
39
40 if (!Receiver)
41 return NULL;
42
Ted Kremenek92c78b62008-04-03 21:44:24 +000043 QualType X = Receiver->getType();
Ted Kremenekbfc6cce2008-04-19 19:12:50 +000044
Ted Kremenekd810bf82008-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 Kremenek639247a2008-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 Kremenek7a681942008-03-27 17:17:22 +000060
Ted Kremenekf00daf02008-04-03 17:57:38 +000061namespace {
Ted Kremenek5fd0e672008-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 Kremenekf00daf02008-04-03 17:57:38 +000069
Ted Kremenek5fd0e672008-09-21 19:01:39 +000070class VISIBILITY_HIDDEN NilArg : public APIMisuse {
Ted Kremenekf00daf02008-04-03 17:57:38 +000071public:
Ted Kremenekf00daf02008-04-03 17:57:38 +000072 virtual ~NilArg() {}
73
74 virtual const char* getName() const {
75 return "nil argument";
Ted Kremenek5fd0e672008-09-21 19:01:39 +000076 }
Ted Kremenekf00daf02008-04-03 17:57:38 +000077
Ted Kremenek0e80dea2008-04-09 21:41:14 +000078 class Report : public BugReport {
79 std::string Msg;
80 const char* s;
81 SourceRange R;
82 public:
Ted Kremenekf00daf02008-04-03 17:57:38 +000083
Ted Kremenekabd89ac2008-08-13 04:27:00 +000084 Report(NilArg& Desc, ExplodedNode<GRState>* N,
Ted Kremeneke3ef1c72008-04-14 17:39:48 +000085 ObjCMessageExpr* ME, unsigned Arg)
86 : BugReport(Desc, N) {
Ted Kremenek0e80dea2008-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 '"
94 << ME->getSelector().getName() << "' cannot be nil.";
95
96 Msg = os.str();
97 s = Msg.c_str();
98 }
99
100 virtual ~Report() {}
101
Ted Kremenek128d65f2008-04-10 16:05:13 +0000102 virtual const char* getDescription() const { return s; }
103
Ted Kremenek5c3407a2008-05-01 22:50:36 +0000104 virtual void getRanges(BugReporter& BR,
105 const SourceRange*& B, const SourceRange*& E) {
Ted Kremenek128d65f2008-04-10 16:05:13 +0000106 B = &R;
107 E = B+1;
108 }
Ted Kremenek0e80dea2008-04-09 21:41:14 +0000109 };
Ted Kremenekf00daf02008-04-03 17:57:38 +0000110};
Ted Kremenek0e80dea2008-04-09 21:41:14 +0000111
Ted Kremenekf00daf02008-04-03 17:57:38 +0000112
113class VISIBILITY_HIDDEN BasicObjCFoundationChecks : public GRSimpleAPICheck {
Ted Kremenek0e80dea2008-04-09 21:41:14 +0000114 NilArg Desc;
Ted Kremenekf00daf02008-04-03 17:57:38 +0000115 ASTContext &Ctx;
Ted Kremenekabd89ac2008-08-13 04:27:00 +0000116 GRStateManager* VMgr;
Ted Kremenekf00daf02008-04-03 17:57:38 +0000117
Ted Kremeneke3ef1c72008-04-14 17:39:48 +0000118 typedef std::vector<BugReport*> ErrorsTy;
Ted Kremenekf00daf02008-04-03 17:57:38 +0000119 ErrorsTy Errors;
120
Ted Kremenekabd89ac2008-08-13 04:27:00 +0000121 RVal GetRVal(const GRState* St, Expr* E) { return VMgr->GetRVal(St, E); }
Ted Kremenekf00daf02008-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 Kremenekabd89ac2008-08-13 04:27:00 +0000132 BasicObjCFoundationChecks(ASTContext& ctx, GRStateManager* vmgr)
Ted Kremenekf00daf02008-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 Kremeneke3ef1c72008-04-14 17:39:48 +0000137 delete *I;
Ted Kremenekf00daf02008-04-03 17:57:38 +0000138 }
139
Ted Kremenekabd89ac2008-08-13 04:27:00 +0000140 virtual bool Audit(ExplodedNode<GRState>* N, GRStateManager&);
Ted Kremenekf00daf02008-04-03 17:57:38 +0000141
Ted Kremenek0e80dea2008-04-09 21:41:14 +0000142 virtual void EmitWarnings(BugReporter& BR);
Ted Kremenekf00daf02008-04-03 17:57:38 +0000143
144private:
145
Ted Kremeneke3ef1c72008-04-14 17:39:48 +0000146 void AddError(BugReport* R) {
147 Errors.push_back(R);
Ted Kremenekf00daf02008-04-03 17:57:38 +0000148 }
149
150 void WarnNilArg(NodeTy* N, ObjCMessageExpr* ME, unsigned Arg) {
Ted Kremeneke3ef1c72008-04-14 17:39:48 +0000151 AddError(new NilArg::Report(Desc, N, ME, Arg));
Ted Kremenekf00daf02008-04-03 17:57:38 +0000152 }
153};
154
155} // end anonymous namespace
156
157
158GRSimpleAPICheck*
159clang::CreateBasicObjCFoundationChecks(ASTContext& Ctx,
Ted Kremenekabd89ac2008-08-13 04:27:00 +0000160 GRStateManager* VMgr) {
Ted Kremenekf00daf02008-04-03 17:57:38 +0000161
162 return new BasicObjCFoundationChecks(Ctx, VMgr);
163}
164
165
166
Ted Kremenekabd89ac2008-08-13 04:27:00 +0000167bool BasicObjCFoundationChecks::Audit(ExplodedNode<GRState>* N,
168 GRStateManager&) {
Ted Kremenekb0a2e472008-03-27 07:25:52 +0000169
170 ObjCMessageExpr* ME =
171 cast<ObjCMessageExpr>(cast<PostStmt>(N->getLocation()).getStmt());
Ted Kremenekb0a2e472008-03-27 07:25:52 +0000172
Ted Kremenek639247a2008-03-27 22:05:32 +0000173 ObjCInterfaceType* ReceiverType = GetReceiverType(ME);
Ted Kremenekb0a2e472008-03-27 07:25:52 +0000174
175 if (!ReceiverType)
Nuno Lopesf44f0932008-05-20 17:33:56 +0000176 return false;
Ted Kremenekb0a2e472008-03-27 07:25:52 +0000177
Ted Kremenek639247a2008-03-27 22:05:32 +0000178 const char* name = ReceiverType->getDecl()->getIdentifier()->getName();
179
180 if (!name)
181 return false;
Ted Kremenekb0a2e472008-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 Lopesf44f0932008-05-20 17:33:56 +0000193 return false;
Ted Kremenekb0a2e472008-03-27 07:25:52 +0000194}
195
Ted Kremenek583c4382008-03-27 21:15:17 +0000196static inline bool isNil(RVal X) {
197 return isa<lval::ConcreteInt>(X);
198}
199
Ted Kremenekb0a2e472008-03-27 07:25:52 +0000200//===----------------------------------------------------------------------===//
201// Error reporting.
202//===----------------------------------------------------------------------===//
203
204
Ted Kremenek0e80dea2008-04-09 21:41:14 +0000205void BasicObjCFoundationChecks::EmitWarnings(BugReporter& BR) {
206
Ted Kremeneke3ef1c72008-04-14 17:39:48 +0000207 for (ErrorsTy::iterator I=Errors.begin(), E=Errors.end(); I!=E; ++I)
Ted Kremenek270ab7d2008-04-18 01:56:37 +0000208 BR.EmitWarning(**I);
Ted Kremenek639247a2008-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
217 if (isNil(GetRVal(N->getState(), E))) {
Ted Kremenekf00daf02008-04-03 17:57:38 +0000218 WarnNilArg(N, ME, Arg);
Ted Kremenek639247a2008-03-27 22:05:32 +0000219 return true;
220 }
221
222 return false;
223}
224
Ted Kremenekb0a2e472008-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
246 std::string name = S.getName();
Ted Kremenekb20dccc2008-03-27 21:23:57 +0000247 assert (!name.empty());
248 const char* cstr = &name[0];
249 unsigned len = name.size();
Ted Kremenek639247a2008-03-27 22:05:32 +0000250
Ted Kremenekb20dccc2008-03-27 21:23:57 +0000251 switch (len) {
252 default:
253 break;
Ted Kremenek44e74042008-03-28 16:09:38 +0000254 case 8:
Ted Kremenek639247a2008-03-27 22:05:32 +0000255 if (!strcmp(cstr, "compare:"))
256 return CheckNilArg(N, 0);
257
258 break;
Ted Kremenek44e74042008-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 Kremenekb0a2e472008-03-27 07:25:52 +0000269
Ted Kremenek639247a2008-03-27 22:05:32 +0000270 case 16:
271 if (!strcmp(cstr, "compare:options:"))
272 return CheckNilArg(N, 0);
Ted Kremenekb20dccc2008-03-27 21:23:57 +0000273
274 break;
Ted Kremenek639247a2008-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 Kremenek44e74042008-03-28 16:09:38 +0000288
Ted Kremenek639247a2008-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 Kremenekb0a2e472008-03-27 07:25:52 +0000300 }
301
302 return false;
303}
Ted Kremenekc1290552008-06-26 23:59:48 +0000304
305//===----------------------------------------------------------------------===//
306// Error reporting.
307//===----------------------------------------------------------------------===//
308
309namespace {
310
Ted Kremenek5fd0e672008-09-21 19:01:39 +0000311class VISIBILITY_HIDDEN BadCFNumberCreate : public APIMisuse{
Ted Kremenekc1290552008-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 Kremenekabd89ac2008-08-13 04:27:00 +0000333 StrBugReport(BugType& D, ExplodedNode<GRState>* N, std::string s)
Ted Kremenekc1290552008-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 Kremenekabd89ac2008-08-13 04:27:00 +0000351 GRStateManager* VMgr;
Ted Kremenekc1290552008-06-26 23:59:48 +0000352
Ted Kremenekabd89ac2008-08-13 04:27:00 +0000353 RVal GetRVal(const GRState* St, Expr* E) { return VMgr->GetRVal(St, E); }
Ted Kremenekc1290552008-06-26 23:59:48 +0000354
355public:
356
Ted Kremenekabd89ac2008-08-13 04:27:00 +0000357 AuditCFNumberCreate(ASTContext& ctx, GRStateManager* vmgr)
Ted Kremenekc1290552008-06-26 23:59:48 +0000358 : Ctx(ctx), II(&Ctx.Idents.get("CFNumberCreate")), VMgr(vmgr) {}
359
360 virtual ~AuditCFNumberCreate() {}
361
Ted Kremenekabd89ac2008-08-13 04:27:00 +0000362 virtual bool Audit(ExplodedNode<GRState>* N, GRStateManager&);
Ted Kremenekc1290552008-06-26 23:59:48 +0000363
364 virtual void EmitWarnings(BugReporter& BR) {
365 Desc.EmitWarnings(BR);
366 }
367
368private:
369
Ted Kremenekb15eba42008-10-04 05:50:14 +0000370 void AddError(TypedRegion* R, Expr* Ex, ExplodedNode<GRState> *N,
Ted Kremenekc1290552008-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 Kremenekabd89ac2008-08-13 04:27:00 +0000468bool AuditCFNumberCreate::Audit(ExplodedNode<GRState>* N,GRStateManager&){
Ted Kremenekc1290552008-06-26 23:59:48 +0000469 CallExpr* CE = cast<CallExpr>(cast<PostStmt>(N->getLocation()).getStmt());
470 Expr* Callee = CE->getCallee();
471 RVal CallV = GetRVal(N->getState(), Callee);
472 lval::FuncVal* FuncV = dyn_cast<lval::FuncVal>(&CallV);
473
474 if (!FuncV || FuncV->getDecl()->getIdentifier() != II || CE->getNumArgs()!=3)
475 return false;
476
477 // Get the value of the "theType" argument.
478 RVal TheTypeVal = GetRVal(N->getState(), CE->getArg(1));
479
480 // FIXME: We really should allow ranges of valid theType values, and
481 // bifurcate the state appropriately.
482 nonlval::ConcreteInt* V = dyn_cast<nonlval::ConcreteInt>(&TheTypeVal);
483
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.
497 RVal TheValueExpr = GetRVal(N->getState(), CE->getArg(2));
498
499 // FIXME: Eventually we should handle arbitrary locations. We can do this
500 // by having an enhanced memory model that does low-level typing.
Ted Kremenekb15eba42008-10-04 05:50:14 +0000501 lval::MemRegionVal* LV = dyn_cast<lval::MemRegionVal>(&TheValueExpr);
Ted Kremenekc1290552008-06-26 23:59:48 +0000502
503 if (!LV)
504 return false;
505
Ted Kremenekb15eba42008-10-04 05:50:14 +0000506 TypedRegion* R = dyn_cast<TypedRegion>(LV->getRegion());
507 if (!R)
508 return false;
509
510
511 QualType T = Ctx.getCanonicalType(R->getType());
Ted Kremenekc1290552008-06-26 23:59:48 +0000512
513 // FIXME: If the pointee isn't an integer type, should we flag a warning?
514 // People can do weird stuff with pointers.
515
516 if (!T->isIntegerType())
517 return false;
518
519 uint64_t SourceSize = Ctx.getTypeSize(T);
520
521 // CHECK: is SourceSize == TargetSize
522
523 if (SourceSize == TargetSize)
524 return false;
525
Ted Kremenekb15eba42008-10-04 05:50:14 +0000526 AddError(R, CE->getArg(2), N, SourceSize, TargetSize, NumberKind);
Ted Kremenekc1290552008-06-26 23:59:48 +0000527
528 // FIXME: We can actually create an abstract "CFNumber" object that has
529 // the bits initialized to the provided values.
530 return SourceSize < TargetSize;
531}
532
Ted Kremenekb15eba42008-10-04 05:50:14 +0000533void AuditCFNumberCreate::AddError(TypedRegion* R, Expr* Ex,
Ted Kremenekabd89ac2008-08-13 04:27:00 +0000534 ExplodedNode<GRState> *N,
Ted Kremenekc1290552008-06-26 23:59:48 +0000535 uint64_t SourceSize, uint64_t TargetSize,
536 uint64_t NumberKind) {
537
538 std::ostringstream os;
539
540 os << (SourceSize == 8 ? "An " : "A ")
541 << SourceSize << " bit integer is used to initialize a CFNumber "
542 "object that represents "
543 << (TargetSize == 8 ? "an " : "a ")
544 << TargetSize << " bit integer. ";
545
546 if (SourceSize < TargetSize)
547 os << (TargetSize - SourceSize)
548 << " bits of the CFNumber value will be garbage." ;
549 else
550 os << (SourceSize - TargetSize)
551 << " bits of the input integer will be lost.";
552
553 StrBugReport* B = new StrBugReport(Desc, N, os.str());
554 B->addRange(Ex->getSourceRange());
555 Desc.AllErrors.push_back(B);
556}
557
558GRSimpleAPICheck*
559clang::CreateAuditCFNumberCreate(ASTContext& Ctx,
Ted Kremenekabd89ac2008-08-13 04:27:00 +0000560 GRStateManager* VMgr) {
Ted Kremenekc1290552008-06-26 23:59:48 +0000561
562 return new AuditCFNumberCreate(Ctx, VMgr);
563}
564
Ted Kremenek9f20c7c2008-07-22 16:21:24 +0000565//===----------------------------------------------------------------------===//
566// Check registration.
567
568void clang::RegisterAppleChecks(GRExprEngine& Eng) {
569 ASTContext& Ctx = Eng.getContext();
Ted Kremenekabd89ac2008-08-13 04:27:00 +0000570 GRStateManager* VMgr = &Eng.getStateManager();
Ted Kremenek9f20c7c2008-07-22 16:21:24 +0000571
572 Eng.AddCheck(CreateBasicObjCFoundationChecks(Ctx, VMgr),
573 Stmt::ObjCMessageExprClass);
574
Ted Kremenekb3538ab2008-09-18 21:25:13 +0000575 Eng.AddCheck(CreateAuditCFNumberCreate(Ctx, VMgr),
576 Stmt::CallExprClass);
577
578 Eng.Register(CreateNSErrorCheck());
Ted Kremenek9f20c7c2008-07-22 16:21:24 +0000579}