blob: 2aad77020719a124dda70423b32c8df326c5de2c [file] [log] [blame]
Ted Kremenekc0414922008-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 Kremeneka4d60b62008-03-27 17:17:22 +000016#include "BasicObjCFoundationChecks.h"
17
Argyrios Kyrtzidis9d4d4f92011-02-16 01:40:52 +000018#include "ClangSACheckers.h"
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +000019#include "clang/StaticAnalyzer/Core/CheckerV2.h"
Argyrios Kyrtzidis507ff532011-02-17 21:39:17 +000020#include "clang/StaticAnalyzer/Core/CheckerManager.h"
Ted Kremenekf8cbac42011-02-10 01:03:03 +000021#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
22#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
23#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
24#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h"
25#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
26#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
27#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
Ted Kremenekd99bd552010-12-23 19:38:26 +000028#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
Daniel Dunbar6e8aa532008-08-11 05:35:13 +000029#include "clang/AST/DeclObjC.h"
Ted Kremenekc0414922008-03-27 07:25:52 +000030#include "clang/AST/Expr.h"
Steve Naroff021ca182008-05-29 21:12:08 +000031#include "clang/AST/ExprObjC.h"
Ted Kremenekc0414922008-03-27 07:25:52 +000032#include "clang/AST/ASTContext.h"
Ted Kremenekc0414922008-03-27 07:25:52 +000033
Ted Kremenekc0414922008-03-27 07:25:52 +000034using namespace clang;
Ted Kremenek98857c92010-12-23 07:20:52 +000035using namespace ento;
Ted Kremeneka4d60b62008-03-27 17:17:22 +000036
Ted Kremenekbd2c8002010-10-20 23:38:56 +000037namespace {
38class APIMisuse : public BugType {
39public:
40 APIMisuse(const char* name) : BugType(name, "API Misuse (Apple)") {}
41};
42} // end anonymous namespace
43
44//===----------------------------------------------------------------------===//
45// Utility functions.
46//===----------------------------------------------------------------------===//
47
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +000048static const ObjCInterfaceType* GetReceiverType(const ObjCMessage &msg) {
49 if (const ObjCInterfaceDecl *ID = msg.getReceiverInterface())
Argyrios Kyrtzidis8e169a52011-01-25 00:03:45 +000050 return ID->getTypeForDecl()->getAs<ObjCInterfaceType>();
Ted Kremenekf20e2282008-04-30 22:48:21 +000051 return NULL;
Ted Kremenek276278e2008-03-27 22:05:32 +000052}
53
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +000054static const char* GetReceiverNameType(const ObjCMessage &msg) {
55 if (const ObjCInterfaceType *ReceiverType = GetReceiverType(msg))
Daniel Dunbar2c422dc92009-10-18 20:26:12 +000056 return ReceiverType->getDecl()->getIdentifier()->getNameStart();
57 return NULL;
Ted Kremenek276278e2008-03-27 22:05:32 +000058}
Ted Kremeneka4d60b62008-03-27 17:17:22 +000059
Ted Kremenekbd2c8002010-10-20 23:38:56 +000060static bool isNSString(llvm::StringRef ClassName) {
61 return ClassName == "NSString" || ClassName == "NSMutableString";
Ted Kremenekc0414922008-03-27 07:25:52 +000062}
63
Zhongxing Xu27f17422008-10-17 05:57:07 +000064static inline bool isNil(SVal X) {
Mike Stump11289f42009-09-09 15:08:12 +000065 return isa<loc::ConcreteInt>(X);
Ted Kremenek27156c82008-03-27 21:15:17 +000066}
67
Ted Kremenekc0414922008-03-27 07:25:52 +000068//===----------------------------------------------------------------------===//
Ted Kremenekbd2c8002010-10-20 23:38:56 +000069// NilArgChecker - Check for prohibited nil arguments to ObjC method calls.
Ted Kremenekc0414922008-03-27 07:25:52 +000070//===----------------------------------------------------------------------===//
71
Benjamin Kramer2fc373e2010-10-22 16:33:16 +000072namespace {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +000073 class NilArgChecker : public CheckerV2<check::PreObjCMessage> {
74 mutable llvm::OwningPtr<APIMisuse> BT;
75
76 void WarnNilArg(CheckerContext &C,
77 const ObjCMessage &msg, unsigned Arg) const;
78
Benjamin Kramer2fc373e2010-10-22 16:33:16 +000079 public:
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +000080 void checkPreObjCMessage(ObjCMessage msg, CheckerContext &C) const;
Benjamin Kramer2fc373e2010-10-22 16:33:16 +000081 };
82}
Mike Stump11289f42009-09-09 15:08:12 +000083
Ted Kremenekbd2c8002010-10-20 23:38:56 +000084void NilArgChecker::WarnNilArg(CheckerContext &C,
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +000085 const ObjCMessage &msg,
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +000086 unsigned int Arg) const
Ted Kremenekbd2c8002010-10-20 23:38:56 +000087{
88 if (!BT)
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +000089 BT.reset(new APIMisuse("nil argument"));
Ted Kremenekbd2c8002010-10-20 23:38:56 +000090
Ted Kremenek750b7ac2010-12-20 21:19:09 +000091 if (ExplodedNode *N = C.generateSink()) {
Ted Kremenekbd2c8002010-10-20 23:38:56 +000092 llvm::SmallString<128> sbuf;
93 llvm::raw_svector_ostream os(sbuf);
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +000094 os << "Argument to '" << GetReceiverNameType(msg) << "' method '"
95 << msg.getSelector().getAsString() << "' cannot be nil";
Mike Stump11289f42009-09-09 15:08:12 +000096
Ted Kremenekbd2c8002010-10-20 23:38:56 +000097 RangedBugReport *R = new RangedBugReport(*BT, os.str(), N);
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +000098 R->addRange(msg.getArgSourceRange(Arg));
Ted Kremenekbd2c8002010-10-20 23:38:56 +000099 C.EmitReport(R);
Ted Kremenek276278e2008-03-27 22:05:32 +0000100 }
Ted Kremenek276278e2008-03-27 22:05:32 +0000101}
102
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000103void NilArgChecker::checkPreObjCMessage(ObjCMessage msg,
104 CheckerContext &C) const {
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +0000105 const ObjCInterfaceType *ReceiverType = GetReceiverType(msg);
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000106 if (!ReceiverType)
107 return;
108
109 if (isNSString(ReceiverType->getDecl()->getIdentifier()->getName())) {
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +0000110 Selector S = msg.getSelector();
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000111
112 if (S.isUnarySelector())
113 return;
114
115 // FIXME: This is going to be really slow doing these checks with
116 // lexical comparisons.
117
118 std::string NameStr = S.getAsString();
119 llvm::StringRef Name(NameStr);
120 assert(!Name.empty());
121
122 // FIXME: Checking for initWithFormat: will not work in most cases
123 // yet because [NSString alloc] returns id, not NSString*. We will
124 // need support for tracking expected-type information in the analyzer
125 // to find these errors.
126 if (Name == "caseInsensitiveCompare:" ||
127 Name == "compare:" ||
128 Name == "compare:options:" ||
129 Name == "compare:options:range:" ||
130 Name == "compare:options:range:locale:" ||
131 Name == "componentsSeparatedByCharactersInSet:" ||
132 Name == "initWithFormat:") {
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +0000133 if (isNil(msg.getArgSVal(0, C.getState())))
134 WarnNilArg(C, msg, 0);
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000135 }
136 }
Ted Kremenekc0414922008-03-27 07:25:52 +0000137}
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000138
139//===----------------------------------------------------------------------===//
140// Error reporting.
141//===----------------------------------------------------------------------===//
142
143namespace {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000144class CFNumberCreateChecker : public CheckerV2< check::PreStmt<CallExpr> > {
145 mutable llvm::OwningPtr<APIMisuse> BT;
146 mutable IdentifierInfo* II;
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000147public:
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000148 CFNumberCreateChecker() : II(0) {}
149
150 void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
151
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000152private:
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000153 void EmitError(const TypedRegion* R, const Expr* Ex,
Mike Stump11289f42009-09-09 15:08:12 +0000154 uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind);
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000155};
156} // end anonymous namespace
157
158enum CFNumberType {
159 kCFNumberSInt8Type = 1,
160 kCFNumberSInt16Type = 2,
161 kCFNumberSInt32Type = 3,
162 kCFNumberSInt64Type = 4,
163 kCFNumberFloat32Type = 5,
164 kCFNumberFloat64Type = 6,
165 kCFNumberCharType = 7,
166 kCFNumberShortType = 8,
167 kCFNumberIntType = 9,
168 kCFNumberLongType = 10,
169 kCFNumberLongLongType = 11,
170 kCFNumberFloatType = 12,
171 kCFNumberDoubleType = 13,
172 kCFNumberCFIndexType = 14,
173 kCFNumberNSIntegerType = 15,
174 kCFNumberCGFloatType = 16
175};
176
177namespace {
178 template<typename T>
179 class Optional {
180 bool IsKnown;
181 T Val;
182 public:
183 Optional() : IsKnown(false), Val(0) {}
184 Optional(const T& val) : IsKnown(true), Val(val) {}
Mike Stump11289f42009-09-09 15:08:12 +0000185
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000186 bool isKnown() const { return IsKnown; }
187
188 const T& getValue() const {
189 assert (isKnown());
190 return Val;
191 }
192
193 operator const T&() const {
194 return getValue();
195 }
196 };
197}
198
199static Optional<uint64_t> GetCFNumberSize(ASTContext& Ctx, uint64_t i) {
Nuno Lopescfca1f02009-12-23 17:49:57 +0000200 static const unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 };
Mike Stump11289f42009-09-09 15:08:12 +0000201
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000202 if (i < kCFNumberCharType)
203 return FixedSize[i-1];
Mike Stump11289f42009-09-09 15:08:12 +0000204
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000205 QualType T;
Mike Stump11289f42009-09-09 15:08:12 +0000206
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000207 switch (i) {
208 case kCFNumberCharType: T = Ctx.CharTy; break;
209 case kCFNumberShortType: T = Ctx.ShortTy; break;
210 case kCFNumberIntType: T = Ctx.IntTy; break;
211 case kCFNumberLongType: T = Ctx.LongTy; break;
212 case kCFNumberLongLongType: T = Ctx.LongLongTy; break;
213 case kCFNumberFloatType: T = Ctx.FloatTy; break;
214 case kCFNumberDoubleType: T = Ctx.DoubleTy; break;
215 case kCFNumberCFIndexType:
216 case kCFNumberNSIntegerType:
217 case kCFNumberCGFloatType:
Mike Stump11289f42009-09-09 15:08:12 +0000218 // FIXME: We need a way to map from names to Type*.
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000219 default:
220 return Optional<uint64_t>();
221 }
Mike Stump11289f42009-09-09 15:08:12 +0000222
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000223 return Ctx.getTypeSize(T);
224}
225
226#if 0
227static const char* GetCFNumberTypeStr(uint64_t i) {
228 static const char* Names[] = {
229 "kCFNumberSInt8Type",
230 "kCFNumberSInt16Type",
231 "kCFNumberSInt32Type",
232 "kCFNumberSInt64Type",
233 "kCFNumberFloat32Type",
234 "kCFNumberFloat64Type",
235 "kCFNumberCharType",
236 "kCFNumberShortType",
237 "kCFNumberIntType",
238 "kCFNumberLongType",
239 "kCFNumberLongLongType",
240 "kCFNumberFloatType",
241 "kCFNumberDoubleType",
242 "kCFNumberCFIndexType",
243 "kCFNumberNSIntegerType",
244 "kCFNumberCGFloatType"
245 };
Mike Stump11289f42009-09-09 15:08:12 +0000246
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000247 return i <= kCFNumberCGFloatType ? Names[i-1] : "Invalid CFNumberType";
248}
249#endif
250
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000251void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE,
252 CheckerContext &C) const {
Mike Stump11289f42009-09-09 15:08:12 +0000253 const Expr* Callee = CE->getCallee();
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000254 const GRState *state = C.getState();
255 SVal CallV = state->getSVal(Callee);
Zhongxing Xuac129432009-04-20 05:24:46 +0000256 const FunctionDecl* FD = CallV.getAsFunctionDecl();
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000257
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000258 if (!FD)
259 return;
260
261 ASTContext &Ctx = C.getASTContext();
262 if (!II)
263 II = &Ctx.Idents.get("CFNumberCreate");
264
265 if (FD->getIdentifier() != II || CE->getNumArgs() != 3)
266 return;
Mike Stump11289f42009-09-09 15:08:12 +0000267
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000268 // Get the value of the "theType" argument.
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000269 SVal TheTypeVal = state->getSVal(CE->getArg(1));
Mike Stump11289f42009-09-09 15:08:12 +0000270
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000271 // FIXME: We really should allow ranges of valid theType values, and
272 // bifurcate the state appropriately.
Zhongxing Xu27f17422008-10-17 05:57:07 +0000273 nonloc::ConcreteInt* V = dyn_cast<nonloc::ConcreteInt>(&TheTypeVal);
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000274 if (!V)
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000275 return;
Mike Stump11289f42009-09-09 15:08:12 +0000276
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000277 uint64_t NumberKind = V->getValue().getLimitedValue();
278 Optional<uint64_t> TargetSize = GetCFNumberSize(Ctx, NumberKind);
Mike Stump11289f42009-09-09 15:08:12 +0000279
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000280 // FIXME: In some cases we can emit an error.
281 if (!TargetSize.isKnown())
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000282 return;
Mike Stump11289f42009-09-09 15:08:12 +0000283
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000284 // Look at the value of the integer being passed by reference. Essentially
285 // we want to catch cases where the value passed in is not equal to the
286 // size of the type being created.
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000287 SVal TheValueExpr = state->getSVal(CE->getArg(2));
Mike Stump11289f42009-09-09 15:08:12 +0000288
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000289 // FIXME: Eventually we should handle arbitrary locations. We can do this
290 // by having an enhanced memory model that does low-level typing.
Zhongxing Xu27f17422008-10-17 05:57:07 +0000291 loc::MemRegionVal* LV = dyn_cast<loc::MemRegionVal>(&TheValueExpr);
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000292 if (!LV)
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000293 return;
Mike Stump11289f42009-09-09 15:08:12 +0000294
Zhanyong Wan85a203e2011-02-16 21:13:32 +0000295 const TypedRegion* R = dyn_cast<TypedRegion>(LV->stripCasts());
Ted Kremenek87a7a452009-07-29 18:17:40 +0000296 if (!R)
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000297 return;
Ted Kremenek87a7a452009-07-29 18:17:40 +0000298
Zhongxing Xu8de0a3d2010-08-11 06:10:55 +0000299 QualType T = Ctx.getCanonicalType(R->getValueType());
Mike Stump11289f42009-09-09 15:08:12 +0000300
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000301 // FIXME: If the pointee isn't an integer type, should we flag a warning?
302 // People can do weird stuff with pointers.
Mike Stump11289f42009-09-09 15:08:12 +0000303
304 if (!T->isIntegerType())
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000305 return;
Mike Stump11289f42009-09-09 15:08:12 +0000306
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000307 uint64_t SourceSize = Ctx.getTypeSize(T);
Mike Stump11289f42009-09-09 15:08:12 +0000308
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000309 // CHECK: is SourceSize == TargetSize
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000310 if (SourceSize == TargetSize)
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000311 return;
Mike Stump11289f42009-09-09 15:08:12 +0000312
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000313 // Generate an error. Only generate a sink if 'SourceSize < TargetSize';
314 // otherwise generate a regular node.
315 //
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000316 // FIXME: We can actually create an abstract "CFNumber" object that has
317 // the bits initialized to the provided values.
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000318 //
Ted Kremenek750b7ac2010-12-20 21:19:09 +0000319 if (ExplodedNode *N = SourceSize < TargetSize ? C.generateSink()
320 : C.generateNode()) {
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000321 llvm::SmallString<128> sbuf;
322 llvm::raw_svector_ostream os(sbuf);
323
324 os << (SourceSize == 8 ? "An " : "A ")
325 << SourceSize << " bit integer is used to initialize a CFNumber "
326 "object that represents "
327 << (TargetSize == 8 ? "an " : "a ")
328 << TargetSize << " bit integer. ";
329
330 if (SourceSize < TargetSize)
331 os << (TargetSize - SourceSize)
332 << " bits of the CFNumber value will be garbage." ;
333 else
334 os << (SourceSize - TargetSize)
335 << " bits of the input integer will be lost.";
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000336
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000337 if (!BT)
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000338 BT.reset(new APIMisuse("Bad use of CFNumberCreate"));
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000339
340 RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
341 report->addRange(CE->getArg(2)->getSourceRange());
342 C.EmitReport(report);
343 }
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000344}
345
Ted Kremenek1f352db2008-07-22 16:21:24 +0000346//===----------------------------------------------------------------------===//
Jordy Rose40c5c242010-07-06 02:34:42 +0000347// CFRetain/CFRelease checking for null arguments.
Ted Kremenekc057f412009-07-14 00:43:42 +0000348//===----------------------------------------------------------------------===//
349
350namespace {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000351class CFRetainReleaseChecker : public CheckerV2< check::PreStmt<CallExpr> > {
352 mutable llvm::OwningPtr<APIMisuse> BT;
353 mutable IdentifierInfo *Retain, *Release;
Ted Kremenekc057f412009-07-14 00:43:42 +0000354public:
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000355 CFRetainReleaseChecker(): Retain(0), Release(0) {}
356 void checkPreStmt(const CallExpr* CE, CheckerContext& C) const;
Ted Kremenekc057f412009-07-14 00:43:42 +0000357};
358} // end anonymous namespace
359
360
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000361void CFRetainReleaseChecker::checkPreStmt(const CallExpr* CE,
362 CheckerContext& C) const {
Ted Kremenekc057f412009-07-14 00:43:42 +0000363 // If the CallExpr doesn't have exactly 1 argument just give up checking.
364 if (CE->getNumArgs() != 1)
Jordy Rose40c5c242010-07-06 02:34:42 +0000365 return;
Mike Stump11289f42009-09-09 15:08:12 +0000366
Jordy Rose40c5c242010-07-06 02:34:42 +0000367 // Get the function declaration of the callee.
368 const GRState* state = C.getState();
Ted Kremenek57f09892010-02-08 16:18:51 +0000369 SVal X = state->getSVal(CE->getCallee());
Ted Kremenekc057f412009-07-14 00:43:42 +0000370 const FunctionDecl* FD = X.getAsFunctionDecl();
Mike Stump11289f42009-09-09 15:08:12 +0000371
Ted Kremenekc057f412009-07-14 00:43:42 +0000372 if (!FD)
Jordy Rose40c5c242010-07-06 02:34:42 +0000373 return;
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000374
375 if (!BT) {
376 ASTContext &Ctx = C.getASTContext();
377 Retain = &Ctx.Idents.get("CFRetain");
378 Release = &Ctx.Idents.get("CFRelease");
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000379 BT.reset(new APIMisuse("null passed to CFRetain/CFRelease"));
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000380 }
Mike Stump11289f42009-09-09 15:08:12 +0000381
Jordy Rose40c5c242010-07-06 02:34:42 +0000382 // Check if we called CFRetain/CFRelease.
Mike Stump11289f42009-09-09 15:08:12 +0000383 const IdentifierInfo *FuncII = FD->getIdentifier();
Ted Kremenekc057f412009-07-14 00:43:42 +0000384 if (!(FuncII == Retain || FuncII == Release))
Jordy Rose40c5c242010-07-06 02:34:42 +0000385 return;
Mike Stump11289f42009-09-09 15:08:12 +0000386
Jordy Rose40c5c242010-07-06 02:34:42 +0000387 // FIXME: The rest of this just checks that the argument is non-null.
388 // It should probably be refactored and combined with AttrNonNullChecker.
389
390 // Get the argument's value.
391 const Expr *Arg = CE->getArg(0);
392 SVal ArgVal = state->getSVal(Arg);
393 DefinedSVal *DefArgVal = dyn_cast<DefinedSVal>(&ArgVal);
394 if (!DefArgVal)
395 return;
396
397 // Get a NULL value.
Ted Kremenek90af9092010-12-02 07:49:45 +0000398 SValBuilder &svalBuilder = C.getSValBuilder();
399 DefinedSVal zero = cast<DefinedSVal>(svalBuilder.makeZeroVal(Arg->getType()));
Jordy Rose40c5c242010-07-06 02:34:42 +0000400
401 // Make an expression asserting that they're equal.
Ted Kremenek90af9092010-12-02 07:49:45 +0000402 DefinedOrUnknownSVal ArgIsNull = svalBuilder.evalEQ(state, zero, *DefArgVal);
Jordy Rose40c5c242010-07-06 02:34:42 +0000403
404 // Are they equal?
405 const GRState *stateTrue, *stateFalse;
Ted Kremenekc5bea1e2010-12-01 22:16:56 +0000406 llvm::tie(stateTrue, stateFalse) = state->assume(ArgIsNull);
Jordy Rose40c5c242010-07-06 02:34:42 +0000407
408 if (stateTrue && !stateFalse) {
Ted Kremenek750b7ac2010-12-20 21:19:09 +0000409 ExplodedNode *N = C.generateSink(stateTrue);
Jordy Rose40c5c242010-07-06 02:34:42 +0000410 if (!N)
411 return;
412
Ted Kremenekc057f412009-07-14 00:43:42 +0000413 const char *description = (FuncII == Retain)
414 ? "Null pointer argument in call to CFRetain"
415 : "Null pointer argument in call to CFRelease";
416
Jordy Rose40c5c242010-07-06 02:34:42 +0000417 EnhancedBugReport *report = new EnhancedBugReport(*BT, description, N);
418 report->addRange(Arg->getSourceRange());
419 report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Arg);
Jordy Rose40c5c242010-07-06 02:34:42 +0000420 C.EmitReport(report);
421 return;
Ted Kremenekc057f412009-07-14 00:43:42 +0000422 }
423
Jordy Rose40c5c242010-07-06 02:34:42 +0000424 // From here on, we know the argument is non-null.
425 C.addTransition(stateFalse);
Ted Kremenekc057f412009-07-14 00:43:42 +0000426}
427
428//===----------------------------------------------------------------------===//
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000429// Check for sending 'retain', 'release', or 'autorelease' directly to a Class.
430//===----------------------------------------------------------------------===//
431
432namespace {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000433class ClassReleaseChecker : public CheckerV2<check::PreObjCMessage> {
434 mutable Selector releaseS;
435 mutable Selector retainS;
436 mutable Selector autoreleaseS;
437 mutable Selector drainS;
438 mutable llvm::OwningPtr<BugType> BT;
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000439
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000440public:
441 void checkPreObjCMessage(ObjCMessage msg, CheckerContext &C) const;
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000442};
443}
444
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000445void ClassReleaseChecker::checkPreObjCMessage(ObjCMessage msg,
446 CheckerContext &C) const {
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000447
448 if (!BT) {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000449 BT.reset(new APIMisuse("message incorrectly sent to class instead of class "
450 "instance"));
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000451
452 ASTContext &Ctx = C.getASTContext();
453 releaseS = GetNullarySelector("release", Ctx);
454 retainS = GetNullarySelector("retain", Ctx);
455 autoreleaseS = GetNullarySelector("autorelease", Ctx);
456 drainS = GetNullarySelector("drain", Ctx);
457 }
458
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +0000459 if (msg.isInstanceMessage())
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000460 return;
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +0000461 const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
462 assert(Class);
Douglas Gregor9a129192010-04-21 00:45:42 +0000463
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +0000464 Selector S = msg.getSelector();
Benjamin Kramer7d875c72009-11-20 10:03:00 +0000465 if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000466 return;
467
Ted Kremenek750b7ac2010-12-20 21:19:09 +0000468 if (ExplodedNode *N = C.generateNode()) {
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000469 llvm::SmallString<200> buf;
470 llvm::raw_svector_ostream os(buf);
Ted Kremenekf5735152009-11-23 22:22:01 +0000471
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000472 os << "The '" << S.getAsString() << "' message should be sent to instances "
473 "of class '" << Class->getName()
474 << "' and not the class directly";
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000475
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000476 RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +0000477 report->addRange(msg.getSourceRange());
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000478 C.EmitReport(report);
479 }
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000480}
481
482//===----------------------------------------------------------------------===//
Ted Kremenek1f352db2008-07-22 16:21:24 +0000483// Check registration.
Ted Kremenekc057f412009-07-14 00:43:42 +0000484//===----------------------------------------------------------------------===//
Argyrios Kyrtzidis9d4d4f92011-02-16 01:40:52 +0000485
Argyrios Kyrtzidis507ff532011-02-17 21:39:17 +0000486void ento::registerNilArgChecker(CheckerManager &mgr) {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000487 mgr.registerChecker<NilArgChecker>();
Argyrios Kyrtzidis9d4d4f92011-02-16 01:40:52 +0000488}
489
Argyrios Kyrtzidis507ff532011-02-17 21:39:17 +0000490void ento::registerCFNumberCreateChecker(CheckerManager &mgr) {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000491 mgr.registerChecker<CFNumberCreateChecker>();
Argyrios Kyrtzidis9d4d4f92011-02-16 01:40:52 +0000492}
493
Argyrios Kyrtzidis507ff532011-02-17 21:39:17 +0000494void ento::registerCFRetainReleaseChecker(CheckerManager &mgr) {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000495 mgr.registerChecker<CFRetainReleaseChecker>();
Ted Kremenek1f352db2008-07-22 16:21:24 +0000496}
Argyrios Kyrtzidis507ff532011-02-17 21:39:17 +0000497
498void ento::registerClassReleaseChecker(CheckerManager &mgr) {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000499 mgr.registerChecker<ClassReleaseChecker>();
Argyrios Kyrtzidis507ff532011-02-17 21:39:17 +0000500}