blob: 1b6c528c2f167ac0af9dbda584e55219e420dbf7 [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 Kyrtzidis695fb502011-02-17 21:39:17 +000019#include "clang/StaticAnalyzer/Core/CheckerManager.h"
Ted Kremenek9b663712011-02-10 01:03:03 +000020#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
21#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
22#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
23#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h"
24#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
25#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
26#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
Ted Kremenek21142582010-12-23 19:38:26 +000027#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
Daniel Dunbarc4a1dea2008-08-11 05:35:13 +000028#include "clang/AST/DeclObjC.h"
Ted Kremenek99c6ad32008-03-27 07:25:52 +000029#include "clang/AST/Expr.h"
Steve Narofff494b572008-05-29 21:12:08 +000030#include "clang/AST/ExprObjC.h"
Ted Kremenek99c6ad32008-03-27 07:25:52 +000031#include "clang/AST/ASTContext.h"
Ted Kremenek99c6ad32008-03-27 07:25:52 +000032
Ted Kremenek99c6ad32008-03-27 07:25:52 +000033using namespace clang;
Ted Kremenek9ef65372010-12-23 07:20:52 +000034using namespace ento;
Ted Kremenek52755612008-03-27 17:17:22 +000035
Ted Kremenek2ce2baa2010-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 Kyrtzidis432424d2011-01-25 00:03:53 +000047static const ObjCInterfaceType* GetReceiverType(const ObjCMessage &msg) {
48 if (const ObjCInterfaceDecl *ID = msg.getReceiverInterface())
Argyrios Kyrtzidis090c47b2011-01-25 00:03:45 +000049 return ID->getTypeForDecl()->getAs<ObjCInterfaceType>();
Ted Kremenekc1ff3cd2008-04-30 22:48:21 +000050 return NULL;
Ted Kremenek4ba62832008-03-27 22:05:32 +000051}
52
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +000053static const char* GetReceiverNameType(const ObjCMessage &msg) {
54 if (const ObjCInterfaceType *ReceiverType = GetReceiverType(msg))
Daniel Dunbare013d682009-10-18 20:26:12 +000055 return ReceiverType->getDecl()->getIdentifier()->getNameStart();
56 return NULL;
Ted Kremenek4ba62832008-03-27 22:05:32 +000057}
Ted Kremenek52755612008-03-27 17:17:22 +000058
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000059static bool isNSString(llvm::StringRef ClassName) {
60 return ClassName == "NSString" || ClassName == "NSMutableString";
Ted Kremenek99c6ad32008-03-27 07:25:52 +000061}
62
Zhongxing Xu1c96b242008-10-17 05:57:07 +000063static inline bool isNil(SVal X) {
Mike Stump1eb44332009-09-09 15:08:12 +000064 return isa<loc::ConcreteInt>(X);
Ted Kremeneke5d5c202008-03-27 21:15:17 +000065}
66
Ted Kremenek99c6ad32008-03-27 07:25:52 +000067//===----------------------------------------------------------------------===//
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000068// NilArgChecker - Check for prohibited nil arguments to ObjC method calls.
Ted Kremenek99c6ad32008-03-27 07:25:52 +000069//===----------------------------------------------------------------------===//
70
Benjamin Kramercb9c0742010-10-22 16:33:16 +000071namespace {
72 class NilArgChecker : public CheckerVisitor<NilArgChecker> {
73 APIMisuse *BT;
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +000074 void WarnNilArg(CheckerContext &C, const ObjCMessage &msg, unsigned Arg);
Benjamin Kramercb9c0742010-10-22 16:33:16 +000075 public:
76 NilArgChecker() : BT(0) {}
77 static void *getTag() { static int x = 0; return &x; }
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +000078 void preVisitObjCMessage(CheckerContext &C, ObjCMessage msg);
Benjamin Kramercb9c0742010-10-22 16:33:16 +000079 };
80}
Mike Stump1eb44332009-09-09 15:08:12 +000081
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000082void NilArgChecker::WarnNilArg(CheckerContext &C,
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +000083 const ObjCMessage &msg,
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000084 unsigned int Arg)
85{
86 if (!BT)
87 BT = new APIMisuse("nil argument");
88
Ted Kremenekd048c6e2010-12-20 21:19:09 +000089 if (ExplodedNode *N = C.generateSink()) {
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000090 llvm::SmallString<128> sbuf;
91 llvm::raw_svector_ostream os(sbuf);
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +000092 os << "Argument to '" << GetReceiverNameType(msg) << "' method '"
93 << msg.getSelector().getAsString() << "' cannot be nil";
Mike Stump1eb44332009-09-09 15:08:12 +000094
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000095 RangedBugReport *R = new RangedBugReport(*BT, os.str(), N);
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +000096 R->addRange(msg.getArgSourceRange(Arg));
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000097 C.EmitReport(R);
Ted Kremenek4ba62832008-03-27 22:05:32 +000098 }
Ted Kremenek4ba62832008-03-27 22:05:32 +000099}
100
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +0000101void NilArgChecker::preVisitObjCMessage(CheckerContext &C,
102 ObjCMessage msg)
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000103{
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +0000104 const ObjCInterfaceType *ReceiverType = GetReceiverType(msg);
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000105 if (!ReceiverType)
106 return;
107
108 if (isNSString(ReceiverType->getDecl()->getIdentifier()->getName())) {
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +0000109 Selector S = msg.getSelector();
Ted Kremenek2ce2baa2010-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 Kyrtzidis432424d2011-01-25 00:03:53 +0000132 if (isNil(msg.getArgSVal(0, C.getState())))
133 WarnNilArg(C, msg, 0);
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000134 }
135 }
Ted Kremenek99c6ad32008-03-27 07:25:52 +0000136}
Ted Kremenek04bc8762008-06-26 23:59:48 +0000137
138//===----------------------------------------------------------------------===//
139// Error reporting.
140//===----------------------------------------------------------------------===//
141
142namespace {
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000143class CFNumberCreateChecker : public CheckerVisitor<CFNumberCreateChecker> {
Ted Kremenekcf118d42009-02-04 23:49:09 +0000144 APIMisuse* BT;
Ted Kremenek04bc8762008-06-26 23:59:48 +0000145 IdentifierInfo* II;
Ted Kremenek04bc8762008-06-26 23:59:48 +0000146public:
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000147 CFNumberCreateChecker() : BT(0), II(0) {}
148 ~CFNumberCreateChecker() {}
149 static void *getTag() { static int x = 0; return &x; }
150 void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
Ted Kremenek04bc8762008-06-26 23:59:48 +0000151private:
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000152 void EmitError(const TypedRegion* R, const Expr* Ex,
Mike Stump1eb44332009-09-09 15:08:12 +0000153 uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind);
Ted Kremenek04bc8762008-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 Stump1eb44332009-09-09 15:08:12 +0000184
Ted Kremenek04bc8762008-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 Lopes2550d702009-12-23 17:49:57 +0000199 static const unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 };
Mike Stump1eb44332009-09-09 15:08:12 +0000200
Ted Kremenek04bc8762008-06-26 23:59:48 +0000201 if (i < kCFNumberCharType)
202 return FixedSize[i-1];
Mike Stump1eb44332009-09-09 15:08:12 +0000203
Ted Kremenek04bc8762008-06-26 23:59:48 +0000204 QualType T;
Mike Stump1eb44332009-09-09 15:08:12 +0000205
Ted Kremenek04bc8762008-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 Stump1eb44332009-09-09 15:08:12 +0000217 // FIXME: We need a way to map from names to Type*.
Ted Kremenek04bc8762008-06-26 23:59:48 +0000218 default:
219 return Optional<uint64_t>();
220 }
Mike Stump1eb44332009-09-09 15:08:12 +0000221
Ted Kremenek04bc8762008-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 Stump1eb44332009-09-09 15:08:12 +0000245
Ted Kremenek04bc8762008-06-26 23:59:48 +0000246 return i <= kCFNumberCGFloatType ? Names[i-1] : "Invalid CFNumberType";
247}
248#endif
249
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000250void CFNumberCreateChecker::PreVisitCallExpr(CheckerContext &C,
251 const CallExpr *CE)
252{
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)
338 BT = new APIMisuse("Bad use of CFNumberCreate");
339
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 {
Jordy Rose61fb55c2010-07-06 02:34:42 +0000351class CFRetainReleaseChecker : public CheckerVisitor<CFRetainReleaseChecker> {
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000352 APIMisuse *BT;
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000353 IdentifierInfo *Retain, *Release;
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000354public:
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000355 CFRetainReleaseChecker(): BT(0), Retain(0), Release(0) {}
Jordy Rose61fb55c2010-07-06 02:34:42 +0000356 static void *getTag() { static int x = 0; return &x; }
Jordy Rose61fb55c2010-07-06 02:34:42 +0000357 void PreVisitCallExpr(CheckerContext& C, const CallExpr* CE);
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000358};
359} // end anonymous namespace
360
361
Jordy Rose61fb55c2010-07-06 02:34:42 +0000362void CFRetainReleaseChecker::PreVisitCallExpr(CheckerContext& C,
363 const CallExpr* CE) {
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000364 // If the CallExpr doesn't have exactly 1 argument just give up checking.
365 if (CE->getNumArgs() != 1)
Jordy Rose61fb55c2010-07-06 02:34:42 +0000366 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000367
Jordy Rose61fb55c2010-07-06 02:34:42 +0000368 // Get the function declaration of the callee.
369 const GRState* state = C.getState();
Ted Kremenek13976632010-02-08 16:18:51 +0000370 SVal X = state->getSVal(CE->getCallee());
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000371 const FunctionDecl* FD = X.getAsFunctionDecl();
Mike Stump1eb44332009-09-09 15:08:12 +0000372
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000373 if (!FD)
Jordy Rose61fb55c2010-07-06 02:34:42 +0000374 return;
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000375
376 if (!BT) {
377 ASTContext &Ctx = C.getASTContext();
378 Retain = &Ctx.Idents.get("CFRetain");
379 Release = &Ctx.Idents.get("CFRelease");
380 BT = new APIMisuse("null passed to CFRetain/CFRelease");
381 }
Mike Stump1eb44332009-09-09 15:08:12 +0000382
Jordy Rose61fb55c2010-07-06 02:34:42 +0000383 // Check if we called CFRetain/CFRelease.
Mike Stump1eb44332009-09-09 15:08:12 +0000384 const IdentifierInfo *FuncII = FD->getIdentifier();
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000385 if (!(FuncII == Retain || FuncII == Release))
Jordy Rose61fb55c2010-07-06 02:34:42 +0000386 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000387
Jordy Rose61fb55c2010-07-06 02:34:42 +0000388 // FIXME: The rest of this just checks that the argument is non-null.
389 // It should probably be refactored and combined with AttrNonNullChecker.
390
391 // Get the argument's value.
392 const Expr *Arg = CE->getArg(0);
393 SVal ArgVal = state->getSVal(Arg);
394 DefinedSVal *DefArgVal = dyn_cast<DefinedSVal>(&ArgVal);
395 if (!DefArgVal)
396 return;
397
398 // Get a NULL value.
Ted Kremenekc8413fd2010-12-02 07:49:45 +0000399 SValBuilder &svalBuilder = C.getSValBuilder();
400 DefinedSVal zero = cast<DefinedSVal>(svalBuilder.makeZeroVal(Arg->getType()));
Jordy Rose61fb55c2010-07-06 02:34:42 +0000401
402 // Make an expression asserting that they're equal.
Ted Kremenekc8413fd2010-12-02 07:49:45 +0000403 DefinedOrUnknownSVal ArgIsNull = svalBuilder.evalEQ(state, zero, *DefArgVal);
Jordy Rose61fb55c2010-07-06 02:34:42 +0000404
405 // Are they equal?
406 const GRState *stateTrue, *stateFalse;
Ted Kremenek28f47b92010-12-01 22:16:56 +0000407 llvm::tie(stateTrue, stateFalse) = state->assume(ArgIsNull);
Jordy Rose61fb55c2010-07-06 02:34:42 +0000408
409 if (stateTrue && !stateFalse) {
Ted Kremenekd048c6e2010-12-20 21:19:09 +0000410 ExplodedNode *N = C.generateSink(stateTrue);
Jordy Rose61fb55c2010-07-06 02:34:42 +0000411 if (!N)
412 return;
413
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000414 const char *description = (FuncII == Retain)
415 ? "Null pointer argument in call to CFRetain"
416 : "Null pointer argument in call to CFRelease";
417
Jordy Rose61fb55c2010-07-06 02:34:42 +0000418 EnhancedBugReport *report = new EnhancedBugReport(*BT, description, N);
419 report->addRange(Arg->getSourceRange());
420 report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Arg);
Jordy Rose61fb55c2010-07-06 02:34:42 +0000421 C.EmitReport(report);
422 return;
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000423 }
424
Jordy Rose61fb55c2010-07-06 02:34:42 +0000425 // From here on, we know the argument is non-null.
426 C.addTransition(stateFalse);
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000427}
428
429//===----------------------------------------------------------------------===//
Ted Kremenek50e837b2009-11-20 05:27:05 +0000430// Check for sending 'retain', 'release', or 'autorelease' directly to a Class.
431//===----------------------------------------------------------------------===//
432
433namespace {
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000434class ClassReleaseChecker : public CheckerVisitor<ClassReleaseChecker> {
Ted Kremenek50e837b2009-11-20 05:27:05 +0000435 Selector releaseS;
436 Selector retainS;
437 Selector autoreleaseS;
438 Selector drainS;
439 BugType *BT;
440public:
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000441 ClassReleaseChecker()
442 : BT(0) {}
Ted Kremenek50e837b2009-11-20 05:27:05 +0000443
444 static void *getTag() { static int x = 0; return &x; }
445
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +0000446 void preVisitObjCMessage(CheckerContext &C, ObjCMessage msg);
Ted Kremenek50e837b2009-11-20 05:27:05 +0000447};
448}
449
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +0000450void ClassReleaseChecker::preVisitObjCMessage(CheckerContext &C,
451 ObjCMessage msg) {
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000452
453 if (!BT) {
454 BT = new APIMisuse("message incorrectly sent to class instead of class "
455 "instance");
456
457 ASTContext &Ctx = C.getASTContext();
458 releaseS = GetNullarySelector("release", Ctx);
459 retainS = GetNullarySelector("retain", Ctx);
460 autoreleaseS = GetNullarySelector("autorelease", Ctx);
461 drainS = GetNullarySelector("drain", Ctx);
462 }
463
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +0000464 if (msg.isInstanceMessage())
Ted Kremenek50e837b2009-11-20 05:27:05 +0000465 return;
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +0000466 const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
467 assert(Class);
Douglas Gregor04badcf2010-04-21 00:45:42 +0000468
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +0000469 Selector S = msg.getSelector();
Benjamin Kramer921ddc42009-11-20 10:03:00 +0000470 if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
Ted Kremenek50e837b2009-11-20 05:27:05 +0000471 return;
472
Ted Kremenekd048c6e2010-12-20 21:19:09 +0000473 if (ExplodedNode *N = C.generateNode()) {
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000474 llvm::SmallString<200> buf;
475 llvm::raw_svector_ostream os(buf);
Ted Kremenek19d67b52009-11-23 22:22:01 +0000476
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000477 os << "The '" << S.getAsString() << "' message should be sent to instances "
478 "of class '" << Class->getName()
479 << "' and not the class directly";
Ted Kremenek50e837b2009-11-20 05:27:05 +0000480
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000481 RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +0000482 report->addRange(msg.getSourceRange());
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000483 C.EmitReport(report);
484 }
Ted Kremenek50e837b2009-11-20 05:27:05 +0000485}
486
487//===----------------------------------------------------------------------===//
Ted Kremenek78d46242008-07-22 16:21:24 +0000488// Check registration.
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000489//===----------------------------------------------------------------------===//
Argyrios Kyrtzidis0b1ba622011-02-16 01:40:52 +0000490
Argyrios Kyrtzidis695fb502011-02-17 21:39:17 +0000491static void RegisterNilArgChecker(ExprEngine& Eng) {
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000492 Eng.registerCheck(new NilArgChecker());
Argyrios Kyrtzidis0b1ba622011-02-16 01:40:52 +0000493}
494
Argyrios Kyrtzidis695fb502011-02-17 21:39:17 +0000495void ento::registerNilArgChecker(CheckerManager &mgr) {
496 mgr.addCheckerRegisterFunction(RegisterNilArgChecker);
497}
498
499static void RegisterCFNumberCreateChecker(ExprEngine& Eng) {
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000500 Eng.registerCheck(new CFNumberCreateChecker());
Argyrios Kyrtzidis0b1ba622011-02-16 01:40:52 +0000501}
502
Argyrios Kyrtzidis695fb502011-02-17 21:39:17 +0000503void ento::registerCFNumberCreateChecker(CheckerManager &mgr) {
504 mgr.addCheckerRegisterFunction(RegisterCFNumberCreateChecker);
505}
506
507static void RegisterCFRetainReleaseChecker(ExprEngine& Eng) {
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000508 Eng.registerCheck(new CFRetainReleaseChecker());
Argyrios Kyrtzidis0b1ba622011-02-16 01:40:52 +0000509}
510
Argyrios Kyrtzidis695fb502011-02-17 21:39:17 +0000511void ento::registerCFRetainReleaseChecker(CheckerManager &mgr) {
512 mgr.addCheckerRegisterFunction(RegisterCFRetainReleaseChecker);
513}
514
515static void RegisterClassReleaseChecker(ExprEngine& Eng) {
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000516 Eng.registerCheck(new ClassReleaseChecker());
Ted Kremenek78d46242008-07-22 16:21:24 +0000517}
Argyrios Kyrtzidis695fb502011-02-17 21:39:17 +0000518
519void ento::registerClassReleaseChecker(CheckerManager &mgr) {
520 mgr.addCheckerRegisterFunction(RegisterClassReleaseChecker);
521}