blob: e002a29379d999656383225ea555e37cfef906be [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
Argyrios Kyrtzidis0b1ba622011-02-16 01:40:52 +000016#include "ClangSACheckers.h"
Argyrios Kyrtzidisec8605f2011-03-01 01:16:21 +000017#include "clang/StaticAnalyzer/Core/Checker.h"
Argyrios Kyrtzidis695fb502011-02-17 21:39:17 +000018#include "clang/StaticAnalyzer/Core/CheckerManager.h"
Argyrios Kyrtzidis983326f2011-02-23 01:05:36 +000019#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
Ted Kremenek9b663712011-02-10 01:03:03 +000020#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
Ted Kremenek9b663712011-02-10 01:03:03 +000021#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
22#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h"
23#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
24#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
Daniel Dunbarc4a1dea2008-08-11 05:35:13 +000025#include "clang/AST/DeclObjC.h"
Ted Kremenek99c6ad32008-03-27 07:25:52 +000026#include "clang/AST/Expr.h"
Steve Narofff494b572008-05-29 21:12:08 +000027#include "clang/AST/ExprObjC.h"
Ted Kremenek99c6ad32008-03-27 07:25:52 +000028#include "clang/AST/ASTContext.h"
Ted Kremenek99c6ad32008-03-27 07:25:52 +000029
Ted Kremenek99c6ad32008-03-27 07:25:52 +000030using namespace clang;
Ted Kremenek9ef65372010-12-23 07:20:52 +000031using namespace ento;
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
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +000044static const ObjCInterfaceType* GetReceiverType(const ObjCMessage &msg) {
45 if (const ObjCInterfaceDecl *ID = msg.getReceiverInterface())
Argyrios Kyrtzidis090c47b2011-01-25 00:03:45 +000046 return ID->getTypeForDecl()->getAs<ObjCInterfaceType>();
Ted Kremenekc1ff3cd2008-04-30 22:48:21 +000047 return NULL;
Ted Kremenek4ba62832008-03-27 22:05:32 +000048}
49
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +000050static const char* GetReceiverNameType(const ObjCMessage &msg) {
51 if (const ObjCInterfaceType *ReceiverType = GetReceiverType(msg))
Daniel Dunbare013d682009-10-18 20:26:12 +000052 return ReceiverType->getDecl()->getIdentifier()->getNameStart();
53 return NULL;
Ted Kremenek4ba62832008-03-27 22:05:32 +000054}
Ted Kremenek52755612008-03-27 17:17:22 +000055
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000056static bool isNSString(llvm::StringRef ClassName) {
57 return ClassName == "NSString" || ClassName == "NSMutableString";
Ted Kremenek99c6ad32008-03-27 07:25:52 +000058}
59
Zhongxing Xu1c96b242008-10-17 05:57:07 +000060static inline bool isNil(SVal X) {
Mike Stump1eb44332009-09-09 15:08:12 +000061 return isa<loc::ConcreteInt>(X);
Ted Kremeneke5d5c202008-03-27 21:15:17 +000062}
63
Ted Kremenek99c6ad32008-03-27 07:25:52 +000064//===----------------------------------------------------------------------===//
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000065// NilArgChecker - Check for prohibited nil arguments to ObjC method calls.
Ted Kremenek99c6ad32008-03-27 07:25:52 +000066//===----------------------------------------------------------------------===//
67
Benjamin Kramercb9c0742010-10-22 16:33:16 +000068namespace {
Argyrios Kyrtzidisec8605f2011-03-01 01:16:21 +000069 class NilArgChecker : public Checker<check::PreObjCMessage> {
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +000070 mutable llvm::OwningPtr<APIMisuse> BT;
71
72 void WarnNilArg(CheckerContext &C,
73 const ObjCMessage &msg, unsigned Arg) const;
74
Benjamin Kramercb9c0742010-10-22 16:33:16 +000075 public:
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +000076 void checkPreObjCMessage(ObjCMessage msg, CheckerContext &C) const;
Benjamin Kramercb9c0742010-10-22 16:33:16 +000077 };
78}
Mike Stump1eb44332009-09-09 15:08:12 +000079
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000080void NilArgChecker::WarnNilArg(CheckerContext &C,
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +000081 const ObjCMessage &msg,
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +000082 unsigned int Arg) const
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000083{
84 if (!BT)
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +000085 BT.reset(new APIMisuse("nil argument"));
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000086
Ted Kremenekd048c6e2010-12-20 21:19:09 +000087 if (ExplodedNode *N = C.generateSink()) {
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000088 llvm::SmallString<128> sbuf;
89 llvm::raw_svector_ostream os(sbuf);
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +000090 os << "Argument to '" << GetReceiverNameType(msg) << "' method '"
91 << msg.getSelector().getAsString() << "' cannot be nil";
Mike Stump1eb44332009-09-09 15:08:12 +000092
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000093 RangedBugReport *R = new RangedBugReport(*BT, os.str(), N);
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +000094 R->addRange(msg.getArgSourceRange(Arg));
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000095 C.EmitReport(R);
Ted Kremenek4ba62832008-03-27 22:05:32 +000096 }
Ted Kremenek4ba62832008-03-27 22:05:32 +000097}
98
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +000099void NilArgChecker::checkPreObjCMessage(ObjCMessage msg,
100 CheckerContext &C) const {
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +0000101 const ObjCInterfaceType *ReceiverType = GetReceiverType(msg);
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000102 if (!ReceiverType)
103 return;
104
105 if (isNSString(ReceiverType->getDecl()->getIdentifier()->getName())) {
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +0000106 Selector S = msg.getSelector();
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000107
108 if (S.isUnarySelector())
109 return;
110
111 // FIXME: This is going to be really slow doing these checks with
112 // lexical comparisons.
113
114 std::string NameStr = S.getAsString();
115 llvm::StringRef Name(NameStr);
116 assert(!Name.empty());
117
118 // FIXME: Checking for initWithFormat: will not work in most cases
119 // yet because [NSString alloc] returns id, not NSString*. We will
120 // need support for tracking expected-type information in the analyzer
121 // to find these errors.
122 if (Name == "caseInsensitiveCompare:" ||
123 Name == "compare:" ||
124 Name == "compare:options:" ||
125 Name == "compare:options:range:" ||
126 Name == "compare:options:range:locale:" ||
127 Name == "componentsSeparatedByCharactersInSet:" ||
128 Name == "initWithFormat:") {
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +0000129 if (isNil(msg.getArgSVal(0, C.getState())))
130 WarnNilArg(C, msg, 0);
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000131 }
132 }
Ted Kremenek99c6ad32008-03-27 07:25:52 +0000133}
Ted Kremenek04bc8762008-06-26 23:59:48 +0000134
135//===----------------------------------------------------------------------===//
136// Error reporting.
137//===----------------------------------------------------------------------===//
138
139namespace {
Argyrios Kyrtzidisec8605f2011-03-01 01:16:21 +0000140class CFNumberCreateChecker : public Checker< check::PreStmt<CallExpr> > {
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000141 mutable llvm::OwningPtr<APIMisuse> BT;
142 mutable IdentifierInfo* II;
Ted Kremenek04bc8762008-06-26 23:59:48 +0000143public:
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000144 CFNumberCreateChecker() : II(0) {}
145
146 void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
147
Ted Kremenek04bc8762008-06-26 23:59:48 +0000148private:
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000149 void EmitError(const TypedRegion* R, const Expr* Ex,
Mike Stump1eb44332009-09-09 15:08:12 +0000150 uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind);
Ted Kremenek04bc8762008-06-26 23:59:48 +0000151};
152} // end anonymous namespace
153
154enum CFNumberType {
155 kCFNumberSInt8Type = 1,
156 kCFNumberSInt16Type = 2,
157 kCFNumberSInt32Type = 3,
158 kCFNumberSInt64Type = 4,
159 kCFNumberFloat32Type = 5,
160 kCFNumberFloat64Type = 6,
161 kCFNumberCharType = 7,
162 kCFNumberShortType = 8,
163 kCFNumberIntType = 9,
164 kCFNumberLongType = 10,
165 kCFNumberLongLongType = 11,
166 kCFNumberFloatType = 12,
167 kCFNumberDoubleType = 13,
168 kCFNumberCFIndexType = 14,
169 kCFNumberNSIntegerType = 15,
170 kCFNumberCGFloatType = 16
171};
172
173namespace {
174 template<typename T>
175 class Optional {
176 bool IsKnown;
177 T Val;
178 public:
179 Optional() : IsKnown(false), Val(0) {}
180 Optional(const T& val) : IsKnown(true), Val(val) {}
Mike Stump1eb44332009-09-09 15:08:12 +0000181
Ted Kremenek04bc8762008-06-26 23:59:48 +0000182 bool isKnown() const { return IsKnown; }
183
184 const T& getValue() const {
185 assert (isKnown());
186 return Val;
187 }
188
189 operator const T&() const {
190 return getValue();
191 }
192 };
193}
194
195static Optional<uint64_t> GetCFNumberSize(ASTContext& Ctx, uint64_t i) {
Nuno Lopes2550d702009-12-23 17:49:57 +0000196 static const unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 };
Mike Stump1eb44332009-09-09 15:08:12 +0000197
Ted Kremenek04bc8762008-06-26 23:59:48 +0000198 if (i < kCFNumberCharType)
199 return FixedSize[i-1];
Mike Stump1eb44332009-09-09 15:08:12 +0000200
Ted Kremenek04bc8762008-06-26 23:59:48 +0000201 QualType T;
Mike Stump1eb44332009-09-09 15:08:12 +0000202
Ted Kremenek04bc8762008-06-26 23:59:48 +0000203 switch (i) {
204 case kCFNumberCharType: T = Ctx.CharTy; break;
205 case kCFNumberShortType: T = Ctx.ShortTy; break;
206 case kCFNumberIntType: T = Ctx.IntTy; break;
207 case kCFNumberLongType: T = Ctx.LongTy; break;
208 case kCFNumberLongLongType: T = Ctx.LongLongTy; break;
209 case kCFNumberFloatType: T = Ctx.FloatTy; break;
210 case kCFNumberDoubleType: T = Ctx.DoubleTy; break;
211 case kCFNumberCFIndexType:
212 case kCFNumberNSIntegerType:
213 case kCFNumberCGFloatType:
Mike Stump1eb44332009-09-09 15:08:12 +0000214 // FIXME: We need a way to map from names to Type*.
Ted Kremenek04bc8762008-06-26 23:59:48 +0000215 default:
216 return Optional<uint64_t>();
217 }
Mike Stump1eb44332009-09-09 15:08:12 +0000218
Ted Kremenek04bc8762008-06-26 23:59:48 +0000219 return Ctx.getTypeSize(T);
220}
221
222#if 0
223static const char* GetCFNumberTypeStr(uint64_t i) {
224 static const char* Names[] = {
225 "kCFNumberSInt8Type",
226 "kCFNumberSInt16Type",
227 "kCFNumberSInt32Type",
228 "kCFNumberSInt64Type",
229 "kCFNumberFloat32Type",
230 "kCFNumberFloat64Type",
231 "kCFNumberCharType",
232 "kCFNumberShortType",
233 "kCFNumberIntType",
234 "kCFNumberLongType",
235 "kCFNumberLongLongType",
236 "kCFNumberFloatType",
237 "kCFNumberDoubleType",
238 "kCFNumberCFIndexType",
239 "kCFNumberNSIntegerType",
240 "kCFNumberCGFloatType"
241 };
Mike Stump1eb44332009-09-09 15:08:12 +0000242
Ted Kremenek04bc8762008-06-26 23:59:48 +0000243 return i <= kCFNumberCGFloatType ? Names[i-1] : "Invalid CFNumberType";
244}
245#endif
246
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000247void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE,
248 CheckerContext &C) const {
Mike Stump1eb44332009-09-09 15:08:12 +0000249 const Expr* Callee = CE->getCallee();
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000250 const GRState *state = C.getState();
251 SVal CallV = state->getSVal(Callee);
Zhongxing Xu369f4472009-04-20 05:24:46 +0000252 const FunctionDecl* FD = CallV.getAsFunctionDecl();
Ted Kremenek04bc8762008-06-26 23:59:48 +0000253
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000254 if (!FD)
255 return;
256
257 ASTContext &Ctx = C.getASTContext();
258 if (!II)
259 II = &Ctx.Idents.get("CFNumberCreate");
260
261 if (FD->getIdentifier() != II || CE->getNumArgs() != 3)
262 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000263
Ted Kremenek04bc8762008-06-26 23:59:48 +0000264 // Get the value of the "theType" argument.
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000265 SVal TheTypeVal = state->getSVal(CE->getArg(1));
Mike Stump1eb44332009-09-09 15:08:12 +0000266
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000267 // FIXME: We really should allow ranges of valid theType values, and
268 // bifurcate the state appropriately.
Zhongxing Xu1c96b242008-10-17 05:57:07 +0000269 nonloc::ConcreteInt* V = dyn_cast<nonloc::ConcreteInt>(&TheTypeVal);
Ted Kremenek04bc8762008-06-26 23:59:48 +0000270 if (!V)
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000271 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000272
Ted Kremenek04bc8762008-06-26 23:59:48 +0000273 uint64_t NumberKind = V->getValue().getLimitedValue();
274 Optional<uint64_t> TargetSize = GetCFNumberSize(Ctx, NumberKind);
Mike Stump1eb44332009-09-09 15:08:12 +0000275
Ted Kremenek04bc8762008-06-26 23:59:48 +0000276 // FIXME: In some cases we can emit an error.
277 if (!TargetSize.isKnown())
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000278 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000279
Ted Kremenek04bc8762008-06-26 23:59:48 +0000280 // Look at the value of the integer being passed by reference. Essentially
281 // we want to catch cases where the value passed in is not equal to the
282 // size of the type being created.
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000283 SVal TheValueExpr = state->getSVal(CE->getArg(2));
Mike Stump1eb44332009-09-09 15:08:12 +0000284
Ted Kremenek04bc8762008-06-26 23:59:48 +0000285 // FIXME: Eventually we should handle arbitrary locations. We can do this
286 // by having an enhanced memory model that does low-level typing.
Zhongxing Xu1c96b242008-10-17 05:57:07 +0000287 loc::MemRegionVal* LV = dyn_cast<loc::MemRegionVal>(&TheValueExpr);
Ted Kremenek04bc8762008-06-26 23:59:48 +0000288 if (!LV)
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000289 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000290
Zhanyong Wan7dfc9422011-02-16 21:13:32 +0000291 const TypedRegion* R = dyn_cast<TypedRegion>(LV->stripCasts());
Ted Kremenek5e77eba2009-07-29 18:17:40 +0000292 if (!R)
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000293 return;
Ted Kremenek5e77eba2009-07-29 18:17:40 +0000294
Zhongxing Xu018220c2010-08-11 06:10:55 +0000295 QualType T = Ctx.getCanonicalType(R->getValueType());
Mike Stump1eb44332009-09-09 15:08:12 +0000296
Ted Kremenek04bc8762008-06-26 23:59:48 +0000297 // FIXME: If the pointee isn't an integer type, should we flag a warning?
298 // People can do weird stuff with pointers.
Mike Stump1eb44332009-09-09 15:08:12 +0000299
300 if (!T->isIntegerType())
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000301 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000302
Ted Kremenek04bc8762008-06-26 23:59:48 +0000303 uint64_t SourceSize = Ctx.getTypeSize(T);
Mike Stump1eb44332009-09-09 15:08:12 +0000304
Ted Kremenek04bc8762008-06-26 23:59:48 +0000305 // CHECK: is SourceSize == TargetSize
Ted Kremenek04bc8762008-06-26 23:59:48 +0000306 if (SourceSize == TargetSize)
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000307 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000308
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000309 // Generate an error. Only generate a sink if 'SourceSize < TargetSize';
310 // otherwise generate a regular node.
311 //
Ted Kremenek04bc8762008-06-26 23:59:48 +0000312 // FIXME: We can actually create an abstract "CFNumber" object that has
313 // the bits initialized to the provided values.
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000314 //
Ted Kremenekd048c6e2010-12-20 21:19:09 +0000315 if (ExplodedNode *N = SourceSize < TargetSize ? C.generateSink()
316 : C.generateNode()) {
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000317 llvm::SmallString<128> sbuf;
318 llvm::raw_svector_ostream os(sbuf);
319
320 os << (SourceSize == 8 ? "An " : "A ")
321 << SourceSize << " bit integer is used to initialize a CFNumber "
322 "object that represents "
323 << (TargetSize == 8 ? "an " : "a ")
324 << TargetSize << " bit integer. ";
325
326 if (SourceSize < TargetSize)
327 os << (TargetSize - SourceSize)
328 << " bits of the CFNumber value will be garbage." ;
329 else
330 os << (SourceSize - TargetSize)
331 << " bits of the input integer will be lost.";
Ted Kremenek04bc8762008-06-26 23:59:48 +0000332
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000333 if (!BT)
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000334 BT.reset(new APIMisuse("Bad use of CFNumberCreate"));
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000335
336 RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
337 report->addRange(CE->getArg(2)->getSourceRange());
338 C.EmitReport(report);
339 }
Ted Kremenek04bc8762008-06-26 23:59:48 +0000340}
341
Ted Kremenek78d46242008-07-22 16:21:24 +0000342//===----------------------------------------------------------------------===//
Jordy Rose61fb55c2010-07-06 02:34:42 +0000343// CFRetain/CFRelease checking for null arguments.
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000344//===----------------------------------------------------------------------===//
345
346namespace {
Argyrios Kyrtzidisec8605f2011-03-01 01:16:21 +0000347class CFRetainReleaseChecker : public Checker< check::PreStmt<CallExpr> > {
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000348 mutable llvm::OwningPtr<APIMisuse> BT;
349 mutable IdentifierInfo *Retain, *Release;
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000350public:
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000351 CFRetainReleaseChecker(): Retain(0), Release(0) {}
352 void checkPreStmt(const CallExpr* CE, CheckerContext& C) const;
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000353};
354} // end anonymous namespace
355
356
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000357void CFRetainReleaseChecker::checkPreStmt(const CallExpr* CE,
358 CheckerContext& C) const {
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000359 // If the CallExpr doesn't have exactly 1 argument just give up checking.
360 if (CE->getNumArgs() != 1)
Jordy Rose61fb55c2010-07-06 02:34:42 +0000361 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000362
Jordy Rose61fb55c2010-07-06 02:34:42 +0000363 // Get the function declaration of the callee.
364 const GRState* state = C.getState();
Ted Kremenek13976632010-02-08 16:18:51 +0000365 SVal X = state->getSVal(CE->getCallee());
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000366 const FunctionDecl* FD = X.getAsFunctionDecl();
Mike Stump1eb44332009-09-09 15:08:12 +0000367
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000368 if (!FD)
Jordy Rose61fb55c2010-07-06 02:34:42 +0000369 return;
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000370
371 if (!BT) {
372 ASTContext &Ctx = C.getASTContext();
373 Retain = &Ctx.Idents.get("CFRetain");
374 Release = &Ctx.Idents.get("CFRelease");
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000375 BT.reset(new APIMisuse("null passed to CFRetain/CFRelease"));
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000376 }
Mike Stump1eb44332009-09-09 15:08:12 +0000377
Jordy Rose61fb55c2010-07-06 02:34:42 +0000378 // Check if we called CFRetain/CFRelease.
Mike Stump1eb44332009-09-09 15:08:12 +0000379 const IdentifierInfo *FuncII = FD->getIdentifier();
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000380 if (!(FuncII == Retain || FuncII == Release))
Jordy Rose61fb55c2010-07-06 02:34:42 +0000381 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000382
Jordy Rose61fb55c2010-07-06 02:34:42 +0000383 // FIXME: The rest of this just checks that the argument is non-null.
384 // It should probably be refactored and combined with AttrNonNullChecker.
385
386 // Get the argument's value.
387 const Expr *Arg = CE->getArg(0);
388 SVal ArgVal = state->getSVal(Arg);
389 DefinedSVal *DefArgVal = dyn_cast<DefinedSVal>(&ArgVal);
390 if (!DefArgVal)
391 return;
392
393 // Get a NULL value.
Ted Kremenekc8413fd2010-12-02 07:49:45 +0000394 SValBuilder &svalBuilder = C.getSValBuilder();
395 DefinedSVal zero = cast<DefinedSVal>(svalBuilder.makeZeroVal(Arg->getType()));
Jordy Rose61fb55c2010-07-06 02:34:42 +0000396
397 // Make an expression asserting that they're equal.
Ted Kremenekc8413fd2010-12-02 07:49:45 +0000398 DefinedOrUnknownSVal ArgIsNull = svalBuilder.evalEQ(state, zero, *DefArgVal);
Jordy Rose61fb55c2010-07-06 02:34:42 +0000399
400 // Are they equal?
401 const GRState *stateTrue, *stateFalse;
Ted Kremenek28f47b92010-12-01 22:16:56 +0000402 llvm::tie(stateTrue, stateFalse) = state->assume(ArgIsNull);
Jordy Rose61fb55c2010-07-06 02:34:42 +0000403
404 if (stateTrue && !stateFalse) {
Ted Kremenekd048c6e2010-12-20 21:19:09 +0000405 ExplodedNode *N = C.generateSink(stateTrue);
Jordy Rose61fb55c2010-07-06 02:34:42 +0000406 if (!N)
407 return;
408
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000409 const char *description = (FuncII == Retain)
410 ? "Null pointer argument in call to CFRetain"
411 : "Null pointer argument in call to CFRelease";
412
Jordy Rose61fb55c2010-07-06 02:34:42 +0000413 EnhancedBugReport *report = new EnhancedBugReport(*BT, description, N);
414 report->addRange(Arg->getSourceRange());
415 report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Arg);
Jordy Rose61fb55c2010-07-06 02:34:42 +0000416 C.EmitReport(report);
417 return;
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000418 }
419
Jordy Rose61fb55c2010-07-06 02:34:42 +0000420 // From here on, we know the argument is non-null.
421 C.addTransition(stateFalse);
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000422}
423
424//===----------------------------------------------------------------------===//
Ted Kremenek50e837b2009-11-20 05:27:05 +0000425// Check for sending 'retain', 'release', or 'autorelease' directly to a Class.
426//===----------------------------------------------------------------------===//
427
428namespace {
Argyrios Kyrtzidisec8605f2011-03-01 01:16:21 +0000429class ClassReleaseChecker : public Checker<check::PreObjCMessage> {
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000430 mutable Selector releaseS;
431 mutable Selector retainS;
432 mutable Selector autoreleaseS;
433 mutable Selector drainS;
434 mutable llvm::OwningPtr<BugType> BT;
Ted Kremenek50e837b2009-11-20 05:27:05 +0000435
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000436public:
437 void checkPreObjCMessage(ObjCMessage msg, CheckerContext &C) const;
Ted Kremenek50e837b2009-11-20 05:27:05 +0000438};
439}
440
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000441void ClassReleaseChecker::checkPreObjCMessage(ObjCMessage msg,
442 CheckerContext &C) const {
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000443
444 if (!BT) {
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000445 BT.reset(new APIMisuse("message incorrectly sent to class instead of class "
446 "instance"));
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000447
448 ASTContext &Ctx = C.getASTContext();
449 releaseS = GetNullarySelector("release", Ctx);
450 retainS = GetNullarySelector("retain", Ctx);
451 autoreleaseS = GetNullarySelector("autorelease", Ctx);
452 drainS = GetNullarySelector("drain", Ctx);
453 }
454
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +0000455 if (msg.isInstanceMessage())
Ted Kremenek50e837b2009-11-20 05:27:05 +0000456 return;
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +0000457 const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
458 assert(Class);
Douglas Gregor04badcf2010-04-21 00:45:42 +0000459
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +0000460 Selector S = msg.getSelector();
Benjamin Kramer921ddc42009-11-20 10:03:00 +0000461 if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
Ted Kremenek50e837b2009-11-20 05:27:05 +0000462 return;
463
Ted Kremenekd048c6e2010-12-20 21:19:09 +0000464 if (ExplodedNode *N = C.generateNode()) {
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000465 llvm::SmallString<200> buf;
466 llvm::raw_svector_ostream os(buf);
Ted Kremenek19d67b52009-11-23 22:22:01 +0000467
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000468 os << "The '" << S.getAsString() << "' message should be sent to instances "
469 "of class '" << Class->getName()
470 << "' and not the class directly";
Ted Kremenek50e837b2009-11-20 05:27:05 +0000471
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000472 RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +0000473 report->addRange(msg.getSourceRange());
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000474 C.EmitReport(report);
475 }
Ted Kremenek50e837b2009-11-20 05:27:05 +0000476}
477
478//===----------------------------------------------------------------------===//
Ted Kremenek78d46242008-07-22 16:21:24 +0000479// Check registration.
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000480//===----------------------------------------------------------------------===//
Argyrios Kyrtzidis0b1ba622011-02-16 01:40:52 +0000481
Argyrios Kyrtzidis695fb502011-02-17 21:39:17 +0000482void ento::registerNilArgChecker(CheckerManager &mgr) {
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000483 mgr.registerChecker<NilArgChecker>();
Argyrios Kyrtzidis0b1ba622011-02-16 01:40:52 +0000484}
485
Argyrios Kyrtzidis695fb502011-02-17 21:39:17 +0000486void ento::registerCFNumberCreateChecker(CheckerManager &mgr) {
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000487 mgr.registerChecker<CFNumberCreateChecker>();
Argyrios Kyrtzidis0b1ba622011-02-16 01:40:52 +0000488}
489
Argyrios Kyrtzidis695fb502011-02-17 21:39:17 +0000490void ento::registerCFRetainReleaseChecker(CheckerManager &mgr) {
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000491 mgr.registerChecker<CFRetainReleaseChecker>();
Ted Kremenek78d46242008-07-22 16:21:24 +0000492}
Argyrios Kyrtzidis695fb502011-02-17 21:39:17 +0000493
494void ento::registerClassReleaseChecker(CheckerManager &mgr) {
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000495 mgr.registerChecker<ClassReleaseChecker>();
Argyrios Kyrtzidis695fb502011-02-17 21:39:17 +0000496}