blob: a1037b9713a861335908a13a74e01fe560b4c3e2 [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"
Ted Kremenek9b663712011-02-10 01:03:03 +000019#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
20#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
21#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
22#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h"
23#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
24#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
25#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
Ted Kremenek21142582010-12-23 19:38:26 +000026#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
Daniel Dunbarc4a1dea2008-08-11 05:35:13 +000027#include "clang/AST/DeclObjC.h"
Ted Kremenek99c6ad32008-03-27 07:25:52 +000028#include "clang/AST/Expr.h"
Steve Narofff494b572008-05-29 21:12:08 +000029#include "clang/AST/ExprObjC.h"
Ted Kremenek99c6ad32008-03-27 07:25:52 +000030#include "clang/AST/ASTContext.h"
Ted Kremenek99c6ad32008-03-27 07:25:52 +000031
Ted Kremenek99c6ad32008-03-27 07:25:52 +000032using namespace clang;
Ted Kremenek9ef65372010-12-23 07:20:52 +000033using namespace ento;
Ted Kremenek52755612008-03-27 17:17:22 +000034
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000035namespace {
36class APIMisuse : public BugType {
37public:
38 APIMisuse(const char* name) : BugType(name, "API Misuse (Apple)") {}
39};
40} // end anonymous namespace
41
42//===----------------------------------------------------------------------===//
43// Utility functions.
44//===----------------------------------------------------------------------===//
45
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +000046static const ObjCInterfaceType* GetReceiverType(const ObjCMessage &msg) {
47 if (const ObjCInterfaceDecl *ID = msg.getReceiverInterface())
Argyrios Kyrtzidis090c47b2011-01-25 00:03:45 +000048 return ID->getTypeForDecl()->getAs<ObjCInterfaceType>();
Ted Kremenekc1ff3cd2008-04-30 22:48:21 +000049 return NULL;
Ted Kremenek4ba62832008-03-27 22:05:32 +000050}
51
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +000052static const char* GetReceiverNameType(const ObjCMessage &msg) {
53 if (const ObjCInterfaceType *ReceiverType = GetReceiverType(msg))
Daniel Dunbare013d682009-10-18 20:26:12 +000054 return ReceiverType->getDecl()->getIdentifier()->getNameStart();
55 return NULL;
Ted Kremenek4ba62832008-03-27 22:05:32 +000056}
Ted Kremenek52755612008-03-27 17:17:22 +000057
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000058static bool isNSString(llvm::StringRef ClassName) {
59 return ClassName == "NSString" || ClassName == "NSMutableString";
Ted Kremenek99c6ad32008-03-27 07:25:52 +000060}
61
Zhongxing Xu1c96b242008-10-17 05:57:07 +000062static inline bool isNil(SVal X) {
Mike Stump1eb44332009-09-09 15:08:12 +000063 return isa<loc::ConcreteInt>(X);
Ted Kremeneke5d5c202008-03-27 21:15:17 +000064}
65
Ted Kremenek99c6ad32008-03-27 07:25:52 +000066//===----------------------------------------------------------------------===//
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000067// NilArgChecker - Check for prohibited nil arguments to ObjC method calls.
Ted Kremenek99c6ad32008-03-27 07:25:52 +000068//===----------------------------------------------------------------------===//
69
Benjamin Kramercb9c0742010-10-22 16:33:16 +000070namespace {
71 class NilArgChecker : public CheckerVisitor<NilArgChecker> {
72 APIMisuse *BT;
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +000073 void WarnNilArg(CheckerContext &C, const ObjCMessage &msg, unsigned Arg);
Benjamin Kramercb9c0742010-10-22 16:33:16 +000074 public:
75 NilArgChecker() : BT(0) {}
76 static void *getTag() { static int x = 0; return &x; }
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +000077 void preVisitObjCMessage(CheckerContext &C, ObjCMessage msg);
Benjamin Kramercb9c0742010-10-22 16:33:16 +000078 };
79}
Mike Stump1eb44332009-09-09 15:08:12 +000080
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000081void NilArgChecker::WarnNilArg(CheckerContext &C,
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +000082 const ObjCMessage &msg,
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000083 unsigned int Arg)
84{
85 if (!BT)
86 BT = new APIMisuse("nil argument");
87
Ted Kremenekd048c6e2010-12-20 21:19:09 +000088 if (ExplodedNode *N = C.generateSink()) {
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000089 llvm::SmallString<128> sbuf;
90 llvm::raw_svector_ostream os(sbuf);
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +000091 os << "Argument to '" << GetReceiverNameType(msg) << "' method '"
92 << msg.getSelector().getAsString() << "' cannot be nil";
Mike Stump1eb44332009-09-09 15:08:12 +000093
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000094 RangedBugReport *R = new RangedBugReport(*BT, os.str(), N);
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +000095 R->addRange(msg.getArgSourceRange(Arg));
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000096 C.EmitReport(R);
Ted Kremenek4ba62832008-03-27 22:05:32 +000097 }
Ted Kremenek4ba62832008-03-27 22:05:32 +000098}
99
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +0000100void NilArgChecker::preVisitObjCMessage(CheckerContext &C,
101 ObjCMessage msg)
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000102{
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +0000103 const ObjCInterfaceType *ReceiverType = GetReceiverType(msg);
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000104 if (!ReceiverType)
105 return;
106
107 if (isNSString(ReceiverType->getDecl()->getIdentifier()->getName())) {
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +0000108 Selector S = msg.getSelector();
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000109
110 if (S.isUnarySelector())
111 return;
112
113 // FIXME: This is going to be really slow doing these checks with
114 // lexical comparisons.
115
116 std::string NameStr = S.getAsString();
117 llvm::StringRef Name(NameStr);
118 assert(!Name.empty());
119
120 // FIXME: Checking for initWithFormat: will not work in most cases
121 // yet because [NSString alloc] returns id, not NSString*. We will
122 // need support for tracking expected-type information in the analyzer
123 // to find these errors.
124 if (Name == "caseInsensitiveCompare:" ||
125 Name == "compare:" ||
126 Name == "compare:options:" ||
127 Name == "compare:options:range:" ||
128 Name == "compare:options:range:locale:" ||
129 Name == "componentsSeparatedByCharactersInSet:" ||
130 Name == "initWithFormat:") {
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +0000131 if (isNil(msg.getArgSVal(0, C.getState())))
132 WarnNilArg(C, msg, 0);
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000133 }
134 }
Ted Kremenek99c6ad32008-03-27 07:25:52 +0000135}
Ted Kremenek04bc8762008-06-26 23:59:48 +0000136
137//===----------------------------------------------------------------------===//
138// Error reporting.
139//===----------------------------------------------------------------------===//
140
141namespace {
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000142class CFNumberCreateChecker : public CheckerVisitor<CFNumberCreateChecker> {
Ted Kremenekcf118d42009-02-04 23:49:09 +0000143 APIMisuse* BT;
Ted Kremenek04bc8762008-06-26 23:59:48 +0000144 IdentifierInfo* II;
Ted Kremenek04bc8762008-06-26 23:59:48 +0000145public:
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000146 CFNumberCreateChecker() : BT(0), II(0) {}
147 ~CFNumberCreateChecker() {}
148 static void *getTag() { static int x = 0; return &x; }
149 void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
Ted Kremenek04bc8762008-06-26 23:59:48 +0000150private:
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000151 void EmitError(const TypedRegion* R, const Expr* Ex,
Mike Stump1eb44332009-09-09 15:08:12 +0000152 uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind);
Ted Kremenek04bc8762008-06-26 23:59:48 +0000153};
154} // end anonymous namespace
155
156enum CFNumberType {
157 kCFNumberSInt8Type = 1,
158 kCFNumberSInt16Type = 2,
159 kCFNumberSInt32Type = 3,
160 kCFNumberSInt64Type = 4,
161 kCFNumberFloat32Type = 5,
162 kCFNumberFloat64Type = 6,
163 kCFNumberCharType = 7,
164 kCFNumberShortType = 8,
165 kCFNumberIntType = 9,
166 kCFNumberLongType = 10,
167 kCFNumberLongLongType = 11,
168 kCFNumberFloatType = 12,
169 kCFNumberDoubleType = 13,
170 kCFNumberCFIndexType = 14,
171 kCFNumberNSIntegerType = 15,
172 kCFNumberCGFloatType = 16
173};
174
175namespace {
176 template<typename T>
177 class Optional {
178 bool IsKnown;
179 T Val;
180 public:
181 Optional() : IsKnown(false), Val(0) {}
182 Optional(const T& val) : IsKnown(true), Val(val) {}
Mike Stump1eb44332009-09-09 15:08:12 +0000183
Ted Kremenek04bc8762008-06-26 23:59:48 +0000184 bool isKnown() const { return IsKnown; }
185
186 const T& getValue() const {
187 assert (isKnown());
188 return Val;
189 }
190
191 operator const T&() const {
192 return getValue();
193 }
194 };
195}
196
197static Optional<uint64_t> GetCFNumberSize(ASTContext& Ctx, uint64_t i) {
Nuno Lopes2550d702009-12-23 17:49:57 +0000198 static const unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 };
Mike Stump1eb44332009-09-09 15:08:12 +0000199
Ted Kremenek04bc8762008-06-26 23:59:48 +0000200 if (i < kCFNumberCharType)
201 return FixedSize[i-1];
Mike Stump1eb44332009-09-09 15:08:12 +0000202
Ted Kremenek04bc8762008-06-26 23:59:48 +0000203 QualType T;
Mike Stump1eb44332009-09-09 15:08:12 +0000204
Ted Kremenek04bc8762008-06-26 23:59:48 +0000205 switch (i) {
206 case kCFNumberCharType: T = Ctx.CharTy; break;
207 case kCFNumberShortType: T = Ctx.ShortTy; break;
208 case kCFNumberIntType: T = Ctx.IntTy; break;
209 case kCFNumberLongType: T = Ctx.LongTy; break;
210 case kCFNumberLongLongType: T = Ctx.LongLongTy; break;
211 case kCFNumberFloatType: T = Ctx.FloatTy; break;
212 case kCFNumberDoubleType: T = Ctx.DoubleTy; break;
213 case kCFNumberCFIndexType:
214 case kCFNumberNSIntegerType:
215 case kCFNumberCGFloatType:
Mike Stump1eb44332009-09-09 15:08:12 +0000216 // FIXME: We need a way to map from names to Type*.
Ted Kremenek04bc8762008-06-26 23:59:48 +0000217 default:
218 return Optional<uint64_t>();
219 }
Mike Stump1eb44332009-09-09 15:08:12 +0000220
Ted Kremenek04bc8762008-06-26 23:59:48 +0000221 return Ctx.getTypeSize(T);
222}
223
224#if 0
225static const char* GetCFNumberTypeStr(uint64_t i) {
226 static const char* Names[] = {
227 "kCFNumberSInt8Type",
228 "kCFNumberSInt16Type",
229 "kCFNumberSInt32Type",
230 "kCFNumberSInt64Type",
231 "kCFNumberFloat32Type",
232 "kCFNumberFloat64Type",
233 "kCFNumberCharType",
234 "kCFNumberShortType",
235 "kCFNumberIntType",
236 "kCFNumberLongType",
237 "kCFNumberLongLongType",
238 "kCFNumberFloatType",
239 "kCFNumberDoubleType",
240 "kCFNumberCFIndexType",
241 "kCFNumberNSIntegerType",
242 "kCFNumberCGFloatType"
243 };
Mike Stump1eb44332009-09-09 15:08:12 +0000244
Ted Kremenek04bc8762008-06-26 23:59:48 +0000245 return i <= kCFNumberCGFloatType ? Names[i-1] : "Invalid CFNumberType";
246}
247#endif
248
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000249void CFNumberCreateChecker::PreVisitCallExpr(CheckerContext &C,
250 const CallExpr *CE)
251{
Mike Stump1eb44332009-09-09 15:08:12 +0000252 const Expr* Callee = CE->getCallee();
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000253 const GRState *state = C.getState();
254 SVal CallV = state->getSVal(Callee);
Zhongxing Xu369f4472009-04-20 05:24:46 +0000255 const FunctionDecl* FD = CallV.getAsFunctionDecl();
Ted Kremenek04bc8762008-06-26 23:59:48 +0000256
Ted Kremenek2ce2baa2010-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 Stump1eb44332009-09-09 15:08:12 +0000266
Ted Kremenek04bc8762008-06-26 23:59:48 +0000267 // Get the value of the "theType" argument.
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000268 SVal TheTypeVal = state->getSVal(CE->getArg(1));
Mike Stump1eb44332009-09-09 15:08:12 +0000269
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000270 // FIXME: We really should allow ranges of valid theType values, and
271 // bifurcate the state appropriately.
Zhongxing Xu1c96b242008-10-17 05:57:07 +0000272 nonloc::ConcreteInt* V = dyn_cast<nonloc::ConcreteInt>(&TheTypeVal);
Ted Kremenek04bc8762008-06-26 23:59:48 +0000273 if (!V)
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000274 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000275
Ted Kremenek04bc8762008-06-26 23:59:48 +0000276 uint64_t NumberKind = V->getValue().getLimitedValue();
277 Optional<uint64_t> TargetSize = GetCFNumberSize(Ctx, NumberKind);
Mike Stump1eb44332009-09-09 15:08:12 +0000278
Ted Kremenek04bc8762008-06-26 23:59:48 +0000279 // FIXME: In some cases we can emit an error.
280 if (!TargetSize.isKnown())
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000281 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000282
Ted Kremenek04bc8762008-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 Kremenek2ce2baa2010-10-20 23:38:56 +0000286 SVal TheValueExpr = state->getSVal(CE->getArg(2));
Mike Stump1eb44332009-09-09 15:08:12 +0000287
Ted Kremenek04bc8762008-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 Xu1c96b242008-10-17 05:57:07 +0000290 loc::MemRegionVal* LV = dyn_cast<loc::MemRegionVal>(&TheValueExpr);
Ted Kremenek04bc8762008-06-26 23:59:48 +0000291 if (!LV)
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000292 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000293
Zhanyong Wan7dfc9422011-02-16 21:13:32 +0000294 const TypedRegion* R = dyn_cast<TypedRegion>(LV->stripCasts());
Ted Kremenek5e77eba2009-07-29 18:17:40 +0000295 if (!R)
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000296 return;
Ted Kremenek5e77eba2009-07-29 18:17:40 +0000297
Zhongxing Xu018220c2010-08-11 06:10:55 +0000298 QualType T = Ctx.getCanonicalType(R->getValueType());
Mike Stump1eb44332009-09-09 15:08:12 +0000299
Ted Kremenek04bc8762008-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 Stump1eb44332009-09-09 15:08:12 +0000302
303 if (!T->isIntegerType())
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000304 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000305
Ted Kremenek04bc8762008-06-26 23:59:48 +0000306 uint64_t SourceSize = Ctx.getTypeSize(T);
Mike Stump1eb44332009-09-09 15:08:12 +0000307
Ted Kremenek04bc8762008-06-26 23:59:48 +0000308 // CHECK: is SourceSize == TargetSize
Ted Kremenek04bc8762008-06-26 23:59:48 +0000309 if (SourceSize == TargetSize)
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000310 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000311
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000312 // Generate an error. Only generate a sink if 'SourceSize < TargetSize';
313 // otherwise generate a regular node.
314 //
Ted Kremenek04bc8762008-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 Kremenek2ce2baa2010-10-20 23:38:56 +0000317 //
Ted Kremenekd048c6e2010-12-20 21:19:09 +0000318 if (ExplodedNode *N = SourceSize < TargetSize ? C.generateSink()
319 : C.generateNode()) {
Ted Kremenek2ce2baa2010-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 Kremenek04bc8762008-06-26 23:59:48 +0000335
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000336 if (!BT)
337 BT = new APIMisuse("Bad use of CFNumberCreate");
338
339 RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
340 report->addRange(CE->getArg(2)->getSourceRange());
341 C.EmitReport(report);
342 }
Ted Kremenek04bc8762008-06-26 23:59:48 +0000343}
344
Ted Kremenek78d46242008-07-22 16:21:24 +0000345//===----------------------------------------------------------------------===//
Jordy Rose61fb55c2010-07-06 02:34:42 +0000346// CFRetain/CFRelease checking for null arguments.
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000347//===----------------------------------------------------------------------===//
348
349namespace {
Jordy Rose61fb55c2010-07-06 02:34:42 +0000350class CFRetainReleaseChecker : public CheckerVisitor<CFRetainReleaseChecker> {
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000351 APIMisuse *BT;
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000352 IdentifierInfo *Retain, *Release;
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000353public:
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000354 CFRetainReleaseChecker(): BT(0), Retain(0), Release(0) {}
Jordy Rose61fb55c2010-07-06 02:34:42 +0000355 static void *getTag() { static int x = 0; return &x; }
Jordy Rose61fb55c2010-07-06 02:34:42 +0000356 void PreVisitCallExpr(CheckerContext& C, const CallExpr* CE);
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000357};
358} // end anonymous namespace
359
360
Jordy Rose61fb55c2010-07-06 02:34:42 +0000361void CFRetainReleaseChecker::PreVisitCallExpr(CheckerContext& C,
362 const CallExpr* CE) {
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");
379 BT = new APIMisuse("null passed to CFRetain/CFRelease");
380 }
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 {
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000433class ClassReleaseChecker : public CheckerVisitor<ClassReleaseChecker> {
Ted Kremenek50e837b2009-11-20 05:27:05 +0000434 Selector releaseS;
435 Selector retainS;
436 Selector autoreleaseS;
437 Selector drainS;
438 BugType *BT;
439public:
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000440 ClassReleaseChecker()
441 : BT(0) {}
Ted Kremenek50e837b2009-11-20 05:27:05 +0000442
443 static void *getTag() { static int x = 0; return &x; }
444
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +0000445 void preVisitObjCMessage(CheckerContext &C, ObjCMessage msg);
Ted Kremenek50e837b2009-11-20 05:27:05 +0000446};
447}
448
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +0000449void ClassReleaseChecker::preVisitObjCMessage(CheckerContext &C,
450 ObjCMessage msg) {
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000451
452 if (!BT) {
453 BT = new APIMisuse("message incorrectly sent to class instead of class "
454 "instance");
455
456 ASTContext &Ctx = C.getASTContext();
457 releaseS = GetNullarySelector("release", Ctx);
458 retainS = GetNullarySelector("retain", Ctx);
459 autoreleaseS = GetNullarySelector("autorelease", Ctx);
460 drainS = GetNullarySelector("drain", Ctx);
461 }
462
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +0000463 if (msg.isInstanceMessage())
Ted Kremenek50e837b2009-11-20 05:27:05 +0000464 return;
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +0000465 const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
466 assert(Class);
Douglas Gregor04badcf2010-04-21 00:45:42 +0000467
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +0000468 Selector S = msg.getSelector();
Benjamin Kramer921ddc42009-11-20 10:03:00 +0000469 if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
Ted Kremenek50e837b2009-11-20 05:27:05 +0000470 return;
471
Ted Kremenekd048c6e2010-12-20 21:19:09 +0000472 if (ExplodedNode *N = C.generateNode()) {
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000473 llvm::SmallString<200> buf;
474 llvm::raw_svector_ostream os(buf);
Ted Kremenek19d67b52009-11-23 22:22:01 +0000475
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000476 os << "The '" << S.getAsString() << "' message should be sent to instances "
477 "of class '" << Class->getName()
478 << "' and not the class directly";
Ted Kremenek50e837b2009-11-20 05:27:05 +0000479
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000480 RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +0000481 report->addRange(msg.getSourceRange());
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000482 C.EmitReport(report);
483 }
Ted Kremenek50e837b2009-11-20 05:27:05 +0000484}
485
486//===----------------------------------------------------------------------===//
Ted Kremenek78d46242008-07-22 16:21:24 +0000487// Check registration.
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000488//===----------------------------------------------------------------------===//
Argyrios Kyrtzidis0b1ba622011-02-16 01:40:52 +0000489
490void ento::registerNilArgChecker(ExprEngine& Eng) {
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000491 Eng.registerCheck(new NilArgChecker());
Argyrios Kyrtzidis0b1ba622011-02-16 01:40:52 +0000492}
493
494void ento::registerCFNumberCreateChecker(ExprEngine& Eng) {
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000495 Eng.registerCheck(new CFNumberCreateChecker());
Argyrios Kyrtzidis0b1ba622011-02-16 01:40:52 +0000496}
497
498void ento::registerCFRetainReleaseChecker(ExprEngine& Eng) {
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000499 Eng.registerCheck(new CFRetainReleaseChecker());
Argyrios Kyrtzidis0b1ba622011-02-16 01:40:52 +0000500}
501
502void ento::registerClassReleaseChecker(ExprEngine& Eng) {
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000503 Eng.registerCheck(new ClassReleaseChecker());
Ted Kremenek78d46242008-07-22 16:21:24 +0000504}