blob: 7aff2010d84dcd833ddf7f8af60090466157b750 [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"
Argyrios Kyrtzidisdff865d2011-02-23 01:05:36 +000021#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
Ted Kremenekf8cbac42011-02-10 01:03:03 +000022#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
Ted Kremenekf8cbac42011-02-10 01:03:03 +000023#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"
Ted Kremenekd99bd552010-12-23 19:38:26 +000027#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
Daniel Dunbar6e8aa532008-08-11 05:35:13 +000028#include "clang/AST/DeclObjC.h"
Ted Kremenekc0414922008-03-27 07:25:52 +000029#include "clang/AST/Expr.h"
Steve Naroff021ca182008-05-29 21:12:08 +000030#include "clang/AST/ExprObjC.h"
Ted Kremenekc0414922008-03-27 07:25:52 +000031#include "clang/AST/ASTContext.h"
Ted Kremenekc0414922008-03-27 07:25:52 +000032
Ted Kremenekc0414922008-03-27 07:25:52 +000033using namespace clang;
Ted Kremenek98857c92010-12-23 07:20:52 +000034using namespace ento;
Ted Kremeneka4d60b62008-03-27 17:17:22 +000035
Ted Kremenekbd2c8002010-10-20 23:38:56 +000036namespace {
37class APIMisuse : public BugType {
38public:
39 APIMisuse(const char* name) : BugType(name, "API Misuse (Apple)") {}
40};
41} // end anonymous namespace
42
43//===----------------------------------------------------------------------===//
44// Utility functions.
45//===----------------------------------------------------------------------===//
46
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +000047static const ObjCInterfaceType* GetReceiverType(const ObjCMessage &msg) {
48 if (const ObjCInterfaceDecl *ID = msg.getReceiverInterface())
Argyrios Kyrtzidis8e169a52011-01-25 00:03:45 +000049 return ID->getTypeForDecl()->getAs<ObjCInterfaceType>();
Ted Kremenekf20e2282008-04-30 22:48:21 +000050 return NULL;
Ted Kremenek276278e2008-03-27 22:05:32 +000051}
52
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +000053static const char* GetReceiverNameType(const ObjCMessage &msg) {
54 if (const ObjCInterfaceType *ReceiverType = GetReceiverType(msg))
Daniel Dunbar2c422dc92009-10-18 20:26:12 +000055 return ReceiverType->getDecl()->getIdentifier()->getNameStart();
56 return NULL;
Ted Kremenek276278e2008-03-27 22:05:32 +000057}
Ted Kremeneka4d60b62008-03-27 17:17:22 +000058
Ted Kremenekbd2c8002010-10-20 23:38:56 +000059static bool isNSString(llvm::StringRef ClassName) {
60 return ClassName == "NSString" || ClassName == "NSMutableString";
Ted Kremenekc0414922008-03-27 07:25:52 +000061}
62
Zhongxing Xu27f17422008-10-17 05:57:07 +000063static inline bool isNil(SVal X) {
Mike Stump11289f42009-09-09 15:08:12 +000064 return isa<loc::ConcreteInt>(X);
Ted Kremenek27156c82008-03-27 21:15:17 +000065}
66
Ted Kremenekc0414922008-03-27 07:25:52 +000067//===----------------------------------------------------------------------===//
Ted Kremenekbd2c8002010-10-20 23:38:56 +000068// NilArgChecker - Check for prohibited nil arguments to ObjC method calls.
Ted Kremenekc0414922008-03-27 07:25:52 +000069//===----------------------------------------------------------------------===//
70
Benjamin Kramer2fc373e2010-10-22 16:33:16 +000071namespace {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +000072 class NilArgChecker : public CheckerV2<check::PreObjCMessage> {
73 mutable llvm::OwningPtr<APIMisuse> BT;
74
75 void WarnNilArg(CheckerContext &C,
76 const ObjCMessage &msg, unsigned Arg) const;
77
Benjamin Kramer2fc373e2010-10-22 16:33:16 +000078 public:
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +000079 void checkPreObjCMessage(ObjCMessage msg, CheckerContext &C) const;
Benjamin Kramer2fc373e2010-10-22 16:33:16 +000080 };
81}
Mike Stump11289f42009-09-09 15:08:12 +000082
Ted Kremenekbd2c8002010-10-20 23:38:56 +000083void NilArgChecker::WarnNilArg(CheckerContext &C,
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +000084 const ObjCMessage &msg,
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +000085 unsigned int Arg) const
Ted Kremenekbd2c8002010-10-20 23:38:56 +000086{
87 if (!BT)
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +000088 BT.reset(new APIMisuse("nil argument"));
Ted Kremenekbd2c8002010-10-20 23:38:56 +000089
Ted Kremenek750b7ac2010-12-20 21:19:09 +000090 if (ExplodedNode *N = C.generateSink()) {
Ted Kremenekbd2c8002010-10-20 23:38:56 +000091 llvm::SmallString<128> sbuf;
92 llvm::raw_svector_ostream os(sbuf);
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +000093 os << "Argument to '" << GetReceiverNameType(msg) << "' method '"
94 << msg.getSelector().getAsString() << "' cannot be nil";
Mike Stump11289f42009-09-09 15:08:12 +000095
Ted Kremenekbd2c8002010-10-20 23:38:56 +000096 RangedBugReport *R = new RangedBugReport(*BT, os.str(), N);
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +000097 R->addRange(msg.getArgSourceRange(Arg));
Ted Kremenekbd2c8002010-10-20 23:38:56 +000098 C.EmitReport(R);
Ted Kremenek276278e2008-03-27 22:05:32 +000099 }
Ted Kremenek276278e2008-03-27 22:05:32 +0000100}
101
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000102void NilArgChecker::checkPreObjCMessage(ObjCMessage msg,
103 CheckerContext &C) const {
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +0000104 const ObjCInterfaceType *ReceiverType = GetReceiverType(msg);
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000105 if (!ReceiverType)
106 return;
107
108 if (isNSString(ReceiverType->getDecl()->getIdentifier()->getName())) {
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +0000109 Selector S = msg.getSelector();
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000110
111 if (S.isUnarySelector())
112 return;
113
114 // FIXME: This is going to be really slow doing these checks with
115 // lexical comparisons.
116
117 std::string NameStr = S.getAsString();
118 llvm::StringRef Name(NameStr);
119 assert(!Name.empty());
120
121 // FIXME: Checking for initWithFormat: will not work in most cases
122 // yet because [NSString alloc] returns id, not NSString*. We will
123 // need support for tracking expected-type information in the analyzer
124 // to find these errors.
125 if (Name == "caseInsensitiveCompare:" ||
126 Name == "compare:" ||
127 Name == "compare:options:" ||
128 Name == "compare:options:range:" ||
129 Name == "compare:options:range:locale:" ||
130 Name == "componentsSeparatedByCharactersInSet:" ||
131 Name == "initWithFormat:") {
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +0000132 if (isNil(msg.getArgSVal(0, C.getState())))
133 WarnNilArg(C, msg, 0);
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000134 }
135 }
Ted Kremenekc0414922008-03-27 07:25:52 +0000136}
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000137
138//===----------------------------------------------------------------------===//
139// Error reporting.
140//===----------------------------------------------------------------------===//
141
142namespace {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000143class CFNumberCreateChecker : public CheckerV2< check::PreStmt<CallExpr> > {
144 mutable llvm::OwningPtr<APIMisuse> BT;
145 mutable IdentifierInfo* II;
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000146public:
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000147 CFNumberCreateChecker() : II(0) {}
148
149 void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
150
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000151private:
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000152 void EmitError(const TypedRegion* R, const Expr* Ex,
Mike Stump11289f42009-09-09 15:08:12 +0000153 uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind);
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000154};
155} // end anonymous namespace
156
157enum CFNumberType {
158 kCFNumberSInt8Type = 1,
159 kCFNumberSInt16Type = 2,
160 kCFNumberSInt32Type = 3,
161 kCFNumberSInt64Type = 4,
162 kCFNumberFloat32Type = 5,
163 kCFNumberFloat64Type = 6,
164 kCFNumberCharType = 7,
165 kCFNumberShortType = 8,
166 kCFNumberIntType = 9,
167 kCFNumberLongType = 10,
168 kCFNumberLongLongType = 11,
169 kCFNumberFloatType = 12,
170 kCFNumberDoubleType = 13,
171 kCFNumberCFIndexType = 14,
172 kCFNumberNSIntegerType = 15,
173 kCFNumberCGFloatType = 16
174};
175
176namespace {
177 template<typename T>
178 class Optional {
179 bool IsKnown;
180 T Val;
181 public:
182 Optional() : IsKnown(false), Val(0) {}
183 Optional(const T& val) : IsKnown(true), Val(val) {}
Mike Stump11289f42009-09-09 15:08:12 +0000184
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000185 bool isKnown() const { return IsKnown; }
186
187 const T& getValue() const {
188 assert (isKnown());
189 return Val;
190 }
191
192 operator const T&() const {
193 return getValue();
194 }
195 };
196}
197
198static Optional<uint64_t> GetCFNumberSize(ASTContext& Ctx, uint64_t i) {
Nuno Lopescfca1f02009-12-23 17:49:57 +0000199 static const unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 };
Mike Stump11289f42009-09-09 15:08:12 +0000200
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000201 if (i < kCFNumberCharType)
202 return FixedSize[i-1];
Mike Stump11289f42009-09-09 15:08:12 +0000203
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000204 QualType T;
Mike Stump11289f42009-09-09 15:08:12 +0000205
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000206 switch (i) {
207 case kCFNumberCharType: T = Ctx.CharTy; break;
208 case kCFNumberShortType: T = Ctx.ShortTy; break;
209 case kCFNumberIntType: T = Ctx.IntTy; break;
210 case kCFNumberLongType: T = Ctx.LongTy; break;
211 case kCFNumberLongLongType: T = Ctx.LongLongTy; break;
212 case kCFNumberFloatType: T = Ctx.FloatTy; break;
213 case kCFNumberDoubleType: T = Ctx.DoubleTy; break;
214 case kCFNumberCFIndexType:
215 case kCFNumberNSIntegerType:
216 case kCFNumberCGFloatType:
Mike Stump11289f42009-09-09 15:08:12 +0000217 // FIXME: We need a way to map from names to Type*.
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000218 default:
219 return Optional<uint64_t>();
220 }
Mike Stump11289f42009-09-09 15:08:12 +0000221
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000222 return Ctx.getTypeSize(T);
223}
224
225#if 0
226static const char* GetCFNumberTypeStr(uint64_t i) {
227 static const char* Names[] = {
228 "kCFNumberSInt8Type",
229 "kCFNumberSInt16Type",
230 "kCFNumberSInt32Type",
231 "kCFNumberSInt64Type",
232 "kCFNumberFloat32Type",
233 "kCFNumberFloat64Type",
234 "kCFNumberCharType",
235 "kCFNumberShortType",
236 "kCFNumberIntType",
237 "kCFNumberLongType",
238 "kCFNumberLongLongType",
239 "kCFNumberFloatType",
240 "kCFNumberDoubleType",
241 "kCFNumberCFIndexType",
242 "kCFNumberNSIntegerType",
243 "kCFNumberCGFloatType"
244 };
Mike Stump11289f42009-09-09 15:08:12 +0000245
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000246 return i <= kCFNumberCGFloatType ? Names[i-1] : "Invalid CFNumberType";
247}
248#endif
249
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000250void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE,
251 CheckerContext &C) const {
Mike Stump11289f42009-09-09 15:08:12 +0000252 const Expr* Callee = CE->getCallee();
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000253 const GRState *state = C.getState();
254 SVal CallV = state->getSVal(Callee);
Zhongxing Xuac129432009-04-20 05:24:46 +0000255 const FunctionDecl* FD = CallV.getAsFunctionDecl();
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000256
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000257 if (!FD)
258 return;
259
260 ASTContext &Ctx = C.getASTContext();
261 if (!II)
262 II = &Ctx.Idents.get("CFNumberCreate");
263
264 if (FD->getIdentifier() != II || CE->getNumArgs() != 3)
265 return;
Mike Stump11289f42009-09-09 15:08:12 +0000266
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000267 // Get the value of the "theType" argument.
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000268 SVal TheTypeVal = state->getSVal(CE->getArg(1));
Mike Stump11289f42009-09-09 15:08:12 +0000269
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000270 // FIXME: We really should allow ranges of valid theType values, and
271 // bifurcate the state appropriately.
Zhongxing Xu27f17422008-10-17 05:57:07 +0000272 nonloc::ConcreteInt* V = dyn_cast<nonloc::ConcreteInt>(&TheTypeVal);
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000273 if (!V)
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000274 return;
Mike Stump11289f42009-09-09 15:08:12 +0000275
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000276 uint64_t NumberKind = V->getValue().getLimitedValue();
277 Optional<uint64_t> TargetSize = GetCFNumberSize(Ctx, NumberKind);
Mike Stump11289f42009-09-09 15:08:12 +0000278
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000279 // FIXME: In some cases we can emit an error.
280 if (!TargetSize.isKnown())
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000281 return;
Mike Stump11289f42009-09-09 15:08:12 +0000282
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000283 // Look at the value of the integer being passed by reference. Essentially
284 // we want to catch cases where the value passed in is not equal to the
285 // size of the type being created.
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000286 SVal TheValueExpr = state->getSVal(CE->getArg(2));
Mike Stump11289f42009-09-09 15:08:12 +0000287
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000288 // FIXME: Eventually we should handle arbitrary locations. We can do this
289 // by having an enhanced memory model that does low-level typing.
Zhongxing Xu27f17422008-10-17 05:57:07 +0000290 loc::MemRegionVal* LV = dyn_cast<loc::MemRegionVal>(&TheValueExpr);
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000291 if (!LV)
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000292 return;
Mike Stump11289f42009-09-09 15:08:12 +0000293
Zhanyong Wan85a203e2011-02-16 21:13:32 +0000294 const TypedRegion* R = dyn_cast<TypedRegion>(LV->stripCasts());
Ted Kremenek87a7a452009-07-29 18:17:40 +0000295 if (!R)
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000296 return;
Ted Kremenek87a7a452009-07-29 18:17:40 +0000297
Zhongxing Xu8de0a3d2010-08-11 06:10:55 +0000298 QualType T = Ctx.getCanonicalType(R->getValueType());
Mike Stump11289f42009-09-09 15:08:12 +0000299
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000300 // FIXME: If the pointee isn't an integer type, should we flag a warning?
301 // People can do weird stuff with pointers.
Mike Stump11289f42009-09-09 15:08:12 +0000302
303 if (!T->isIntegerType())
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000304 return;
Mike Stump11289f42009-09-09 15:08:12 +0000305
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000306 uint64_t SourceSize = Ctx.getTypeSize(T);
Mike Stump11289f42009-09-09 15:08:12 +0000307
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000308 // CHECK: is SourceSize == TargetSize
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000309 if (SourceSize == TargetSize)
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000310 return;
Mike Stump11289f42009-09-09 15:08:12 +0000311
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000312 // Generate an error. Only generate a sink if 'SourceSize < TargetSize';
313 // otherwise generate a regular node.
314 //
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000315 // FIXME: We can actually create an abstract "CFNumber" object that has
316 // the bits initialized to the provided values.
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000317 //
Ted Kremenek750b7ac2010-12-20 21:19:09 +0000318 if (ExplodedNode *N = SourceSize < TargetSize ? C.generateSink()
319 : C.generateNode()) {
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000320 llvm::SmallString<128> sbuf;
321 llvm::raw_svector_ostream os(sbuf);
322
323 os << (SourceSize == 8 ? "An " : "A ")
324 << SourceSize << " bit integer is used to initialize a CFNumber "
325 "object that represents "
326 << (TargetSize == 8 ? "an " : "a ")
327 << TargetSize << " bit integer. ";
328
329 if (SourceSize < TargetSize)
330 os << (TargetSize - SourceSize)
331 << " bits of the CFNumber value will be garbage." ;
332 else
333 os << (SourceSize - TargetSize)
334 << " bits of the input integer will be lost.";
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000335
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000336 if (!BT)
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000337 BT.reset(new APIMisuse("Bad use of CFNumberCreate"));
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000338
339 RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
340 report->addRange(CE->getArg(2)->getSourceRange());
341 C.EmitReport(report);
342 }
Ted Kremenekcf1ab192008-06-26 23:59:48 +0000343}
344
Ted Kremenek1f352db2008-07-22 16:21:24 +0000345//===----------------------------------------------------------------------===//
Jordy Rose40c5c242010-07-06 02:34:42 +0000346// CFRetain/CFRelease checking for null arguments.
Ted Kremenekc057f412009-07-14 00:43:42 +0000347//===----------------------------------------------------------------------===//
348
349namespace {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000350class CFRetainReleaseChecker : public CheckerV2< check::PreStmt<CallExpr> > {
351 mutable llvm::OwningPtr<APIMisuse> BT;
352 mutable IdentifierInfo *Retain, *Release;
Ted Kremenekc057f412009-07-14 00:43:42 +0000353public:
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000354 CFRetainReleaseChecker(): Retain(0), Release(0) {}
355 void checkPreStmt(const CallExpr* CE, CheckerContext& C) const;
Ted Kremenekc057f412009-07-14 00:43:42 +0000356};
357} // end anonymous namespace
358
359
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000360void CFRetainReleaseChecker::checkPreStmt(const CallExpr* CE,
361 CheckerContext& C) const {
Ted Kremenekc057f412009-07-14 00:43:42 +0000362 // If the CallExpr doesn't have exactly 1 argument just give up checking.
363 if (CE->getNumArgs() != 1)
Jordy Rose40c5c242010-07-06 02:34:42 +0000364 return;
Mike Stump11289f42009-09-09 15:08:12 +0000365
Jordy Rose40c5c242010-07-06 02:34:42 +0000366 // Get the function declaration of the callee.
367 const GRState* state = C.getState();
Ted Kremenek57f09892010-02-08 16:18:51 +0000368 SVal X = state->getSVal(CE->getCallee());
Ted Kremenekc057f412009-07-14 00:43:42 +0000369 const FunctionDecl* FD = X.getAsFunctionDecl();
Mike Stump11289f42009-09-09 15:08:12 +0000370
Ted Kremenekc057f412009-07-14 00:43:42 +0000371 if (!FD)
Jordy Rose40c5c242010-07-06 02:34:42 +0000372 return;
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000373
374 if (!BT) {
375 ASTContext &Ctx = C.getASTContext();
376 Retain = &Ctx.Idents.get("CFRetain");
377 Release = &Ctx.Idents.get("CFRelease");
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000378 BT.reset(new APIMisuse("null passed to CFRetain/CFRelease"));
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000379 }
Mike Stump11289f42009-09-09 15:08:12 +0000380
Jordy Rose40c5c242010-07-06 02:34:42 +0000381 // Check if we called CFRetain/CFRelease.
Mike Stump11289f42009-09-09 15:08:12 +0000382 const IdentifierInfo *FuncII = FD->getIdentifier();
Ted Kremenekc057f412009-07-14 00:43:42 +0000383 if (!(FuncII == Retain || FuncII == Release))
Jordy Rose40c5c242010-07-06 02:34:42 +0000384 return;
Mike Stump11289f42009-09-09 15:08:12 +0000385
Jordy Rose40c5c242010-07-06 02:34:42 +0000386 // FIXME: The rest of this just checks that the argument is non-null.
387 // It should probably be refactored and combined with AttrNonNullChecker.
388
389 // Get the argument's value.
390 const Expr *Arg = CE->getArg(0);
391 SVal ArgVal = state->getSVal(Arg);
392 DefinedSVal *DefArgVal = dyn_cast<DefinedSVal>(&ArgVal);
393 if (!DefArgVal)
394 return;
395
396 // Get a NULL value.
Ted Kremenek90af9092010-12-02 07:49:45 +0000397 SValBuilder &svalBuilder = C.getSValBuilder();
398 DefinedSVal zero = cast<DefinedSVal>(svalBuilder.makeZeroVal(Arg->getType()));
Jordy Rose40c5c242010-07-06 02:34:42 +0000399
400 // Make an expression asserting that they're equal.
Ted Kremenek90af9092010-12-02 07:49:45 +0000401 DefinedOrUnknownSVal ArgIsNull = svalBuilder.evalEQ(state, zero, *DefArgVal);
Jordy Rose40c5c242010-07-06 02:34:42 +0000402
403 // Are they equal?
404 const GRState *stateTrue, *stateFalse;
Ted Kremenekc5bea1e2010-12-01 22:16:56 +0000405 llvm::tie(stateTrue, stateFalse) = state->assume(ArgIsNull);
Jordy Rose40c5c242010-07-06 02:34:42 +0000406
407 if (stateTrue && !stateFalse) {
Ted Kremenek750b7ac2010-12-20 21:19:09 +0000408 ExplodedNode *N = C.generateSink(stateTrue);
Jordy Rose40c5c242010-07-06 02:34:42 +0000409 if (!N)
410 return;
411
Ted Kremenekc057f412009-07-14 00:43:42 +0000412 const char *description = (FuncII == Retain)
413 ? "Null pointer argument in call to CFRetain"
414 : "Null pointer argument in call to CFRelease";
415
Jordy Rose40c5c242010-07-06 02:34:42 +0000416 EnhancedBugReport *report = new EnhancedBugReport(*BT, description, N);
417 report->addRange(Arg->getSourceRange());
418 report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Arg);
Jordy Rose40c5c242010-07-06 02:34:42 +0000419 C.EmitReport(report);
420 return;
Ted Kremenekc057f412009-07-14 00:43:42 +0000421 }
422
Jordy Rose40c5c242010-07-06 02:34:42 +0000423 // From here on, we know the argument is non-null.
424 C.addTransition(stateFalse);
Ted Kremenekc057f412009-07-14 00:43:42 +0000425}
426
427//===----------------------------------------------------------------------===//
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000428// Check for sending 'retain', 'release', or 'autorelease' directly to a Class.
429//===----------------------------------------------------------------------===//
430
431namespace {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000432class ClassReleaseChecker : public CheckerV2<check::PreObjCMessage> {
433 mutable Selector releaseS;
434 mutable Selector retainS;
435 mutable Selector autoreleaseS;
436 mutable Selector drainS;
437 mutable llvm::OwningPtr<BugType> BT;
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000438
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000439public:
440 void checkPreObjCMessage(ObjCMessage msg, CheckerContext &C) const;
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000441};
442}
443
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000444void ClassReleaseChecker::checkPreObjCMessage(ObjCMessage msg,
445 CheckerContext &C) const {
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000446
447 if (!BT) {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000448 BT.reset(new APIMisuse("message incorrectly sent to class instead of class "
449 "instance"));
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000450
451 ASTContext &Ctx = C.getASTContext();
452 releaseS = GetNullarySelector("release", Ctx);
453 retainS = GetNullarySelector("retain", Ctx);
454 autoreleaseS = GetNullarySelector("autorelease", Ctx);
455 drainS = GetNullarySelector("drain", Ctx);
456 }
457
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +0000458 if (msg.isInstanceMessage())
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000459 return;
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +0000460 const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
461 assert(Class);
Douglas Gregor9a129192010-04-21 00:45:42 +0000462
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +0000463 Selector S = msg.getSelector();
Benjamin Kramer7d875c72009-11-20 10:03:00 +0000464 if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000465 return;
466
Ted Kremenek750b7ac2010-12-20 21:19:09 +0000467 if (ExplodedNode *N = C.generateNode()) {
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000468 llvm::SmallString<200> buf;
469 llvm::raw_svector_ostream os(buf);
Ted Kremenekf5735152009-11-23 22:22:01 +0000470
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000471 os << "The '" << S.getAsString() << "' message should be sent to instances "
472 "of class '" << Class->getName()
473 << "' and not the class directly";
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000474
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000475 RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
Argyrios Kyrtzidis37ab7262011-01-25 00:03:53 +0000476 report->addRange(msg.getSourceRange());
Ted Kremenekbd2c8002010-10-20 23:38:56 +0000477 C.EmitReport(report);
478 }
Ted Kremeneka4f7c182009-11-20 05:27:05 +0000479}
480
481//===----------------------------------------------------------------------===//
Ted Kremenek1f352db2008-07-22 16:21:24 +0000482// Check registration.
Ted Kremenekc057f412009-07-14 00:43:42 +0000483//===----------------------------------------------------------------------===//
Argyrios Kyrtzidis9d4d4f92011-02-16 01:40:52 +0000484
Argyrios Kyrtzidis507ff532011-02-17 21:39:17 +0000485void ento::registerNilArgChecker(CheckerManager &mgr) {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000486 mgr.registerChecker<NilArgChecker>();
Argyrios Kyrtzidis9d4d4f92011-02-16 01:40:52 +0000487}
488
Argyrios Kyrtzidis507ff532011-02-17 21:39:17 +0000489void ento::registerCFNumberCreateChecker(CheckerManager &mgr) {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000490 mgr.registerChecker<CFNumberCreateChecker>();
Argyrios Kyrtzidis9d4d4f92011-02-16 01:40:52 +0000491}
492
Argyrios Kyrtzidis507ff532011-02-17 21:39:17 +0000493void ento::registerCFRetainReleaseChecker(CheckerManager &mgr) {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000494 mgr.registerChecker<CFRetainReleaseChecker>();
Ted Kremenek1f352db2008-07-22 16:21:24 +0000495}
Argyrios Kyrtzidis507ff532011-02-17 21:39:17 +0000496
497void ento::registerClassReleaseChecker(CheckerManager &mgr) {
Argyrios Kyrtzidisdd058d82011-02-23 00:16:10 +0000498 mgr.registerChecker<ClassReleaseChecker>();
Argyrios Kyrtzidis507ff532011-02-17 21:39:17 +0000499}