blob: 3910196265ba47690cdb5ebcfc422a70f062f746 [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
Ted Kremenek21142582010-12-23 19:38:26 +000018#include "clang/StaticAnalyzer/PathSensitive/ExplodedGraph.h"
19#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
20#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
21#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
22#include "clang/StaticAnalyzer/BugReporter/BugType.h"
23#include "clang/StaticAnalyzer/PathSensitive/MemRegion.h"
24#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
25#include "clang/StaticAnalyzer/Checkers/LocalCheckers.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
Steve Naroff14108da2009-07-10 23:34:53 +000045static const ObjCInterfaceType* GetReceiverType(const ObjCMessageExpr* ME) {
Argyrios Kyrtzidis090c47b2011-01-25 00:03:45 +000046 if (ObjCInterfaceDecl *ID = ME->getReceiverInterface())
47 return ID->getTypeForDecl()->getAs<ObjCInterfaceType>();
Ted Kremenekc1ff3cd2008-04-30 22:48:21 +000048 return NULL;
Ted Kremenek4ba62832008-03-27 22:05:32 +000049}
50
Steve Naroff14108da2009-07-10 23:34:53 +000051static const char* GetReceiverNameType(const ObjCMessageExpr* ME) {
Daniel Dunbare013d682009-10-18 20:26:12 +000052 if (const ObjCInterfaceType *ReceiverType = GetReceiverType(ME))
53 return ReceiverType->getDecl()->getIdentifier()->getNameStart();
54 return NULL;
Ted Kremenek4ba62832008-03-27 22:05:32 +000055}
Ted Kremenek52755612008-03-27 17:17:22 +000056
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000057static bool isNSString(llvm::StringRef ClassName) {
58 return ClassName == "NSString" || ClassName == "NSMutableString";
Ted Kremenek99c6ad32008-03-27 07:25:52 +000059}
60
Zhongxing Xu1c96b242008-10-17 05:57:07 +000061static inline bool isNil(SVal X) {
Mike Stump1eb44332009-09-09 15:08:12 +000062 return isa<loc::ConcreteInt>(X);
Ted Kremeneke5d5c202008-03-27 21:15:17 +000063}
64
Ted Kremenek99c6ad32008-03-27 07:25:52 +000065//===----------------------------------------------------------------------===//
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000066// NilArgChecker - Check for prohibited nil arguments to ObjC method calls.
Ted Kremenek99c6ad32008-03-27 07:25:52 +000067//===----------------------------------------------------------------------===//
68
Benjamin Kramercb9c0742010-10-22 16:33:16 +000069namespace {
70 class NilArgChecker : public CheckerVisitor<NilArgChecker> {
71 APIMisuse *BT;
72 void WarnNilArg(CheckerContext &C, const ObjCMessageExpr* ME, unsigned Arg);
73 public:
74 NilArgChecker() : BT(0) {}
75 static void *getTag() { static int x = 0; return &x; }
76 void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME);
77 };
78}
Mike Stump1eb44332009-09-09 15:08:12 +000079
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000080void NilArgChecker::WarnNilArg(CheckerContext &C,
81 const clang::ObjCMessageExpr *ME,
82 unsigned int Arg)
83{
84 if (!BT)
85 BT = new APIMisuse("nil argument");
86
Ted Kremenekd048c6e2010-12-20 21:19:09 +000087 if (ExplodedNode *N = C.generateSink()) {
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000088 llvm::SmallString<128> sbuf;
89 llvm::raw_svector_ostream os(sbuf);
90 os << "Argument to '" << GetReceiverNameType(ME) << "' method '"
91 << ME->getSelector().getAsString() << "' cannot be nil";
Mike Stump1eb44332009-09-09 15:08:12 +000092
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000093 RangedBugReport *R = new RangedBugReport(*BT, os.str(), N);
94 R->addRange(ME->getArg(Arg)->getSourceRange());
95 C.EmitReport(R);
Ted Kremenek4ba62832008-03-27 22:05:32 +000096 }
Ted Kremenek4ba62832008-03-27 22:05:32 +000097}
98
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000099void NilArgChecker::PreVisitObjCMessageExpr(CheckerContext &C,
100 const ObjCMessageExpr *ME)
101{
102 const ObjCInterfaceType *ReceiverType = GetReceiverType(ME);
103 if (!ReceiverType)
104 return;
105
106 if (isNSString(ReceiverType->getDecl()->getIdentifier()->getName())) {
107 Selector S = ME->getSelector();
108
109 if (S.isUnarySelector())
110 return;
111
112 // FIXME: This is going to be really slow doing these checks with
113 // lexical comparisons.
114
115 std::string NameStr = S.getAsString();
116 llvm::StringRef Name(NameStr);
117 assert(!Name.empty());
118
119 // FIXME: Checking for initWithFormat: will not work in most cases
120 // yet because [NSString alloc] returns id, not NSString*. We will
121 // need support for tracking expected-type information in the analyzer
122 // to find these errors.
123 if (Name == "caseInsensitiveCompare:" ||
124 Name == "compare:" ||
125 Name == "compare:options:" ||
126 Name == "compare:options:range:" ||
127 Name == "compare:options:range:locale:" ||
128 Name == "componentsSeparatedByCharactersInSet:" ||
129 Name == "initWithFormat:") {
130 if (isNil(C.getState()->getSVal(ME->getArg(0))))
131 WarnNilArg(C, ME, 0);
132 }
133 }
Ted Kremenek99c6ad32008-03-27 07:25:52 +0000134}
Ted Kremenek04bc8762008-06-26 23:59:48 +0000135
136//===----------------------------------------------------------------------===//
137// Error reporting.
138//===----------------------------------------------------------------------===//
139
140namespace {
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000141class CFNumberCreateChecker : public CheckerVisitor<CFNumberCreateChecker> {
Ted Kremenekcf118d42009-02-04 23:49:09 +0000142 APIMisuse* BT;
Ted Kremenek04bc8762008-06-26 23:59:48 +0000143 IdentifierInfo* II;
Ted Kremenek04bc8762008-06-26 23:59:48 +0000144public:
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000145 CFNumberCreateChecker() : BT(0), II(0) {}
146 ~CFNumberCreateChecker() {}
147 static void *getTag() { static int x = 0; return &x; }
148 void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
Ted Kremenek04bc8762008-06-26 23:59:48 +0000149private:
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000150 void EmitError(const TypedRegion* R, const Expr* Ex,
Mike Stump1eb44332009-09-09 15:08:12 +0000151 uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind);
Ted Kremenek04bc8762008-06-26 23:59:48 +0000152};
153} // end anonymous namespace
154
155enum CFNumberType {
156 kCFNumberSInt8Type = 1,
157 kCFNumberSInt16Type = 2,
158 kCFNumberSInt32Type = 3,
159 kCFNumberSInt64Type = 4,
160 kCFNumberFloat32Type = 5,
161 kCFNumberFloat64Type = 6,
162 kCFNumberCharType = 7,
163 kCFNumberShortType = 8,
164 kCFNumberIntType = 9,
165 kCFNumberLongType = 10,
166 kCFNumberLongLongType = 11,
167 kCFNumberFloatType = 12,
168 kCFNumberDoubleType = 13,
169 kCFNumberCFIndexType = 14,
170 kCFNumberNSIntegerType = 15,
171 kCFNumberCGFloatType = 16
172};
173
174namespace {
175 template<typename T>
176 class Optional {
177 bool IsKnown;
178 T Val;
179 public:
180 Optional() : IsKnown(false), Val(0) {}
181 Optional(const T& val) : IsKnown(true), Val(val) {}
Mike Stump1eb44332009-09-09 15:08:12 +0000182
Ted Kremenek04bc8762008-06-26 23:59:48 +0000183 bool isKnown() const { return IsKnown; }
184
185 const T& getValue() const {
186 assert (isKnown());
187 return Val;
188 }
189
190 operator const T&() const {
191 return getValue();
192 }
193 };
194}
195
196static Optional<uint64_t> GetCFNumberSize(ASTContext& Ctx, uint64_t i) {
Nuno Lopes2550d702009-12-23 17:49:57 +0000197 static const unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 };
Mike Stump1eb44332009-09-09 15:08:12 +0000198
Ted Kremenek04bc8762008-06-26 23:59:48 +0000199 if (i < kCFNumberCharType)
200 return FixedSize[i-1];
Mike Stump1eb44332009-09-09 15:08:12 +0000201
Ted Kremenek04bc8762008-06-26 23:59:48 +0000202 QualType T;
Mike Stump1eb44332009-09-09 15:08:12 +0000203
Ted Kremenek04bc8762008-06-26 23:59:48 +0000204 switch (i) {
205 case kCFNumberCharType: T = Ctx.CharTy; break;
206 case kCFNumberShortType: T = Ctx.ShortTy; break;
207 case kCFNumberIntType: T = Ctx.IntTy; break;
208 case kCFNumberLongType: T = Ctx.LongTy; break;
209 case kCFNumberLongLongType: T = Ctx.LongLongTy; break;
210 case kCFNumberFloatType: T = Ctx.FloatTy; break;
211 case kCFNumberDoubleType: T = Ctx.DoubleTy; break;
212 case kCFNumberCFIndexType:
213 case kCFNumberNSIntegerType:
214 case kCFNumberCGFloatType:
Mike Stump1eb44332009-09-09 15:08:12 +0000215 // FIXME: We need a way to map from names to Type*.
Ted Kremenek04bc8762008-06-26 23:59:48 +0000216 default:
217 return Optional<uint64_t>();
218 }
Mike Stump1eb44332009-09-09 15:08:12 +0000219
Ted Kremenek04bc8762008-06-26 23:59:48 +0000220 return Ctx.getTypeSize(T);
221}
222
223#if 0
224static const char* GetCFNumberTypeStr(uint64_t i) {
225 static const char* Names[] = {
226 "kCFNumberSInt8Type",
227 "kCFNumberSInt16Type",
228 "kCFNumberSInt32Type",
229 "kCFNumberSInt64Type",
230 "kCFNumberFloat32Type",
231 "kCFNumberFloat64Type",
232 "kCFNumberCharType",
233 "kCFNumberShortType",
234 "kCFNumberIntType",
235 "kCFNumberLongType",
236 "kCFNumberLongLongType",
237 "kCFNumberFloatType",
238 "kCFNumberDoubleType",
239 "kCFNumberCFIndexType",
240 "kCFNumberNSIntegerType",
241 "kCFNumberCGFloatType"
242 };
Mike Stump1eb44332009-09-09 15:08:12 +0000243
Ted Kremenek04bc8762008-06-26 23:59:48 +0000244 return i <= kCFNumberCGFloatType ? Names[i-1] : "Invalid CFNumberType";
245}
246#endif
247
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000248void CFNumberCreateChecker::PreVisitCallExpr(CheckerContext &C,
249 const CallExpr *CE)
250{
Mike Stump1eb44332009-09-09 15:08:12 +0000251 const Expr* Callee = CE->getCallee();
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000252 const GRState *state = C.getState();
253 SVal CallV = state->getSVal(Callee);
Zhongxing Xu369f4472009-04-20 05:24:46 +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
Zhongxing Xu479529e2009-11-10 02:17:20 +0000293 const TypedRegion* R = dyn_cast<TypedRegion>(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)
336 BT = new APIMisuse("Bad use of CFNumberCreate");
337
338 RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
339 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 {
Jordy Rose61fb55c2010-07-06 02:34:42 +0000349class CFRetainReleaseChecker : public CheckerVisitor<CFRetainReleaseChecker> {
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000350 APIMisuse *BT;
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000351 IdentifierInfo *Retain, *Release;
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000352public:
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000353 CFRetainReleaseChecker(): BT(0), Retain(0), Release(0) {}
Jordy Rose61fb55c2010-07-06 02:34:42 +0000354 static void *getTag() { static int x = 0; return &x; }
Jordy Rose61fb55c2010-07-06 02:34:42 +0000355 void PreVisitCallExpr(CheckerContext& C, const CallExpr* CE);
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000356};
357} // end anonymous namespace
358
359
Jordy Rose61fb55c2010-07-06 02:34:42 +0000360void CFRetainReleaseChecker::PreVisitCallExpr(CheckerContext& C,
361 const CallExpr* CE) {
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000362 // If the CallExpr doesn't have exactly 1 argument just give up checking.
363 if (CE->getNumArgs() != 1)
Jordy Rose61fb55c2010-07-06 02:34:42 +0000364 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000365
Jordy Rose61fb55c2010-07-06 02:34:42 +0000366 // Get the function declaration of the callee.
367 const GRState* state = C.getState();
Ted Kremenek13976632010-02-08 16:18:51 +0000368 SVal X = state->getSVal(CE->getCallee());
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000369 const FunctionDecl* FD = X.getAsFunctionDecl();
Mike Stump1eb44332009-09-09 15:08:12 +0000370
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000371 if (!FD)
Jordy Rose61fb55c2010-07-06 02:34:42 +0000372 return;
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000373
374 if (!BT) {
375 ASTContext &Ctx = C.getASTContext();
376 Retain = &Ctx.Idents.get("CFRetain");
377 Release = &Ctx.Idents.get("CFRelease");
378 BT = new APIMisuse("null passed to CFRetain/CFRelease");
379 }
Mike Stump1eb44332009-09-09 15:08:12 +0000380
Jordy Rose61fb55c2010-07-06 02:34:42 +0000381 // Check if we called CFRetain/CFRelease.
Mike Stump1eb44332009-09-09 15:08:12 +0000382 const IdentifierInfo *FuncII = FD->getIdentifier();
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000383 if (!(FuncII == Retain || FuncII == Release))
Jordy Rose61fb55c2010-07-06 02:34:42 +0000384 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000385
Jordy Rose61fb55c2010-07-06 02:34:42 +0000386 // FIXME: The rest of this just checks that the argument is non-null.
387 // It should probably be refactored and combined with AttrNonNullChecker.
388
389 // Get the argument's value.
390 const Expr *Arg = CE->getArg(0);
391 SVal ArgVal = state->getSVal(Arg);
392 DefinedSVal *DefArgVal = dyn_cast<DefinedSVal>(&ArgVal);
393 if (!DefArgVal)
394 return;
395
396 // Get a NULL value.
Ted Kremenekc8413fd2010-12-02 07:49:45 +0000397 SValBuilder &svalBuilder = C.getSValBuilder();
398 DefinedSVal zero = cast<DefinedSVal>(svalBuilder.makeZeroVal(Arg->getType()));
Jordy Rose61fb55c2010-07-06 02:34:42 +0000399
400 // Make an expression asserting that they're equal.
Ted Kremenekc8413fd2010-12-02 07:49:45 +0000401 DefinedOrUnknownSVal ArgIsNull = svalBuilder.evalEQ(state, zero, *DefArgVal);
Jordy Rose61fb55c2010-07-06 02:34:42 +0000402
403 // Are they equal?
404 const GRState *stateTrue, *stateFalse;
Ted Kremenek28f47b92010-12-01 22:16:56 +0000405 llvm::tie(stateTrue, stateFalse) = state->assume(ArgIsNull);
Jordy Rose61fb55c2010-07-06 02:34:42 +0000406
407 if (stateTrue && !stateFalse) {
Ted Kremenekd048c6e2010-12-20 21:19:09 +0000408 ExplodedNode *N = C.generateSink(stateTrue);
Jordy Rose61fb55c2010-07-06 02:34:42 +0000409 if (!N)
410 return;
411
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000412 const char *description = (FuncII == Retain)
413 ? "Null pointer argument in call to CFRetain"
414 : "Null pointer argument in call to CFRelease";
415
Jordy Rose61fb55c2010-07-06 02:34:42 +0000416 EnhancedBugReport *report = new EnhancedBugReport(*BT, description, N);
417 report->addRange(Arg->getSourceRange());
418 report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Arg);
Jordy Rose61fb55c2010-07-06 02:34:42 +0000419 C.EmitReport(report);
420 return;
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000421 }
422
Jordy Rose61fb55c2010-07-06 02:34:42 +0000423 // From here on, we know the argument is non-null.
424 C.addTransition(stateFalse);
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000425}
426
427//===----------------------------------------------------------------------===//
Ted Kremenek50e837b2009-11-20 05:27:05 +0000428// Check for sending 'retain', 'release', or 'autorelease' directly to a Class.
429//===----------------------------------------------------------------------===//
430
431namespace {
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000432class ClassReleaseChecker : public CheckerVisitor<ClassReleaseChecker> {
Ted Kremenek50e837b2009-11-20 05:27:05 +0000433 Selector releaseS;
434 Selector retainS;
435 Selector autoreleaseS;
436 Selector drainS;
437 BugType *BT;
438public:
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000439 ClassReleaseChecker()
440 : BT(0) {}
Ted Kremenek50e837b2009-11-20 05:27:05 +0000441
442 static void *getTag() { static int x = 0; return &x; }
443
444 void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME);
445};
446}
447
448void ClassReleaseChecker::PreVisitObjCMessageExpr(CheckerContext &C,
449 const ObjCMessageExpr *ME) {
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000450
451 if (!BT) {
452 BT = new APIMisuse("message incorrectly sent to class instead of class "
453 "instance");
454
455 ASTContext &Ctx = C.getASTContext();
456 releaseS = GetNullarySelector("release", Ctx);
457 retainS = GetNullarySelector("retain", Ctx);
458 autoreleaseS = GetNullarySelector("autorelease", Ctx);
459 drainS = GetNullarySelector("drain", Ctx);
460 }
461
Douglas Gregor04badcf2010-04-21 00:45:42 +0000462 ObjCInterfaceDecl *Class = 0;
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000463
Douglas Gregor04badcf2010-04-21 00:45:42 +0000464 switch (ME->getReceiverKind()) {
465 case ObjCMessageExpr::Class:
John McCall506b57e2010-05-17 21:00:27 +0000466 Class = ME->getClassReceiver()->getAs<ObjCObjectType>()->getInterface();
Douglas Gregor04badcf2010-04-21 00:45:42 +0000467 break;
Douglas Gregor04badcf2010-04-21 00:45:42 +0000468 case ObjCMessageExpr::SuperClass:
John McCall506b57e2010-05-17 21:00:27 +0000469 Class = ME->getSuperType()->getAs<ObjCObjectType>()->getInterface();
Douglas Gregor04badcf2010-04-21 00:45:42 +0000470 break;
Douglas Gregor04badcf2010-04-21 00:45:42 +0000471 case ObjCMessageExpr::Instance:
472 case ObjCMessageExpr::SuperInstance:
Ted Kremenek50e837b2009-11-20 05:27:05 +0000473 return;
Douglas Gregor04badcf2010-04-21 00:45:42 +0000474 }
475
Ted Kremenek50e837b2009-11-20 05:27:05 +0000476 Selector S = ME->getSelector();
Benjamin Kramer921ddc42009-11-20 10:03:00 +0000477 if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
Ted Kremenek50e837b2009-11-20 05:27:05 +0000478 return;
479
Ted Kremenekd048c6e2010-12-20 21:19:09 +0000480 if (ExplodedNode *N = C.generateNode()) {
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000481 llvm::SmallString<200> buf;
482 llvm::raw_svector_ostream os(buf);
Ted Kremenek19d67b52009-11-23 22:22:01 +0000483
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000484 os << "The '" << S.getAsString() << "' message should be sent to instances "
485 "of class '" << Class->getName()
486 << "' and not the class directly";
Ted Kremenek50e837b2009-11-20 05:27:05 +0000487
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000488 RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
489 report->addRange(ME->getSourceRange());
490 C.EmitReport(report);
491 }
Ted Kremenek50e837b2009-11-20 05:27:05 +0000492}
493
494//===----------------------------------------------------------------------===//
Ted Kremenek78d46242008-07-22 16:21:24 +0000495// Check registration.
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000496//===----------------------------------------------------------------------===//
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000497
Ted Kremenek9ef65372010-12-23 07:20:52 +0000498void ento::RegisterAppleChecks(ExprEngine& Eng, const Decl &D) {
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000499 Eng.registerCheck(new NilArgChecker());
500 Eng.registerCheck(new CFNumberCreateChecker());
501 RegisterNSErrorChecks(Eng.getBugReporter(), Eng, D);
Ted Kremenek54cb7cc2009-11-03 08:03:59 +0000502 RegisterNSAutoreleasePoolChecks(Eng);
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000503 Eng.registerCheck(new CFRetainReleaseChecker());
504 Eng.registerCheck(new ClassReleaseChecker());
Ted Kremenek78d46242008-07-22 16:21:24 +0000505}