blob: 47785aca20f67f31fdac3b73da0e4786bf670df7 [file] [log] [blame]
Ted Kremenek99c6ad32008-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 Kremenek52755612008-03-27 17:17:22 +000016#include "BasicObjCFoundationChecks.h"
17
Ted Kremenek99c6ad32008-03-27 07:25:52 +000018#include "clang/Analysis/PathSensitive/ExplodedGraph.h"
19#include "clang/Analysis/PathSensitive/GRSimpleAPICheck.h"
Ted Kremenek78d46242008-07-22 16:21:24 +000020#include "clang/Analysis/PathSensitive/GRExprEngine.h"
Ted Kremenek4adc81e2008-08-13 04:27:00 +000021#include "clang/Analysis/PathSensitive/GRState.h"
Ted Kremenekf1ae7052008-04-03 17:57:38 +000022#include "clang/Analysis/PathSensitive/BugReporter.h"
Ted Kremenek99c6ad32008-03-27 07:25:52 +000023#include "clang/Analysis/PathDiagnostic.h"
Ted Kremenek78d46242008-07-22 16:21:24 +000024#include "clang/Analysis/LocalCheckers.h"
25
Daniel Dunbarc4a1dea2008-08-11 05:35:13 +000026#include "clang/AST/DeclObjC.h"
Ted Kremenek99c6ad32008-03-27 07:25:52 +000027#include "clang/AST/Expr.h"
Steve Narofff494b572008-05-29 21:12:08 +000028#include "clang/AST/ExprObjC.h"
Ted Kremenek99c6ad32008-03-27 07:25:52 +000029#include "clang/AST/ASTContext.h"
30#include "llvm/Support/Compiler.h"
31
Ted Kremenek4ba62832008-03-27 22:05:32 +000032#include <sstream>
Ted Kremenek99c6ad32008-03-27 07:25:52 +000033
34using namespace clang;
Ted Kremenek52755612008-03-27 17:17:22 +000035
Ted Kremenek4ba62832008-03-27 22:05:32 +000036static ObjCInterfaceType* GetReceiverType(ObjCMessageExpr* ME) {
37 Expr* Receiver = ME->getReceiver();
38
39 if (!Receiver)
40 return NULL;
41
Ted Kremenek7956f752008-04-03 21:44:24 +000042 QualType X = Receiver->getType();
Ted Kremenek6bdafbf2008-04-19 19:12:50 +000043
Ted Kremenekc1ff3cd2008-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 Kremenek4ba62832008-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 Kremenek52755612008-03-27 17:17:22 +000059
Ted Kremenekf1ae7052008-04-03 17:57:38 +000060namespace {
61
Ted Kremenek95cc1ba2008-04-18 20:54:29 +000062class VISIBILITY_HIDDEN NilArg : public BugTypeCacheLocation {
Ted Kremenekf1ae7052008-04-03 17:57:38 +000063public:
Ted Kremenekf1ae7052008-04-03 17:57:38 +000064 virtual ~NilArg() {}
65
66 virtual const char* getName() const {
67 return "nil argument";
68 }
69
Ted Kremenek50a6d0c2008-04-09 21:41:14 +000070 class Report : public BugReport {
71 std::string Msg;
72 const char* s;
73 SourceRange R;
74 public:
Ted Kremenekf1ae7052008-04-03 17:57:38 +000075
Ted Kremenek4adc81e2008-08-13 04:27:00 +000076 Report(NilArg& Desc, ExplodedNode<GRState>* N,
Ted Kremenekd2f642b2008-04-14 17:39:48 +000077 ObjCMessageExpr* ME, unsigned Arg)
78 : BugReport(Desc, N) {
Ted Kremenek50a6d0c2008-04-09 21:41:14 +000079
80 Expr* E = ME->getArg(Arg);
81 R = E->getSourceRange();
82
83 std::ostringstream os;
84
85 os << "Argument to '" << GetReceiverNameType(ME) << "' method '"
86 << ME->getSelector().getName() << "' cannot be nil.";
87
88 Msg = os.str();
89 s = Msg.c_str();
90 }
91
92 virtual ~Report() {}
93
Ted Kremenek4d35dac2008-04-10 16:05:13 +000094 virtual const char* getDescription() const { return s; }
95
Ted Kremenekbb77e9b2008-05-01 22:50:36 +000096 virtual void getRanges(BugReporter& BR,
97 const SourceRange*& B, const SourceRange*& E) {
Ted Kremenek4d35dac2008-04-10 16:05:13 +000098 B = &R;
99 E = B+1;
100 }
Ted Kremenek50a6d0c2008-04-09 21:41:14 +0000101 };
Ted Kremenekf1ae7052008-04-03 17:57:38 +0000102};
Ted Kremenek50a6d0c2008-04-09 21:41:14 +0000103
Ted Kremenekf1ae7052008-04-03 17:57:38 +0000104
105class VISIBILITY_HIDDEN BasicObjCFoundationChecks : public GRSimpleAPICheck {
Ted Kremenek50a6d0c2008-04-09 21:41:14 +0000106 NilArg Desc;
Ted Kremenekf1ae7052008-04-03 17:57:38 +0000107 ASTContext &Ctx;
Ted Kremenek4adc81e2008-08-13 04:27:00 +0000108 GRStateManager* VMgr;
Ted Kremenekf1ae7052008-04-03 17:57:38 +0000109
Ted Kremenekd2f642b2008-04-14 17:39:48 +0000110 typedef std::vector<BugReport*> ErrorsTy;
Ted Kremenekf1ae7052008-04-03 17:57:38 +0000111 ErrorsTy Errors;
112
Ted Kremenek4adc81e2008-08-13 04:27:00 +0000113 RVal GetRVal(const GRState* St, Expr* E) { return VMgr->GetRVal(St, E); }
Ted Kremenekf1ae7052008-04-03 17:57:38 +0000114
115 bool isNSString(ObjCInterfaceType* T, const char* suffix);
116 bool AuditNSString(NodeTy* N, ObjCMessageExpr* ME);
117
118 void Warn(NodeTy* N, Expr* E, const std::string& s);
119 void WarnNilArg(NodeTy* N, Expr* E);
120
121 bool CheckNilArg(NodeTy* N, unsigned Arg);
122
123public:
Ted Kremenek4adc81e2008-08-13 04:27:00 +0000124 BasicObjCFoundationChecks(ASTContext& ctx, GRStateManager* vmgr)
Ted Kremenekf1ae7052008-04-03 17:57:38 +0000125 : Ctx(ctx), VMgr(vmgr) {}
126
127 virtual ~BasicObjCFoundationChecks() {
128 for (ErrorsTy::iterator I = Errors.begin(), E = Errors.end(); I!=E; ++I)
Ted Kremenekd2f642b2008-04-14 17:39:48 +0000129 delete *I;
Ted Kremenekf1ae7052008-04-03 17:57:38 +0000130 }
131
Ted Kremenek4adc81e2008-08-13 04:27:00 +0000132 virtual bool Audit(ExplodedNode<GRState>* N, GRStateManager&);
Ted Kremenekf1ae7052008-04-03 17:57:38 +0000133
Ted Kremenek50a6d0c2008-04-09 21:41:14 +0000134 virtual void EmitWarnings(BugReporter& BR);
Ted Kremenekf1ae7052008-04-03 17:57:38 +0000135
136private:
137
Ted Kremenekd2f642b2008-04-14 17:39:48 +0000138 void AddError(BugReport* R) {
139 Errors.push_back(R);
Ted Kremenekf1ae7052008-04-03 17:57:38 +0000140 }
141
142 void WarnNilArg(NodeTy* N, ObjCMessageExpr* ME, unsigned Arg) {
Ted Kremenekd2f642b2008-04-14 17:39:48 +0000143 AddError(new NilArg::Report(Desc, N, ME, Arg));
Ted Kremenekf1ae7052008-04-03 17:57:38 +0000144 }
145};
146
147} // end anonymous namespace
148
149
150GRSimpleAPICheck*
151clang::CreateBasicObjCFoundationChecks(ASTContext& Ctx,
Ted Kremenek4adc81e2008-08-13 04:27:00 +0000152 GRStateManager* VMgr) {
Ted Kremenekf1ae7052008-04-03 17:57:38 +0000153
154 return new BasicObjCFoundationChecks(Ctx, VMgr);
155}
156
157
158
Ted Kremenek4adc81e2008-08-13 04:27:00 +0000159bool BasicObjCFoundationChecks::Audit(ExplodedNode<GRState>* N,
160 GRStateManager&) {
Ted Kremenek99c6ad32008-03-27 07:25:52 +0000161
162 ObjCMessageExpr* ME =
163 cast<ObjCMessageExpr>(cast<PostStmt>(N->getLocation()).getStmt());
Ted Kremenek99c6ad32008-03-27 07:25:52 +0000164
Ted Kremenek4ba62832008-03-27 22:05:32 +0000165 ObjCInterfaceType* ReceiverType = GetReceiverType(ME);
Ted Kremenek99c6ad32008-03-27 07:25:52 +0000166
167 if (!ReceiverType)
Nuno Lopesf7427942008-05-20 17:33:56 +0000168 return false;
Ted Kremenek99c6ad32008-03-27 07:25:52 +0000169
Ted Kremenek4ba62832008-03-27 22:05:32 +0000170 const char* name = ReceiverType->getDecl()->getIdentifier()->getName();
171
172 if (!name)
173 return false;
Ted Kremenek99c6ad32008-03-27 07:25:52 +0000174
175 if (name[0] != 'N' || name[1] != 'S')
176 return false;
177
178 name += 2;
179
180 // FIXME: Make all of this faster.
181
182 if (isNSString(ReceiverType, name))
183 return AuditNSString(N, ME);
184
Nuno Lopesf7427942008-05-20 17:33:56 +0000185 return false;
Ted Kremenek99c6ad32008-03-27 07:25:52 +0000186}
187
Ted Kremeneke5d5c202008-03-27 21:15:17 +0000188static inline bool isNil(RVal X) {
189 return isa<lval::ConcreteInt>(X);
190}
191
Ted Kremenek99c6ad32008-03-27 07:25:52 +0000192//===----------------------------------------------------------------------===//
193// Error reporting.
194//===----------------------------------------------------------------------===//
195
196
Ted Kremenek50a6d0c2008-04-09 21:41:14 +0000197void BasicObjCFoundationChecks::EmitWarnings(BugReporter& BR) {
198
Ted Kremenekd2f642b2008-04-14 17:39:48 +0000199 for (ErrorsTy::iterator I=Errors.begin(), E=Errors.end(); I!=E; ++I)
Ted Kremenek75840e12008-04-18 01:56:37 +0000200 BR.EmitWarning(**I);
Ted Kremenek4ba62832008-03-27 22:05:32 +0000201}
202
203bool BasicObjCFoundationChecks::CheckNilArg(NodeTy* N, unsigned Arg) {
204 ObjCMessageExpr* ME =
205 cast<ObjCMessageExpr>(cast<PostStmt>(N->getLocation()).getStmt());
206
207 Expr * E = ME->getArg(Arg);
208
209 if (isNil(GetRVal(N->getState(), E))) {
Ted Kremenekf1ae7052008-04-03 17:57:38 +0000210 WarnNilArg(N, ME, Arg);
Ted Kremenek4ba62832008-03-27 22:05:32 +0000211 return true;
212 }
213
214 return false;
215}
216
Ted Kremenek99c6ad32008-03-27 07:25:52 +0000217//===----------------------------------------------------------------------===//
218// NSString checking.
219//===----------------------------------------------------------------------===//
220
221bool BasicObjCFoundationChecks::isNSString(ObjCInterfaceType* T,
222 const char* suffix) {
223
224 return !strcmp("String", suffix) || !strcmp("MutableString", suffix);
225}
226
227bool BasicObjCFoundationChecks::AuditNSString(NodeTy* N,
228 ObjCMessageExpr* ME) {
229
230 Selector S = ME->getSelector();
231
232 if (S.isUnarySelector())
233 return false;
234
235 // FIXME: This is going to be really slow doing these checks with
236 // lexical comparisons.
237
238 std::string name = S.getName();
Ted Kremenek9b3fdea2008-03-27 21:23:57 +0000239 assert (!name.empty());
240 const char* cstr = &name[0];
241 unsigned len = name.size();
Ted Kremenek4ba62832008-03-27 22:05:32 +0000242
Ted Kremenek9b3fdea2008-03-27 21:23:57 +0000243 switch (len) {
244 default:
245 break;
Ted Kremenek8730e132008-03-28 16:09:38 +0000246 case 8:
Ted Kremenek4ba62832008-03-27 22:05:32 +0000247 if (!strcmp(cstr, "compare:"))
248 return CheckNilArg(N, 0);
249
250 break;
Ted Kremenek8730e132008-03-28 16:09:38 +0000251
252 case 15:
253 // FIXME: Checking for initWithFormat: will not work in most cases
254 // yet because [NSString alloc] returns id, not NSString*. We will
255 // need support for tracking expected-type information in the analyzer
256 // to find these errors.
257 if (!strcmp(cstr, "initWithFormat:"))
258 return CheckNilArg(N, 0);
259
260 break;
Ted Kremenek99c6ad32008-03-27 07:25:52 +0000261
Ted Kremenek4ba62832008-03-27 22:05:32 +0000262 case 16:
263 if (!strcmp(cstr, "compare:options:"))
264 return CheckNilArg(N, 0);
Ted Kremenek9b3fdea2008-03-27 21:23:57 +0000265
266 break;
Ted Kremenek4ba62832008-03-27 22:05:32 +0000267
268 case 22:
269 if (!strcmp(cstr, "compare:options:range:"))
270 return CheckNilArg(N, 0);
271
272 break;
273
274 case 23:
275
276 if (!strcmp(cstr, "caseInsensitiveCompare:"))
277 return CheckNilArg(N, 0);
278
279 break;
Ted Kremenek8730e132008-03-28 16:09:38 +0000280
Ted Kremenek4ba62832008-03-27 22:05:32 +0000281 case 29:
282 if (!strcmp(cstr, "compare:options:range:locale:"))
283 return CheckNilArg(N, 0);
284
285 break;
286
287 case 37:
288 if (!strcmp(cstr, "componentsSeparatedByCharactersInSet:"))
289 return CheckNilArg(N, 0);
290
291 break;
Ted Kremenek99c6ad32008-03-27 07:25:52 +0000292 }
293
294 return false;
295}
Ted Kremenek04bc8762008-06-26 23:59:48 +0000296
297//===----------------------------------------------------------------------===//
298// Error reporting.
299//===----------------------------------------------------------------------===//
300
301namespace {
302
303class VISIBILITY_HIDDEN BadCFNumberCreate : public BugTypeCacheLocation {
304public:
305 typedef std::vector<BugReport*> AllErrorsTy;
306 AllErrorsTy AllErrors;
307
308 virtual const char* getName() const {
309 return "Bad use of CFNumberCreate";
310 }
311
312 virtual void EmitWarnings(BugReporter& BR) {
313 // FIXME: Refactor this method.
314 for (AllErrorsTy::iterator I=AllErrors.begin(), E=AllErrors.end(); I!=E;++I)
315 BR.EmitWarning(**I);
316 }
317};
318
319 // FIXME: This entire class should be refactored into the common
320 // BugReporter classes.
321class VISIBILITY_HIDDEN StrBugReport : public RangedBugReport {
322 std::string str;
323 const char* cstr;
324public:
Ted Kremenek4adc81e2008-08-13 04:27:00 +0000325 StrBugReport(BugType& D, ExplodedNode<GRState>* N, std::string s)
Ted Kremenek04bc8762008-06-26 23:59:48 +0000326 : RangedBugReport(D, N), str(s) {
327 cstr = str.c_str();
328 }
329
330 virtual const char* getDescription() const { return cstr; }
331};
332
333
334class VISIBILITY_HIDDEN AuditCFNumberCreate : public GRSimpleAPICheck {
335 // FIXME: Who should own this?
336 BadCFNumberCreate Desc;
337
338 // FIXME: Either this should be refactored into GRSimpleAPICheck, or
339 // it should always be passed with a call to Audit. The latter
340 // approach makes this class more stateless.
341 ASTContext& Ctx;
342 IdentifierInfo* II;
Ted Kremenek4adc81e2008-08-13 04:27:00 +0000343 GRStateManager* VMgr;
Ted Kremenek04bc8762008-06-26 23:59:48 +0000344
Ted Kremenek4adc81e2008-08-13 04:27:00 +0000345 RVal GetRVal(const GRState* St, Expr* E) { return VMgr->GetRVal(St, E); }
Ted Kremenek04bc8762008-06-26 23:59:48 +0000346
347public:
348
Ted Kremenek4adc81e2008-08-13 04:27:00 +0000349 AuditCFNumberCreate(ASTContext& ctx, GRStateManager* vmgr)
Ted Kremenek04bc8762008-06-26 23:59:48 +0000350 : Ctx(ctx), II(&Ctx.Idents.get("CFNumberCreate")), VMgr(vmgr) {}
351
352 virtual ~AuditCFNumberCreate() {}
353
Ted Kremenek4adc81e2008-08-13 04:27:00 +0000354 virtual bool Audit(ExplodedNode<GRState>* N, GRStateManager&);
Ted Kremenek04bc8762008-06-26 23:59:48 +0000355
356 virtual void EmitWarnings(BugReporter& BR) {
357 Desc.EmitWarnings(BR);
358 }
359
360private:
361
Ted Kremenek4adc81e2008-08-13 04:27:00 +0000362 void AddError(VarDecl* V, Expr* Ex, ExplodedNode<GRState> *N,
Ted Kremenek04bc8762008-06-26 23:59:48 +0000363 uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind);
364};
365} // end anonymous namespace
366
367enum CFNumberType {
368 kCFNumberSInt8Type = 1,
369 kCFNumberSInt16Type = 2,
370 kCFNumberSInt32Type = 3,
371 kCFNumberSInt64Type = 4,
372 kCFNumberFloat32Type = 5,
373 kCFNumberFloat64Type = 6,
374 kCFNumberCharType = 7,
375 kCFNumberShortType = 8,
376 kCFNumberIntType = 9,
377 kCFNumberLongType = 10,
378 kCFNumberLongLongType = 11,
379 kCFNumberFloatType = 12,
380 kCFNumberDoubleType = 13,
381 kCFNumberCFIndexType = 14,
382 kCFNumberNSIntegerType = 15,
383 kCFNumberCGFloatType = 16
384};
385
386namespace {
387 template<typename T>
388 class Optional {
389 bool IsKnown;
390 T Val;
391 public:
392 Optional() : IsKnown(false), Val(0) {}
393 Optional(const T& val) : IsKnown(true), Val(val) {}
394
395 bool isKnown() const { return IsKnown; }
396
397 const T& getValue() const {
398 assert (isKnown());
399 return Val;
400 }
401
402 operator const T&() const {
403 return getValue();
404 }
405 };
406}
407
408static Optional<uint64_t> GetCFNumberSize(ASTContext& Ctx, uint64_t i) {
409 static unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 };
410
411 if (i < kCFNumberCharType)
412 return FixedSize[i-1];
413
414 QualType T;
415
416 switch (i) {
417 case kCFNumberCharType: T = Ctx.CharTy; break;
418 case kCFNumberShortType: T = Ctx.ShortTy; break;
419 case kCFNumberIntType: T = Ctx.IntTy; break;
420 case kCFNumberLongType: T = Ctx.LongTy; break;
421 case kCFNumberLongLongType: T = Ctx.LongLongTy; break;
422 case kCFNumberFloatType: T = Ctx.FloatTy; break;
423 case kCFNumberDoubleType: T = Ctx.DoubleTy; break;
424 case kCFNumberCFIndexType:
425 case kCFNumberNSIntegerType:
426 case kCFNumberCGFloatType:
427 // FIXME: We need a way to map from names to Type*.
428 default:
429 return Optional<uint64_t>();
430 }
431
432 return Ctx.getTypeSize(T);
433}
434
435#if 0
436static const char* GetCFNumberTypeStr(uint64_t i) {
437 static const char* Names[] = {
438 "kCFNumberSInt8Type",
439 "kCFNumberSInt16Type",
440 "kCFNumberSInt32Type",
441 "kCFNumberSInt64Type",
442 "kCFNumberFloat32Type",
443 "kCFNumberFloat64Type",
444 "kCFNumberCharType",
445 "kCFNumberShortType",
446 "kCFNumberIntType",
447 "kCFNumberLongType",
448 "kCFNumberLongLongType",
449 "kCFNumberFloatType",
450 "kCFNumberDoubleType",
451 "kCFNumberCFIndexType",
452 "kCFNumberNSIntegerType",
453 "kCFNumberCGFloatType"
454 };
455
456 return i <= kCFNumberCGFloatType ? Names[i-1] : "Invalid CFNumberType";
457}
458#endif
459
Ted Kremenek4adc81e2008-08-13 04:27:00 +0000460bool AuditCFNumberCreate::Audit(ExplodedNode<GRState>* N,GRStateManager&){
Ted Kremenek04bc8762008-06-26 23:59:48 +0000461 CallExpr* CE = cast<CallExpr>(cast<PostStmt>(N->getLocation()).getStmt());
462 Expr* Callee = CE->getCallee();
463 RVal CallV = GetRVal(N->getState(), Callee);
464 lval::FuncVal* FuncV = dyn_cast<lval::FuncVal>(&CallV);
465
466 if (!FuncV || FuncV->getDecl()->getIdentifier() != II || CE->getNumArgs()!=3)
467 return false;
468
469 // Get the value of the "theType" argument.
470 RVal TheTypeVal = GetRVal(N->getState(), CE->getArg(1));
471
472 // FIXME: We really should allow ranges of valid theType values, and
473 // bifurcate the state appropriately.
474 nonlval::ConcreteInt* V = dyn_cast<nonlval::ConcreteInt>(&TheTypeVal);
475
476 if (!V)
477 return false;
478
479 uint64_t NumberKind = V->getValue().getLimitedValue();
480 Optional<uint64_t> TargetSize = GetCFNumberSize(Ctx, NumberKind);
481
482 // FIXME: In some cases we can emit an error.
483 if (!TargetSize.isKnown())
484 return false;
485
486 // Look at the value of the integer being passed by reference. Essentially
487 // we want to catch cases where the value passed in is not equal to the
488 // size of the type being created.
489 RVal TheValueExpr = GetRVal(N->getState(), CE->getArg(2));
490
491 // FIXME: Eventually we should handle arbitrary locations. We can do this
492 // by having an enhanced memory model that does low-level typing.
493 lval::DeclVal* LV = dyn_cast<lval::DeclVal>(&TheValueExpr);
494
495 if (!LV)
496 return false;
497
Chris Lattnerb77792e2008-07-26 22:17:49 +0000498 QualType T = Ctx.getCanonicalType(LV->getDecl()->getType());
Ted Kremenek04bc8762008-06-26 23:59:48 +0000499
500 // FIXME: If the pointee isn't an integer type, should we flag a warning?
501 // People can do weird stuff with pointers.
502
503 if (!T->isIntegerType())
504 return false;
505
506 uint64_t SourceSize = Ctx.getTypeSize(T);
507
508 // CHECK: is SourceSize == TargetSize
509
510 if (SourceSize == TargetSize)
511 return false;
512
513 AddError(LV->getDecl(), CE->getArg(2), N, SourceSize, TargetSize, NumberKind);
514
515 // FIXME: We can actually create an abstract "CFNumber" object that has
516 // the bits initialized to the provided values.
517 return SourceSize < TargetSize;
518}
519
520void AuditCFNumberCreate::AddError(VarDecl* V, Expr* Ex,
Ted Kremenek4adc81e2008-08-13 04:27:00 +0000521 ExplodedNode<GRState> *N,
Ted Kremenek04bc8762008-06-26 23:59:48 +0000522 uint64_t SourceSize, uint64_t TargetSize,
523 uint64_t NumberKind) {
524
525 std::ostringstream os;
526
527 os << (SourceSize == 8 ? "An " : "A ")
528 << SourceSize << " bit integer is used to initialize a CFNumber "
529 "object that represents "
530 << (TargetSize == 8 ? "an " : "a ")
531 << TargetSize << " bit integer. ";
532
533 if (SourceSize < TargetSize)
534 os << (TargetSize - SourceSize)
535 << " bits of the CFNumber value will be garbage." ;
536 else
537 os << (SourceSize - TargetSize)
538 << " bits of the input integer will be lost.";
539
540 StrBugReport* B = new StrBugReport(Desc, N, os.str());
541 B->addRange(Ex->getSourceRange());
542 Desc.AllErrors.push_back(B);
543}
544
545GRSimpleAPICheck*
546clang::CreateAuditCFNumberCreate(ASTContext& Ctx,
Ted Kremenek4adc81e2008-08-13 04:27:00 +0000547 GRStateManager* VMgr) {
Ted Kremenek04bc8762008-06-26 23:59:48 +0000548
549 return new AuditCFNumberCreate(Ctx, VMgr);
550}
551
Ted Kremenek78d46242008-07-22 16:21:24 +0000552//===----------------------------------------------------------------------===//
553// Check registration.
554
555void clang::RegisterAppleChecks(GRExprEngine& Eng) {
556 ASTContext& Ctx = Eng.getContext();
Ted Kremenek4adc81e2008-08-13 04:27:00 +0000557 GRStateManager* VMgr = &Eng.getStateManager();
Ted Kremenek78d46242008-07-22 16:21:24 +0000558
559 Eng.AddCheck(CreateBasicObjCFoundationChecks(Ctx, VMgr),
560 Stmt::ObjCMessageExprClass);
561
Ted Kremenekcfdf9b42008-09-18 21:25:13 +0000562 Eng.AddCheck(CreateAuditCFNumberCreate(Ctx, VMgr),
563 Stmt::CallExprClass);
564
565 Eng.Register(CreateNSErrorCheck());
Ted Kremenek78d46242008-07-22 16:21:24 +0000566}