blob: a6f980ad49dcaa15bef1ea0d75abd33031070c19 [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//===----------------------------------------------------------------------===//
Anders Carlsson4597b7b2011-03-13 20:35:21 +0000480// Check for passing non-Objective-C types to variadic methods that expect
481// only Objective-C types.
482//===----------------------------------------------------------------------===//
483
484namespace {
485class VariadicMethodTypeChecker : public Checker<check::PreObjCMessage> {
486 mutable Selector arrayWithObjectsS;
487 mutable Selector dictionaryWithObjectsAndKeysS;
488 mutable Selector setWithObjectsS;
489 mutable Selector initWithObjectsS;
490 mutable Selector initWithObjectsAndKeysS;
491 mutable llvm::OwningPtr<BugType> BT;
492
493 bool isVariadicMessage(const ObjCMessage &msg) const;
494
495public:
496 void checkPreObjCMessage(ObjCMessage msg, CheckerContext &C) const;
497};
498}
499
500/// isVariadicMessage - Returns whether the given message is a variadic message,
501/// where all arguments must be Objective-C types.
502bool
503VariadicMethodTypeChecker::isVariadicMessage(const ObjCMessage &msg) const {
504 const ObjCMethodDecl *MD = msg.getMethodDecl();
505 if (!MD)
506 return false;
507
508 if (!MD->isVariadic())
509 return false;
510
511 Selector S = msg.getSelector();
512
513 if (msg.isInstanceMessage()) {
514 // FIXME: Ideally we'd look at the receiver interface here, but that's not
515 // useful for init, because alloc returns 'id'. In theory, this could lead
516 // to false positives, for example if there existed a class that had an
517 // initWithObjects: implementation that does accept non-Objective-C pointer
518 // types, but the chance of that happening is pretty small compared to the
519 // gains that this analysis gives.
520 const ObjCInterfaceDecl *Class = MD->getClassInterface();
521
522 // -[NSArray initWithObjects:]
523 if (isReceiverClassOrSuperclass(Class, "NSArray") &&
524 S == initWithObjectsS)
525 return true;
526
527 // -[NSDictionary initWithObjectsAndKeys:]
528 if (isReceiverClassOrSuperclass(Class, "NSDictionary") &&
529 S == initWithObjectsAndKeysS)
530 return true;
531
532 // -[NSSet initWithObjects:]
533 if (isReceiverClassOrSuperclass(Class, "NSSet") &&
534 S == initWithObjectsS)
535 return true;
536 } else {
537 const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
538
539 // -[NSArray arrayWithObjects:]
540 if (isReceiverClassOrSuperclass(Class, "NSArray") &&
541 S == arrayWithObjectsS)
542 return true;
543
544 // -[NSDictionary dictionaryWithObjectsAndKeys:]
545 if (isReceiverClassOrSuperclass(Class, "NSDictionary") &&
546 S == dictionaryWithObjectsAndKeysS)
547 return true;
548
549 // -[NSSet setWithObjects:]
550 if (isReceiverClassOrSuperclass(Class, "NSSet") &&
551 S == setWithObjectsS)
552 return true;
553 }
554
555 return false;
556}
557
558void VariadicMethodTypeChecker::checkPreObjCMessage(ObjCMessage msg,
559 CheckerContext &C) const {
560 if (!BT) {
561 BT.reset(new APIMisuse("Arguments passed to variadic method aren't all "
562 "Objective-C pointer types"));
563
564 ASTContext &Ctx = C.getASTContext();
565 arrayWithObjectsS = GetUnarySelector("arrayWithObjects", Ctx);
566 dictionaryWithObjectsAndKeysS =
567 GetUnarySelector("dictionaryWithObjectsAndKeys", Ctx);
568 setWithObjectsS = GetUnarySelector("setWithObjects", Ctx);
569
570 initWithObjectsS = GetUnarySelector("initWithObjects", Ctx);
571 initWithObjectsAndKeysS = GetUnarySelector("initWithObjectsAndKeys", Ctx);
572 }
573
574 if (!isVariadicMessage(msg))
575 return;
576
577 // We are not interested in the selector arguments since they have
578 // well-defined types, so the compiler will issue a warning for them.
579 unsigned variadicArgsBegin = msg.getSelector().getNumArgs();
580
581 // We're not interested in the last argument since it has to be nil or the
582 // compiler would have issued a warning for it elsewhere.
583 unsigned variadicArgsEnd = msg.getNumArgs() - 1;
584
585 if (variadicArgsEnd <= variadicArgsBegin)
586 return;
587
588 // Verify that all arguments have Objective-C types.
589 for (unsigned I = variadicArgsBegin; I != variadicArgsEnd; ++I) {
590 QualType ArgTy = msg.getArgType(I);
591 if (ArgTy->isObjCObjectPointerType())
592 continue;
593
594 ExplodedNode *N = C.generateNode();
595 if (!N)
596 continue;
597
598 llvm::SmallString<128> sbuf;
599 llvm::raw_svector_ostream os(sbuf);
600
601 if (const char *TypeName = GetReceiverNameType(msg))
602 os << "Argument to '" << TypeName << "' method '";
603 else
604 os << "Argument to method '";
605
606 os << msg.getSelector().getAsString()
607 << "' should be an Objective-C pointer type, not '"
608 << ArgTy.getAsString() << "'";
609
610 RangedBugReport *R = new RangedBugReport(*BT, os.str(), N);
611 R->addRange(msg.getArgSourceRange(I));
612 C.EmitReport(R);
613 }
614}
615
616//===----------------------------------------------------------------------===//
Ted Kremenek78d46242008-07-22 16:21:24 +0000617// Check registration.
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000618//===----------------------------------------------------------------------===//
Argyrios Kyrtzidis0b1ba622011-02-16 01:40:52 +0000619
Argyrios Kyrtzidis695fb502011-02-17 21:39:17 +0000620void ento::registerNilArgChecker(CheckerManager &mgr) {
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000621 mgr.registerChecker<NilArgChecker>();
Argyrios Kyrtzidis0b1ba622011-02-16 01:40:52 +0000622}
623
Argyrios Kyrtzidis695fb502011-02-17 21:39:17 +0000624void ento::registerCFNumberCreateChecker(CheckerManager &mgr) {
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000625 mgr.registerChecker<CFNumberCreateChecker>();
Argyrios Kyrtzidis0b1ba622011-02-16 01:40:52 +0000626}
627
Argyrios Kyrtzidis695fb502011-02-17 21:39:17 +0000628void ento::registerCFRetainReleaseChecker(CheckerManager &mgr) {
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000629 mgr.registerChecker<CFRetainReleaseChecker>();
Ted Kremenek78d46242008-07-22 16:21:24 +0000630}
Argyrios Kyrtzidis695fb502011-02-17 21:39:17 +0000631
632void ento::registerClassReleaseChecker(CheckerManager &mgr) {
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000633 mgr.registerChecker<ClassReleaseChecker>();
Argyrios Kyrtzidis695fb502011-02-17 21:39:17 +0000634}
Anders Carlsson4597b7b2011-03-13 20:35:21 +0000635
636void ento::registerVariadicMethodTypeChecker(CheckerManager &mgr) {
637 mgr.registerChecker<VariadicMethodTypeChecker>();
638}