blob: 5db957fcfb91d82ff0abee36e05dde36c0e61900 [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 Kremenek1309f9a2010-01-25 04:41:41 +000018#include "clang/Checker/PathSensitive/ExplodedGraph.h"
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000019#include "clang/Checker/PathSensitive/CheckerVisitor.h"
Ted Kremenek1309f9a2010-01-25 04:41:41 +000020#include "clang/Checker/PathSensitive/GRExprEngine.h"
21#include "clang/Checker/PathSensitive/GRState.h"
Benjamin Kramer5e2d2c22010-03-27 21:19:47 +000022#include "clang/Checker/BugReporter/BugType.h"
Ted Kremenek1309f9a2010-01-25 04:41:41 +000023#include "clang/Checker/PathSensitive/MemRegion.h"
Ted Kremenek1309f9a2010-01-25 04:41:41 +000024#include "clang/Checker/PathSensitive/CheckerVisitor.h"
Ted Kremenek97053092010-01-26 22:59:55 +000025#include "clang/Checker/Checkers/LocalCheckers.h"
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"
Ted Kremenek99c6ad32008-03-27 07:25:52 +000030
Ted Kremenek99c6ad32008-03-27 07:25:52 +000031using namespace clang;
Ted Kremenek52755612008-03-27 17:17:22 +000032
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000033namespace {
34class APIMisuse : public BugType {
35public:
36 APIMisuse(const char* name) : BugType(name, "API Misuse (Apple)") {}
37};
38} // end anonymous namespace
39
40//===----------------------------------------------------------------------===//
41// Utility functions.
42//===----------------------------------------------------------------------===//
43
Steve Naroff14108da2009-07-10 23:34:53 +000044static const ObjCInterfaceType* GetReceiverType(const ObjCMessageExpr* ME) {
Douglas Gregor04badcf2010-04-21 00:45:42 +000045 QualType T;
46 switch (ME->getReceiverKind()) {
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000047 case ObjCMessageExpr::Instance:
48 T = ME->getInstanceReceiver()->getType();
49 break;
50
51 case ObjCMessageExpr::SuperInstance:
52 T = ME->getSuperType();
53 break;
54
55 case ObjCMessageExpr::Class:
56 case ObjCMessageExpr::SuperClass:
57 return 0;
Douglas Gregor04badcf2010-04-21 00:45:42 +000058 }
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000059
Douglas Gregor04badcf2010-04-21 00:45:42 +000060 if (const ObjCObjectPointerType *PT = T->getAs<ObjCObjectPointerType>())
Steve Naroff14108da2009-07-10 23:34:53 +000061 return PT->getInterfaceType();
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000062
Ted Kremenekc1ff3cd2008-04-30 22:48:21 +000063 return NULL;
Ted Kremenek4ba62832008-03-27 22:05:32 +000064}
65
Steve Naroff14108da2009-07-10 23:34:53 +000066static const char* GetReceiverNameType(const ObjCMessageExpr* ME) {
Daniel Dunbare013d682009-10-18 20:26:12 +000067 if (const ObjCInterfaceType *ReceiverType = GetReceiverType(ME))
68 return ReceiverType->getDecl()->getIdentifier()->getNameStart();
69 return NULL;
Ted Kremenek4ba62832008-03-27 22:05:32 +000070}
Ted Kremenek52755612008-03-27 17:17:22 +000071
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000072static bool isNSString(llvm::StringRef ClassName) {
73 return ClassName == "NSString" || ClassName == "NSMutableString";
Ted Kremenek99c6ad32008-03-27 07:25:52 +000074}
75
Zhongxing Xu1c96b242008-10-17 05:57:07 +000076static inline bool isNil(SVal X) {
Mike Stump1eb44332009-09-09 15:08:12 +000077 return isa<loc::ConcreteInt>(X);
Ted Kremeneke5d5c202008-03-27 21:15:17 +000078}
79
Ted Kremenek99c6ad32008-03-27 07:25:52 +000080//===----------------------------------------------------------------------===//
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000081// NilArgChecker - Check for prohibited nil arguments to ObjC method calls.
Ted Kremenek99c6ad32008-03-27 07:25:52 +000082//===----------------------------------------------------------------------===//
83
Benjamin Kramercb9c0742010-10-22 16:33:16 +000084namespace {
85 class NilArgChecker : public CheckerVisitor<NilArgChecker> {
86 APIMisuse *BT;
87 void WarnNilArg(CheckerContext &C, const ObjCMessageExpr* ME, unsigned Arg);
88 public:
89 NilArgChecker() : BT(0) {}
90 static void *getTag() { static int x = 0; return &x; }
91 void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME);
92 };
93}
Mike Stump1eb44332009-09-09 15:08:12 +000094
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000095void NilArgChecker::WarnNilArg(CheckerContext &C,
96 const clang::ObjCMessageExpr *ME,
97 unsigned int Arg)
98{
99 if (!BT)
100 BT = new APIMisuse("nil argument");
101
102 if (ExplodedNode *N = C.GenerateSink()) {
103 llvm::SmallString<128> sbuf;
104 llvm::raw_svector_ostream os(sbuf);
105 os << "Argument to '" << GetReceiverNameType(ME) << "' method '"
106 << ME->getSelector().getAsString() << "' cannot be nil";
Mike Stump1eb44332009-09-09 15:08:12 +0000107
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000108 RangedBugReport *R = new RangedBugReport(*BT, os.str(), N);
109 R->addRange(ME->getArg(Arg)->getSourceRange());
110 C.EmitReport(R);
Ted Kremenek4ba62832008-03-27 22:05:32 +0000111 }
Ted Kremenek4ba62832008-03-27 22:05:32 +0000112}
113
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000114void NilArgChecker::PreVisitObjCMessageExpr(CheckerContext &C,
115 const ObjCMessageExpr *ME)
116{
117 const ObjCInterfaceType *ReceiverType = GetReceiverType(ME);
118 if (!ReceiverType)
119 return;
120
121 if (isNSString(ReceiverType->getDecl()->getIdentifier()->getName())) {
122 Selector S = ME->getSelector();
123
124 if (S.isUnarySelector())
125 return;
126
127 // FIXME: This is going to be really slow doing these checks with
128 // lexical comparisons.
129
130 std::string NameStr = S.getAsString();
131 llvm::StringRef Name(NameStr);
132 assert(!Name.empty());
133
134 // FIXME: Checking for initWithFormat: will not work in most cases
135 // yet because [NSString alloc] returns id, not NSString*. We will
136 // need support for tracking expected-type information in the analyzer
137 // to find these errors.
138 if (Name == "caseInsensitiveCompare:" ||
139 Name == "compare:" ||
140 Name == "compare:options:" ||
141 Name == "compare:options:range:" ||
142 Name == "compare:options:range:locale:" ||
143 Name == "componentsSeparatedByCharactersInSet:" ||
144 Name == "initWithFormat:") {
145 if (isNil(C.getState()->getSVal(ME->getArg(0))))
146 WarnNilArg(C, ME, 0);
147 }
148 }
Ted Kremenek99c6ad32008-03-27 07:25:52 +0000149}
Ted Kremenek04bc8762008-06-26 23:59:48 +0000150
151//===----------------------------------------------------------------------===//
152// Error reporting.
153//===----------------------------------------------------------------------===//
154
155namespace {
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000156class CFNumberCreateChecker : public CheckerVisitor<CFNumberCreateChecker> {
Ted Kremenekcf118d42009-02-04 23:49:09 +0000157 APIMisuse* BT;
Ted Kremenek04bc8762008-06-26 23:59:48 +0000158 IdentifierInfo* II;
Ted Kremenek04bc8762008-06-26 23:59:48 +0000159public:
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000160 CFNumberCreateChecker() : BT(0), II(0) {}
161 ~CFNumberCreateChecker() {}
162 static void *getTag() { static int x = 0; return &x; }
163 void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
Ted Kremenek04bc8762008-06-26 23:59:48 +0000164private:
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000165 void EmitError(const TypedRegion* R, const Expr* Ex,
Mike Stump1eb44332009-09-09 15:08:12 +0000166 uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind);
Ted Kremenek04bc8762008-06-26 23:59:48 +0000167};
168} // end anonymous namespace
169
170enum CFNumberType {
171 kCFNumberSInt8Type = 1,
172 kCFNumberSInt16Type = 2,
173 kCFNumberSInt32Type = 3,
174 kCFNumberSInt64Type = 4,
175 kCFNumberFloat32Type = 5,
176 kCFNumberFloat64Type = 6,
177 kCFNumberCharType = 7,
178 kCFNumberShortType = 8,
179 kCFNumberIntType = 9,
180 kCFNumberLongType = 10,
181 kCFNumberLongLongType = 11,
182 kCFNumberFloatType = 12,
183 kCFNumberDoubleType = 13,
184 kCFNumberCFIndexType = 14,
185 kCFNumberNSIntegerType = 15,
186 kCFNumberCGFloatType = 16
187};
188
189namespace {
190 template<typename T>
191 class Optional {
192 bool IsKnown;
193 T Val;
194 public:
195 Optional() : IsKnown(false), Val(0) {}
196 Optional(const T& val) : IsKnown(true), Val(val) {}
Mike Stump1eb44332009-09-09 15:08:12 +0000197
Ted Kremenek04bc8762008-06-26 23:59:48 +0000198 bool isKnown() const { return IsKnown; }
199
200 const T& getValue() const {
201 assert (isKnown());
202 return Val;
203 }
204
205 operator const T&() const {
206 return getValue();
207 }
208 };
209}
210
211static Optional<uint64_t> GetCFNumberSize(ASTContext& Ctx, uint64_t i) {
Nuno Lopes2550d702009-12-23 17:49:57 +0000212 static const unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 };
Mike Stump1eb44332009-09-09 15:08:12 +0000213
Ted Kremenek04bc8762008-06-26 23:59:48 +0000214 if (i < kCFNumberCharType)
215 return FixedSize[i-1];
Mike Stump1eb44332009-09-09 15:08:12 +0000216
Ted Kremenek04bc8762008-06-26 23:59:48 +0000217 QualType T;
Mike Stump1eb44332009-09-09 15:08:12 +0000218
Ted Kremenek04bc8762008-06-26 23:59:48 +0000219 switch (i) {
220 case kCFNumberCharType: T = Ctx.CharTy; break;
221 case kCFNumberShortType: T = Ctx.ShortTy; break;
222 case kCFNumberIntType: T = Ctx.IntTy; break;
223 case kCFNumberLongType: T = Ctx.LongTy; break;
224 case kCFNumberLongLongType: T = Ctx.LongLongTy; break;
225 case kCFNumberFloatType: T = Ctx.FloatTy; break;
226 case kCFNumberDoubleType: T = Ctx.DoubleTy; break;
227 case kCFNumberCFIndexType:
228 case kCFNumberNSIntegerType:
229 case kCFNumberCGFloatType:
Mike Stump1eb44332009-09-09 15:08:12 +0000230 // FIXME: We need a way to map from names to Type*.
Ted Kremenek04bc8762008-06-26 23:59:48 +0000231 default:
232 return Optional<uint64_t>();
233 }
Mike Stump1eb44332009-09-09 15:08:12 +0000234
Ted Kremenek04bc8762008-06-26 23:59:48 +0000235 return Ctx.getTypeSize(T);
236}
237
238#if 0
239static const char* GetCFNumberTypeStr(uint64_t i) {
240 static const char* Names[] = {
241 "kCFNumberSInt8Type",
242 "kCFNumberSInt16Type",
243 "kCFNumberSInt32Type",
244 "kCFNumberSInt64Type",
245 "kCFNumberFloat32Type",
246 "kCFNumberFloat64Type",
247 "kCFNumberCharType",
248 "kCFNumberShortType",
249 "kCFNumberIntType",
250 "kCFNumberLongType",
251 "kCFNumberLongLongType",
252 "kCFNumberFloatType",
253 "kCFNumberDoubleType",
254 "kCFNumberCFIndexType",
255 "kCFNumberNSIntegerType",
256 "kCFNumberCGFloatType"
257 };
Mike Stump1eb44332009-09-09 15:08:12 +0000258
Ted Kremenek04bc8762008-06-26 23:59:48 +0000259 return i <= kCFNumberCGFloatType ? Names[i-1] : "Invalid CFNumberType";
260}
261#endif
262
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000263void CFNumberCreateChecker::PreVisitCallExpr(CheckerContext &C,
264 const CallExpr *CE)
265{
Mike Stump1eb44332009-09-09 15:08:12 +0000266 const Expr* Callee = CE->getCallee();
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000267 const GRState *state = C.getState();
268 SVal CallV = state->getSVal(Callee);
Zhongxing Xu369f4472009-04-20 05:24:46 +0000269 const FunctionDecl* FD = CallV.getAsFunctionDecl();
Ted Kremenek04bc8762008-06-26 23:59:48 +0000270
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000271 if (!FD)
272 return;
273
274 ASTContext &Ctx = C.getASTContext();
275 if (!II)
276 II = &Ctx.Idents.get("CFNumberCreate");
277
278 if (FD->getIdentifier() != II || CE->getNumArgs() != 3)
279 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000280
Ted Kremenek04bc8762008-06-26 23:59:48 +0000281 // Get the value of the "theType" argument.
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000282 SVal TheTypeVal = state->getSVal(CE->getArg(1));
Mike Stump1eb44332009-09-09 15:08:12 +0000283
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000284 // FIXME: We really should allow ranges of valid theType values, and
285 // bifurcate the state appropriately.
Zhongxing Xu1c96b242008-10-17 05:57:07 +0000286 nonloc::ConcreteInt* V = dyn_cast<nonloc::ConcreteInt>(&TheTypeVal);
Ted Kremenek04bc8762008-06-26 23:59:48 +0000287 if (!V)
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000288 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000289
Ted Kremenek04bc8762008-06-26 23:59:48 +0000290 uint64_t NumberKind = V->getValue().getLimitedValue();
291 Optional<uint64_t> TargetSize = GetCFNumberSize(Ctx, NumberKind);
Mike Stump1eb44332009-09-09 15:08:12 +0000292
Ted Kremenek04bc8762008-06-26 23:59:48 +0000293 // FIXME: In some cases we can emit an error.
294 if (!TargetSize.isKnown())
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000295 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000296
Ted Kremenek04bc8762008-06-26 23:59:48 +0000297 // Look at the value of the integer being passed by reference. Essentially
298 // we want to catch cases where the value passed in is not equal to the
299 // size of the type being created.
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000300 SVal TheValueExpr = state->getSVal(CE->getArg(2));
Mike Stump1eb44332009-09-09 15:08:12 +0000301
Ted Kremenek04bc8762008-06-26 23:59:48 +0000302 // FIXME: Eventually we should handle arbitrary locations. We can do this
303 // by having an enhanced memory model that does low-level typing.
Zhongxing Xu1c96b242008-10-17 05:57:07 +0000304 loc::MemRegionVal* LV = dyn_cast<loc::MemRegionVal>(&TheValueExpr);
Ted Kremenek04bc8762008-06-26 23:59:48 +0000305 if (!LV)
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000306 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000307
Zhongxing Xu479529e2009-11-10 02:17:20 +0000308 const TypedRegion* R = dyn_cast<TypedRegion>(LV->StripCasts());
Ted Kremenek5e77eba2009-07-29 18:17:40 +0000309 if (!R)
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000310 return;
Ted Kremenek5e77eba2009-07-29 18:17:40 +0000311
Zhongxing Xu018220c2010-08-11 06:10:55 +0000312 QualType T = Ctx.getCanonicalType(R->getValueType());
Mike Stump1eb44332009-09-09 15:08:12 +0000313
Ted Kremenek04bc8762008-06-26 23:59:48 +0000314 // FIXME: If the pointee isn't an integer type, should we flag a warning?
315 // People can do weird stuff with pointers.
Mike Stump1eb44332009-09-09 15:08:12 +0000316
317 if (!T->isIntegerType())
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000318 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000319
Ted Kremenek04bc8762008-06-26 23:59:48 +0000320 uint64_t SourceSize = Ctx.getTypeSize(T);
Mike Stump1eb44332009-09-09 15:08:12 +0000321
Ted Kremenek04bc8762008-06-26 23:59:48 +0000322 // CHECK: is SourceSize == TargetSize
Ted Kremenek04bc8762008-06-26 23:59:48 +0000323 if (SourceSize == TargetSize)
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000324 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000325
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000326 // Generate an error. Only generate a sink if 'SourceSize < TargetSize';
327 // otherwise generate a regular node.
328 //
Ted Kremenek04bc8762008-06-26 23:59:48 +0000329 // FIXME: We can actually create an abstract "CFNumber" object that has
330 // the bits initialized to the provided values.
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000331 //
332 if (ExplodedNode *N = SourceSize < TargetSize ? C.GenerateSink()
333 : C.GenerateNode()) {
334 llvm::SmallString<128> sbuf;
335 llvm::raw_svector_ostream os(sbuf);
336
337 os << (SourceSize == 8 ? "An " : "A ")
338 << SourceSize << " bit integer is used to initialize a CFNumber "
339 "object that represents "
340 << (TargetSize == 8 ? "an " : "a ")
341 << TargetSize << " bit integer. ";
342
343 if (SourceSize < TargetSize)
344 os << (TargetSize - SourceSize)
345 << " bits of the CFNumber value will be garbage." ;
346 else
347 os << (SourceSize - TargetSize)
348 << " bits of the input integer will be lost.";
Ted Kremenek04bc8762008-06-26 23:59:48 +0000349
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000350 if (!BT)
351 BT = new APIMisuse("Bad use of CFNumberCreate");
352
353 RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
354 report->addRange(CE->getArg(2)->getSourceRange());
355 C.EmitReport(report);
356 }
Ted Kremenek04bc8762008-06-26 23:59:48 +0000357}
358
Ted Kremenek78d46242008-07-22 16:21:24 +0000359//===----------------------------------------------------------------------===//
Jordy Rose61fb55c2010-07-06 02:34:42 +0000360// CFRetain/CFRelease checking for null arguments.
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000361//===----------------------------------------------------------------------===//
362
363namespace {
Jordy Rose61fb55c2010-07-06 02:34:42 +0000364class CFRetainReleaseChecker : public CheckerVisitor<CFRetainReleaseChecker> {
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000365 APIMisuse *BT;
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000366 IdentifierInfo *Retain, *Release;
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000367public:
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000368 CFRetainReleaseChecker(): BT(0), Retain(0), Release(0) {}
Jordy Rose61fb55c2010-07-06 02:34:42 +0000369 static void *getTag() { static int x = 0; return &x; }
Jordy Rose61fb55c2010-07-06 02:34:42 +0000370 void PreVisitCallExpr(CheckerContext& C, const CallExpr* CE);
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000371};
372} // end anonymous namespace
373
374
Jordy Rose61fb55c2010-07-06 02:34:42 +0000375void CFRetainReleaseChecker::PreVisitCallExpr(CheckerContext& C,
376 const CallExpr* CE) {
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000377 // If the CallExpr doesn't have exactly 1 argument just give up checking.
378 if (CE->getNumArgs() != 1)
Jordy Rose61fb55c2010-07-06 02:34:42 +0000379 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000380
Jordy Rose61fb55c2010-07-06 02:34:42 +0000381 // Get the function declaration of the callee.
382 const GRState* state = C.getState();
Ted Kremenek13976632010-02-08 16:18:51 +0000383 SVal X = state->getSVal(CE->getCallee());
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000384 const FunctionDecl* FD = X.getAsFunctionDecl();
Mike Stump1eb44332009-09-09 15:08:12 +0000385
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000386 if (!FD)
Jordy Rose61fb55c2010-07-06 02:34:42 +0000387 return;
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000388
389 if (!BT) {
390 ASTContext &Ctx = C.getASTContext();
391 Retain = &Ctx.Idents.get("CFRetain");
392 Release = &Ctx.Idents.get("CFRelease");
393 BT = new APIMisuse("null passed to CFRetain/CFRelease");
394 }
Mike Stump1eb44332009-09-09 15:08:12 +0000395
Jordy Rose61fb55c2010-07-06 02:34:42 +0000396 // Check if we called CFRetain/CFRelease.
Mike Stump1eb44332009-09-09 15:08:12 +0000397 const IdentifierInfo *FuncII = FD->getIdentifier();
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000398 if (!(FuncII == Retain || FuncII == Release))
Jordy Rose61fb55c2010-07-06 02:34:42 +0000399 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000400
Jordy Rose61fb55c2010-07-06 02:34:42 +0000401 // FIXME: The rest of this just checks that the argument is non-null.
402 // It should probably be refactored and combined with AttrNonNullChecker.
403
404 // Get the argument's value.
405 const Expr *Arg = CE->getArg(0);
406 SVal ArgVal = state->getSVal(Arg);
407 DefinedSVal *DefArgVal = dyn_cast<DefinedSVal>(&ArgVal);
408 if (!DefArgVal)
409 return;
410
411 // Get a NULL value.
412 ValueManager &ValMgr = C.getValueManager();
413 DefinedSVal Zero = cast<DefinedSVal>(ValMgr.makeZeroVal(Arg->getType()));
414
415 // Make an expression asserting that they're equal.
Ted Kremenek846eabd2010-12-01 21:28:31 +0000416 SValBuilder &svalBuilder = ValMgr.getSValBuilder();
Ted Kremenek9c149532010-12-01 21:57:22 +0000417 DefinedOrUnknownSVal ArgIsNull = svalBuilder.evalEQ(state, Zero, *DefArgVal);
Jordy Rose61fb55c2010-07-06 02:34:42 +0000418
419 // Are they equal?
420 const GRState *stateTrue, *stateFalse;
421 llvm::tie(stateTrue, stateFalse) = state->Assume(ArgIsNull);
422
423 if (stateTrue && !stateFalse) {
424 ExplodedNode *N = C.GenerateSink(stateTrue);
425 if (!N)
426 return;
427
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000428 const char *description = (FuncII == Retain)
429 ? "Null pointer argument in call to CFRetain"
430 : "Null pointer argument in call to CFRelease";
431
Jordy Rose61fb55c2010-07-06 02:34:42 +0000432 EnhancedBugReport *report = new EnhancedBugReport(*BT, description, N);
433 report->addRange(Arg->getSourceRange());
434 report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Arg);
Jordy Rose61fb55c2010-07-06 02:34:42 +0000435 C.EmitReport(report);
436 return;
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000437 }
438
Jordy Rose61fb55c2010-07-06 02:34:42 +0000439 // From here on, we know the argument is non-null.
440 C.addTransition(stateFalse);
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000441}
442
443//===----------------------------------------------------------------------===//
Ted Kremenek50e837b2009-11-20 05:27:05 +0000444// Check for sending 'retain', 'release', or 'autorelease' directly to a Class.
445//===----------------------------------------------------------------------===//
446
447namespace {
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000448class ClassReleaseChecker : public CheckerVisitor<ClassReleaseChecker> {
Ted Kremenek50e837b2009-11-20 05:27:05 +0000449 Selector releaseS;
450 Selector retainS;
451 Selector autoreleaseS;
452 Selector drainS;
453 BugType *BT;
454public:
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000455 ClassReleaseChecker()
456 : BT(0) {}
Ted Kremenek50e837b2009-11-20 05:27:05 +0000457
458 static void *getTag() { static int x = 0; return &x; }
459
460 void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME);
461};
462}
463
464void ClassReleaseChecker::PreVisitObjCMessageExpr(CheckerContext &C,
465 const ObjCMessageExpr *ME) {
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000466
467 if (!BT) {
468 BT = new APIMisuse("message incorrectly sent to class instead of class "
469 "instance");
470
471 ASTContext &Ctx = C.getASTContext();
472 releaseS = GetNullarySelector("release", Ctx);
473 retainS = GetNullarySelector("retain", Ctx);
474 autoreleaseS = GetNullarySelector("autorelease", Ctx);
475 drainS = GetNullarySelector("drain", Ctx);
476 }
477
Douglas Gregor04badcf2010-04-21 00:45:42 +0000478 ObjCInterfaceDecl *Class = 0;
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000479
Douglas Gregor04badcf2010-04-21 00:45:42 +0000480 switch (ME->getReceiverKind()) {
481 case ObjCMessageExpr::Class:
John McCall506b57e2010-05-17 21:00:27 +0000482 Class = ME->getClassReceiver()->getAs<ObjCObjectType>()->getInterface();
Douglas Gregor04badcf2010-04-21 00:45:42 +0000483 break;
Douglas Gregor04badcf2010-04-21 00:45:42 +0000484 case ObjCMessageExpr::SuperClass:
John McCall506b57e2010-05-17 21:00:27 +0000485 Class = ME->getSuperType()->getAs<ObjCObjectType>()->getInterface();
Douglas Gregor04badcf2010-04-21 00:45:42 +0000486 break;
Douglas Gregor04badcf2010-04-21 00:45:42 +0000487 case ObjCMessageExpr::Instance:
488 case ObjCMessageExpr::SuperInstance:
Ted Kremenek50e837b2009-11-20 05:27:05 +0000489 return;
Douglas Gregor04badcf2010-04-21 00:45:42 +0000490 }
491
Ted Kremenek50e837b2009-11-20 05:27:05 +0000492 Selector S = ME->getSelector();
Benjamin Kramer921ddc42009-11-20 10:03:00 +0000493 if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
Ted Kremenek50e837b2009-11-20 05:27:05 +0000494 return;
495
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000496 if (ExplodedNode *N = C.GenerateNode()) {
497 llvm::SmallString<200> buf;
498 llvm::raw_svector_ostream os(buf);
Ted Kremenek19d67b52009-11-23 22:22:01 +0000499
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000500 os << "The '" << S.getAsString() << "' message should be sent to instances "
501 "of class '" << Class->getName()
502 << "' and not the class directly";
Ted Kremenek50e837b2009-11-20 05:27:05 +0000503
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000504 RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
505 report->addRange(ME->getSourceRange());
506 C.EmitReport(report);
507 }
Ted Kremenek50e837b2009-11-20 05:27:05 +0000508}
509
510//===----------------------------------------------------------------------===//
Ted Kremenek78d46242008-07-22 16:21:24 +0000511// Check registration.
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000512//===----------------------------------------------------------------------===//
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000513
Zhongxing Xu5ab128b2009-08-21 02:18:44 +0000514void clang::RegisterAppleChecks(GRExprEngine& Eng, const Decl &D) {
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000515 Eng.registerCheck(new NilArgChecker());
516 Eng.registerCheck(new CFNumberCreateChecker());
517 RegisterNSErrorChecks(Eng.getBugReporter(), Eng, D);
Ted Kremenek54cb7cc2009-11-03 08:03:59 +0000518 RegisterNSAutoreleasePoolChecks(Eng);
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000519 Eng.registerCheck(new CFRetainReleaseChecker());
520 Eng.registerCheck(new ClassReleaseChecker());
Ted Kremenek78d46242008-07-22 16:21:24 +0000521}