blob: 521f317d631219c226e9f37ea292081a01e85edf [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 Kremenekb0a2e472008-03-27 07:25:52 +000023#include "clang/Analysis/PathDiagnostic.h"
Ted Kremenek9f20c7c2008-07-22 16:21:24 +000024#include "clang/Analysis/LocalCheckers.h"
25
Daniel Dunbar64789f82008-08-11 05:35:13 +000026#include "clang/AST/DeclObjC.h"
Ted Kremenekb0a2e472008-03-27 07:25:52 +000027#include "clang/AST/Expr.h"
Steve Naroff9ed3e772008-05-29 21:12:08 +000028#include "clang/AST/ExprObjC.h"
Ted Kremenekb0a2e472008-03-27 07:25:52 +000029#include "clang/AST/ASTContext.h"
30#include "llvm/Support/Compiler.h"
31
Ted Kremenek639247a2008-03-27 22:05:32 +000032#include <sstream>
Ted Kremenekb0a2e472008-03-27 07:25:52 +000033
34using namespace clang;
Ted Kremenek7a681942008-03-27 17:17:22 +000035
Ted Kremenek639247a2008-03-27 22:05:32 +000036static ObjCInterfaceType* GetReceiverType(ObjCMessageExpr* ME) {
37 Expr* Receiver = ME->getReceiver();
38
39 if (!Receiver)
40 return NULL;
41
Ted Kremenek92c78b62008-04-03 21:44:24 +000042 QualType X = Receiver->getType();
Ted Kremenekbfc6cce2008-04-19 19:12:50 +000043
Ted Kremenekd810bf82008-04-30 22:48:21 +000044 if (X->isPointerType()) {
45 Type* TP = X.getTypePtr();
46 const PointerType* T = TP->getAsPointerType();
47 return dyn_cast<ObjCInterfaceType>(T->getPointeeType().getTypePtr());
48 }
49
50 // FIXME: Support ObjCQualifiedIdType?
51 return NULL;
Ted Kremenek639247a2008-03-27 22:05:32 +000052}
53
54static const char* GetReceiverNameType(ObjCMessageExpr* ME) {
55 ObjCInterfaceType* ReceiverType = GetReceiverType(ME);
56 return ReceiverType ? ReceiverType->getDecl()->getIdentifier()->getName()
57 : NULL;
58}
Ted Kremenek7a681942008-03-27 17:17:22 +000059
Ted Kremenekf00daf02008-04-03 17:57:38 +000060namespace {
Ted Kremenek5fd0e672008-09-21 19:01:39 +000061
62class VISIBILITY_HIDDEN APIMisuse : public BugTypeCacheLocation {
63public:
64 const char* getCategory() const {
65 return "API Misuse (Apple)";
66 }
67};
Ted Kremenekf00daf02008-04-03 17:57:38 +000068
Ted Kremenek5fd0e672008-09-21 19:01:39 +000069class VISIBILITY_HIDDEN NilArg : public APIMisuse {
Ted Kremenekf00daf02008-04-03 17:57:38 +000070public:
Ted Kremenekf00daf02008-04-03 17:57:38 +000071 virtual ~NilArg() {}
72
73 virtual const char* getName() const {
74 return "nil argument";
Ted Kremenek5fd0e672008-09-21 19:01:39 +000075 }
Ted Kremenekf00daf02008-04-03 17:57:38 +000076
Ted Kremenek0e80dea2008-04-09 21:41:14 +000077 class Report : public BugReport {
78 std::string Msg;
79 const char* s;
80 SourceRange R;
81 public:
Ted Kremenekf00daf02008-04-03 17:57:38 +000082
Ted Kremenekabd89ac2008-08-13 04:27:00 +000083 Report(NilArg& Desc, ExplodedNode<GRState>* N,
Ted Kremeneke3ef1c72008-04-14 17:39:48 +000084 ObjCMessageExpr* ME, unsigned Arg)
85 : BugReport(Desc, N) {
Ted Kremenek0e80dea2008-04-09 21:41:14 +000086
87 Expr* E = ME->getArg(Arg);
88 R = E->getSourceRange();
89
90 std::ostringstream os;
91
92 os << "Argument to '" << GetReceiverNameType(ME) << "' method '"
93 << ME->getSelector().getName() << "' cannot be nil.";
94
95 Msg = os.str();
96 s = Msg.c_str();
97 }
98
99 virtual ~Report() {}
100
Ted Kremenek128d65f2008-04-10 16:05:13 +0000101 virtual const char* getDescription() const { return s; }
102
Ted Kremenek5c3407a2008-05-01 22:50:36 +0000103 virtual void getRanges(BugReporter& BR,
104 const SourceRange*& B, const SourceRange*& E) {
Ted Kremenek128d65f2008-04-10 16:05:13 +0000105 B = &R;
106 E = B+1;
107 }
Ted Kremenek0e80dea2008-04-09 21:41:14 +0000108 };
Ted Kremenekf00daf02008-04-03 17:57:38 +0000109};
Ted Kremenek0e80dea2008-04-09 21:41:14 +0000110
Ted Kremenekf00daf02008-04-03 17:57:38 +0000111
112class VISIBILITY_HIDDEN BasicObjCFoundationChecks : public GRSimpleAPICheck {
Ted Kremenek0e80dea2008-04-09 21:41:14 +0000113 NilArg Desc;
Ted Kremenekf00daf02008-04-03 17:57:38 +0000114 ASTContext &Ctx;
Ted Kremenekabd89ac2008-08-13 04:27:00 +0000115 GRStateManager* VMgr;
Ted Kremenekf00daf02008-04-03 17:57:38 +0000116
Ted Kremeneke3ef1c72008-04-14 17:39:48 +0000117 typedef std::vector<BugReport*> ErrorsTy;
Ted Kremenekf00daf02008-04-03 17:57:38 +0000118 ErrorsTy Errors;
119
Ted Kremenekabd89ac2008-08-13 04:27:00 +0000120 RVal GetRVal(const GRState* St, Expr* E) { return VMgr->GetRVal(St, E); }
Ted Kremenekf00daf02008-04-03 17:57:38 +0000121
122 bool isNSString(ObjCInterfaceType* T, const char* suffix);
123 bool AuditNSString(NodeTy* N, ObjCMessageExpr* ME);
124
125 void Warn(NodeTy* N, Expr* E, const std::string& s);
126 void WarnNilArg(NodeTy* N, Expr* E);
127
128 bool CheckNilArg(NodeTy* N, unsigned Arg);
129
130public:
Ted Kremenekabd89ac2008-08-13 04:27:00 +0000131 BasicObjCFoundationChecks(ASTContext& ctx, GRStateManager* vmgr)
Ted Kremenekf00daf02008-04-03 17:57:38 +0000132 : Ctx(ctx), VMgr(vmgr) {}
133
134 virtual ~BasicObjCFoundationChecks() {
135 for (ErrorsTy::iterator I = Errors.begin(), E = Errors.end(); I!=E; ++I)
Ted Kremeneke3ef1c72008-04-14 17:39:48 +0000136 delete *I;
Ted Kremenekf00daf02008-04-03 17:57:38 +0000137 }
138
Ted Kremenekabd89ac2008-08-13 04:27:00 +0000139 virtual bool Audit(ExplodedNode<GRState>* N, GRStateManager&);
Ted Kremenekf00daf02008-04-03 17:57:38 +0000140
Ted Kremenek0e80dea2008-04-09 21:41:14 +0000141 virtual void EmitWarnings(BugReporter& BR);
Ted Kremenekf00daf02008-04-03 17:57:38 +0000142
143private:
144
Ted Kremeneke3ef1c72008-04-14 17:39:48 +0000145 void AddError(BugReport* R) {
146 Errors.push_back(R);
Ted Kremenekf00daf02008-04-03 17:57:38 +0000147 }
148
149 void WarnNilArg(NodeTy* N, ObjCMessageExpr* ME, unsigned Arg) {
Ted Kremeneke3ef1c72008-04-14 17:39:48 +0000150 AddError(new NilArg::Report(Desc, N, ME, Arg));
Ted Kremenekf00daf02008-04-03 17:57:38 +0000151 }
152};
153
154} // end anonymous namespace
155
156
157GRSimpleAPICheck*
158clang::CreateBasicObjCFoundationChecks(ASTContext& Ctx,
Ted Kremenekabd89ac2008-08-13 04:27:00 +0000159 GRStateManager* VMgr) {
Ted Kremenekf00daf02008-04-03 17:57:38 +0000160
161 return new BasicObjCFoundationChecks(Ctx, VMgr);
162}
163
164
165
Ted Kremenekabd89ac2008-08-13 04:27:00 +0000166bool BasicObjCFoundationChecks::Audit(ExplodedNode<GRState>* N,
167 GRStateManager&) {
Ted Kremenekb0a2e472008-03-27 07:25:52 +0000168
169 ObjCMessageExpr* ME =
170 cast<ObjCMessageExpr>(cast<PostStmt>(N->getLocation()).getStmt());
Ted Kremenekb0a2e472008-03-27 07:25:52 +0000171
Ted Kremenek639247a2008-03-27 22:05:32 +0000172 ObjCInterfaceType* ReceiverType = GetReceiverType(ME);
Ted Kremenekb0a2e472008-03-27 07:25:52 +0000173
174 if (!ReceiverType)
Nuno Lopesf44f0932008-05-20 17:33:56 +0000175 return false;
Ted Kremenekb0a2e472008-03-27 07:25:52 +0000176
Ted Kremenek639247a2008-03-27 22:05:32 +0000177 const char* name = ReceiverType->getDecl()->getIdentifier()->getName();
178
179 if (!name)
180 return false;
Ted Kremenekb0a2e472008-03-27 07:25:52 +0000181
182 if (name[0] != 'N' || name[1] != 'S')
183 return false;
184
185 name += 2;
186
187 // FIXME: Make all of this faster.
188
189 if (isNSString(ReceiverType, name))
190 return AuditNSString(N, ME);
191
Nuno Lopesf44f0932008-05-20 17:33:56 +0000192 return false;
Ted Kremenekb0a2e472008-03-27 07:25:52 +0000193}
194
Ted Kremenek583c4382008-03-27 21:15:17 +0000195static inline bool isNil(RVal X) {
196 return isa<lval::ConcreteInt>(X);
197}
198
Ted Kremenekb0a2e472008-03-27 07:25:52 +0000199//===----------------------------------------------------------------------===//
200// Error reporting.
201//===----------------------------------------------------------------------===//
202
203
Ted Kremenek0e80dea2008-04-09 21:41:14 +0000204void BasicObjCFoundationChecks::EmitWarnings(BugReporter& BR) {
205
Ted Kremeneke3ef1c72008-04-14 17:39:48 +0000206 for (ErrorsTy::iterator I=Errors.begin(), E=Errors.end(); I!=E; ++I)
Ted Kremenek270ab7d2008-04-18 01:56:37 +0000207 BR.EmitWarning(**I);
Ted Kremenek639247a2008-03-27 22:05:32 +0000208}
209
210bool BasicObjCFoundationChecks::CheckNilArg(NodeTy* N, unsigned Arg) {
211 ObjCMessageExpr* ME =
212 cast<ObjCMessageExpr>(cast<PostStmt>(N->getLocation()).getStmt());
213
214 Expr * E = ME->getArg(Arg);
215
216 if (isNil(GetRVal(N->getState(), E))) {
Ted Kremenekf00daf02008-04-03 17:57:38 +0000217 WarnNilArg(N, ME, Arg);
Ted Kremenek639247a2008-03-27 22:05:32 +0000218 return true;
219 }
220
221 return false;
222}
223
Ted Kremenekb0a2e472008-03-27 07:25:52 +0000224//===----------------------------------------------------------------------===//
225// NSString checking.
226//===----------------------------------------------------------------------===//
227
228bool BasicObjCFoundationChecks::isNSString(ObjCInterfaceType* T,
229 const char* suffix) {
230
231 return !strcmp("String", suffix) || !strcmp("MutableString", suffix);
232}
233
234bool BasicObjCFoundationChecks::AuditNSString(NodeTy* N,
235 ObjCMessageExpr* ME) {
236
237 Selector S = ME->getSelector();
238
239 if (S.isUnarySelector())
240 return false;
241
242 // FIXME: This is going to be really slow doing these checks with
243 // lexical comparisons.
244
245 std::string name = S.getName();
Ted Kremenekb20dccc2008-03-27 21:23:57 +0000246 assert (!name.empty());
247 const char* cstr = &name[0];
248 unsigned len = name.size();
Ted Kremenek639247a2008-03-27 22:05:32 +0000249
Ted Kremenekb20dccc2008-03-27 21:23:57 +0000250 switch (len) {
251 default:
252 break;
Ted Kremenek44e74042008-03-28 16:09:38 +0000253 case 8:
Ted Kremenek639247a2008-03-27 22:05:32 +0000254 if (!strcmp(cstr, "compare:"))
255 return CheckNilArg(N, 0);
256
257 break;
Ted Kremenek44e74042008-03-28 16:09:38 +0000258
259 case 15:
260 // FIXME: Checking for initWithFormat: will not work in most cases
261 // yet because [NSString alloc] returns id, not NSString*. We will
262 // need support for tracking expected-type information in the analyzer
263 // to find these errors.
264 if (!strcmp(cstr, "initWithFormat:"))
265 return CheckNilArg(N, 0);
266
267 break;
Ted Kremenekb0a2e472008-03-27 07:25:52 +0000268
Ted Kremenek639247a2008-03-27 22:05:32 +0000269 case 16:
270 if (!strcmp(cstr, "compare:options:"))
271 return CheckNilArg(N, 0);
Ted Kremenekb20dccc2008-03-27 21:23:57 +0000272
273 break;
Ted Kremenek639247a2008-03-27 22:05:32 +0000274
275 case 22:
276 if (!strcmp(cstr, "compare:options:range:"))
277 return CheckNilArg(N, 0);
278
279 break;
280
281 case 23:
282
283 if (!strcmp(cstr, "caseInsensitiveCompare:"))
284 return CheckNilArg(N, 0);
285
286 break;
Ted Kremenek44e74042008-03-28 16:09:38 +0000287
Ted Kremenek639247a2008-03-27 22:05:32 +0000288 case 29:
289 if (!strcmp(cstr, "compare:options:range:locale:"))
290 return CheckNilArg(N, 0);
291
292 break;
293
294 case 37:
295 if (!strcmp(cstr, "componentsSeparatedByCharactersInSet:"))
296 return CheckNilArg(N, 0);
297
298 break;
Ted Kremenekb0a2e472008-03-27 07:25:52 +0000299 }
300
301 return false;
302}
Ted Kremenekc1290552008-06-26 23:59:48 +0000303
304//===----------------------------------------------------------------------===//
305// Error reporting.
306//===----------------------------------------------------------------------===//
307
308namespace {
309
Ted Kremenek5fd0e672008-09-21 19:01:39 +0000310class VISIBILITY_HIDDEN BadCFNumberCreate : public APIMisuse{
Ted Kremenekc1290552008-06-26 23:59:48 +0000311public:
312 typedef std::vector<BugReport*> AllErrorsTy;
313 AllErrorsTy AllErrors;
314
315 virtual const char* getName() const {
316 return "Bad use of CFNumberCreate";
317 }
318
319 virtual void EmitWarnings(BugReporter& BR) {
320 // FIXME: Refactor this method.
321 for (AllErrorsTy::iterator I=AllErrors.begin(), E=AllErrors.end(); I!=E;++I)
322 BR.EmitWarning(**I);
323 }
324};
325
326 // FIXME: This entire class should be refactored into the common
327 // BugReporter classes.
328class VISIBILITY_HIDDEN StrBugReport : public RangedBugReport {
329 std::string str;
330 const char* cstr;
331public:
Ted Kremenekabd89ac2008-08-13 04:27:00 +0000332 StrBugReport(BugType& D, ExplodedNode<GRState>* N, std::string s)
Ted Kremenekc1290552008-06-26 23:59:48 +0000333 : RangedBugReport(D, N), str(s) {
334 cstr = str.c_str();
335 }
336
337 virtual const char* getDescription() const { return cstr; }
338};
339
340
341class VISIBILITY_HIDDEN AuditCFNumberCreate : public GRSimpleAPICheck {
342 // FIXME: Who should own this?
343 BadCFNumberCreate Desc;
344
345 // FIXME: Either this should be refactored into GRSimpleAPICheck, or
346 // it should always be passed with a call to Audit. The latter
347 // approach makes this class more stateless.
348 ASTContext& Ctx;
349 IdentifierInfo* II;
Ted Kremenekabd89ac2008-08-13 04:27:00 +0000350 GRStateManager* VMgr;
Ted Kremenekc1290552008-06-26 23:59:48 +0000351
Ted Kremenekabd89ac2008-08-13 04:27:00 +0000352 RVal GetRVal(const GRState* St, Expr* E) { return VMgr->GetRVal(St, E); }
Ted Kremenekc1290552008-06-26 23:59:48 +0000353
354public:
355
Ted Kremenekabd89ac2008-08-13 04:27:00 +0000356 AuditCFNumberCreate(ASTContext& ctx, GRStateManager* vmgr)
Ted Kremenekc1290552008-06-26 23:59:48 +0000357 : Ctx(ctx), II(&Ctx.Idents.get("CFNumberCreate")), VMgr(vmgr) {}
358
359 virtual ~AuditCFNumberCreate() {}
360
Ted Kremenekabd89ac2008-08-13 04:27:00 +0000361 virtual bool Audit(ExplodedNode<GRState>* N, GRStateManager&);
Ted Kremenekc1290552008-06-26 23:59:48 +0000362
363 virtual void EmitWarnings(BugReporter& BR) {
364 Desc.EmitWarnings(BR);
365 }
366
367private:
368
Ted Kremenekabd89ac2008-08-13 04:27:00 +0000369 void AddError(VarDecl* V, Expr* Ex, ExplodedNode<GRState> *N,
Ted Kremenekc1290552008-06-26 23:59:48 +0000370 uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind);
371};
372} // end anonymous namespace
373
374enum CFNumberType {
375 kCFNumberSInt8Type = 1,
376 kCFNumberSInt16Type = 2,
377 kCFNumberSInt32Type = 3,
378 kCFNumberSInt64Type = 4,
379 kCFNumberFloat32Type = 5,
380 kCFNumberFloat64Type = 6,
381 kCFNumberCharType = 7,
382 kCFNumberShortType = 8,
383 kCFNumberIntType = 9,
384 kCFNumberLongType = 10,
385 kCFNumberLongLongType = 11,
386 kCFNumberFloatType = 12,
387 kCFNumberDoubleType = 13,
388 kCFNumberCFIndexType = 14,
389 kCFNumberNSIntegerType = 15,
390 kCFNumberCGFloatType = 16
391};
392
393namespace {
394 template<typename T>
395 class Optional {
396 bool IsKnown;
397 T Val;
398 public:
399 Optional() : IsKnown(false), Val(0) {}
400 Optional(const T& val) : IsKnown(true), Val(val) {}
401
402 bool isKnown() const { return IsKnown; }
403
404 const T& getValue() const {
405 assert (isKnown());
406 return Val;
407 }
408
409 operator const T&() const {
410 return getValue();
411 }
412 };
413}
414
415static Optional<uint64_t> GetCFNumberSize(ASTContext& Ctx, uint64_t i) {
416 static unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 };
417
418 if (i < kCFNumberCharType)
419 return FixedSize[i-1];
420
421 QualType T;
422
423 switch (i) {
424 case kCFNumberCharType: T = Ctx.CharTy; break;
425 case kCFNumberShortType: T = Ctx.ShortTy; break;
426 case kCFNumberIntType: T = Ctx.IntTy; break;
427 case kCFNumberLongType: T = Ctx.LongTy; break;
428 case kCFNumberLongLongType: T = Ctx.LongLongTy; break;
429 case kCFNumberFloatType: T = Ctx.FloatTy; break;
430 case kCFNumberDoubleType: T = Ctx.DoubleTy; break;
431 case kCFNumberCFIndexType:
432 case kCFNumberNSIntegerType:
433 case kCFNumberCGFloatType:
434 // FIXME: We need a way to map from names to Type*.
435 default:
436 return Optional<uint64_t>();
437 }
438
439 return Ctx.getTypeSize(T);
440}
441
442#if 0
443static const char* GetCFNumberTypeStr(uint64_t i) {
444 static const char* Names[] = {
445 "kCFNumberSInt8Type",
446 "kCFNumberSInt16Type",
447 "kCFNumberSInt32Type",
448 "kCFNumberSInt64Type",
449 "kCFNumberFloat32Type",
450 "kCFNumberFloat64Type",
451 "kCFNumberCharType",
452 "kCFNumberShortType",
453 "kCFNumberIntType",
454 "kCFNumberLongType",
455 "kCFNumberLongLongType",
456 "kCFNumberFloatType",
457 "kCFNumberDoubleType",
458 "kCFNumberCFIndexType",
459 "kCFNumberNSIntegerType",
460 "kCFNumberCGFloatType"
461 };
462
463 return i <= kCFNumberCGFloatType ? Names[i-1] : "Invalid CFNumberType";
464}
465#endif
466
Ted Kremenekabd89ac2008-08-13 04:27:00 +0000467bool AuditCFNumberCreate::Audit(ExplodedNode<GRState>* N,GRStateManager&){
Ted Kremenekc1290552008-06-26 23:59:48 +0000468 CallExpr* CE = cast<CallExpr>(cast<PostStmt>(N->getLocation()).getStmt());
469 Expr* Callee = CE->getCallee();
470 RVal CallV = GetRVal(N->getState(), Callee);
471 lval::FuncVal* FuncV = dyn_cast<lval::FuncVal>(&CallV);
472
473 if (!FuncV || FuncV->getDecl()->getIdentifier() != II || CE->getNumArgs()!=3)
474 return false;
475
476 // Get the value of the "theType" argument.
477 RVal TheTypeVal = GetRVal(N->getState(), CE->getArg(1));
478
479 // FIXME: We really should allow ranges of valid theType values, and
480 // bifurcate the state appropriately.
481 nonlval::ConcreteInt* V = dyn_cast<nonlval::ConcreteInt>(&TheTypeVal);
482
483 if (!V)
484 return false;
485
486 uint64_t NumberKind = V->getValue().getLimitedValue();
487 Optional<uint64_t> TargetSize = GetCFNumberSize(Ctx, NumberKind);
488
489 // FIXME: In some cases we can emit an error.
490 if (!TargetSize.isKnown())
491 return false;
492
493 // Look at the value of the integer being passed by reference. Essentially
494 // we want to catch cases where the value passed in is not equal to the
495 // size of the type being created.
496 RVal TheValueExpr = GetRVal(N->getState(), CE->getArg(2));
497
498 // FIXME: Eventually we should handle arbitrary locations. We can do this
499 // by having an enhanced memory model that does low-level typing.
500 lval::DeclVal* LV = dyn_cast<lval::DeclVal>(&TheValueExpr);
501
502 if (!LV)
503 return false;
504
Chris Lattnerd5a56aa2008-07-26 22:17:49 +0000505 QualType T = Ctx.getCanonicalType(LV->getDecl()->getType());
Ted Kremenekc1290552008-06-26 23:59:48 +0000506
507 // FIXME: If the pointee isn't an integer type, should we flag a warning?
508 // People can do weird stuff with pointers.
509
510 if (!T->isIntegerType())
511 return false;
512
513 uint64_t SourceSize = Ctx.getTypeSize(T);
514
515 // CHECK: is SourceSize == TargetSize
516
517 if (SourceSize == TargetSize)
518 return false;
519
520 AddError(LV->getDecl(), CE->getArg(2), N, SourceSize, TargetSize, NumberKind);
521
522 // FIXME: We can actually create an abstract "CFNumber" object that has
523 // the bits initialized to the provided values.
524 return SourceSize < TargetSize;
525}
526
527void AuditCFNumberCreate::AddError(VarDecl* V, Expr* Ex,
Ted Kremenekabd89ac2008-08-13 04:27:00 +0000528 ExplodedNode<GRState> *N,
Ted Kremenekc1290552008-06-26 23:59:48 +0000529 uint64_t SourceSize, uint64_t TargetSize,
530 uint64_t NumberKind) {
531
532 std::ostringstream os;
533
534 os << (SourceSize == 8 ? "An " : "A ")
535 << SourceSize << " bit integer is used to initialize a CFNumber "
536 "object that represents "
537 << (TargetSize == 8 ? "an " : "a ")
538 << TargetSize << " bit integer. ";
539
540 if (SourceSize < TargetSize)
541 os << (TargetSize - SourceSize)
542 << " bits of the CFNumber value will be garbage." ;
543 else
544 os << (SourceSize - TargetSize)
545 << " bits of the input integer will be lost.";
546
547 StrBugReport* B = new StrBugReport(Desc, N, os.str());
548 B->addRange(Ex->getSourceRange());
549 Desc.AllErrors.push_back(B);
550}
551
552GRSimpleAPICheck*
553clang::CreateAuditCFNumberCreate(ASTContext& Ctx,
Ted Kremenekabd89ac2008-08-13 04:27:00 +0000554 GRStateManager* VMgr) {
Ted Kremenekc1290552008-06-26 23:59:48 +0000555
556 return new AuditCFNumberCreate(Ctx, VMgr);
557}
558
Ted Kremenek9f20c7c2008-07-22 16:21:24 +0000559//===----------------------------------------------------------------------===//
560// Check registration.
561
562void clang::RegisterAppleChecks(GRExprEngine& Eng) {
563 ASTContext& Ctx = Eng.getContext();
Ted Kremenekabd89ac2008-08-13 04:27:00 +0000564 GRStateManager* VMgr = &Eng.getStateManager();
Ted Kremenek9f20c7c2008-07-22 16:21:24 +0000565
566 Eng.AddCheck(CreateBasicObjCFoundationChecks(Ctx, VMgr),
567 Stmt::ObjCMessageExprClass);
568
Ted Kremenekb3538ab2008-09-18 21:25:13 +0000569 Eng.AddCheck(CreateAuditCFNumberCreate(Ctx, VMgr),
570 Stmt::CallExprClass);
571
572 Eng.Register(CreateNSErrorCheck());
Ted Kremenek9f20c7c2008-07-22 16:21:24 +0000573}