blob: 6398d9415b424ddfddd8ebc89e5909cd90e0c65d [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
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000084class NilArgChecker : public CheckerVisitor<NilArgChecker> {
85 APIMisuse *BT;
86 void AuditNSString(CheckerContext &C, const ObjCMessageExpr* ME);
87 void WarnNilArg(CheckerContext &C, const ObjCMessageExpr* ME, unsigned Arg);
88public:
89 NilArgChecker() : BT(0) {}
90 static void *getTag() { static int x = 0; return &x; }
91 void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME);
92};
Mike Stump1eb44332009-09-09 15:08:12 +000093
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000094void NilArgChecker::WarnNilArg(CheckerContext &C,
95 const clang::ObjCMessageExpr *ME,
96 unsigned int Arg)
97{
98 if (!BT)
99 BT = new APIMisuse("nil argument");
100
101 if (ExplodedNode *N = C.GenerateSink()) {
102 llvm::SmallString<128> sbuf;
103 llvm::raw_svector_ostream os(sbuf);
104 os << "Argument to '" << GetReceiverNameType(ME) << "' method '"
105 << ME->getSelector().getAsString() << "' cannot be nil";
Mike Stump1eb44332009-09-09 15:08:12 +0000106
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000107 RangedBugReport *R = new RangedBugReport(*BT, os.str(), N);
108 R->addRange(ME->getArg(Arg)->getSourceRange());
109 C.EmitReport(R);
Ted Kremenek4ba62832008-03-27 22:05:32 +0000110 }
Ted Kremenek4ba62832008-03-27 22:05:32 +0000111}
112
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000113void NilArgChecker::PreVisitObjCMessageExpr(CheckerContext &C,
114 const ObjCMessageExpr *ME)
115{
116 const ObjCInterfaceType *ReceiverType = GetReceiverType(ME);
117 if (!ReceiverType)
118 return;
119
120 if (isNSString(ReceiverType->getDecl()->getIdentifier()->getName())) {
121 Selector S = ME->getSelector();
122
123 if (S.isUnarySelector())
124 return;
125
126 // FIXME: This is going to be really slow doing these checks with
127 // lexical comparisons.
128
129 std::string NameStr = S.getAsString();
130 llvm::StringRef Name(NameStr);
131 assert(!Name.empty());
132
133 // FIXME: Checking for initWithFormat: will not work in most cases
134 // yet because [NSString alloc] returns id, not NSString*. We will
135 // need support for tracking expected-type information in the analyzer
136 // to find these errors.
137 if (Name == "caseInsensitiveCompare:" ||
138 Name == "compare:" ||
139 Name == "compare:options:" ||
140 Name == "compare:options:range:" ||
141 Name == "compare:options:range:locale:" ||
142 Name == "componentsSeparatedByCharactersInSet:" ||
143 Name == "initWithFormat:") {
144 if (isNil(C.getState()->getSVal(ME->getArg(0))))
145 WarnNilArg(C, ME, 0);
146 }
147 }
Ted Kremenek99c6ad32008-03-27 07:25:52 +0000148}
Ted Kremenek04bc8762008-06-26 23:59:48 +0000149
150//===----------------------------------------------------------------------===//
151// Error reporting.
152//===----------------------------------------------------------------------===//
153
154namespace {
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000155class CFNumberCreateChecker : public CheckerVisitor<CFNumberCreateChecker> {
Ted Kremenekcf118d42009-02-04 23:49:09 +0000156 APIMisuse* BT;
Ted Kremenek04bc8762008-06-26 23:59:48 +0000157 IdentifierInfo* II;
Ted Kremenek04bc8762008-06-26 23:59:48 +0000158public:
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000159 CFNumberCreateChecker() : BT(0), II(0) {}
160 ~CFNumberCreateChecker() {}
161 static void *getTag() { static int x = 0; return &x; }
162 void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
Ted Kremenek04bc8762008-06-26 23:59:48 +0000163private:
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000164 void EmitError(const TypedRegion* R, const Expr* Ex,
Mike Stump1eb44332009-09-09 15:08:12 +0000165 uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind);
Ted Kremenek04bc8762008-06-26 23:59:48 +0000166};
167} // end anonymous namespace
168
169enum CFNumberType {
170 kCFNumberSInt8Type = 1,
171 kCFNumberSInt16Type = 2,
172 kCFNumberSInt32Type = 3,
173 kCFNumberSInt64Type = 4,
174 kCFNumberFloat32Type = 5,
175 kCFNumberFloat64Type = 6,
176 kCFNumberCharType = 7,
177 kCFNumberShortType = 8,
178 kCFNumberIntType = 9,
179 kCFNumberLongType = 10,
180 kCFNumberLongLongType = 11,
181 kCFNumberFloatType = 12,
182 kCFNumberDoubleType = 13,
183 kCFNumberCFIndexType = 14,
184 kCFNumberNSIntegerType = 15,
185 kCFNumberCGFloatType = 16
186};
187
188namespace {
189 template<typename T>
190 class Optional {
191 bool IsKnown;
192 T Val;
193 public:
194 Optional() : IsKnown(false), Val(0) {}
195 Optional(const T& val) : IsKnown(true), Val(val) {}
Mike Stump1eb44332009-09-09 15:08:12 +0000196
Ted Kremenek04bc8762008-06-26 23:59:48 +0000197 bool isKnown() const { return IsKnown; }
198
199 const T& getValue() const {
200 assert (isKnown());
201 return Val;
202 }
203
204 operator const T&() const {
205 return getValue();
206 }
207 };
208}
209
210static Optional<uint64_t> GetCFNumberSize(ASTContext& Ctx, uint64_t i) {
Nuno Lopes2550d702009-12-23 17:49:57 +0000211 static const unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 };
Mike Stump1eb44332009-09-09 15:08:12 +0000212
Ted Kremenek04bc8762008-06-26 23:59:48 +0000213 if (i < kCFNumberCharType)
214 return FixedSize[i-1];
Mike Stump1eb44332009-09-09 15:08:12 +0000215
Ted Kremenek04bc8762008-06-26 23:59:48 +0000216 QualType T;
Mike Stump1eb44332009-09-09 15:08:12 +0000217
Ted Kremenek04bc8762008-06-26 23:59:48 +0000218 switch (i) {
219 case kCFNumberCharType: T = Ctx.CharTy; break;
220 case kCFNumberShortType: T = Ctx.ShortTy; break;
221 case kCFNumberIntType: T = Ctx.IntTy; break;
222 case kCFNumberLongType: T = Ctx.LongTy; break;
223 case kCFNumberLongLongType: T = Ctx.LongLongTy; break;
224 case kCFNumberFloatType: T = Ctx.FloatTy; break;
225 case kCFNumberDoubleType: T = Ctx.DoubleTy; break;
226 case kCFNumberCFIndexType:
227 case kCFNumberNSIntegerType:
228 case kCFNumberCGFloatType:
Mike Stump1eb44332009-09-09 15:08:12 +0000229 // FIXME: We need a way to map from names to Type*.
Ted Kremenek04bc8762008-06-26 23:59:48 +0000230 default:
231 return Optional<uint64_t>();
232 }
Mike Stump1eb44332009-09-09 15:08:12 +0000233
Ted Kremenek04bc8762008-06-26 23:59:48 +0000234 return Ctx.getTypeSize(T);
235}
236
237#if 0
238static const char* GetCFNumberTypeStr(uint64_t i) {
239 static const char* Names[] = {
240 "kCFNumberSInt8Type",
241 "kCFNumberSInt16Type",
242 "kCFNumberSInt32Type",
243 "kCFNumberSInt64Type",
244 "kCFNumberFloat32Type",
245 "kCFNumberFloat64Type",
246 "kCFNumberCharType",
247 "kCFNumberShortType",
248 "kCFNumberIntType",
249 "kCFNumberLongType",
250 "kCFNumberLongLongType",
251 "kCFNumberFloatType",
252 "kCFNumberDoubleType",
253 "kCFNumberCFIndexType",
254 "kCFNumberNSIntegerType",
255 "kCFNumberCGFloatType"
256 };
Mike Stump1eb44332009-09-09 15:08:12 +0000257
Ted Kremenek04bc8762008-06-26 23:59:48 +0000258 return i <= kCFNumberCGFloatType ? Names[i-1] : "Invalid CFNumberType";
259}
260#endif
261
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000262void CFNumberCreateChecker::PreVisitCallExpr(CheckerContext &C,
263 const CallExpr *CE)
264{
Mike Stump1eb44332009-09-09 15:08:12 +0000265 const Expr* Callee = CE->getCallee();
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000266 const GRState *state = C.getState();
267 SVal CallV = state->getSVal(Callee);
Zhongxing Xu369f4472009-04-20 05:24:46 +0000268 const FunctionDecl* FD = CallV.getAsFunctionDecl();
Ted Kremenek04bc8762008-06-26 23:59:48 +0000269
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000270 if (!FD)
271 return;
272
273 ASTContext &Ctx = C.getASTContext();
274 if (!II)
275 II = &Ctx.Idents.get("CFNumberCreate");
276
277 if (FD->getIdentifier() != II || CE->getNumArgs() != 3)
278 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000279
Ted Kremenek04bc8762008-06-26 23:59:48 +0000280 // Get the value of the "theType" argument.
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000281 SVal TheTypeVal = state->getSVal(CE->getArg(1));
Mike Stump1eb44332009-09-09 15:08:12 +0000282
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000283 // FIXME: We really should allow ranges of valid theType values, and
284 // bifurcate the state appropriately.
Zhongxing Xu1c96b242008-10-17 05:57:07 +0000285 nonloc::ConcreteInt* V = dyn_cast<nonloc::ConcreteInt>(&TheTypeVal);
Ted Kremenek04bc8762008-06-26 23:59:48 +0000286 if (!V)
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000287 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000288
Ted Kremenek04bc8762008-06-26 23:59:48 +0000289 uint64_t NumberKind = V->getValue().getLimitedValue();
290 Optional<uint64_t> TargetSize = GetCFNumberSize(Ctx, NumberKind);
Mike Stump1eb44332009-09-09 15:08:12 +0000291
Ted Kremenek04bc8762008-06-26 23:59:48 +0000292 // FIXME: In some cases we can emit an error.
293 if (!TargetSize.isKnown())
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000294 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000295
Ted Kremenek04bc8762008-06-26 23:59:48 +0000296 // Look at the value of the integer being passed by reference. Essentially
297 // we want to catch cases where the value passed in is not equal to the
298 // size of the type being created.
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000299 SVal TheValueExpr = state->getSVal(CE->getArg(2));
Mike Stump1eb44332009-09-09 15:08:12 +0000300
Ted Kremenek04bc8762008-06-26 23:59:48 +0000301 // FIXME: Eventually we should handle arbitrary locations. We can do this
302 // by having an enhanced memory model that does low-level typing.
Zhongxing Xu1c96b242008-10-17 05:57:07 +0000303 loc::MemRegionVal* LV = dyn_cast<loc::MemRegionVal>(&TheValueExpr);
Ted Kremenek04bc8762008-06-26 23:59:48 +0000304 if (!LV)
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000305 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000306
Zhongxing Xu479529e2009-11-10 02:17:20 +0000307 const TypedRegion* R = dyn_cast<TypedRegion>(LV->StripCasts());
Ted Kremenek5e77eba2009-07-29 18:17:40 +0000308 if (!R)
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000309 return;
Ted Kremenek5e77eba2009-07-29 18:17:40 +0000310
Zhongxing Xu018220c2010-08-11 06:10:55 +0000311 QualType T = Ctx.getCanonicalType(R->getValueType());
Mike Stump1eb44332009-09-09 15:08:12 +0000312
Ted Kremenek04bc8762008-06-26 23:59:48 +0000313 // FIXME: If the pointee isn't an integer type, should we flag a warning?
314 // People can do weird stuff with pointers.
Mike Stump1eb44332009-09-09 15:08:12 +0000315
316 if (!T->isIntegerType())
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000317 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000318
Ted Kremenek04bc8762008-06-26 23:59:48 +0000319 uint64_t SourceSize = Ctx.getTypeSize(T);
Mike Stump1eb44332009-09-09 15:08:12 +0000320
Ted Kremenek04bc8762008-06-26 23:59:48 +0000321 // CHECK: is SourceSize == TargetSize
Ted Kremenek04bc8762008-06-26 23:59:48 +0000322 if (SourceSize == TargetSize)
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000323 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000324
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000325 // Generate an error. Only generate a sink if 'SourceSize < TargetSize';
326 // otherwise generate a regular node.
327 //
Ted Kremenek04bc8762008-06-26 23:59:48 +0000328 // FIXME: We can actually create an abstract "CFNumber" object that has
329 // the bits initialized to the provided values.
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000330 //
331 if (ExplodedNode *N = SourceSize < TargetSize ? C.GenerateSink()
332 : C.GenerateNode()) {
333 llvm::SmallString<128> sbuf;
334 llvm::raw_svector_ostream os(sbuf);
335
336 os << (SourceSize == 8 ? "An " : "A ")
337 << SourceSize << " bit integer is used to initialize a CFNumber "
338 "object that represents "
339 << (TargetSize == 8 ? "an " : "a ")
340 << TargetSize << " bit integer. ";
341
342 if (SourceSize < TargetSize)
343 os << (TargetSize - SourceSize)
344 << " bits of the CFNumber value will be garbage." ;
345 else
346 os << (SourceSize - TargetSize)
347 << " bits of the input integer will be lost.";
Ted Kremenek04bc8762008-06-26 23:59:48 +0000348
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000349 if (!BT)
350 BT = new APIMisuse("Bad use of CFNumberCreate");
351
352 RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
353 report->addRange(CE->getArg(2)->getSourceRange());
354 C.EmitReport(report);
355 }
Ted Kremenek04bc8762008-06-26 23:59:48 +0000356}
357
Ted Kremenek78d46242008-07-22 16:21:24 +0000358//===----------------------------------------------------------------------===//
Jordy Rose61fb55c2010-07-06 02:34:42 +0000359// CFRetain/CFRelease checking for null arguments.
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000360//===----------------------------------------------------------------------===//
361
362namespace {
Jordy Rose61fb55c2010-07-06 02:34:42 +0000363class CFRetainReleaseChecker : public CheckerVisitor<CFRetainReleaseChecker> {
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000364 APIMisuse *BT;
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000365 IdentifierInfo *Retain, *Release;
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000366public:
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000367 CFRetainReleaseChecker(): BT(0), Retain(0), Release(0) {}
Jordy Rose61fb55c2010-07-06 02:34:42 +0000368 static void *getTag() { static int x = 0; return &x; }
Jordy Rose61fb55c2010-07-06 02:34:42 +0000369 void PreVisitCallExpr(CheckerContext& C, const CallExpr* CE);
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000370};
371} // end anonymous namespace
372
373
Jordy Rose61fb55c2010-07-06 02:34:42 +0000374void CFRetainReleaseChecker::PreVisitCallExpr(CheckerContext& C,
375 const CallExpr* CE) {
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000376 // If the CallExpr doesn't have exactly 1 argument just give up checking.
377 if (CE->getNumArgs() != 1)
Jordy Rose61fb55c2010-07-06 02:34:42 +0000378 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000379
Jordy Rose61fb55c2010-07-06 02:34:42 +0000380 // Get the function declaration of the callee.
381 const GRState* state = C.getState();
Ted Kremenek13976632010-02-08 16:18:51 +0000382 SVal X = state->getSVal(CE->getCallee());
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000383 const FunctionDecl* FD = X.getAsFunctionDecl();
Mike Stump1eb44332009-09-09 15:08:12 +0000384
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000385 if (!FD)
Jordy Rose61fb55c2010-07-06 02:34:42 +0000386 return;
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000387
388 if (!BT) {
389 ASTContext &Ctx = C.getASTContext();
390 Retain = &Ctx.Idents.get("CFRetain");
391 Release = &Ctx.Idents.get("CFRelease");
392 BT = new APIMisuse("null passed to CFRetain/CFRelease");
393 }
Mike Stump1eb44332009-09-09 15:08:12 +0000394
Jordy Rose61fb55c2010-07-06 02:34:42 +0000395 // Check if we called CFRetain/CFRelease.
Mike Stump1eb44332009-09-09 15:08:12 +0000396 const IdentifierInfo *FuncII = FD->getIdentifier();
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000397 if (!(FuncII == Retain || FuncII == Release))
Jordy Rose61fb55c2010-07-06 02:34:42 +0000398 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000399
Jordy Rose61fb55c2010-07-06 02:34:42 +0000400 // FIXME: The rest of this just checks that the argument is non-null.
401 // It should probably be refactored and combined with AttrNonNullChecker.
402
403 // Get the argument's value.
404 const Expr *Arg = CE->getArg(0);
405 SVal ArgVal = state->getSVal(Arg);
406 DefinedSVal *DefArgVal = dyn_cast<DefinedSVal>(&ArgVal);
407 if (!DefArgVal)
408 return;
409
410 // Get a NULL value.
411 ValueManager &ValMgr = C.getValueManager();
412 DefinedSVal Zero = cast<DefinedSVal>(ValMgr.makeZeroVal(Arg->getType()));
413
414 // Make an expression asserting that they're equal.
415 SValuator &SVator = ValMgr.getSValuator();
416 DefinedOrUnknownSVal ArgIsNull = SVator.EvalEQ(state, Zero, *DefArgVal);
417
418 // Are they equal?
419 const GRState *stateTrue, *stateFalse;
420 llvm::tie(stateTrue, stateFalse) = state->Assume(ArgIsNull);
421
422 if (stateTrue && !stateFalse) {
423 ExplodedNode *N = C.GenerateSink(stateTrue);
424 if (!N)
425 return;
426
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000427 const char *description = (FuncII == Retain)
428 ? "Null pointer argument in call to CFRetain"
429 : "Null pointer argument in call to CFRelease";
430
Jordy Rose61fb55c2010-07-06 02:34:42 +0000431 EnhancedBugReport *report = new EnhancedBugReport(*BT, description, N);
432 report->addRange(Arg->getSourceRange());
433 report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Arg);
Jordy Rose61fb55c2010-07-06 02:34:42 +0000434 C.EmitReport(report);
435 return;
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000436 }
437
Jordy Rose61fb55c2010-07-06 02:34:42 +0000438 // From here on, we know the argument is non-null.
439 C.addTransition(stateFalse);
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000440}
441
442//===----------------------------------------------------------------------===//
Ted Kremenek50e837b2009-11-20 05:27:05 +0000443// Check for sending 'retain', 'release', or 'autorelease' directly to a Class.
444//===----------------------------------------------------------------------===//
445
446namespace {
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000447class ClassReleaseChecker : public CheckerVisitor<ClassReleaseChecker> {
Ted Kremenek50e837b2009-11-20 05:27:05 +0000448 Selector releaseS;
449 Selector retainS;
450 Selector autoreleaseS;
451 Selector drainS;
452 BugType *BT;
453public:
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000454 ClassReleaseChecker()
455 : BT(0) {}
Ted Kremenek50e837b2009-11-20 05:27:05 +0000456
457 static void *getTag() { static int x = 0; return &x; }
458
459 void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME);
460};
461}
462
463void ClassReleaseChecker::PreVisitObjCMessageExpr(CheckerContext &C,
464 const ObjCMessageExpr *ME) {
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000465
466 if (!BT) {
467 BT = new APIMisuse("message incorrectly sent to class instead of class "
468 "instance");
469
470 ASTContext &Ctx = C.getASTContext();
471 releaseS = GetNullarySelector("release", Ctx);
472 retainS = GetNullarySelector("retain", Ctx);
473 autoreleaseS = GetNullarySelector("autorelease", Ctx);
474 drainS = GetNullarySelector("drain", Ctx);
475 }
476
Douglas Gregor04badcf2010-04-21 00:45:42 +0000477 ObjCInterfaceDecl *Class = 0;
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000478
Douglas Gregor04badcf2010-04-21 00:45:42 +0000479 switch (ME->getReceiverKind()) {
480 case ObjCMessageExpr::Class:
John McCall506b57e2010-05-17 21:00:27 +0000481 Class = ME->getClassReceiver()->getAs<ObjCObjectType>()->getInterface();
Douglas Gregor04badcf2010-04-21 00:45:42 +0000482 break;
Douglas Gregor04badcf2010-04-21 00:45:42 +0000483 case ObjCMessageExpr::SuperClass:
John McCall506b57e2010-05-17 21:00:27 +0000484 Class = ME->getSuperType()->getAs<ObjCObjectType>()->getInterface();
Douglas Gregor04badcf2010-04-21 00:45:42 +0000485 break;
Douglas Gregor04badcf2010-04-21 00:45:42 +0000486 case ObjCMessageExpr::Instance:
487 case ObjCMessageExpr::SuperInstance:
Ted Kremenek50e837b2009-11-20 05:27:05 +0000488 return;
Douglas Gregor04badcf2010-04-21 00:45:42 +0000489 }
490
Ted Kremenek50e837b2009-11-20 05:27:05 +0000491 Selector S = ME->getSelector();
Benjamin Kramer921ddc42009-11-20 10:03:00 +0000492 if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
Ted Kremenek50e837b2009-11-20 05:27:05 +0000493 return;
494
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000495 if (ExplodedNode *N = C.GenerateNode()) {
496 llvm::SmallString<200> buf;
497 llvm::raw_svector_ostream os(buf);
Ted Kremenek19d67b52009-11-23 22:22:01 +0000498
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000499 os << "The '" << S.getAsString() << "' message should be sent to instances "
500 "of class '" << Class->getName()
501 << "' and not the class directly";
Ted Kremenek50e837b2009-11-20 05:27:05 +0000502
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000503 RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
504 report->addRange(ME->getSourceRange());
505 C.EmitReport(report);
506 }
Ted Kremenek50e837b2009-11-20 05:27:05 +0000507}
508
509//===----------------------------------------------------------------------===//
Ted Kremenek78d46242008-07-22 16:21:24 +0000510// Check registration.
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000511//===----------------------------------------------------------------------===//
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000512
Zhongxing Xu5ab128b2009-08-21 02:18:44 +0000513void clang::RegisterAppleChecks(GRExprEngine& Eng, const Decl &D) {
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000514 Eng.registerCheck(new NilArgChecker());
515 Eng.registerCheck(new CFNumberCreateChecker());
516 RegisterNSErrorChecks(Eng.getBugReporter(), Eng, D);
Ted Kremenek54cb7cc2009-11-03 08:03:59 +0000517 RegisterNSAutoreleasePoolChecks(Eng);
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000518 Eng.registerCheck(new CFRetainReleaseChecker());
519 Eng.registerCheck(new ClassReleaseChecker());
Ted Kremenek78d46242008-07-22 16:21:24 +0000520}