blob: 2aad77020719a124dda70423b32c8df326c5de2c [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
Ted Kremenek52755612008-03-27 17:17:22 +000016#include "BasicObjCFoundationChecks.h"
17
Argyrios Kyrtzidis0b1ba622011-02-16 01:40:52 +000018#include "ClangSACheckers.h"
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +000019#include "clang/StaticAnalyzer/Core/CheckerV2.h"
Argyrios Kyrtzidis695fb502011-02-17 21:39:17 +000020#include "clang/StaticAnalyzer/Core/CheckerManager.h"
Ted Kremenek9b663712011-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 Kremenek21142582010-12-23 19:38:26 +000028#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
Daniel Dunbarc4a1dea2008-08-11 05:35:13 +000029#include "clang/AST/DeclObjC.h"
Ted Kremenek99c6ad32008-03-27 07:25:52 +000030#include "clang/AST/Expr.h"
Steve Narofff494b572008-05-29 21:12:08 +000031#include "clang/AST/ExprObjC.h"
Ted Kremenek99c6ad32008-03-27 07:25:52 +000032#include "clang/AST/ASTContext.h"
Ted Kremenek99c6ad32008-03-27 07:25:52 +000033
Ted Kremenek99c6ad32008-03-27 07:25:52 +000034using namespace clang;
Ted Kremenek9ef65372010-12-23 07:20:52 +000035using namespace ento;
Ted Kremenek52755612008-03-27 17:17:22 +000036
Ted Kremenek2ce2baa2010-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 Kyrtzidis432424d2011-01-25 00:03:53 +000048static const ObjCInterfaceType* GetReceiverType(const ObjCMessage &msg) {
49 if (const ObjCInterfaceDecl *ID = msg.getReceiverInterface())
Argyrios Kyrtzidis090c47b2011-01-25 00:03:45 +000050 return ID->getTypeForDecl()->getAs<ObjCInterfaceType>();
Ted Kremenekc1ff3cd2008-04-30 22:48:21 +000051 return NULL;
Ted Kremenek4ba62832008-03-27 22:05:32 +000052}
53
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +000054static const char* GetReceiverNameType(const ObjCMessage &msg) {
55 if (const ObjCInterfaceType *ReceiverType = GetReceiverType(msg))
Daniel Dunbare013d682009-10-18 20:26:12 +000056 return ReceiverType->getDecl()->getIdentifier()->getNameStart();
57 return NULL;
Ted Kremenek4ba62832008-03-27 22:05:32 +000058}
Ted Kremenek52755612008-03-27 17:17:22 +000059
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000060static bool isNSString(llvm::StringRef ClassName) {
61 return ClassName == "NSString" || ClassName == "NSMutableString";
Ted Kremenek99c6ad32008-03-27 07:25:52 +000062}
63
Zhongxing Xu1c96b242008-10-17 05:57:07 +000064static inline bool isNil(SVal X) {
Mike Stump1eb44332009-09-09 15:08:12 +000065 return isa<loc::ConcreteInt>(X);
Ted Kremeneke5d5c202008-03-27 21:15:17 +000066}
67
Ted Kremenek99c6ad32008-03-27 07:25:52 +000068//===----------------------------------------------------------------------===//
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000069// NilArgChecker - Check for prohibited nil arguments to ObjC method calls.
Ted Kremenek99c6ad32008-03-27 07:25:52 +000070//===----------------------------------------------------------------------===//
71
Benjamin Kramercb9c0742010-10-22 16:33:16 +000072namespace {
Argyrios Kyrtzidis74eed0e2011-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 Kramercb9c0742010-10-22 16:33:16 +000079 public:
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +000080 void checkPreObjCMessage(ObjCMessage msg, CheckerContext &C) const;
Benjamin Kramercb9c0742010-10-22 16:33:16 +000081 };
82}
Mike Stump1eb44332009-09-09 15:08:12 +000083
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000084void NilArgChecker::WarnNilArg(CheckerContext &C,
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +000085 const ObjCMessage &msg,
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +000086 unsigned int Arg) const
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000087{
88 if (!BT)
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +000089 BT.reset(new APIMisuse("nil argument"));
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000090
Ted Kremenekd048c6e2010-12-20 21:19:09 +000091 if (ExplodedNode *N = C.generateSink()) {
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000092 llvm::SmallString<128> sbuf;
93 llvm::raw_svector_ostream os(sbuf);
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +000094 os << "Argument to '" << GetReceiverNameType(msg) << "' method '"
95 << msg.getSelector().getAsString() << "' cannot be nil";
Mike Stump1eb44332009-09-09 15:08:12 +000096
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000097 RangedBugReport *R = new RangedBugReport(*BT, os.str(), N);
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +000098 R->addRange(msg.getArgSourceRange(Arg));
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000099 C.EmitReport(R);
Ted Kremenek4ba62832008-03-27 22:05:32 +0000100 }
Ted Kremenek4ba62832008-03-27 22:05:32 +0000101}
102
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000103void NilArgChecker::checkPreObjCMessage(ObjCMessage msg,
104 CheckerContext &C) const {
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +0000105 const ObjCInterfaceType *ReceiverType = GetReceiverType(msg);
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000106 if (!ReceiverType)
107 return;
108
109 if (isNSString(ReceiverType->getDecl()->getIdentifier()->getName())) {
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +0000110 Selector S = msg.getSelector();
Ted Kremenek2ce2baa2010-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 Kyrtzidis432424d2011-01-25 00:03:53 +0000133 if (isNil(msg.getArgSVal(0, C.getState())))
134 WarnNilArg(C, msg, 0);
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000135 }
136 }
Ted Kremenek99c6ad32008-03-27 07:25:52 +0000137}
Ted Kremenek04bc8762008-06-26 23:59:48 +0000138
139//===----------------------------------------------------------------------===//
140// Error reporting.
141//===----------------------------------------------------------------------===//
142
143namespace {
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000144class CFNumberCreateChecker : public CheckerV2< check::PreStmt<CallExpr> > {
145 mutable llvm::OwningPtr<APIMisuse> BT;
146 mutable IdentifierInfo* II;
Ted Kremenek04bc8762008-06-26 23:59:48 +0000147public:
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000148 CFNumberCreateChecker() : II(0) {}
149
150 void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
151
Ted Kremenek04bc8762008-06-26 23:59:48 +0000152private:
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000153 void EmitError(const TypedRegion* R, const Expr* Ex,
Mike Stump1eb44332009-09-09 15:08:12 +0000154 uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind);
Ted Kremenek04bc8762008-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 Stump1eb44332009-09-09 15:08:12 +0000185
Ted Kremenek04bc8762008-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 Lopes2550d702009-12-23 17:49:57 +0000200 static const unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 };
Mike Stump1eb44332009-09-09 15:08:12 +0000201
Ted Kremenek04bc8762008-06-26 23:59:48 +0000202 if (i < kCFNumberCharType)
203 return FixedSize[i-1];
Mike Stump1eb44332009-09-09 15:08:12 +0000204
Ted Kremenek04bc8762008-06-26 23:59:48 +0000205 QualType T;
Mike Stump1eb44332009-09-09 15:08:12 +0000206
Ted Kremenek04bc8762008-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 Stump1eb44332009-09-09 15:08:12 +0000218 // FIXME: We need a way to map from names to Type*.
Ted Kremenek04bc8762008-06-26 23:59:48 +0000219 default:
220 return Optional<uint64_t>();
221 }
Mike Stump1eb44332009-09-09 15:08:12 +0000222
Ted Kremenek04bc8762008-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 Stump1eb44332009-09-09 15:08:12 +0000246
Ted Kremenek04bc8762008-06-26 23:59:48 +0000247 return i <= kCFNumberCGFloatType ? Names[i-1] : "Invalid CFNumberType";
248}
249#endif
250
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000251void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE,
252 CheckerContext &C) const {
Mike Stump1eb44332009-09-09 15:08:12 +0000253 const Expr* Callee = CE->getCallee();
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000254 const GRState *state = C.getState();
255 SVal CallV = state->getSVal(Callee);
Zhongxing Xu369f4472009-04-20 05:24:46 +0000256 const FunctionDecl* FD = CallV.getAsFunctionDecl();
Ted Kremenek04bc8762008-06-26 23:59:48 +0000257
Ted Kremenek2ce2baa2010-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 Stump1eb44332009-09-09 15:08:12 +0000267
Ted Kremenek04bc8762008-06-26 23:59:48 +0000268 // Get the value of the "theType" argument.
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000269 SVal TheTypeVal = state->getSVal(CE->getArg(1));
Mike Stump1eb44332009-09-09 15:08:12 +0000270
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000271 // FIXME: We really should allow ranges of valid theType values, and
272 // bifurcate the state appropriately.
Zhongxing Xu1c96b242008-10-17 05:57:07 +0000273 nonloc::ConcreteInt* V = dyn_cast<nonloc::ConcreteInt>(&TheTypeVal);
Ted Kremenek04bc8762008-06-26 23:59:48 +0000274 if (!V)
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000275 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000276
Ted Kremenek04bc8762008-06-26 23:59:48 +0000277 uint64_t NumberKind = V->getValue().getLimitedValue();
278 Optional<uint64_t> TargetSize = GetCFNumberSize(Ctx, NumberKind);
Mike Stump1eb44332009-09-09 15:08:12 +0000279
Ted Kremenek04bc8762008-06-26 23:59:48 +0000280 // FIXME: In some cases we can emit an error.
281 if (!TargetSize.isKnown())
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000282 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000283
Ted Kremenek04bc8762008-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 Kremenek2ce2baa2010-10-20 23:38:56 +0000287 SVal TheValueExpr = state->getSVal(CE->getArg(2));
Mike Stump1eb44332009-09-09 15:08:12 +0000288
Ted Kremenek04bc8762008-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 Xu1c96b242008-10-17 05:57:07 +0000291 loc::MemRegionVal* LV = dyn_cast<loc::MemRegionVal>(&TheValueExpr);
Ted Kremenek04bc8762008-06-26 23:59:48 +0000292 if (!LV)
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000293 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000294
Zhanyong Wan7dfc9422011-02-16 21:13:32 +0000295 const TypedRegion* R = dyn_cast<TypedRegion>(LV->stripCasts());
Ted Kremenek5e77eba2009-07-29 18:17:40 +0000296 if (!R)
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000297 return;
Ted Kremenek5e77eba2009-07-29 18:17:40 +0000298
Zhongxing Xu018220c2010-08-11 06:10:55 +0000299 QualType T = Ctx.getCanonicalType(R->getValueType());
Mike Stump1eb44332009-09-09 15:08:12 +0000300
Ted Kremenek04bc8762008-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 Stump1eb44332009-09-09 15:08:12 +0000303
304 if (!T->isIntegerType())
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000305 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000306
Ted Kremenek04bc8762008-06-26 23:59:48 +0000307 uint64_t SourceSize = Ctx.getTypeSize(T);
Mike Stump1eb44332009-09-09 15:08:12 +0000308
Ted Kremenek04bc8762008-06-26 23:59:48 +0000309 // CHECK: is SourceSize == TargetSize
Ted Kremenek04bc8762008-06-26 23:59:48 +0000310 if (SourceSize == TargetSize)
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000311 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000312
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000313 // Generate an error. Only generate a sink if 'SourceSize < TargetSize';
314 // otherwise generate a regular node.
315 //
Ted Kremenek04bc8762008-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 Kremenek2ce2baa2010-10-20 23:38:56 +0000318 //
Ted Kremenekd048c6e2010-12-20 21:19:09 +0000319 if (ExplodedNode *N = SourceSize < TargetSize ? C.generateSink()
320 : C.generateNode()) {
Ted Kremenek2ce2baa2010-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 Kremenek04bc8762008-06-26 23:59:48 +0000336
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000337 if (!BT)
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000338 BT.reset(new APIMisuse("Bad use of CFNumberCreate"));
Ted Kremenek2ce2baa2010-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 Kremenek04bc8762008-06-26 23:59:48 +0000344}
345
Ted Kremenek78d46242008-07-22 16:21:24 +0000346//===----------------------------------------------------------------------===//
Jordy Rose61fb55c2010-07-06 02:34:42 +0000347// CFRetain/CFRelease checking for null arguments.
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000348//===----------------------------------------------------------------------===//
349
350namespace {
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000351class CFRetainReleaseChecker : public CheckerV2< check::PreStmt<CallExpr> > {
352 mutable llvm::OwningPtr<APIMisuse> BT;
353 mutable IdentifierInfo *Retain, *Release;
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000354public:
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000355 CFRetainReleaseChecker(): Retain(0), Release(0) {}
356 void checkPreStmt(const CallExpr* CE, CheckerContext& C) const;
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000357};
358} // end anonymous namespace
359
360
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000361void CFRetainReleaseChecker::checkPreStmt(const CallExpr* CE,
362 CheckerContext& C) const {
Ted Kremenek79b4f7d2009-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 Rose61fb55c2010-07-06 02:34:42 +0000365 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000366
Jordy Rose61fb55c2010-07-06 02:34:42 +0000367 // Get the function declaration of the callee.
368 const GRState* state = C.getState();
Ted Kremenek13976632010-02-08 16:18:51 +0000369 SVal X = state->getSVal(CE->getCallee());
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000370 const FunctionDecl* FD = X.getAsFunctionDecl();
Mike Stump1eb44332009-09-09 15:08:12 +0000371
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000372 if (!FD)
Jordy Rose61fb55c2010-07-06 02:34:42 +0000373 return;
Ted Kremenek2ce2baa2010-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 Kyrtzidis74eed0e2011-02-23 00:16:10 +0000379 BT.reset(new APIMisuse("null passed to CFRetain/CFRelease"));
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000380 }
Mike Stump1eb44332009-09-09 15:08:12 +0000381
Jordy Rose61fb55c2010-07-06 02:34:42 +0000382 // Check if we called CFRetain/CFRelease.
Mike Stump1eb44332009-09-09 15:08:12 +0000383 const IdentifierInfo *FuncII = FD->getIdentifier();
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000384 if (!(FuncII == Retain || FuncII == Release))
Jordy Rose61fb55c2010-07-06 02:34:42 +0000385 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000386
Jordy Rose61fb55c2010-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 Kremenekc8413fd2010-12-02 07:49:45 +0000398 SValBuilder &svalBuilder = C.getSValBuilder();
399 DefinedSVal zero = cast<DefinedSVal>(svalBuilder.makeZeroVal(Arg->getType()));
Jordy Rose61fb55c2010-07-06 02:34:42 +0000400
401 // Make an expression asserting that they're equal.
Ted Kremenekc8413fd2010-12-02 07:49:45 +0000402 DefinedOrUnknownSVal ArgIsNull = svalBuilder.evalEQ(state, zero, *DefArgVal);
Jordy Rose61fb55c2010-07-06 02:34:42 +0000403
404 // Are they equal?
405 const GRState *stateTrue, *stateFalse;
Ted Kremenek28f47b92010-12-01 22:16:56 +0000406 llvm::tie(stateTrue, stateFalse) = state->assume(ArgIsNull);
Jordy Rose61fb55c2010-07-06 02:34:42 +0000407
408 if (stateTrue && !stateFalse) {
Ted Kremenekd048c6e2010-12-20 21:19:09 +0000409 ExplodedNode *N = C.generateSink(stateTrue);
Jordy Rose61fb55c2010-07-06 02:34:42 +0000410 if (!N)
411 return;
412
Ted Kremenek79b4f7d2009-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 Rose61fb55c2010-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 Rose61fb55c2010-07-06 02:34:42 +0000420 C.EmitReport(report);
421 return;
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000422 }
423
Jordy Rose61fb55c2010-07-06 02:34:42 +0000424 // From here on, we know the argument is non-null.
425 C.addTransition(stateFalse);
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000426}
427
428//===----------------------------------------------------------------------===//
Ted Kremenek50e837b2009-11-20 05:27:05 +0000429// Check for sending 'retain', 'release', or 'autorelease' directly to a Class.
430//===----------------------------------------------------------------------===//
431
432namespace {
Argyrios Kyrtzidis74eed0e2011-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 Kremenek50e837b2009-11-20 05:27:05 +0000439
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000440public:
441 void checkPreObjCMessage(ObjCMessage msg, CheckerContext &C) const;
Ted Kremenek50e837b2009-11-20 05:27:05 +0000442};
443}
444
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000445void ClassReleaseChecker::checkPreObjCMessage(ObjCMessage msg,
446 CheckerContext &C) const {
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000447
448 if (!BT) {
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000449 BT.reset(new APIMisuse("message incorrectly sent to class instead of class "
450 "instance"));
Ted Kremenek2ce2baa2010-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 Kyrtzidis432424d2011-01-25 00:03:53 +0000459 if (msg.isInstanceMessage())
Ted Kremenek50e837b2009-11-20 05:27:05 +0000460 return;
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +0000461 const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
462 assert(Class);
Douglas Gregor04badcf2010-04-21 00:45:42 +0000463
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +0000464 Selector S = msg.getSelector();
Benjamin Kramer921ddc42009-11-20 10:03:00 +0000465 if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
Ted Kremenek50e837b2009-11-20 05:27:05 +0000466 return;
467
Ted Kremenekd048c6e2010-12-20 21:19:09 +0000468 if (ExplodedNode *N = C.generateNode()) {
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000469 llvm::SmallString<200> buf;
470 llvm::raw_svector_ostream os(buf);
Ted Kremenek19d67b52009-11-23 22:22:01 +0000471
Ted Kremenek2ce2baa2010-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 Kremenek50e837b2009-11-20 05:27:05 +0000475
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000476 RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +0000477 report->addRange(msg.getSourceRange());
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000478 C.EmitReport(report);
479 }
Ted Kremenek50e837b2009-11-20 05:27:05 +0000480}
481
482//===----------------------------------------------------------------------===//
Ted Kremenek78d46242008-07-22 16:21:24 +0000483// Check registration.
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000484//===----------------------------------------------------------------------===//
Argyrios Kyrtzidis0b1ba622011-02-16 01:40:52 +0000485
Argyrios Kyrtzidis695fb502011-02-17 21:39:17 +0000486void ento::registerNilArgChecker(CheckerManager &mgr) {
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000487 mgr.registerChecker<NilArgChecker>();
Argyrios Kyrtzidis0b1ba622011-02-16 01:40:52 +0000488}
489
Argyrios Kyrtzidis695fb502011-02-17 21:39:17 +0000490void ento::registerCFNumberCreateChecker(CheckerManager &mgr) {
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000491 mgr.registerChecker<CFNumberCreateChecker>();
Argyrios Kyrtzidis0b1ba622011-02-16 01:40:52 +0000492}
493
Argyrios Kyrtzidis695fb502011-02-17 21:39:17 +0000494void ento::registerCFRetainReleaseChecker(CheckerManager &mgr) {
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000495 mgr.registerChecker<CFRetainReleaseChecker>();
Ted Kremenek78d46242008-07-22 16:21:24 +0000496}
Argyrios Kyrtzidis695fb502011-02-17 21:39:17 +0000497
498void ento::registerClassReleaseChecker(CheckerManager &mgr) {
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000499 mgr.registerChecker<ClassReleaseChecker>();
Argyrios Kyrtzidis695fb502011-02-17 21:39:17 +0000500}