blob: 1631df8af9883d74d4b68d1c201305fd62250d27 [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
Argyrios Kyrtzidis0b1ba622011-02-16 01:40:52 +000016#include "ClangSACheckers.h"
Ted Kremenek928c4152011-03-17 04:01:35 +000017#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
Argyrios Kyrtzidisec8605f2011-03-01 01:16:21 +000018#include "clang/StaticAnalyzer/Core/Checker.h"
Argyrios Kyrtzidis695fb502011-02-17 21:39:17 +000019#include "clang/StaticAnalyzer/Core/CheckerManager.h"
Argyrios Kyrtzidis983326f2011-02-23 01:05:36 +000020#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
Ted Kremenek9b663712011-02-10 01:03:03 +000021#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
Ted Kremenek9b663712011-02-10 01:03:03 +000022#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
Ted Kremenek18c66fd2011-08-15 22:09:50 +000023#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
Ted Kremenek9b663712011-02-10 01:03:03 +000024#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
25#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
Daniel Dunbarc4a1dea2008-08-11 05:35:13 +000026#include "clang/AST/DeclObjC.h"
Ted Kremenek99c6ad32008-03-27 07:25:52 +000027#include "clang/AST/Expr.h"
Steve Narofff494b572008-05-29 21:12:08 +000028#include "clang/AST/ExprObjC.h"
Ted Kremenek99c6ad32008-03-27 07:25:52 +000029#include "clang/AST/ASTContext.h"
Ted Kremenek99c6ad32008-03-27 07:25:52 +000030
Ted Kremenek99c6ad32008-03-27 07:25:52 +000031using namespace clang;
Ted Kremenek9ef65372010-12-23 07:20:52 +000032using namespace ento;
Ted Kremenek52755612008-03-27 17:17:22 +000033
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000034namespace {
35class APIMisuse : public BugType {
36public:
37 APIMisuse(const char* name) : BugType(name, "API Misuse (Apple)") {}
38};
39} // end anonymous namespace
40
41//===----------------------------------------------------------------------===//
42// Utility functions.
43//===----------------------------------------------------------------------===//
44
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +000045static const char* GetReceiverNameType(const ObjCMessage &msg) {
Anders Carlssonb62bdce2011-03-08 20:05:26 +000046 if (const ObjCInterfaceDecl *ID = msg.getReceiverInterface())
47 return ID->getIdentifier()->getNameStart();
48 return 0;
Ted Kremenek4ba62832008-03-27 22:05:32 +000049}
Ted Kremenek52755612008-03-27 17:17:22 +000050
Anders Carlssonb62bdce2011-03-08 20:05:26 +000051static bool isReceiverClassOrSuperclass(const ObjCInterfaceDecl *ID,
Chris Lattner5f9e2722011-07-23 10:55:15 +000052 StringRef ClassName) {
Anders Carlssonb62bdce2011-03-08 20:05:26 +000053 if (ID->getIdentifier()->getName() == ClassName)
54 return true;
55
56 if (const ObjCInterfaceDecl *Super = ID->getSuperClass())
57 return isReceiverClassOrSuperclass(Super, ClassName);
58
59 return false;
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 {
Argyrios Kyrtzidisec8605f2011-03-01 01:16:21 +000071 class NilArgChecker : public Checker<check::PreObjCMessage> {
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +000072 mutable llvm::OwningPtr<APIMisuse> BT;
73
74 void WarnNilArg(CheckerContext &C,
75 const ObjCMessage &msg, unsigned Arg) const;
76
Benjamin Kramercb9c0742010-10-22 16:33:16 +000077 public:
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +000078 void checkPreObjCMessage(ObjCMessage msg, CheckerContext &C) const;
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,
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +000084 unsigned int Arg) const
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000085{
86 if (!BT)
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +000087 BT.reset(new APIMisuse("nil argument"));
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000088
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
Anna Zakse172e8b2011-08-17 23:00:25 +000095 BugReport *R = new BugReport(*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 Kyrtzidis74eed0e2011-02-23 00:16:10 +0000101void NilArgChecker::checkPreObjCMessage(ObjCMessage msg,
102 CheckerContext &C) const {
Anders Carlssonb62bdce2011-03-08 20:05:26 +0000103 const ObjCInterfaceDecl *ID = msg.getReceiverInterface();
104 if (!ID)
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000105 return;
106
Anders Carlssonb62bdce2011-03-08 20:05:26 +0000107 if (isReceiverClassOrSuperclass(ID, "NSString")) {
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();
Chris Lattner5f9e2722011-07-23 10:55:15 +0000117 StringRef Name(NameStr);
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000118 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 {
Argyrios Kyrtzidisec8605f2011-03-01 01:16:21 +0000142class CFNumberCreateChecker : public Checker< check::PreStmt<CallExpr> > {
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000143 mutable llvm::OwningPtr<APIMisuse> BT;
144 mutable IdentifierInfo* II;
Ted Kremenek04bc8762008-06-26 23:59:48 +0000145public:
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000146 CFNumberCreateChecker() : II(0) {}
147
148 void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
149
Ted Kremenek04bc8762008-06-26 23:59:48 +0000150private:
Ted Kremenek9c378f72011-08-12 23:37:29 +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
Ted Kremenek9c378f72011-08-12 23:37:29 +0000197static 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
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000249void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE,
250 CheckerContext &C) const {
Ted Kremenek9c378f72011-08-12 23:37:29 +0000251 const Expr *Callee = CE->getCallee();
Ted Kremenek18c66fd2011-08-15 22:09:50 +0000252 const ProgramState *state = C.getState();
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000253 SVal CallV = state->getSVal(Callee);
Ted Kremenek9c378f72011-08-12 23:37:29 +0000254 const FunctionDecl *FD = CallV.getAsFunctionDecl();
Ted Kremenek04bc8762008-06-26 23:59:48 +0000255
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000256 if (!FD)
257 return;
258
259 ASTContext &Ctx = C.getASTContext();
260 if (!II)
261 II = &Ctx.Idents.get("CFNumberCreate");
262
263 if (FD->getIdentifier() != II || CE->getNumArgs() != 3)
264 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000265
Ted Kremenek04bc8762008-06-26 23:59:48 +0000266 // Get the value of the "theType" argument.
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000267 SVal TheTypeVal = state->getSVal(CE->getArg(1));
Mike Stump1eb44332009-09-09 15:08:12 +0000268
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000269 // FIXME: We really should allow ranges of valid theType values, and
270 // bifurcate the state appropriately.
Zhongxing Xu1c96b242008-10-17 05:57:07 +0000271 nonloc::ConcreteInt* V = dyn_cast<nonloc::ConcreteInt>(&TheTypeVal);
Ted Kremenek04bc8762008-06-26 23:59:48 +0000272 if (!V)
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000273 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000274
Ted Kremenek04bc8762008-06-26 23:59:48 +0000275 uint64_t NumberKind = V->getValue().getLimitedValue();
276 Optional<uint64_t> TargetSize = GetCFNumberSize(Ctx, NumberKind);
Mike Stump1eb44332009-09-09 15:08:12 +0000277
Ted Kremenek04bc8762008-06-26 23:59:48 +0000278 // FIXME: In some cases we can emit an error.
279 if (!TargetSize.isKnown())
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000280 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000281
Ted Kremenek04bc8762008-06-26 23:59:48 +0000282 // Look at the value of the integer being passed by reference. Essentially
283 // we want to catch cases where the value passed in is not equal to the
284 // size of the type being created.
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000285 SVal TheValueExpr = state->getSVal(CE->getArg(2));
Mike Stump1eb44332009-09-09 15:08:12 +0000286
Ted Kremenek04bc8762008-06-26 23:59:48 +0000287 // FIXME: Eventually we should handle arbitrary locations. We can do this
288 // by having an enhanced memory model that does low-level typing.
Zhongxing Xu1c96b242008-10-17 05:57:07 +0000289 loc::MemRegionVal* LV = dyn_cast<loc::MemRegionVal>(&TheValueExpr);
Ted Kremenek04bc8762008-06-26 23:59:48 +0000290 if (!LV)
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000291 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000292
Ted Kremenek96979342011-08-12 20:02:48 +0000293 const TypedValueRegion* R = dyn_cast<TypedValueRegion>(LV->stripCasts());
Ted Kremenek5e77eba2009-07-29 18:17:40 +0000294 if (!R)
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000295 return;
Ted Kremenek5e77eba2009-07-29 18:17:40 +0000296
Zhongxing Xu018220c2010-08-11 06:10:55 +0000297 QualType T = Ctx.getCanonicalType(R->getValueType());
Mike Stump1eb44332009-09-09 15:08:12 +0000298
Ted Kremenek04bc8762008-06-26 23:59:48 +0000299 // FIXME: If the pointee isn't an integer type, should we flag a warning?
300 // People can do weird stuff with pointers.
Mike Stump1eb44332009-09-09 15:08:12 +0000301
302 if (!T->isIntegerType())
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000303 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000304
Ted Kremenek04bc8762008-06-26 23:59:48 +0000305 uint64_t SourceSize = Ctx.getTypeSize(T);
Mike Stump1eb44332009-09-09 15:08:12 +0000306
Ted Kremenek04bc8762008-06-26 23:59:48 +0000307 // CHECK: is SourceSize == TargetSize
Ted Kremenek04bc8762008-06-26 23:59:48 +0000308 if (SourceSize == TargetSize)
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000309 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000310
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000311 // Generate an error. Only generate a sink if 'SourceSize < TargetSize';
312 // otherwise generate a regular node.
313 //
Ted Kremenek04bc8762008-06-26 23:59:48 +0000314 // FIXME: We can actually create an abstract "CFNumber" object that has
315 // the bits initialized to the provided values.
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000316 //
Ted Kremenekd048c6e2010-12-20 21:19:09 +0000317 if (ExplodedNode *N = SourceSize < TargetSize ? C.generateSink()
318 : C.generateNode()) {
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000319 llvm::SmallString<128> sbuf;
320 llvm::raw_svector_ostream os(sbuf);
321
322 os << (SourceSize == 8 ? "An " : "A ")
323 << SourceSize << " bit integer is used to initialize a CFNumber "
324 "object that represents "
325 << (TargetSize == 8 ? "an " : "a ")
326 << TargetSize << " bit integer. ";
327
328 if (SourceSize < TargetSize)
329 os << (TargetSize - SourceSize)
330 << " bits of the CFNumber value will be garbage." ;
331 else
332 os << (SourceSize - TargetSize)
333 << " bits of the input integer will be lost.";
Ted Kremenek04bc8762008-06-26 23:59:48 +0000334
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000335 if (!BT)
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000336 BT.reset(new APIMisuse("Bad use of CFNumberCreate"));
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000337
Anna Zakse172e8b2011-08-17 23:00:25 +0000338 BugReport *report = new BugReport(*BT, os.str(), N);
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000339 report->addRange(CE->getArg(2)->getSourceRange());
340 C.EmitReport(report);
341 }
Ted Kremenek04bc8762008-06-26 23:59:48 +0000342}
343
Ted Kremenek78d46242008-07-22 16:21:24 +0000344//===----------------------------------------------------------------------===//
Jordy Rose61fb55c2010-07-06 02:34:42 +0000345// CFRetain/CFRelease checking for null arguments.
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000346//===----------------------------------------------------------------------===//
347
348namespace {
Argyrios Kyrtzidisec8605f2011-03-01 01:16:21 +0000349class CFRetainReleaseChecker : public Checker< check::PreStmt<CallExpr> > {
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000350 mutable llvm::OwningPtr<APIMisuse> BT;
351 mutable IdentifierInfo *Retain, *Release;
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000352public:
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000353 CFRetainReleaseChecker(): Retain(0), Release(0) {}
Ted Kremenek9c378f72011-08-12 23:37:29 +0000354 void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000355};
356} // end anonymous namespace
357
358
Ted Kremenek9c378f72011-08-12 23:37:29 +0000359void CFRetainReleaseChecker::checkPreStmt(const CallExpr *CE,
360 CheckerContext &C) const {
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000361 // If the CallExpr doesn't have exactly 1 argument just give up checking.
362 if (CE->getNumArgs() != 1)
Jordy Rose61fb55c2010-07-06 02:34:42 +0000363 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000364
Jordy Rose61fb55c2010-07-06 02:34:42 +0000365 // Get the function declaration of the callee.
Ted Kremenek18c66fd2011-08-15 22:09:50 +0000366 const ProgramState *state = C.getState();
Ted Kremenek13976632010-02-08 16:18:51 +0000367 SVal X = state->getSVal(CE->getCallee());
Ted Kremenek9c378f72011-08-12 23:37:29 +0000368 const FunctionDecl *FD = X.getAsFunctionDecl();
Mike Stump1eb44332009-09-09 15:08:12 +0000369
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000370 if (!FD)
Jordy Rose61fb55c2010-07-06 02:34:42 +0000371 return;
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000372
373 if (!BT) {
374 ASTContext &Ctx = C.getASTContext();
375 Retain = &Ctx.Idents.get("CFRetain");
376 Release = &Ctx.Idents.get("CFRelease");
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000377 BT.reset(new APIMisuse("null passed to CFRetain/CFRelease"));
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000378 }
Mike Stump1eb44332009-09-09 15:08:12 +0000379
Jordy Rose61fb55c2010-07-06 02:34:42 +0000380 // Check if we called CFRetain/CFRelease.
Mike Stump1eb44332009-09-09 15:08:12 +0000381 const IdentifierInfo *FuncII = FD->getIdentifier();
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000382 if (!(FuncII == Retain || FuncII == Release))
Jordy Rose61fb55c2010-07-06 02:34:42 +0000383 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000384
Jordy Rose61fb55c2010-07-06 02:34:42 +0000385 // FIXME: The rest of this just checks that the argument is non-null.
386 // It should probably be refactored and combined with AttrNonNullChecker.
387
388 // Get the argument's value.
389 const Expr *Arg = CE->getArg(0);
390 SVal ArgVal = state->getSVal(Arg);
391 DefinedSVal *DefArgVal = dyn_cast<DefinedSVal>(&ArgVal);
392 if (!DefArgVal)
393 return;
394
395 // Get a NULL value.
Ted Kremenekc8413fd2010-12-02 07:49:45 +0000396 SValBuilder &svalBuilder = C.getSValBuilder();
397 DefinedSVal zero = cast<DefinedSVal>(svalBuilder.makeZeroVal(Arg->getType()));
Jordy Rose61fb55c2010-07-06 02:34:42 +0000398
399 // Make an expression asserting that they're equal.
Ted Kremenekc8413fd2010-12-02 07:49:45 +0000400 DefinedOrUnknownSVal ArgIsNull = svalBuilder.evalEQ(state, zero, *DefArgVal);
Jordy Rose61fb55c2010-07-06 02:34:42 +0000401
402 // Are they equal?
Ted Kremenek18c66fd2011-08-15 22:09:50 +0000403 const ProgramState *stateTrue, *stateFalse;
Ted Kremenek28f47b92010-12-01 22:16:56 +0000404 llvm::tie(stateTrue, stateFalse) = state->assume(ArgIsNull);
Jordy Rose61fb55c2010-07-06 02:34:42 +0000405
406 if (stateTrue && !stateFalse) {
Ted Kremenekd048c6e2010-12-20 21:19:09 +0000407 ExplodedNode *N = C.generateSink(stateTrue);
Jordy Rose61fb55c2010-07-06 02:34:42 +0000408 if (!N)
409 return;
410
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000411 const char *description = (FuncII == Retain)
412 ? "Null pointer argument in call to CFRetain"
413 : "Null pointer argument in call to CFRelease";
414
Anna Zakse172e8b2011-08-17 23:00:25 +0000415 BugReport *report = new BugReport(*BT, description, N);
Jordy Rose61fb55c2010-07-06 02:34:42 +0000416 report->addRange(Arg->getSourceRange());
Anna Zaks50bbc162011-08-19 22:33:38 +0000417 report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Arg));
Jordy Rose61fb55c2010-07-06 02:34:42 +0000418 C.EmitReport(report);
419 return;
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000420 }
421
Jordy Rose61fb55c2010-07-06 02:34:42 +0000422 // From here on, we know the argument is non-null.
423 C.addTransition(stateFalse);
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000424}
425
426//===----------------------------------------------------------------------===//
Ted Kremenek50e837b2009-11-20 05:27:05 +0000427// Check for sending 'retain', 'release', or 'autorelease' directly to a Class.
428//===----------------------------------------------------------------------===//
429
430namespace {
Argyrios Kyrtzidisec8605f2011-03-01 01:16:21 +0000431class ClassReleaseChecker : public Checker<check::PreObjCMessage> {
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000432 mutable Selector releaseS;
433 mutable Selector retainS;
434 mutable Selector autoreleaseS;
435 mutable Selector drainS;
436 mutable llvm::OwningPtr<BugType> BT;
Ted Kremenek50e837b2009-11-20 05:27:05 +0000437
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000438public:
439 void checkPreObjCMessage(ObjCMessage msg, CheckerContext &C) const;
Ted Kremenek50e837b2009-11-20 05:27:05 +0000440};
441}
442
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000443void ClassReleaseChecker::checkPreObjCMessage(ObjCMessage msg,
444 CheckerContext &C) const {
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000445
446 if (!BT) {
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000447 BT.reset(new APIMisuse("message incorrectly sent to class instead of class "
448 "instance"));
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000449
450 ASTContext &Ctx = C.getASTContext();
451 releaseS = GetNullarySelector("release", Ctx);
452 retainS = GetNullarySelector("retain", Ctx);
453 autoreleaseS = GetNullarySelector("autorelease", Ctx);
454 drainS = GetNullarySelector("drain", Ctx);
455 }
456
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +0000457 if (msg.isInstanceMessage())
Ted Kremenek50e837b2009-11-20 05:27:05 +0000458 return;
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +0000459 const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
460 assert(Class);
Douglas Gregor04badcf2010-04-21 00:45:42 +0000461
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +0000462 Selector S = msg.getSelector();
Benjamin Kramer921ddc42009-11-20 10:03:00 +0000463 if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
Ted Kremenek50e837b2009-11-20 05:27:05 +0000464 return;
465
Ted Kremenekd048c6e2010-12-20 21:19:09 +0000466 if (ExplodedNode *N = C.generateNode()) {
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000467 llvm::SmallString<200> buf;
468 llvm::raw_svector_ostream os(buf);
Ted Kremenek19d67b52009-11-23 22:22:01 +0000469
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000470 os << "The '" << S.getAsString() << "' message should be sent to instances "
471 "of class '" << Class->getName()
472 << "' and not the class directly";
Ted Kremenek50e837b2009-11-20 05:27:05 +0000473
Anna Zakse172e8b2011-08-17 23:00:25 +0000474 BugReport *report = new BugReport(*BT, os.str(), N);
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +0000475 report->addRange(msg.getSourceRange());
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000476 C.EmitReport(report);
477 }
Ted Kremenek50e837b2009-11-20 05:27:05 +0000478}
479
480//===----------------------------------------------------------------------===//
Anders Carlsson4597b7b2011-03-13 20:35:21 +0000481// Check for passing non-Objective-C types to variadic methods that expect
482// only Objective-C types.
483//===----------------------------------------------------------------------===//
484
485namespace {
486class VariadicMethodTypeChecker : public Checker<check::PreObjCMessage> {
487 mutable Selector arrayWithObjectsS;
488 mutable Selector dictionaryWithObjectsAndKeysS;
489 mutable Selector setWithObjectsS;
490 mutable Selector initWithObjectsS;
491 mutable Selector initWithObjectsAndKeysS;
492 mutable llvm::OwningPtr<BugType> BT;
493
494 bool isVariadicMessage(const ObjCMessage &msg) const;
495
496public:
497 void checkPreObjCMessage(ObjCMessage msg, CheckerContext &C) const;
498};
499}
500
501/// isVariadicMessage - Returns whether the given message is a variadic message,
502/// where all arguments must be Objective-C types.
503bool
504VariadicMethodTypeChecker::isVariadicMessage(const ObjCMessage &msg) const {
505 const ObjCMethodDecl *MD = msg.getMethodDecl();
Ted Kremenek9281efe2011-04-12 21:47:05 +0000506
507 if (!MD || !MD->isVariadic() || isa<ObjCProtocolDecl>(MD->getDeclContext()))
Anders Carlsson4597b7b2011-03-13 20:35:21 +0000508 return false;
509
510 Selector S = msg.getSelector();
511
512 if (msg.isInstanceMessage()) {
513 // FIXME: Ideally we'd look at the receiver interface here, but that's not
514 // useful for init, because alloc returns 'id'. In theory, this could lead
515 // to false positives, for example if there existed a class that had an
516 // initWithObjects: implementation that does accept non-Objective-C pointer
517 // types, but the chance of that happening is pretty small compared to the
518 // gains that this analysis gives.
519 const ObjCInterfaceDecl *Class = MD->getClassInterface();
520
521 // -[NSArray initWithObjects:]
522 if (isReceiverClassOrSuperclass(Class, "NSArray") &&
523 S == initWithObjectsS)
524 return true;
525
526 // -[NSDictionary initWithObjectsAndKeys:]
527 if (isReceiverClassOrSuperclass(Class, "NSDictionary") &&
528 S == initWithObjectsAndKeysS)
529 return true;
530
531 // -[NSSet initWithObjects:]
532 if (isReceiverClassOrSuperclass(Class, "NSSet") &&
533 S == initWithObjectsS)
534 return true;
535 } else {
536 const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
537
538 // -[NSArray arrayWithObjects:]
539 if (isReceiverClassOrSuperclass(Class, "NSArray") &&
540 S == arrayWithObjectsS)
541 return true;
542
543 // -[NSDictionary dictionaryWithObjectsAndKeys:]
544 if (isReceiverClassOrSuperclass(Class, "NSDictionary") &&
545 S == dictionaryWithObjectsAndKeysS)
546 return true;
547
548 // -[NSSet setWithObjects:]
549 if (isReceiverClassOrSuperclass(Class, "NSSet") &&
550 S == setWithObjectsS)
551 return true;
552 }
553
554 return false;
555}
556
557void VariadicMethodTypeChecker::checkPreObjCMessage(ObjCMessage msg,
558 CheckerContext &C) const {
559 if (!BT) {
560 BT.reset(new APIMisuse("Arguments passed to variadic method aren't all "
561 "Objective-C pointer types"));
562
563 ASTContext &Ctx = C.getASTContext();
564 arrayWithObjectsS = GetUnarySelector("arrayWithObjects", Ctx);
565 dictionaryWithObjectsAndKeysS =
566 GetUnarySelector("dictionaryWithObjectsAndKeys", Ctx);
567 setWithObjectsS = GetUnarySelector("setWithObjects", Ctx);
568
569 initWithObjectsS = GetUnarySelector("initWithObjects", Ctx);
570 initWithObjectsAndKeysS = GetUnarySelector("initWithObjectsAndKeys", Ctx);
571 }
572
573 if (!isVariadicMessage(msg))
574 return;
575
576 // We are not interested in the selector arguments since they have
577 // well-defined types, so the compiler will issue a warning for them.
578 unsigned variadicArgsBegin = msg.getSelector().getNumArgs();
579
580 // We're not interested in the last argument since it has to be nil or the
581 // compiler would have issued a warning for it elsewhere.
582 unsigned variadicArgsEnd = msg.getNumArgs() - 1;
583
584 if (variadicArgsEnd <= variadicArgsBegin)
585 return;
586
587 // Verify that all arguments have Objective-C types.
Ted Kremenek6fb5c1f2011-03-14 19:50:37 +0000588 llvm::Optional<ExplodedNode*> errorNode;
Ted Kremenek18c66fd2011-08-15 22:09:50 +0000589 const ProgramState *state = C.getState();
Ted Kremenek6fb5c1f2011-03-14 19:50:37 +0000590
Anders Carlsson4597b7b2011-03-13 20:35:21 +0000591 for (unsigned I = variadicArgsBegin; I != variadicArgsEnd; ++I) {
592 QualType ArgTy = msg.getArgType(I);
593 if (ArgTy->isObjCObjectPointerType())
594 continue;
595
Anders Carlssonf05982b2011-04-19 01:16:46 +0000596 // Block pointers are treaded as Objective-C pointers.
597 if (ArgTy->isBlockPointerType())
598 continue;
599
Ted Kremenekd5fde212011-03-16 00:22:51 +0000600 // Ignore pointer constants.
601 if (isa<loc::ConcreteInt>(msg.getArgSVal(I, state)))
602 continue;
Ted Kremenek928c4152011-03-17 04:01:35 +0000603
Ted Kremenekf3f92932011-03-17 04:10:25 +0000604 // Ignore pointer types annotated with 'NSObject' attribute.
605 if (C.getASTContext().isObjCNSObjectType(ArgTy))
606 continue;
607
Ted Kremenek928c4152011-03-17 04:01:35 +0000608 // Ignore CF references, which can be toll-free bridged.
Ted Kremenek05560482011-07-16 19:50:32 +0000609 if (coreFoundation::isCFObjectRef(ArgTy))
Ted Kremenek928c4152011-03-17 04:01:35 +0000610 continue;
Ted Kremenekd5fde212011-03-16 00:22:51 +0000611
Ted Kremenek6fb5c1f2011-03-14 19:50:37 +0000612 // Generate only one error node to use for all bug reports.
613 if (!errorNode.hasValue()) {
614 errorNode = C.generateNode();
615 }
616
617 if (!errorNode.getValue())
Anders Carlsson4597b7b2011-03-13 20:35:21 +0000618 continue;
619
620 llvm::SmallString<128> sbuf;
621 llvm::raw_svector_ostream os(sbuf);
622
623 if (const char *TypeName = GetReceiverNameType(msg))
624 os << "Argument to '" << TypeName << "' method '";
625 else
626 os << "Argument to method '";
627
628 os << msg.getSelector().getAsString()
629 << "' should be an Objective-C pointer type, not '"
630 << ArgTy.getAsString() << "'";
631
Anna Zakse172e8b2011-08-17 23:00:25 +0000632 BugReport *R = new BugReport(*BT, os.str(),
Ted Kremenek6fb5c1f2011-03-14 19:50:37 +0000633 errorNode.getValue());
Anders Carlsson4597b7b2011-03-13 20:35:21 +0000634 R->addRange(msg.getArgSourceRange(I));
635 C.EmitReport(R);
636 }
637}
638
639//===----------------------------------------------------------------------===//
Ted Kremenek78d46242008-07-22 16:21:24 +0000640// Check registration.
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000641//===----------------------------------------------------------------------===//
Argyrios Kyrtzidis0b1ba622011-02-16 01:40:52 +0000642
Argyrios Kyrtzidis695fb502011-02-17 21:39:17 +0000643void ento::registerNilArgChecker(CheckerManager &mgr) {
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000644 mgr.registerChecker<NilArgChecker>();
Argyrios Kyrtzidis0b1ba622011-02-16 01:40:52 +0000645}
646
Argyrios Kyrtzidis695fb502011-02-17 21:39:17 +0000647void ento::registerCFNumberCreateChecker(CheckerManager &mgr) {
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000648 mgr.registerChecker<CFNumberCreateChecker>();
Argyrios Kyrtzidis0b1ba622011-02-16 01:40:52 +0000649}
650
Argyrios Kyrtzidis695fb502011-02-17 21:39:17 +0000651void ento::registerCFRetainReleaseChecker(CheckerManager &mgr) {
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000652 mgr.registerChecker<CFRetainReleaseChecker>();
Ted Kremenek78d46242008-07-22 16:21:24 +0000653}
Argyrios Kyrtzidis695fb502011-02-17 21:39:17 +0000654
655void ento::registerClassReleaseChecker(CheckerManager &mgr) {
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000656 mgr.registerChecker<ClassReleaseChecker>();
Argyrios Kyrtzidis695fb502011-02-17 21:39:17 +0000657}
Anders Carlsson4597b7b2011-03-13 20:35:21 +0000658
659void ento::registerVariadicMethodTypeChecker(CheckerManager &mgr) {
660 mgr.registerChecker<VariadicMethodTypeChecker>();
661}