blob: 8e83160a2014aa54aba0e37cdce07c07b6569c06 [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 Kremenek3a8f40e2010-12-23 07:22:02 +000018#include "clang/EntoSA/PathSensitive/ExplodedGraph.h"
19#include "clang/EntoSA/PathSensitive/CheckerVisitor.h"
20#include "clang/EntoSA/PathSensitive/ExprEngine.h"
21#include "clang/EntoSA/PathSensitive/GRState.h"
22#include "clang/EntoSA/BugReporter/BugType.h"
23#include "clang/EntoSA/PathSensitive/MemRegion.h"
24#include "clang/EntoSA/PathSensitive/CheckerVisitor.h"
25#include "clang/EntoSA/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 Kremenek9ef65372010-12-23 07:20:52 +000032using namespace ento;
Ted Kremenek52755612008-03-27 17:17:22 +000033
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000034namespace {
35class APIMisuse : public BugType {
36public:
37 APIMisuse(const char* name) : BugType(name, "API Misuse (Apple)") {}
38};
39} // end anonymous namespace
40
41//===----------------------------------------------------------------------===//
42// Utility functions.
43//===----------------------------------------------------------------------===//
44
Steve Naroff14108da2009-07-10 23:34:53 +000045static const ObjCInterfaceType* GetReceiverType(const ObjCMessageExpr* ME) {
Douglas Gregor04badcf2010-04-21 00:45:42 +000046 QualType T;
47 switch (ME->getReceiverKind()) {
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000048 case ObjCMessageExpr::Instance:
49 T = ME->getInstanceReceiver()->getType();
50 break;
51
52 case ObjCMessageExpr::SuperInstance:
53 T = ME->getSuperType();
54 break;
55
56 case ObjCMessageExpr::Class:
57 case ObjCMessageExpr::SuperClass:
58 return 0;
Douglas Gregor04badcf2010-04-21 00:45:42 +000059 }
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000060
Douglas Gregor04badcf2010-04-21 00:45:42 +000061 if (const ObjCObjectPointerType *PT = T->getAs<ObjCObjectPointerType>())
Steve Naroff14108da2009-07-10 23:34:53 +000062 return PT->getInterfaceType();
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000063
Ted Kremenekc1ff3cd2008-04-30 22:48:21 +000064 return NULL;
Ted Kremenek4ba62832008-03-27 22:05:32 +000065}
66
Steve Naroff14108da2009-07-10 23:34:53 +000067static const char* GetReceiverNameType(const ObjCMessageExpr* ME) {
Daniel Dunbare013d682009-10-18 20:26:12 +000068 if (const ObjCInterfaceType *ReceiverType = GetReceiverType(ME))
69 return ReceiverType->getDecl()->getIdentifier()->getNameStart();
70 return NULL;
Ted Kremenek4ba62832008-03-27 22:05:32 +000071}
Ted Kremenek52755612008-03-27 17:17:22 +000072
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000073static bool isNSString(llvm::StringRef ClassName) {
74 return ClassName == "NSString" || ClassName == "NSMutableString";
Ted Kremenek99c6ad32008-03-27 07:25:52 +000075}
76
Zhongxing Xu1c96b242008-10-17 05:57:07 +000077static inline bool isNil(SVal X) {
Mike Stump1eb44332009-09-09 15:08:12 +000078 return isa<loc::ConcreteInt>(X);
Ted Kremeneke5d5c202008-03-27 21:15:17 +000079}
80
Ted Kremenek99c6ad32008-03-27 07:25:52 +000081//===----------------------------------------------------------------------===//
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000082// NilArgChecker - Check for prohibited nil arguments to ObjC method calls.
Ted Kremenek99c6ad32008-03-27 07:25:52 +000083//===----------------------------------------------------------------------===//
84
Benjamin Kramercb9c0742010-10-22 16:33:16 +000085namespace {
86 class NilArgChecker : public CheckerVisitor<NilArgChecker> {
87 APIMisuse *BT;
88 void WarnNilArg(CheckerContext &C, const ObjCMessageExpr* ME, unsigned Arg);
89 public:
90 NilArgChecker() : BT(0) {}
91 static void *getTag() { static int x = 0; return &x; }
92 void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME);
93 };
94}
Mike Stump1eb44332009-09-09 15:08:12 +000095
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000096void NilArgChecker::WarnNilArg(CheckerContext &C,
97 const clang::ObjCMessageExpr *ME,
98 unsigned int Arg)
99{
100 if (!BT)
101 BT = new APIMisuse("nil argument");
102
Ted Kremenekd048c6e2010-12-20 21:19:09 +0000103 if (ExplodedNode *N = C.generateSink()) {
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000104 llvm::SmallString<128> sbuf;
105 llvm::raw_svector_ostream os(sbuf);
106 os << "Argument to '" << GetReceiverNameType(ME) << "' method '"
107 << ME->getSelector().getAsString() << "' cannot be nil";
Mike Stump1eb44332009-09-09 15:08:12 +0000108
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000109 RangedBugReport *R = new RangedBugReport(*BT, os.str(), N);
110 R->addRange(ME->getArg(Arg)->getSourceRange());
111 C.EmitReport(R);
Ted Kremenek4ba62832008-03-27 22:05:32 +0000112 }
Ted Kremenek4ba62832008-03-27 22:05:32 +0000113}
114
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000115void NilArgChecker::PreVisitObjCMessageExpr(CheckerContext &C,
116 const ObjCMessageExpr *ME)
117{
118 const ObjCInterfaceType *ReceiverType = GetReceiverType(ME);
119 if (!ReceiverType)
120 return;
121
122 if (isNSString(ReceiverType->getDecl()->getIdentifier()->getName())) {
123 Selector S = ME->getSelector();
124
125 if (S.isUnarySelector())
126 return;
127
128 // FIXME: This is going to be really slow doing these checks with
129 // lexical comparisons.
130
131 std::string NameStr = S.getAsString();
132 llvm::StringRef Name(NameStr);
133 assert(!Name.empty());
134
135 // FIXME: Checking for initWithFormat: will not work in most cases
136 // yet because [NSString alloc] returns id, not NSString*. We will
137 // need support for tracking expected-type information in the analyzer
138 // to find these errors.
139 if (Name == "caseInsensitiveCompare:" ||
140 Name == "compare:" ||
141 Name == "compare:options:" ||
142 Name == "compare:options:range:" ||
143 Name == "compare:options:range:locale:" ||
144 Name == "componentsSeparatedByCharactersInSet:" ||
145 Name == "initWithFormat:") {
146 if (isNil(C.getState()->getSVal(ME->getArg(0))))
147 WarnNilArg(C, ME, 0);
148 }
149 }
Ted Kremenek99c6ad32008-03-27 07:25:52 +0000150}
Ted Kremenek04bc8762008-06-26 23:59:48 +0000151
152//===----------------------------------------------------------------------===//
153// Error reporting.
154//===----------------------------------------------------------------------===//
155
156namespace {
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000157class CFNumberCreateChecker : public CheckerVisitor<CFNumberCreateChecker> {
Ted Kremenekcf118d42009-02-04 23:49:09 +0000158 APIMisuse* BT;
Ted Kremenek04bc8762008-06-26 23:59:48 +0000159 IdentifierInfo* II;
Ted Kremenek04bc8762008-06-26 23:59:48 +0000160public:
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000161 CFNumberCreateChecker() : BT(0), II(0) {}
162 ~CFNumberCreateChecker() {}
163 static void *getTag() { static int x = 0; return &x; }
164 void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
Ted Kremenek04bc8762008-06-26 23:59:48 +0000165private:
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000166 void EmitError(const TypedRegion* R, const Expr* Ex,
Mike Stump1eb44332009-09-09 15:08:12 +0000167 uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind);
Ted Kremenek04bc8762008-06-26 23:59:48 +0000168};
169} // end anonymous namespace
170
171enum CFNumberType {
172 kCFNumberSInt8Type = 1,
173 kCFNumberSInt16Type = 2,
174 kCFNumberSInt32Type = 3,
175 kCFNumberSInt64Type = 4,
176 kCFNumberFloat32Type = 5,
177 kCFNumberFloat64Type = 6,
178 kCFNumberCharType = 7,
179 kCFNumberShortType = 8,
180 kCFNumberIntType = 9,
181 kCFNumberLongType = 10,
182 kCFNumberLongLongType = 11,
183 kCFNumberFloatType = 12,
184 kCFNumberDoubleType = 13,
185 kCFNumberCFIndexType = 14,
186 kCFNumberNSIntegerType = 15,
187 kCFNumberCGFloatType = 16
188};
189
190namespace {
191 template<typename T>
192 class Optional {
193 bool IsKnown;
194 T Val;
195 public:
196 Optional() : IsKnown(false), Val(0) {}
197 Optional(const T& val) : IsKnown(true), Val(val) {}
Mike Stump1eb44332009-09-09 15:08:12 +0000198
Ted Kremenek04bc8762008-06-26 23:59:48 +0000199 bool isKnown() const { return IsKnown; }
200
201 const T& getValue() const {
202 assert (isKnown());
203 return Val;
204 }
205
206 operator const T&() const {
207 return getValue();
208 }
209 };
210}
211
212static Optional<uint64_t> GetCFNumberSize(ASTContext& Ctx, uint64_t i) {
Nuno Lopes2550d702009-12-23 17:49:57 +0000213 static const unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 };
Mike Stump1eb44332009-09-09 15:08:12 +0000214
Ted Kremenek04bc8762008-06-26 23:59:48 +0000215 if (i < kCFNumberCharType)
216 return FixedSize[i-1];
Mike Stump1eb44332009-09-09 15:08:12 +0000217
Ted Kremenek04bc8762008-06-26 23:59:48 +0000218 QualType T;
Mike Stump1eb44332009-09-09 15:08:12 +0000219
Ted Kremenek04bc8762008-06-26 23:59:48 +0000220 switch (i) {
221 case kCFNumberCharType: T = Ctx.CharTy; break;
222 case kCFNumberShortType: T = Ctx.ShortTy; break;
223 case kCFNumberIntType: T = Ctx.IntTy; break;
224 case kCFNumberLongType: T = Ctx.LongTy; break;
225 case kCFNumberLongLongType: T = Ctx.LongLongTy; break;
226 case kCFNumberFloatType: T = Ctx.FloatTy; break;
227 case kCFNumberDoubleType: T = Ctx.DoubleTy; break;
228 case kCFNumberCFIndexType:
229 case kCFNumberNSIntegerType:
230 case kCFNumberCGFloatType:
Mike Stump1eb44332009-09-09 15:08:12 +0000231 // FIXME: We need a way to map from names to Type*.
Ted Kremenek04bc8762008-06-26 23:59:48 +0000232 default:
233 return Optional<uint64_t>();
234 }
Mike Stump1eb44332009-09-09 15:08:12 +0000235
Ted Kremenek04bc8762008-06-26 23:59:48 +0000236 return Ctx.getTypeSize(T);
237}
238
239#if 0
240static const char* GetCFNumberTypeStr(uint64_t i) {
241 static const char* Names[] = {
242 "kCFNumberSInt8Type",
243 "kCFNumberSInt16Type",
244 "kCFNumberSInt32Type",
245 "kCFNumberSInt64Type",
246 "kCFNumberFloat32Type",
247 "kCFNumberFloat64Type",
248 "kCFNumberCharType",
249 "kCFNumberShortType",
250 "kCFNumberIntType",
251 "kCFNumberLongType",
252 "kCFNumberLongLongType",
253 "kCFNumberFloatType",
254 "kCFNumberDoubleType",
255 "kCFNumberCFIndexType",
256 "kCFNumberNSIntegerType",
257 "kCFNumberCGFloatType"
258 };
Mike Stump1eb44332009-09-09 15:08:12 +0000259
Ted Kremenek04bc8762008-06-26 23:59:48 +0000260 return i <= kCFNumberCGFloatType ? Names[i-1] : "Invalid CFNumberType";
261}
262#endif
263
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000264void CFNumberCreateChecker::PreVisitCallExpr(CheckerContext &C,
265 const CallExpr *CE)
266{
Mike Stump1eb44332009-09-09 15:08:12 +0000267 const Expr* Callee = CE->getCallee();
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000268 const GRState *state = C.getState();
269 SVal CallV = state->getSVal(Callee);
Zhongxing Xu369f4472009-04-20 05:24:46 +0000270 const FunctionDecl* FD = CallV.getAsFunctionDecl();
Ted Kremenek04bc8762008-06-26 23:59:48 +0000271
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000272 if (!FD)
273 return;
274
275 ASTContext &Ctx = C.getASTContext();
276 if (!II)
277 II = &Ctx.Idents.get("CFNumberCreate");
278
279 if (FD->getIdentifier() != II || CE->getNumArgs() != 3)
280 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000281
Ted Kremenek04bc8762008-06-26 23:59:48 +0000282 // Get the value of the "theType" argument.
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000283 SVal TheTypeVal = state->getSVal(CE->getArg(1));
Mike Stump1eb44332009-09-09 15:08:12 +0000284
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000285 // FIXME: We really should allow ranges of valid theType values, and
286 // bifurcate the state appropriately.
Zhongxing Xu1c96b242008-10-17 05:57:07 +0000287 nonloc::ConcreteInt* V = dyn_cast<nonloc::ConcreteInt>(&TheTypeVal);
Ted Kremenek04bc8762008-06-26 23:59:48 +0000288 if (!V)
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000289 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000290
Ted Kremenek04bc8762008-06-26 23:59:48 +0000291 uint64_t NumberKind = V->getValue().getLimitedValue();
292 Optional<uint64_t> TargetSize = GetCFNumberSize(Ctx, NumberKind);
Mike Stump1eb44332009-09-09 15:08:12 +0000293
Ted Kremenek04bc8762008-06-26 23:59:48 +0000294 // FIXME: In some cases we can emit an error.
295 if (!TargetSize.isKnown())
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000296 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000297
Ted Kremenek04bc8762008-06-26 23:59:48 +0000298 // Look at the value of the integer being passed by reference. Essentially
299 // we want to catch cases where the value passed in is not equal to the
300 // size of the type being created.
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000301 SVal TheValueExpr = state->getSVal(CE->getArg(2));
Mike Stump1eb44332009-09-09 15:08:12 +0000302
Ted Kremenek04bc8762008-06-26 23:59:48 +0000303 // FIXME: Eventually we should handle arbitrary locations. We can do this
304 // by having an enhanced memory model that does low-level typing.
Zhongxing Xu1c96b242008-10-17 05:57:07 +0000305 loc::MemRegionVal* LV = dyn_cast<loc::MemRegionVal>(&TheValueExpr);
Ted Kremenek04bc8762008-06-26 23:59:48 +0000306 if (!LV)
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000307 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000308
Zhongxing Xu479529e2009-11-10 02:17:20 +0000309 const TypedRegion* R = dyn_cast<TypedRegion>(LV->StripCasts());
Ted Kremenek5e77eba2009-07-29 18:17:40 +0000310 if (!R)
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000311 return;
Ted Kremenek5e77eba2009-07-29 18:17:40 +0000312
Zhongxing Xu018220c2010-08-11 06:10:55 +0000313 QualType T = Ctx.getCanonicalType(R->getValueType());
Mike Stump1eb44332009-09-09 15:08:12 +0000314
Ted Kremenek04bc8762008-06-26 23:59:48 +0000315 // FIXME: If the pointee isn't an integer type, should we flag a warning?
316 // People can do weird stuff with pointers.
Mike Stump1eb44332009-09-09 15:08:12 +0000317
318 if (!T->isIntegerType())
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000319 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000320
Ted Kremenek04bc8762008-06-26 23:59:48 +0000321 uint64_t SourceSize = Ctx.getTypeSize(T);
Mike Stump1eb44332009-09-09 15:08:12 +0000322
Ted Kremenek04bc8762008-06-26 23:59:48 +0000323 // CHECK: is SourceSize == TargetSize
Ted Kremenek04bc8762008-06-26 23:59:48 +0000324 if (SourceSize == TargetSize)
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000325 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000326
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000327 // Generate an error. Only generate a sink if 'SourceSize < TargetSize';
328 // otherwise generate a regular node.
329 //
Ted Kremenek04bc8762008-06-26 23:59:48 +0000330 // FIXME: We can actually create an abstract "CFNumber" object that has
331 // the bits initialized to the provided values.
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000332 //
Ted Kremenekd048c6e2010-12-20 21:19:09 +0000333 if (ExplodedNode *N = SourceSize < TargetSize ? C.generateSink()
334 : C.generateNode()) {
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000335 llvm::SmallString<128> sbuf;
336 llvm::raw_svector_ostream os(sbuf);
337
338 os << (SourceSize == 8 ? "An " : "A ")
339 << SourceSize << " bit integer is used to initialize a CFNumber "
340 "object that represents "
341 << (TargetSize == 8 ? "an " : "a ")
342 << TargetSize << " bit integer. ";
343
344 if (SourceSize < TargetSize)
345 os << (TargetSize - SourceSize)
346 << " bits of the CFNumber value will be garbage." ;
347 else
348 os << (SourceSize - TargetSize)
349 << " bits of the input integer will be lost.";
Ted Kremenek04bc8762008-06-26 23:59:48 +0000350
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000351 if (!BT)
352 BT = new APIMisuse("Bad use of CFNumberCreate");
353
354 RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
355 report->addRange(CE->getArg(2)->getSourceRange());
356 C.EmitReport(report);
357 }
Ted Kremenek04bc8762008-06-26 23:59:48 +0000358}
359
Ted Kremenek78d46242008-07-22 16:21:24 +0000360//===----------------------------------------------------------------------===//
Jordy Rose61fb55c2010-07-06 02:34:42 +0000361// CFRetain/CFRelease checking for null arguments.
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000362//===----------------------------------------------------------------------===//
363
364namespace {
Jordy Rose61fb55c2010-07-06 02:34:42 +0000365class CFRetainReleaseChecker : public CheckerVisitor<CFRetainReleaseChecker> {
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000366 APIMisuse *BT;
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000367 IdentifierInfo *Retain, *Release;
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000368public:
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000369 CFRetainReleaseChecker(): BT(0), Retain(0), Release(0) {}
Jordy Rose61fb55c2010-07-06 02:34:42 +0000370 static void *getTag() { static int x = 0; return &x; }
Jordy Rose61fb55c2010-07-06 02:34:42 +0000371 void PreVisitCallExpr(CheckerContext& C, const CallExpr* CE);
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000372};
373} // end anonymous namespace
374
375
Jordy Rose61fb55c2010-07-06 02:34:42 +0000376void CFRetainReleaseChecker::PreVisitCallExpr(CheckerContext& C,
377 const CallExpr* CE) {
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000378 // If the CallExpr doesn't have exactly 1 argument just give up checking.
379 if (CE->getNumArgs() != 1)
Jordy Rose61fb55c2010-07-06 02:34:42 +0000380 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000381
Jordy Rose61fb55c2010-07-06 02:34:42 +0000382 // Get the function declaration of the callee.
383 const GRState* state = C.getState();
Ted Kremenek13976632010-02-08 16:18:51 +0000384 SVal X = state->getSVal(CE->getCallee());
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000385 const FunctionDecl* FD = X.getAsFunctionDecl();
Mike Stump1eb44332009-09-09 15:08:12 +0000386
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000387 if (!FD)
Jordy Rose61fb55c2010-07-06 02:34:42 +0000388 return;
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000389
390 if (!BT) {
391 ASTContext &Ctx = C.getASTContext();
392 Retain = &Ctx.Idents.get("CFRetain");
393 Release = &Ctx.Idents.get("CFRelease");
394 BT = new APIMisuse("null passed to CFRetain/CFRelease");
395 }
Mike Stump1eb44332009-09-09 15:08:12 +0000396
Jordy Rose61fb55c2010-07-06 02:34:42 +0000397 // Check if we called CFRetain/CFRelease.
Mike Stump1eb44332009-09-09 15:08:12 +0000398 const IdentifierInfo *FuncII = FD->getIdentifier();
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000399 if (!(FuncII == Retain || FuncII == Release))
Jordy Rose61fb55c2010-07-06 02:34:42 +0000400 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000401
Jordy Rose61fb55c2010-07-06 02:34:42 +0000402 // FIXME: The rest of this just checks that the argument is non-null.
403 // It should probably be refactored and combined with AttrNonNullChecker.
404
405 // Get the argument's value.
406 const Expr *Arg = CE->getArg(0);
407 SVal ArgVal = state->getSVal(Arg);
408 DefinedSVal *DefArgVal = dyn_cast<DefinedSVal>(&ArgVal);
409 if (!DefArgVal)
410 return;
411
412 // Get a NULL value.
Ted Kremenekc8413fd2010-12-02 07:49:45 +0000413 SValBuilder &svalBuilder = C.getSValBuilder();
414 DefinedSVal zero = cast<DefinedSVal>(svalBuilder.makeZeroVal(Arg->getType()));
Jordy Rose61fb55c2010-07-06 02:34:42 +0000415
416 // Make an expression asserting that they're equal.
Ted Kremenekc8413fd2010-12-02 07:49:45 +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;
Ted Kremenek28f47b92010-12-01 22:16:56 +0000421 llvm::tie(stateTrue, stateFalse) = state->assume(ArgIsNull);
Jordy Rose61fb55c2010-07-06 02:34:42 +0000422
423 if (stateTrue && !stateFalse) {
Ted Kremenekd048c6e2010-12-20 21:19:09 +0000424 ExplodedNode *N = C.generateSink(stateTrue);
Jordy Rose61fb55c2010-07-06 02:34:42 +0000425 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 Kremenekd048c6e2010-12-20 21:19:09 +0000496 if (ExplodedNode *N = C.generateNode()) {
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000497 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
Ted Kremenek9ef65372010-12-23 07:20:52 +0000514void ento::RegisterAppleChecks(ExprEngine& 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}