blob: 033dc02cd7ffe9ebf6e2e93a42b449927a86e50b [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 Kremenek9e240492008-10-04 05:50:14 +000023#include "clang/Analysis/PathSensitive/MemRegion.h"
Ted Kremenek99c6ad32008-03-27 07:25:52 +000024#include "clang/Analysis/PathDiagnostic.h"
Ted Kremenek78d46242008-07-22 16:21:24 +000025#include "clang/Analysis/LocalCheckers.h"
26
Daniel Dunbarc4a1dea2008-08-11 05:35:13 +000027#include "clang/AST/DeclObjC.h"
Ted Kremenek99c6ad32008-03-27 07:25:52 +000028#include "clang/AST/Expr.h"
Steve Narofff494b572008-05-29 21:12:08 +000029#include "clang/AST/ExprObjC.h"
Ted Kremenek99c6ad32008-03-27 07:25:52 +000030#include "clang/AST/ASTContext.h"
31#include "llvm/Support/Compiler.h"
32
Ted Kremenek4ba62832008-03-27 22:05:32 +000033#include <sstream>
Ted Kremenek99c6ad32008-03-27 07:25:52 +000034
35using namespace clang;
Ted Kremenek52755612008-03-27 17:17:22 +000036
Ted Kremenek4ba62832008-03-27 22:05:32 +000037static ObjCInterfaceType* GetReceiverType(ObjCMessageExpr* ME) {
38 Expr* Receiver = ME->getReceiver();
39
40 if (!Receiver)
41 return NULL;
42
Ted Kremenek7956f752008-04-03 21:44:24 +000043 QualType X = Receiver->getType();
Ted Kremenek6bdafbf2008-04-19 19:12:50 +000044
Ted Kremenekc1ff3cd2008-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 Kremenek4ba62832008-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 Kremenek52755612008-03-27 17:17:22 +000060
Ted Kremenekf1ae7052008-04-03 17:57:38 +000061namespace {
Ted Kremenekb344f912008-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 Kremenekf1ae7052008-04-03 17:57:38 +000069
Ted Kremenekb344f912008-09-21 19:01:39 +000070class VISIBILITY_HIDDEN NilArg : public APIMisuse {
Ted Kremenekf1ae7052008-04-03 17:57:38 +000071public:
Ted Kremenekf1ae7052008-04-03 17:57:38 +000072 virtual ~NilArg() {}
73
74 virtual const char* getName() const {
75 return "nil argument";
Ted Kremenekb344f912008-09-21 19:01:39 +000076 }
Ted Kremenekf1ae7052008-04-03 17:57:38 +000077
Ted Kremenek50a6d0c2008-04-09 21:41:14 +000078 class Report : public BugReport {
79 std::string Msg;
80 const char* s;
81 SourceRange R;
82 public:
Ted Kremenekf1ae7052008-04-03 17:57:38 +000083
Ted Kremenek4adc81e2008-08-13 04:27:00 +000084 Report(NilArg& Desc, ExplodedNode<GRState>* N,
Ted Kremenekd2f642b2008-04-14 17:39:48 +000085 ObjCMessageExpr* ME, unsigned Arg)
86 : BugReport(Desc, N) {
Ted Kremenek50a6d0c2008-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 Kremenek4d35dac2008-04-10 16:05:13 +0000102 virtual const char* getDescription() const { return s; }
103
Ted Kremenekbb77e9b2008-05-01 22:50:36 +0000104 virtual void getRanges(BugReporter& BR,
105 const SourceRange*& B, const SourceRange*& E) {
Ted Kremenek4d35dac2008-04-10 16:05:13 +0000106 B = &R;
107 E = B+1;
108 }
Ted Kremenek50a6d0c2008-04-09 21:41:14 +0000109 };
Ted Kremenekf1ae7052008-04-03 17:57:38 +0000110};
Ted Kremenek50a6d0c2008-04-09 21:41:14 +0000111
Ted Kremenekf1ae7052008-04-03 17:57:38 +0000112
113class VISIBILITY_HIDDEN BasicObjCFoundationChecks : public GRSimpleAPICheck {
Ted Kremenek50a6d0c2008-04-09 21:41:14 +0000114 NilArg Desc;
Ted Kremenekf1ae7052008-04-03 17:57:38 +0000115 ASTContext &Ctx;
Ted Kremenek4adc81e2008-08-13 04:27:00 +0000116 GRStateManager* VMgr;
Ted Kremenekf1ae7052008-04-03 17:57:38 +0000117
Ted Kremenekd2f642b2008-04-14 17:39:48 +0000118 typedef std::vector<BugReport*> ErrorsTy;
Ted Kremenekf1ae7052008-04-03 17:57:38 +0000119 ErrorsTy Errors;
120
Zhongxing Xu1c96b242008-10-17 05:57:07 +0000121 SVal GetSVal(const GRState* St, Expr* E) { return VMgr->GetSVal(St, E); }
Ted Kremenekf1ae7052008-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 Kremenek4adc81e2008-08-13 04:27:00 +0000132 BasicObjCFoundationChecks(ASTContext& ctx, GRStateManager* vmgr)
Ted Kremenekf1ae7052008-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 Kremenekd2f642b2008-04-14 17:39:48 +0000137 delete *I;
Ted Kremenekf1ae7052008-04-03 17:57:38 +0000138 }
139
Ted Kremenek4adc81e2008-08-13 04:27:00 +0000140 virtual bool Audit(ExplodedNode<GRState>* N, GRStateManager&);
Ted Kremenekf1ae7052008-04-03 17:57:38 +0000141
Ted Kremenek50a6d0c2008-04-09 21:41:14 +0000142 virtual void EmitWarnings(BugReporter& BR);
Ted Kremenekf1ae7052008-04-03 17:57:38 +0000143
144private:
145
Ted Kremenekd2f642b2008-04-14 17:39:48 +0000146 void AddError(BugReport* R) {
147 Errors.push_back(R);
Ted Kremenekf1ae7052008-04-03 17:57:38 +0000148 }
149
150 void WarnNilArg(NodeTy* N, ObjCMessageExpr* ME, unsigned Arg) {
Ted Kremenekd2f642b2008-04-14 17:39:48 +0000151 AddError(new NilArg::Report(Desc, N, ME, Arg));
Ted Kremenekf1ae7052008-04-03 17:57:38 +0000152 }
153};
154
155} // end anonymous namespace
156
157
158GRSimpleAPICheck*
159clang::CreateBasicObjCFoundationChecks(ASTContext& Ctx,
Ted Kremenek4adc81e2008-08-13 04:27:00 +0000160 GRStateManager* VMgr) {
Ted Kremenekf1ae7052008-04-03 17:57:38 +0000161
162 return new BasicObjCFoundationChecks(Ctx, VMgr);
163}
164
165
166
Ted Kremenek4adc81e2008-08-13 04:27:00 +0000167bool BasicObjCFoundationChecks::Audit(ExplodedNode<GRState>* N,
168 GRStateManager&) {
Ted Kremenek99c6ad32008-03-27 07:25:52 +0000169
170 ObjCMessageExpr* ME =
171 cast<ObjCMessageExpr>(cast<PostStmt>(N->getLocation()).getStmt());
Ted Kremenek99c6ad32008-03-27 07:25:52 +0000172
Ted Kremenek4ba62832008-03-27 22:05:32 +0000173 ObjCInterfaceType* ReceiverType = GetReceiverType(ME);
Ted Kremenek99c6ad32008-03-27 07:25:52 +0000174
175 if (!ReceiverType)
Nuno Lopesf7427942008-05-20 17:33:56 +0000176 return false;
Ted Kremenek99c6ad32008-03-27 07:25:52 +0000177
Ted Kremenek4ba62832008-03-27 22:05:32 +0000178 const char* name = ReceiverType->getDecl()->getIdentifier()->getName();
179
180 if (!name)
181 return false;
Ted Kremenek99c6ad32008-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 Lopesf7427942008-05-20 17:33:56 +0000193 return false;
Ted Kremenek99c6ad32008-03-27 07:25:52 +0000194}
195
Zhongxing Xu1c96b242008-10-17 05:57:07 +0000196static inline bool isNil(SVal X) {
197 return isa<loc::ConcreteInt>(X);
Ted Kremeneke5d5c202008-03-27 21:15:17 +0000198}
199
Ted Kremenek99c6ad32008-03-27 07:25:52 +0000200//===----------------------------------------------------------------------===//
201// Error reporting.
202//===----------------------------------------------------------------------===//
203
204
Ted Kremenek50a6d0c2008-04-09 21:41:14 +0000205void BasicObjCFoundationChecks::EmitWarnings(BugReporter& BR) {
206
Ted Kremenekd2f642b2008-04-14 17:39:48 +0000207 for (ErrorsTy::iterator I=Errors.begin(), E=Errors.end(); I!=E; ++I)
Ted Kremenek75840e12008-04-18 01:56:37 +0000208 BR.EmitWarning(**I);
Ted Kremenek4ba62832008-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 Xu1c96b242008-10-17 05:57:07 +0000217 if (isNil(GetSVal(N->getState(), E))) {
Ted Kremenekf1ae7052008-04-03 17:57:38 +0000218 WarnNilArg(N, ME, Arg);
Ted Kremenek4ba62832008-03-27 22:05:32 +0000219 return true;
220 }
221
222 return false;
223}
224
Ted Kremenek99c6ad32008-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 Kremenek9b3fdea2008-03-27 21:23:57 +0000247 assert (!name.empty());
248 const char* cstr = &name[0];
249 unsigned len = name.size();
Ted Kremenek4ba62832008-03-27 22:05:32 +0000250
Ted Kremenek9b3fdea2008-03-27 21:23:57 +0000251 switch (len) {
252 default:
253 break;
Ted Kremenek8730e132008-03-28 16:09:38 +0000254 case 8:
Ted Kremenek4ba62832008-03-27 22:05:32 +0000255 if (!strcmp(cstr, "compare:"))
256 return CheckNilArg(N, 0);
257
258 break;
Ted Kremenek8730e132008-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 Kremenek99c6ad32008-03-27 07:25:52 +0000269
Ted Kremenek4ba62832008-03-27 22:05:32 +0000270 case 16:
271 if (!strcmp(cstr, "compare:options:"))
272 return CheckNilArg(N, 0);
Ted Kremenek9b3fdea2008-03-27 21:23:57 +0000273
274 break;
Ted Kremenek4ba62832008-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 Kremenek8730e132008-03-28 16:09:38 +0000288
Ted Kremenek4ba62832008-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 Kremenek99c6ad32008-03-27 07:25:52 +0000300 }
301
302 return false;
303}
Ted Kremenek04bc8762008-06-26 23:59:48 +0000304
305//===----------------------------------------------------------------------===//
306// Error reporting.
307//===----------------------------------------------------------------------===//
308
309namespace {
310
Ted Kremenekb344f912008-09-21 19:01:39 +0000311class VISIBILITY_HIDDEN BadCFNumberCreate : public APIMisuse{
Ted Kremenek04bc8762008-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 Kremenek4adc81e2008-08-13 04:27:00 +0000333 StrBugReport(BugType& D, ExplodedNode<GRState>* N, std::string s)
Ted Kremenek04bc8762008-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 Kremenek4adc81e2008-08-13 04:27:00 +0000351 GRStateManager* VMgr;
Ted Kremenek04bc8762008-06-26 23:59:48 +0000352
Zhongxing Xu1c96b242008-10-17 05:57:07 +0000353 SVal GetSVal(const GRState* St, Expr* E) { return VMgr->GetSVal(St, E); }
Ted Kremenek04bc8762008-06-26 23:59:48 +0000354
355public:
356
Ted Kremenek4adc81e2008-08-13 04:27:00 +0000357 AuditCFNumberCreate(ASTContext& ctx, GRStateManager* vmgr)
Ted Kremenek04bc8762008-06-26 23:59:48 +0000358 : Ctx(ctx), II(&Ctx.Idents.get("CFNumberCreate")), VMgr(vmgr) {}
359
360 virtual ~AuditCFNumberCreate() {}
361
Ted Kremenek4adc81e2008-08-13 04:27:00 +0000362 virtual bool Audit(ExplodedNode<GRState>* N, GRStateManager&);
Ted Kremenek04bc8762008-06-26 23:59:48 +0000363
364 virtual void EmitWarnings(BugReporter& BR) {
365 Desc.EmitWarnings(BR);
366 }
367
368private:
369
Ted Kremenek993f1c72008-10-17 20:28:54 +0000370 void AddError(const TypedRegion* R, Expr* Ex, ExplodedNode<GRState> *N,
Ted Kremenek04bc8762008-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 Kremenek4adc81e2008-08-13 04:27:00 +0000468bool AuditCFNumberCreate::Audit(ExplodedNode<GRState>* N,GRStateManager&){
Ted Kremenek04bc8762008-06-26 23:59:48 +0000469 CallExpr* CE = cast<CallExpr>(cast<PostStmt>(N->getLocation()).getStmt());
470 Expr* Callee = CE->getCallee();
Zhongxing Xu1c96b242008-10-17 05:57:07 +0000471 SVal CallV = GetSVal(N->getState(), Callee);
472 loc::FuncVal* FuncV = dyn_cast<loc::FuncVal>(&CallV);
Ted Kremenek04bc8762008-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 Xu1c96b242008-10-17 05:57:07 +0000478 SVal TheTypeVal = GetSVal(N->getState(), CE->getArg(1));
Ted Kremenek04bc8762008-06-26 23:59:48 +0000479
480 // FIXME: We really should allow ranges of valid theType values, and
481 // bifurcate the state appropriately.
Zhongxing Xu1c96b242008-10-17 05:57:07 +0000482 nonloc::ConcreteInt* V = dyn_cast<nonloc::ConcreteInt>(&TheTypeVal);
Ted Kremenek04bc8762008-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 Xu1c96b242008-10-17 05:57:07 +0000497 SVal TheValueExpr = GetSVal(N->getState(), CE->getArg(2));
Ted Kremenek04bc8762008-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 Xu1c96b242008-10-17 05:57:07 +0000501 loc::MemRegionVal* LV = dyn_cast<loc::MemRegionVal>(&TheValueExpr);
Ted Kremenek04bc8762008-06-26 23:59:48 +0000502
503 if (!LV)
504 return false;
505
Ted Kremenek993f1c72008-10-17 20:28:54 +0000506 const TypedRegion* R = dyn_cast<TypedRegion>(LV->getRegion());
Ted Kremenek9e240492008-10-04 05:50:14 +0000507 if (!R)
508 return false;
509
510
Ted Kremenek9deb0e32008-10-24 20:32:16 +0000511 QualType T = Ctx.getCanonicalType(R->getType(Ctx));
Ted Kremenek04bc8762008-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 Kremenek9e240492008-10-04 05:50:14 +0000526 AddError(R, CE->getArg(2), N, SourceSize, TargetSize, NumberKind);
Ted Kremenek04bc8762008-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 Kremenek993f1c72008-10-17 20:28:54 +0000533void AuditCFNumberCreate::AddError(const TypedRegion* R, Expr* Ex,
Ted Kremenek4adc81e2008-08-13 04:27:00 +0000534 ExplodedNode<GRState> *N,
Ted Kremenek04bc8762008-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 Kremenek4adc81e2008-08-13 04:27:00 +0000560 GRStateManager* VMgr) {
Ted Kremenek04bc8762008-06-26 23:59:48 +0000561
562 return new AuditCFNumberCreate(Ctx, VMgr);
563}
564
Ted Kremenek78d46242008-07-22 16:21:24 +0000565//===----------------------------------------------------------------------===//
566// Check registration.
567
568void clang::RegisterAppleChecks(GRExprEngine& Eng) {
569 ASTContext& Ctx = Eng.getContext();
Ted Kremenek4adc81e2008-08-13 04:27:00 +0000570 GRStateManager* VMgr = &Eng.getStateManager();
Ted Kremenek78d46242008-07-22 16:21:24 +0000571
572 Eng.AddCheck(CreateBasicObjCFoundationChecks(Ctx, VMgr),
573 Stmt::ObjCMessageExprClass);
574
Ted Kremenekcfdf9b42008-09-18 21:25:13 +0000575 Eng.AddCheck(CreateAuditCFNumberCreate(Ctx, VMgr),
576 Stmt::CallExprClass);
577
578 Eng.Register(CreateNSErrorCheck());
Ted Kremenek78d46242008-07-22 16:21:24 +0000579}