blob: f7a1ebe3863e4a3792212a33aa6e0f0dd1088ce7 [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 char* GetReceiverNameType(const ObjCMessage &msg) {
Anders Carlssonb62bdce2011-03-08 20:05:26 +000045 if (const ObjCInterfaceDecl *ID = msg.getReceiverInterface())
46 return ID->getIdentifier()->getNameStart();
47 return 0;
Ted Kremenek4ba62832008-03-27 22:05:32 +000048}
Ted Kremenek52755612008-03-27 17:17:22 +000049
Anders Carlssonb62bdce2011-03-08 20:05:26 +000050static bool isReceiverClassOrSuperclass(const ObjCInterfaceDecl *ID,
51 llvm::StringRef ClassName) {
52 if (ID->getIdentifier()->getName() == ClassName)
53 return true;
54
55 if (const ObjCInterfaceDecl *Super = ID->getSuperClass())
56 return isReceiverClassOrSuperclass(Super, ClassName);
57
58 return false;
Ted Kremenek99c6ad32008-03-27 07:25:52 +000059}
60
Zhongxing Xu1c96b242008-10-17 05:57:07 +000061static inline bool isNil(SVal X) {
Mike Stump1eb44332009-09-09 15:08:12 +000062 return isa<loc::ConcreteInt>(X);
Ted Kremeneke5d5c202008-03-27 21:15:17 +000063}
64
Ted Kremenek99c6ad32008-03-27 07:25:52 +000065//===----------------------------------------------------------------------===//
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000066// NilArgChecker - Check for prohibited nil arguments to ObjC method calls.
Ted Kremenek99c6ad32008-03-27 07:25:52 +000067//===----------------------------------------------------------------------===//
68
Benjamin Kramercb9c0742010-10-22 16:33:16 +000069namespace {
Argyrios Kyrtzidisec8605f2011-03-01 01:16:21 +000070 class NilArgChecker : public Checker<check::PreObjCMessage> {
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +000071 mutable llvm::OwningPtr<APIMisuse> BT;
72
73 void WarnNilArg(CheckerContext &C,
74 const ObjCMessage &msg, unsigned Arg) const;
75
Benjamin Kramercb9c0742010-10-22 16:33:16 +000076 public:
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +000077 void checkPreObjCMessage(ObjCMessage msg, CheckerContext &C) const;
Benjamin Kramercb9c0742010-10-22 16:33:16 +000078 };
79}
Mike Stump1eb44332009-09-09 15:08:12 +000080
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000081void NilArgChecker::WarnNilArg(CheckerContext &C,
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +000082 const ObjCMessage &msg,
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +000083 unsigned int Arg) const
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000084{
85 if (!BT)
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +000086 BT.reset(new APIMisuse("nil argument"));
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000087
Ted Kremenekd048c6e2010-12-20 21:19:09 +000088 if (ExplodedNode *N = C.generateSink()) {
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000089 llvm::SmallString<128> sbuf;
90 llvm::raw_svector_ostream os(sbuf);
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +000091 os << "Argument to '" << GetReceiverNameType(msg) << "' method '"
92 << msg.getSelector().getAsString() << "' cannot be nil";
Mike Stump1eb44332009-09-09 15:08:12 +000093
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000094 RangedBugReport *R = new RangedBugReport(*BT, os.str(), N);
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +000095 R->addRange(msg.getArgSourceRange(Arg));
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000096 C.EmitReport(R);
Ted Kremenek4ba62832008-03-27 22:05:32 +000097 }
Ted Kremenek4ba62832008-03-27 22:05:32 +000098}
99
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000100void NilArgChecker::checkPreObjCMessage(ObjCMessage msg,
101 CheckerContext &C) const {
Anders Carlssonb62bdce2011-03-08 20:05:26 +0000102 const ObjCInterfaceDecl *ID = msg.getReceiverInterface();
103 if (!ID)
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000104 return;
105
Anders Carlssonb62bdce2011-03-08 20:05:26 +0000106 if (isReceiverClassOrSuperclass(ID, "NSString")) {
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +0000107 Selector S = msg.getSelector();
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000108
109 if (S.isUnarySelector())
110 return;
111
112 // FIXME: This is going to be really slow doing these checks with
113 // lexical comparisons.
114
115 std::string NameStr = S.getAsString();
116 llvm::StringRef Name(NameStr);
117 assert(!Name.empty());
118
119 // FIXME: Checking for initWithFormat: will not work in most cases
120 // yet because [NSString alloc] returns id, not NSString*. We will
121 // need support for tracking expected-type information in the analyzer
122 // to find these errors.
123 if (Name == "caseInsensitiveCompare:" ||
124 Name == "compare:" ||
125 Name == "compare:options:" ||
126 Name == "compare:options:range:" ||
127 Name == "compare:options:range:locale:" ||
128 Name == "componentsSeparatedByCharactersInSet:" ||
129 Name == "initWithFormat:") {
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +0000130 if (isNil(msg.getArgSVal(0, C.getState())))
131 WarnNilArg(C, msg, 0);
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000132 }
133 }
Ted Kremenek99c6ad32008-03-27 07:25:52 +0000134}
Ted Kremenek04bc8762008-06-26 23:59:48 +0000135
136//===----------------------------------------------------------------------===//
137// Error reporting.
138//===----------------------------------------------------------------------===//
139
140namespace {
Argyrios Kyrtzidisec8605f2011-03-01 01:16:21 +0000141class CFNumberCreateChecker : public Checker< check::PreStmt<CallExpr> > {
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000142 mutable llvm::OwningPtr<APIMisuse> BT;
143 mutable IdentifierInfo* II;
Ted Kremenek04bc8762008-06-26 23:59:48 +0000144public:
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000145 CFNumberCreateChecker() : II(0) {}
146
147 void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
148
Ted Kremenek04bc8762008-06-26 23:59:48 +0000149private:
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000150 void EmitError(const TypedRegion* R, const Expr* Ex,
Mike Stump1eb44332009-09-09 15:08:12 +0000151 uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind);
Ted Kremenek04bc8762008-06-26 23:59:48 +0000152};
153} // end anonymous namespace
154
155enum CFNumberType {
156 kCFNumberSInt8Type = 1,
157 kCFNumberSInt16Type = 2,
158 kCFNumberSInt32Type = 3,
159 kCFNumberSInt64Type = 4,
160 kCFNumberFloat32Type = 5,
161 kCFNumberFloat64Type = 6,
162 kCFNumberCharType = 7,
163 kCFNumberShortType = 8,
164 kCFNumberIntType = 9,
165 kCFNumberLongType = 10,
166 kCFNumberLongLongType = 11,
167 kCFNumberFloatType = 12,
168 kCFNumberDoubleType = 13,
169 kCFNumberCFIndexType = 14,
170 kCFNumberNSIntegerType = 15,
171 kCFNumberCGFloatType = 16
172};
173
174namespace {
175 template<typename T>
176 class Optional {
177 bool IsKnown;
178 T Val;
179 public:
180 Optional() : IsKnown(false), Val(0) {}
181 Optional(const T& val) : IsKnown(true), Val(val) {}
Mike Stump1eb44332009-09-09 15:08:12 +0000182
Ted Kremenek04bc8762008-06-26 23:59:48 +0000183 bool isKnown() const { return IsKnown; }
184
185 const T& getValue() const {
186 assert (isKnown());
187 return Val;
188 }
189
190 operator const T&() const {
191 return getValue();
192 }
193 };
194}
195
196static Optional<uint64_t> GetCFNumberSize(ASTContext& Ctx, uint64_t i) {
Nuno Lopes2550d702009-12-23 17:49:57 +0000197 static const unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 };
Mike Stump1eb44332009-09-09 15:08:12 +0000198
Ted Kremenek04bc8762008-06-26 23:59:48 +0000199 if (i < kCFNumberCharType)
200 return FixedSize[i-1];
Mike Stump1eb44332009-09-09 15:08:12 +0000201
Ted Kremenek04bc8762008-06-26 23:59:48 +0000202 QualType T;
Mike Stump1eb44332009-09-09 15:08:12 +0000203
Ted Kremenek04bc8762008-06-26 23:59:48 +0000204 switch (i) {
205 case kCFNumberCharType: T = Ctx.CharTy; break;
206 case kCFNumberShortType: T = Ctx.ShortTy; break;
207 case kCFNumberIntType: T = Ctx.IntTy; break;
208 case kCFNumberLongType: T = Ctx.LongTy; break;
209 case kCFNumberLongLongType: T = Ctx.LongLongTy; break;
210 case kCFNumberFloatType: T = Ctx.FloatTy; break;
211 case kCFNumberDoubleType: T = Ctx.DoubleTy; break;
212 case kCFNumberCFIndexType:
213 case kCFNumberNSIntegerType:
214 case kCFNumberCGFloatType:
Mike Stump1eb44332009-09-09 15:08:12 +0000215 // FIXME: We need a way to map from names to Type*.
Ted Kremenek04bc8762008-06-26 23:59:48 +0000216 default:
217 return Optional<uint64_t>();
218 }
Mike Stump1eb44332009-09-09 15:08:12 +0000219
Ted Kremenek04bc8762008-06-26 23:59:48 +0000220 return Ctx.getTypeSize(T);
221}
222
223#if 0
224static const char* GetCFNumberTypeStr(uint64_t i) {
225 static const char* Names[] = {
226 "kCFNumberSInt8Type",
227 "kCFNumberSInt16Type",
228 "kCFNumberSInt32Type",
229 "kCFNumberSInt64Type",
230 "kCFNumberFloat32Type",
231 "kCFNumberFloat64Type",
232 "kCFNumberCharType",
233 "kCFNumberShortType",
234 "kCFNumberIntType",
235 "kCFNumberLongType",
236 "kCFNumberLongLongType",
237 "kCFNumberFloatType",
238 "kCFNumberDoubleType",
239 "kCFNumberCFIndexType",
240 "kCFNumberNSIntegerType",
241 "kCFNumberCGFloatType"
242 };
Mike Stump1eb44332009-09-09 15:08:12 +0000243
Ted Kremenek04bc8762008-06-26 23:59:48 +0000244 return i <= kCFNumberCGFloatType ? Names[i-1] : "Invalid CFNumberType";
245}
246#endif
247
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000248void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE,
249 CheckerContext &C) const {
Mike Stump1eb44332009-09-09 15:08:12 +0000250 const Expr* Callee = CE->getCallee();
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000251 const GRState *state = C.getState();
252 SVal CallV = state->getSVal(Callee);
Zhongxing Xu369f4472009-04-20 05:24:46 +0000253 const FunctionDecl* FD = CallV.getAsFunctionDecl();
Ted Kremenek04bc8762008-06-26 23:59:48 +0000254
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000255 if (!FD)
256 return;
257
258 ASTContext &Ctx = C.getASTContext();
259 if (!II)
260 II = &Ctx.Idents.get("CFNumberCreate");
261
262 if (FD->getIdentifier() != II || CE->getNumArgs() != 3)
263 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000264
Ted Kremenek04bc8762008-06-26 23:59:48 +0000265 // Get the value of the "theType" argument.
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000266 SVal TheTypeVal = state->getSVal(CE->getArg(1));
Mike Stump1eb44332009-09-09 15:08:12 +0000267
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000268 // FIXME: We really should allow ranges of valid theType values, and
269 // bifurcate the state appropriately.
Zhongxing Xu1c96b242008-10-17 05:57:07 +0000270 nonloc::ConcreteInt* V = dyn_cast<nonloc::ConcreteInt>(&TheTypeVal);
Ted Kremenek04bc8762008-06-26 23:59:48 +0000271 if (!V)
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000272 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000273
Ted Kremenek04bc8762008-06-26 23:59:48 +0000274 uint64_t NumberKind = V->getValue().getLimitedValue();
275 Optional<uint64_t> TargetSize = GetCFNumberSize(Ctx, NumberKind);
Mike Stump1eb44332009-09-09 15:08:12 +0000276
Ted Kremenek04bc8762008-06-26 23:59:48 +0000277 // FIXME: In some cases we can emit an error.
278 if (!TargetSize.isKnown())
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000279 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000280
Ted Kremenek04bc8762008-06-26 23:59:48 +0000281 // Look at the value of the integer being passed by reference. Essentially
282 // we want to catch cases where the value passed in is not equal to the
283 // size of the type being created.
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000284 SVal TheValueExpr = state->getSVal(CE->getArg(2));
Mike Stump1eb44332009-09-09 15:08:12 +0000285
Ted Kremenek04bc8762008-06-26 23:59:48 +0000286 // FIXME: Eventually we should handle arbitrary locations. We can do this
287 // by having an enhanced memory model that does low-level typing.
Zhongxing Xu1c96b242008-10-17 05:57:07 +0000288 loc::MemRegionVal* LV = dyn_cast<loc::MemRegionVal>(&TheValueExpr);
Ted Kremenek04bc8762008-06-26 23:59:48 +0000289 if (!LV)
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000290 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000291
Zhanyong Wan7dfc9422011-02-16 21:13:32 +0000292 const TypedRegion* R = dyn_cast<TypedRegion>(LV->stripCasts());
Ted Kremenek5e77eba2009-07-29 18:17:40 +0000293 if (!R)
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000294 return;
Ted Kremenek5e77eba2009-07-29 18:17:40 +0000295
Zhongxing Xu018220c2010-08-11 06:10:55 +0000296 QualType T = Ctx.getCanonicalType(R->getValueType());
Mike Stump1eb44332009-09-09 15:08:12 +0000297
Ted Kremenek04bc8762008-06-26 23:59:48 +0000298 // FIXME: If the pointee isn't an integer type, should we flag a warning?
299 // People can do weird stuff with pointers.
Mike Stump1eb44332009-09-09 15:08:12 +0000300
301 if (!T->isIntegerType())
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000302 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000303
Ted Kremenek04bc8762008-06-26 23:59:48 +0000304 uint64_t SourceSize = Ctx.getTypeSize(T);
Mike Stump1eb44332009-09-09 15:08:12 +0000305
Ted Kremenek04bc8762008-06-26 23:59:48 +0000306 // CHECK: is SourceSize == TargetSize
Ted Kremenek04bc8762008-06-26 23:59:48 +0000307 if (SourceSize == TargetSize)
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000308 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000309
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000310 // Generate an error. Only generate a sink if 'SourceSize < TargetSize';
311 // otherwise generate a regular node.
312 //
Ted Kremenek04bc8762008-06-26 23:59:48 +0000313 // FIXME: We can actually create an abstract "CFNumber" object that has
314 // the bits initialized to the provided values.
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000315 //
Ted Kremenekd048c6e2010-12-20 21:19:09 +0000316 if (ExplodedNode *N = SourceSize < TargetSize ? C.generateSink()
317 : C.generateNode()) {
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000318 llvm::SmallString<128> sbuf;
319 llvm::raw_svector_ostream os(sbuf);
320
321 os << (SourceSize == 8 ? "An " : "A ")
322 << SourceSize << " bit integer is used to initialize a CFNumber "
323 "object that represents "
324 << (TargetSize == 8 ? "an " : "a ")
325 << TargetSize << " bit integer. ";
326
327 if (SourceSize < TargetSize)
328 os << (TargetSize - SourceSize)
329 << " bits of the CFNumber value will be garbage." ;
330 else
331 os << (SourceSize - TargetSize)
332 << " bits of the input integer will be lost.";
Ted Kremenek04bc8762008-06-26 23:59:48 +0000333
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000334 if (!BT)
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000335 BT.reset(new APIMisuse("Bad use of CFNumberCreate"));
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000336
337 RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
338 report->addRange(CE->getArg(2)->getSourceRange());
339 C.EmitReport(report);
340 }
Ted Kremenek04bc8762008-06-26 23:59:48 +0000341}
342
Ted Kremenek78d46242008-07-22 16:21:24 +0000343//===----------------------------------------------------------------------===//
Jordy Rose61fb55c2010-07-06 02:34:42 +0000344// CFRetain/CFRelease checking for null arguments.
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000345//===----------------------------------------------------------------------===//
346
347namespace {
Argyrios Kyrtzidisec8605f2011-03-01 01:16:21 +0000348class CFRetainReleaseChecker : public Checker< check::PreStmt<CallExpr> > {
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000349 mutable llvm::OwningPtr<APIMisuse> BT;
350 mutable IdentifierInfo *Retain, *Release;
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000351public:
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000352 CFRetainReleaseChecker(): Retain(0), Release(0) {}
353 void checkPreStmt(const CallExpr* CE, CheckerContext& C) const;
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000354};
355} // end anonymous namespace
356
357
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000358void CFRetainReleaseChecker::checkPreStmt(const CallExpr* CE,
359 CheckerContext& C) const {
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000360 // If the CallExpr doesn't have exactly 1 argument just give up checking.
361 if (CE->getNumArgs() != 1)
Jordy Rose61fb55c2010-07-06 02:34:42 +0000362 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000363
Jordy Rose61fb55c2010-07-06 02:34:42 +0000364 // Get the function declaration of the callee.
365 const GRState* state = C.getState();
Ted Kremenek13976632010-02-08 16:18:51 +0000366 SVal X = state->getSVal(CE->getCallee());
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000367 const FunctionDecl* FD = X.getAsFunctionDecl();
Mike Stump1eb44332009-09-09 15:08:12 +0000368
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000369 if (!FD)
Jordy Rose61fb55c2010-07-06 02:34:42 +0000370 return;
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000371
372 if (!BT) {
373 ASTContext &Ctx = C.getASTContext();
374 Retain = &Ctx.Idents.get("CFRetain");
375 Release = &Ctx.Idents.get("CFRelease");
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000376 BT.reset(new APIMisuse("null passed to CFRetain/CFRelease"));
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000377 }
Mike Stump1eb44332009-09-09 15:08:12 +0000378
Jordy Rose61fb55c2010-07-06 02:34:42 +0000379 // Check if we called CFRetain/CFRelease.
Mike Stump1eb44332009-09-09 15:08:12 +0000380 const IdentifierInfo *FuncII = FD->getIdentifier();
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000381 if (!(FuncII == Retain || FuncII == Release))
Jordy Rose61fb55c2010-07-06 02:34:42 +0000382 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000383
Jordy Rose61fb55c2010-07-06 02:34:42 +0000384 // FIXME: The rest of this just checks that the argument is non-null.
385 // It should probably be refactored and combined with AttrNonNullChecker.
386
387 // Get the argument's value.
388 const Expr *Arg = CE->getArg(0);
389 SVal ArgVal = state->getSVal(Arg);
390 DefinedSVal *DefArgVal = dyn_cast<DefinedSVal>(&ArgVal);
391 if (!DefArgVal)
392 return;
393
394 // Get a NULL value.
Ted Kremenekc8413fd2010-12-02 07:49:45 +0000395 SValBuilder &svalBuilder = C.getSValBuilder();
396 DefinedSVal zero = cast<DefinedSVal>(svalBuilder.makeZeroVal(Arg->getType()));
Jordy Rose61fb55c2010-07-06 02:34:42 +0000397
398 // Make an expression asserting that they're equal.
Ted Kremenekc8413fd2010-12-02 07:49:45 +0000399 DefinedOrUnknownSVal ArgIsNull = svalBuilder.evalEQ(state, zero, *DefArgVal);
Jordy Rose61fb55c2010-07-06 02:34:42 +0000400
401 // Are they equal?
402 const GRState *stateTrue, *stateFalse;
Ted Kremenek28f47b92010-12-01 22:16:56 +0000403 llvm::tie(stateTrue, stateFalse) = state->assume(ArgIsNull);
Jordy Rose61fb55c2010-07-06 02:34:42 +0000404
405 if (stateTrue && !stateFalse) {
Ted Kremenekd048c6e2010-12-20 21:19:09 +0000406 ExplodedNode *N = C.generateSink(stateTrue);
Jordy Rose61fb55c2010-07-06 02:34:42 +0000407 if (!N)
408 return;
409
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000410 const char *description = (FuncII == Retain)
411 ? "Null pointer argument in call to CFRetain"
412 : "Null pointer argument in call to CFRelease";
413
Jordy Rose61fb55c2010-07-06 02:34:42 +0000414 EnhancedBugReport *report = new EnhancedBugReport(*BT, description, N);
415 report->addRange(Arg->getSourceRange());
416 report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Arg);
Jordy Rose61fb55c2010-07-06 02:34:42 +0000417 C.EmitReport(report);
418 return;
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000419 }
420
Jordy Rose61fb55c2010-07-06 02:34:42 +0000421 // From here on, we know the argument is non-null.
422 C.addTransition(stateFalse);
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000423}
424
425//===----------------------------------------------------------------------===//
Ted Kremenek50e837b2009-11-20 05:27:05 +0000426// Check for sending 'retain', 'release', or 'autorelease' directly to a Class.
427//===----------------------------------------------------------------------===//
428
429namespace {
Argyrios Kyrtzidisec8605f2011-03-01 01:16:21 +0000430class ClassReleaseChecker : public Checker<check::PreObjCMessage> {
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000431 mutable Selector releaseS;
432 mutable Selector retainS;
433 mutable Selector autoreleaseS;
434 mutable Selector drainS;
435 mutable llvm::OwningPtr<BugType> BT;
Ted Kremenek50e837b2009-11-20 05:27:05 +0000436
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000437public:
438 void checkPreObjCMessage(ObjCMessage msg, CheckerContext &C) const;
Ted Kremenek50e837b2009-11-20 05:27:05 +0000439};
440}
441
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000442void ClassReleaseChecker::checkPreObjCMessage(ObjCMessage msg,
443 CheckerContext &C) const {
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000444
445 if (!BT) {
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000446 BT.reset(new APIMisuse("message incorrectly sent to class instead of class "
447 "instance"));
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000448
449 ASTContext &Ctx = C.getASTContext();
450 releaseS = GetNullarySelector("release", Ctx);
451 retainS = GetNullarySelector("retain", Ctx);
452 autoreleaseS = GetNullarySelector("autorelease", Ctx);
453 drainS = GetNullarySelector("drain", Ctx);
454 }
455
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +0000456 if (msg.isInstanceMessage())
Ted Kremenek50e837b2009-11-20 05:27:05 +0000457 return;
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +0000458 const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
459 assert(Class);
Douglas Gregor04badcf2010-04-21 00:45:42 +0000460
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +0000461 Selector S = msg.getSelector();
Benjamin Kramer921ddc42009-11-20 10:03:00 +0000462 if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
Ted Kremenek50e837b2009-11-20 05:27:05 +0000463 return;
464
Ted Kremenekd048c6e2010-12-20 21:19:09 +0000465 if (ExplodedNode *N = C.generateNode()) {
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000466 llvm::SmallString<200> buf;
467 llvm::raw_svector_ostream os(buf);
Ted Kremenek19d67b52009-11-23 22:22:01 +0000468
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000469 os << "The '" << S.getAsString() << "' message should be sent to instances "
470 "of class '" << Class->getName()
471 << "' and not the class directly";
Ted Kremenek50e837b2009-11-20 05:27:05 +0000472
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000473 RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +0000474 report->addRange(msg.getSourceRange());
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000475 C.EmitReport(report);
476 }
Ted Kremenek50e837b2009-11-20 05:27:05 +0000477}
478
479//===----------------------------------------------------------------------===//
Ted Kremenek78d46242008-07-22 16:21:24 +0000480// Check registration.
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000481//===----------------------------------------------------------------------===//
Argyrios Kyrtzidis0b1ba622011-02-16 01:40:52 +0000482
Argyrios Kyrtzidis695fb502011-02-17 21:39:17 +0000483void ento::registerNilArgChecker(CheckerManager &mgr) {
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000484 mgr.registerChecker<NilArgChecker>();
Argyrios Kyrtzidis0b1ba622011-02-16 01:40:52 +0000485}
486
Argyrios Kyrtzidis695fb502011-02-17 21:39:17 +0000487void ento::registerCFNumberCreateChecker(CheckerManager &mgr) {
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000488 mgr.registerChecker<CFNumberCreateChecker>();
Argyrios Kyrtzidis0b1ba622011-02-16 01:40:52 +0000489}
490
Argyrios Kyrtzidis695fb502011-02-17 21:39:17 +0000491void ento::registerCFRetainReleaseChecker(CheckerManager &mgr) {
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000492 mgr.registerChecker<CFRetainReleaseChecker>();
Ted Kremenek78d46242008-07-22 16:21:24 +0000493}
Argyrios Kyrtzidis695fb502011-02-17 21:39:17 +0000494
495void ento::registerClassReleaseChecker(CheckerManager &mgr) {
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000496 mgr.registerChecker<ClassReleaseChecker>();
Argyrios Kyrtzidis695fb502011-02-17 21:39:17 +0000497}