blob: e62632cad8f3bf5b16b46e0d433b65e78d4e999f [file] [log] [blame]
Chris Lattnerbda0b622008-03-15 23:59:48 +00001// CFRefCount.cpp - Transfer functions for tracking simple values -*- C++ -*--//
Ted Kremenek2fff37e2008-03-06 00:08:09 +00002//
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//
Gabor Greif843e9342008-03-06 10:40:09 +000010// This file defines the methods for CFRefCount, which implements
Ted Kremenek2fff37e2008-03-06 00:08:09 +000011// a reference count checker for Core Foundation (Mac OS X).
12//
13//===----------------------------------------------------------------------===//
14
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000015#include "GRSimpleVals.h"
Ted Kremenek072192b2008-04-30 23:47:44 +000016#include "clang/Basic/LangOptions.h"
Ted Kremenekc9fa2f72008-05-01 23:13:35 +000017#include "clang/Basic/SourceManager.h"
Ted Kremenek2fff37e2008-03-06 00:08:09 +000018#include "clang/Analysis/PathSensitive/ValueState.h"
Ted Kremenek4dc41cc2008-03-31 18:26:32 +000019#include "clang/Analysis/PathDiagnostic.h"
Ted Kremenek2fff37e2008-03-06 00:08:09 +000020#include "clang/Analysis/LocalCheckers.h"
Ted Kremenekfa34b332008-04-09 01:10:13 +000021#include "clang/Analysis/PathDiagnostic.h"
22#include "clang/Analysis/PathSensitive/BugReporter.h"
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000023#include "llvm/ADT/DenseMap.h"
24#include "llvm/ADT/FoldingSet.h"
25#include "llvm/ADT/ImmutableMap.h"
Ted Kremenekfa34b332008-04-09 01:10:13 +000026#include "llvm/Support/Compiler.h"
Ted Kremenekf3948042008-03-11 19:44:10 +000027#include <ostream>
Ted Kremenek2cf943a2008-04-18 04:55:01 +000028#include <sstream>
Ted Kremenek2fff37e2008-03-06 00:08:09 +000029
30using namespace clang;
31
Ted Kremenek05cbe1a2008-04-09 23:49:11 +000032//===----------------------------------------------------------------------===//
Ted Kremenek4fd88972008-04-17 18:12:53 +000033// Utility functions.
34//===----------------------------------------------------------------------===//
35
Ted Kremenekb83e02e2008-05-01 18:31:44 +000036static inline Selector GetNullarySelector(const char* name, ASTContext& Ctx) {
Ted Kremenek4fd88972008-04-17 18:12:53 +000037 IdentifierInfo* II = &Ctx.Idents.get(name);
38 return Ctx.Selectors.getSelector(0, &II);
39}
40
41//===----------------------------------------------------------------------===//
Ted Kremenek05cbe1a2008-04-09 23:49:11 +000042// Symbolic Evaluation of Reference Counting Logic
43//===----------------------------------------------------------------------===//
44
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000045namespace {
46 enum ArgEffect { IncRef, DecRef, DoNothing };
Ted Kremenek891d5cc2008-04-24 17:22:33 +000047 typedef std::vector<std::pair<unsigned,ArgEffect> > ArgEffects;
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000048}
Ted Kremenek2fff37e2008-03-06 00:08:09 +000049
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000050namespace llvm {
51 template <> struct FoldingSetTrait<ArgEffects> {
Ted Kremenek3ea0b6a2008-04-10 22:58:08 +000052 static void Profile(const ArgEffects& X, FoldingSetNodeID& ID) {
Ted Kremenek891d5cc2008-04-24 17:22:33 +000053 for (ArgEffects::const_iterator I = X.begin(), E = X.end(); I!= E; ++I) {
54 ID.AddInteger(I->first);
55 ID.AddInteger((unsigned) I->second);
56 }
Ted Kremenek3ea0b6a2008-04-10 22:58:08 +000057 }
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000058 };
59} // end llvm namespace
60
61namespace {
Ted Kremenek2fff37e2008-03-06 00:08:09 +000062
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000063class RetEffect {
64public:
Ted Kremenek940b1d82008-04-10 23:44:06 +000065 enum Kind { NoRet = 0x0, Alias = 0x1, OwnedSymbol = 0x2,
66 NotOwnedSymbol = 0x3 };
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000067
68private:
69 unsigned Data;
Ted Kremenek3ea0b6a2008-04-10 22:58:08 +000070 RetEffect(Kind k, unsigned D) { Data = (D << 2) | (unsigned) k; }
Ted Kremenek2fff37e2008-03-06 00:08:09 +000071
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000072public:
73
74 Kind getKind() const { return (Kind) (Data & 0x3); }
75
76 unsigned getValue() const {
77 assert(getKind() == Alias);
Ted Kremenek3ea0b6a2008-04-10 22:58:08 +000078 return Data >> 2;
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000079 }
Ted Kremeneke7bd9c22008-04-11 22:25:11 +000080
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000081 static RetEffect MakeAlias(unsigned Idx) { return RetEffect(Alias, Idx); }
Ted Kremenek2fff37e2008-03-06 00:08:09 +000082
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000083 static RetEffect MakeOwned() { return RetEffect(OwnedSymbol, 0); }
Ted Kremenek2fff37e2008-03-06 00:08:09 +000084
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000085 static RetEffect MakeNotOwned() { return RetEffect(NotOwnedSymbol, 0); }
86
Ted Kremenek940b1d82008-04-10 23:44:06 +000087 static RetEffect MakeNoRet() { return RetEffect(NoRet, 0); }
88
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000089 operator Kind() const { return getKind(); }
90
91 void Profile(llvm::FoldingSetNodeID& ID) const { ID.AddInteger(Data); }
92};
93
94
95class CFRefSummary : public llvm::FoldingSetNode {
96 ArgEffects* Args;
97 RetEffect Ret;
98public:
99
100 CFRefSummary(ArgEffects* A, RetEffect R) : Args(A), Ret(R) {}
101
102 unsigned getNumArgs() const { return Args->size(); }
103
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000104 ArgEffect getArg(unsigned idx) const {
Ted Kremenek891d5cc2008-04-24 17:22:33 +0000105 if (!Args)
106 return DoNothing;
107
108 // If Args is present, it is likely to contain only 1 element.
109 // Just do a linear search. Do it from the back because functions with
110 // large numbers of arguments will be tail heavy with respect to which
111 // argument they actually modify with respect to the reference count.
112
113 for (ArgEffects::reverse_iterator I=Args->rbegin(), E=Args->rend();
114 I!=E; ++I) {
115
116 if (idx > I->first)
117 return DoNothing;
118
119 if (idx == I->first)
120 return I->second;
121 }
122
123 return DoNothing;
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000124 }
125
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000126 RetEffect getRet() const {
127 return Ret;
128 }
129
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000130 typedef ArgEffects::const_iterator arg_iterator;
131
132 arg_iterator begin_args() const { return Args->begin(); }
133 arg_iterator end_args() const { return Args->end(); }
134
135 static void Profile(llvm::FoldingSetNodeID& ID, ArgEffects* A, RetEffect R) {
136 ID.AddPointer(A);
137 ID.Add(R);
138 }
139
140 void Profile(llvm::FoldingSetNodeID& ID) const {
141 Profile(ID, Args, Ret);
142 }
143};
144
145
146class CFRefSummaryManager {
147 typedef llvm::FoldingSet<llvm::FoldingSetNodeWrapper<ArgEffects> > AESetTy;
148 typedef llvm::FoldingSet<CFRefSummary> SummarySetTy;
149 typedef llvm::DenseMap<FunctionDecl*, CFRefSummary*> SummaryMapTy;
150
Ted Kremenek377e2302008-04-29 05:33:51 +0000151 ASTContext& Ctx;
152 const bool GCEnabled;
153
Ted Kremenek3ea0b6a2008-04-10 22:58:08 +0000154 SummarySetTy SummarySet;
155 SummaryMapTy SummaryMap;
156 AESetTy AESet;
157 llvm::BumpPtrAllocator BPAlloc;
Ted Kremenek891d5cc2008-04-24 17:22:33 +0000158 ArgEffects ScratchArgs;
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000159
160 ArgEffects* getArgEffects();
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000161
Ted Kremenek377e2302008-04-29 05:33:51 +0000162 enum CFUnaryFunc { cfretain, cfrelease, cfmakecollectable };
163 CFRefSummary* getUnaryCFSummary(FunctionTypeProto* FT, CFUnaryFunc func);
164
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000165 CFRefSummary* getCFSummary(FunctionDecl* FD, const char* FName);
166
167 CFRefSummary* getCFSummaryCreateRule(FunctionTypeProto* FT);
168 CFRefSummary* getCFSummaryGetRule(FunctionTypeProto* FT);
169
170 CFRefSummary* getPersistentSummary(ArgEffects* AE, RetEffect RE);
Ted Kremenek891d5cc2008-04-24 17:22:33 +0000171
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000172public:
Ted Kremenek377e2302008-04-29 05:33:51 +0000173 CFRefSummaryManager(ASTContext& ctx, bool gcenabled)
174 : Ctx(ctx), GCEnabled(gcenabled) {}
175
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000176 ~CFRefSummaryManager();
177
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000178 CFRefSummary* getSummary(FunctionDecl* FD, ASTContext& Ctx);
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000179};
180
181} // end anonymous namespace
182
183//===----------------------------------------------------------------------===//
184// Implementation of checker data structures.
185//===----------------------------------------------------------------------===//
186
187CFRefSummaryManager::~CFRefSummaryManager() {
188
189 // FIXME: The ArgEffects could eventually be allocated from BPAlloc,
190 // mitigating the need to do explicit cleanup of the
191 // Argument-Effect summaries.
192
193 for (AESetTy::iterator I = AESet.begin(), E = AESet.end(); I!=E; ++I)
194 I->getValue().~ArgEffects();
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000195}
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000196
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000197ArgEffects* CFRefSummaryManager::getArgEffects() {
198
Ted Kremenek891d5cc2008-04-24 17:22:33 +0000199 if (ScratchArgs.empty())
200 return NULL;
201
202 // Compute a profile for a non-empty ScratchArgs.
203
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000204 llvm::FoldingSetNodeID profile;
Ted Kremenek891d5cc2008-04-24 17:22:33 +0000205
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000206 profile.Add(ScratchArgs);
207 void* InsertPos;
208
Ted Kremenek891d5cc2008-04-24 17:22:33 +0000209 // Look up the uniqued copy, or create a new one.
210
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000211 llvm::FoldingSetNodeWrapper<ArgEffects>* E =
212 AESet.FindNodeOrInsertPos(profile, InsertPos);
213
Ted Kremenek891d5cc2008-04-24 17:22:33 +0000214 if (E) {
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000215 ScratchArgs.clear();
216 return &E->getValue();
217 }
218
219 E = (llvm::FoldingSetNodeWrapper<ArgEffects>*)
220 BPAlloc.Allocate<llvm::FoldingSetNodeWrapper<ArgEffects> >();
221
222 new (E) llvm::FoldingSetNodeWrapper<ArgEffects>(ScratchArgs);
223 AESet.InsertNode(E, InsertPos);
224
225 ScratchArgs.clear();
226 return &E->getValue();
227}
228
229CFRefSummary* CFRefSummaryManager::getPersistentSummary(ArgEffects* AE,
230 RetEffect RE) {
231
Ted Kremenek891d5cc2008-04-24 17:22:33 +0000232 // Generate a profile for the summary.
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000233 llvm::FoldingSetNodeID profile;
234 CFRefSummary::Profile(profile, AE, RE);
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000235
Ted Kremenek891d5cc2008-04-24 17:22:33 +0000236 // Look up the uniqued summary, or create one if it doesn't exist.
237 void* InsertPos;
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000238 CFRefSummary* Summ = SummarySet.FindNodeOrInsertPos(profile, InsertPos);
239
240 if (Summ)
241 return Summ;
242
Ted Kremenek891d5cc2008-04-24 17:22:33 +0000243 // Create the summary and return it.
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000244 Summ = (CFRefSummary*) BPAlloc.Allocate<CFRefSummary>();
245 new (Summ) CFRefSummary(AE, RE);
246 SummarySet.InsertNode(Summ, InsertPos);
247
248 return Summ;
249}
250
251
252CFRefSummary* CFRefSummaryManager::getSummary(FunctionDecl* FD,
253 ASTContext& Ctx) {
254
255 SourceLocation Loc = FD->getLocation();
256
257 if (!Loc.isFileID())
258 return NULL;
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000259
Ted Kremenek891d5cc2008-04-24 17:22:33 +0000260
261 // Look up a summary in our cache of FunctionDecls -> Summaries.
262 SummaryMapTy::iterator I = SummaryMap.find(FD);
263
264 if (I != SummaryMap.end())
265 return I->second;
266
267 // No summary. Generate one.
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000268 const char* FName = FD->getIdentifier()->getName();
269
270 if (FName[0] == 'C' && FName[1] == 'F') {
271 CFRefSummary* S = getCFSummary(FD, FName);
272 SummaryMap[FD] = S;
273 return S;
274 }
Ted Kremenek891d5cc2008-04-24 17:22:33 +0000275
276 // Function has no ref-count effects. Return the NULL summary.
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000277 return NULL;
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000278}
279
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000280CFRefSummary* CFRefSummaryManager::getCFSummary(FunctionDecl* FD,
281 const char* FName) {
282
283 // For now, only generate summaries for functions that have a prototype.
284
285 FunctionTypeProto* FT =
286 dyn_cast<FunctionTypeProto>(FD->getType().getTypePtr());
287
288 if (!FT)
289 return NULL;
290
291 FName += 2;
292
293 if (strcmp(FName, "Retain") == 0)
Ted Kremenek377e2302008-04-29 05:33:51 +0000294 return getUnaryCFSummary(FT, cfretain);
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000295
296 if (strcmp(FName, "Release") == 0)
Ted Kremenek377e2302008-04-29 05:33:51 +0000297 return getUnaryCFSummary(FT, cfrelease);
Ted Kremenek9040c652008-05-01 21:31:50 +0000298
Ted Kremenek377e2302008-04-29 05:33:51 +0000299 if (strcmp(FName, "MakeCollectable") == 0)
300 return getUnaryCFSummary(FT, cfmakecollectable);
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000301
302 assert (ScratchArgs.empty());
303 bool usesCreateRule = false;
304
305 if (strstr(FName, "Create"))
306 usesCreateRule = true;
307
308 if (!usesCreateRule && strstr(FName, "Copy"))
309 usesCreateRule = true;
310
311 if (usesCreateRule)
312 return getCFSummaryCreateRule(FT);
313
314 if (strstr(FName, "Get"))
315 return getCFSummaryGetRule(FT);
316
317 return NULL;
318}
319
Ted Kremenek377e2302008-04-29 05:33:51 +0000320CFRefSummary*
321CFRefSummaryManager::getUnaryCFSummary(FunctionTypeProto* FT, CFUnaryFunc func) {
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000322
323 if (FT->getNumArgs() != 1)
324 return NULL;
325
326 TypedefType* ArgT = dyn_cast<TypedefType>(FT->getArgType(0).getTypePtr());
327
328 if (!ArgT)
329 return NULL;
330
331 // For CFRetain/CFRelease, the first (and only) argument is of type
332 // "CFTypeRef".
333
334 const char* TDName = ArgT->getDecl()->getIdentifier()->getName();
335 assert (TDName);
336
Ted Kremenek3ea0b6a2008-04-10 22:58:08 +0000337 if (strcmp("CFTypeRef", TDName) != 0)
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000338 return NULL;
339
Ted Kremenekc0c3f5d2008-04-30 20:17:27 +0000340 if (!ArgT->isPointerType())
341 return NULL;
Ted Kremenek3ea0b6a2008-04-10 22:58:08 +0000342
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000343 QualType RetTy = FT->getResultType();
344
Ted Kremenek377e2302008-04-29 05:33:51 +0000345 switch (func) {
346 case cfretain: {
347
348 // CFRetain: the return type should also be "CFTypeRef".
349 if (RetTy.getTypePtr() != ArgT)
350 return NULL;
351
352 // The function's interface checks out. Generate a canned summary.
353 assert (ScratchArgs.empty());
354 ScratchArgs.push_back(std::make_pair(0, IncRef));
355 return getPersistentSummary(getArgEffects(), RetEffect::MakeAlias(0));
356 }
357
358 case cfrelease: {
359
360 // CFRelease: the return type should be void.
361
362 if (RetTy != Ctx.VoidTy)
363 return NULL;
364
365 assert (ScratchArgs.empty());
366 ScratchArgs.push_back(std::make_pair(0, DecRef));
367 return getPersistentSummary(getArgEffects(), RetEffect::MakeNoRet());
368 }
369
370 case cfmakecollectable: {
371
372 // CFRetain: the return type should also be "CFTypeRef".
373 if (RetTy.getTypePtr() != ArgT)
374 return NULL;
375
376 // The function's interface checks out. Generate a canned summary.
377 assert (ScratchArgs.empty());
378
379 if (GCEnabled)
380 ScratchArgs.push_back(std::make_pair(0, DecRef));
381
382 return getPersistentSummary(getArgEffects(), RetEffect::MakeAlias(0));
383
384
385 }
386
387 default:
388 assert (false && "Not a support unary function.");
Ted Kremenek940b1d82008-04-10 23:44:06 +0000389 }
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000390}
391
392static bool isCFRefType(QualType T) {
393
394 if (!T->isPointerType())
395 return false;
396
397 // Check the typedef for the name "CF" and the substring "Ref".
398
399 TypedefType* TD = dyn_cast<TypedefType>(T.getTypePtr());
400
401 if (!TD)
402 return false;
403
404 const char* TDName = TD->getDecl()->getIdentifier()->getName();
405 assert (TDName);
406
407 if (TDName[0] != 'C' || TDName[1] != 'F')
408 return false;
409
410 if (strstr(TDName, "Ref") == 0)
411 return false;
412
413 return true;
414}
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000415
416CFRefSummary*
417CFRefSummaryManager::getCFSummaryCreateRule(FunctionTypeProto* FT) {
418
419 if (!isCFRefType(FT->getResultType()))
Ted Kremeneka0df99f2008-04-11 20:11:19 +0000420 return NULL;
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000421
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000422 // FIXME: Add special-cases for functions that retain/release. For now
423 // just handle the default case.
Ted Kremenek891d5cc2008-04-24 17:22:33 +0000424
425 assert (ScratchArgs.empty());
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000426 return getPersistentSummary(getArgEffects(), RetEffect::MakeOwned());
427}
428
429CFRefSummary*
430CFRefSummaryManager::getCFSummaryGetRule(FunctionTypeProto* FT) {
431
Ted Kremeneka0df99f2008-04-11 20:11:19 +0000432 QualType RetTy = FT->getResultType();
433
434 // FIXME: For now we assume that all pointer types returned are referenced
435 // counted. Since this is the "Get" rule, we assume non-ownership, which
436 // works fine for things that are not reference counted. We do this because
437 // some generic data structures return "void*". We need something better
438 // in the future.
439
440 if (!isCFRefType(RetTy) && !RetTy->isPointerType())
441 return NULL;
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000442
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000443 // FIXME: Add special-cases for functions that retain/release. For now
444 // just handle the default case.
445
Ted Kremenek891d5cc2008-04-24 17:22:33 +0000446 assert (ScratchArgs.empty());
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000447 return getPersistentSummary(getArgEffects(), RetEffect::MakeNotOwned());
448}
449
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000450//===----------------------------------------------------------------------===//
Ted Kremenek13922612008-04-16 20:40:59 +0000451// Reference-counting logic (typestate + counts).
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000452//===----------------------------------------------------------------------===//
453
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000454namespace {
455
Ted Kremenek05cbe1a2008-04-09 23:49:11 +0000456class VISIBILITY_HIDDEN RefVal {
Ted Kremenek4fd88972008-04-17 18:12:53 +0000457public:
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000458
Ted Kremenek4fd88972008-04-17 18:12:53 +0000459 enum Kind {
460 Owned = 0, // Owning reference.
461 NotOwned, // Reference is not owned by still valid (not freed).
462 Released, // Object has been released.
463 ReturnedOwned, // Returned object passes ownership to caller.
464 ReturnedNotOwned, // Return object does not pass ownership to caller.
465 ErrorUseAfterRelease, // Object used after released.
466 ErrorReleaseNotOwned, // Release of an object that was not owned.
467 ErrorLeak // A memory leak due to excessive reference counts.
468 };
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000469
Ted Kremenek4fd88972008-04-17 18:12:53 +0000470private:
471
472 Kind kind;
473 unsigned Cnt;
474
475 RefVal(Kind k, unsigned cnt) : kind(k), Cnt(cnt) {}
476
477 RefVal(Kind k) : kind(k), Cnt(0) {}
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000478
479public:
Ted Kremenekdb863712008-04-16 22:32:20 +0000480
Ted Kremenek4fd88972008-04-17 18:12:53 +0000481 Kind getKind() const { return kind; }
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000482
Ted Kremenek4fd88972008-04-17 18:12:53 +0000483 unsigned getCount() const { return Cnt; }
484
485 // Useful predicates.
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000486
Ted Kremenek73c750b2008-03-11 18:14:09 +0000487 static bool isError(Kind k) { return k >= ErrorUseAfterRelease; }
488
Ted Kremenekdb863712008-04-16 22:32:20 +0000489 static bool isLeak(Kind k) { return k == ErrorLeak; }
490
Ted Kremeneke7bd9c22008-04-11 22:25:11 +0000491 bool isOwned() const {
492 return getKind() == Owned;
493 }
494
Ted Kremenekdb863712008-04-16 22:32:20 +0000495 bool isNotOwned() const {
496 return getKind() == NotOwned;
497 }
498
Ted Kremenek4fd88972008-04-17 18:12:53 +0000499 bool isReturnedOwned() const {
500 return getKind() == ReturnedOwned;
501 }
502
503 bool isReturnedNotOwned() const {
504 return getKind() == ReturnedNotOwned;
505 }
506
507 bool isNonLeakError() const {
508 Kind k = getKind();
509 return isError(k) && !isLeak(k);
510 }
511
512 // State creation: normal state.
513
Ted Kremenek61b9f872008-04-10 23:09:18 +0000514 static RefVal makeOwned(unsigned Count = 0) {
515 return RefVal(Owned, Count);
516 }
517
518 static RefVal makeNotOwned(unsigned Count = 0) {
519 return RefVal(NotOwned, Count);
520 }
Ted Kremenek4fd88972008-04-17 18:12:53 +0000521
522 static RefVal makeReturnedOwned(unsigned Count) {
523 return RefVal(ReturnedOwned, Count);
524 }
525
526 static RefVal makeReturnedNotOwned() {
527 return RefVal(ReturnedNotOwned);
528 }
529
530 // State creation: errors.
Ted Kremenek61b9f872008-04-10 23:09:18 +0000531
Ted Kremenekdb863712008-04-16 22:32:20 +0000532 static RefVal makeLeak() { return RefVal(ErrorLeak); }
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000533 static RefVal makeReleased() { return RefVal(Released); }
534 static RefVal makeUseAfterRelease() { return RefVal(ErrorUseAfterRelease); }
535 static RefVal makeReleaseNotOwned() { return RefVal(ErrorReleaseNotOwned); }
Ted Kremenek4fd88972008-04-17 18:12:53 +0000536
537 // Comparison, profiling, and pretty-printing.
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000538
Ted Kremenek4fd88972008-04-17 18:12:53 +0000539 bool operator==(const RefVal& X) const {
540 return kind == X.kind && Cnt == X.Cnt;
541 }
Ted Kremenekf3948042008-03-11 19:44:10 +0000542
Ted Kremenek4fd88972008-04-17 18:12:53 +0000543 void Profile(llvm::FoldingSetNodeID& ID) const {
544 ID.AddInteger((unsigned) kind);
545 ID.AddInteger(Cnt);
546 }
547
Ted Kremenekf3948042008-03-11 19:44:10 +0000548 void print(std::ostream& Out) const;
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000549};
Ted Kremenekf3948042008-03-11 19:44:10 +0000550
551void RefVal::print(std::ostream& Out) const {
552 switch (getKind()) {
553 default: assert(false);
Ted Kremenek61b9f872008-04-10 23:09:18 +0000554 case Owned: {
555 Out << "Owned";
556 unsigned cnt = getCount();
557 if (cnt) Out << " (+ " << cnt << ")";
Ted Kremenekf3948042008-03-11 19:44:10 +0000558 break;
Ted Kremenek61b9f872008-04-10 23:09:18 +0000559 }
Ted Kremenekf3948042008-03-11 19:44:10 +0000560
Ted Kremenek61b9f872008-04-10 23:09:18 +0000561 case NotOwned: {
Ted Kremenek4fd88972008-04-17 18:12:53 +0000562 Out << "NotOwned";
Ted Kremenek61b9f872008-04-10 23:09:18 +0000563 unsigned cnt = getCount();
564 if (cnt) Out << " (+ " << cnt << ")";
Ted Kremenekf3948042008-03-11 19:44:10 +0000565 break;
Ted Kremenek61b9f872008-04-10 23:09:18 +0000566 }
Ted Kremenekf3948042008-03-11 19:44:10 +0000567
Ted Kremenek4fd88972008-04-17 18:12:53 +0000568 case ReturnedOwned: {
569 Out << "ReturnedOwned";
570 unsigned cnt = getCount();
571 if (cnt) Out << " (+ " << cnt << ")";
572 break;
573 }
574
575 case ReturnedNotOwned: {
576 Out << "ReturnedNotOwned";
577 unsigned cnt = getCount();
578 if (cnt) Out << " (+ " << cnt << ")";
579 break;
580 }
581
Ted Kremenekf3948042008-03-11 19:44:10 +0000582 case Released:
583 Out << "Released";
584 break;
585
Ted Kremenekdb863712008-04-16 22:32:20 +0000586 case ErrorLeak:
587 Out << "Leaked";
588 break;
589
Ted Kremenekf3948042008-03-11 19:44:10 +0000590 case ErrorUseAfterRelease:
591 Out << "Use-After-Release [ERROR]";
592 break;
593
594 case ErrorReleaseNotOwned:
595 Out << "Release of Not-Owned [ERROR]";
596 break;
597 }
598}
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000599
Ted Kremenek13922612008-04-16 20:40:59 +0000600//===----------------------------------------------------------------------===//
601// Transfer functions.
602//===----------------------------------------------------------------------===//
603
Ted Kremenek05cbe1a2008-04-09 23:49:11 +0000604class VISIBILITY_HIDDEN CFRefCount : public GRSimpleVals {
Ted Kremenek8dd56462008-04-18 03:39:05 +0000605public:
Ted Kremenekf3948042008-03-11 19:44:10 +0000606 // Type definitions.
607
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000608 typedef llvm::ImmutableMap<SymbolID, RefVal> RefBindings;
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000609 typedef RefBindings::Factory RefBFactoryTy;
Ted Kremenek73c750b2008-03-11 18:14:09 +0000610
Ted Kremenek8dd56462008-04-18 03:39:05 +0000611 typedef llvm::DenseMap<GRExprEngine::NodeTy*,std::pair<Expr*, SymbolID> >
612 ReleasesNotOwnedTy;
613
614 typedef ReleasesNotOwnedTy UseAfterReleasesTy;
615
616 typedef llvm::DenseMap<GRExprEngine::NodeTy*, std::vector<SymbolID>*>
Ted Kremenekdb863712008-04-16 22:32:20 +0000617 LeaksTy;
Ted Kremenek8dd56462008-04-18 03:39:05 +0000618
Ted Kremenekf3948042008-03-11 19:44:10 +0000619 class BindingsPrinter : public ValueState::CheckerStatePrinter {
620 public:
621 virtual void PrintCheckerState(std::ostream& Out, void* State,
622 const char* nl, const char* sep);
623 };
Ted Kremenek8dd56462008-04-18 03:39:05 +0000624
625private:
Ted Kremenekf3948042008-03-11 19:44:10 +0000626 // Instance variables.
627
Ted Kremeneke5c30122008-04-29 05:13:59 +0000628 CFRefSummaryManager Summaries;
Ted Kremenek072192b2008-04-30 23:47:44 +0000629 const bool GCEnabled;
630 const LangOptions& LOpts;
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000631 RefBFactoryTy RefBFactory;
632
Ted Kremenek73c750b2008-03-11 18:14:09 +0000633 UseAfterReleasesTy UseAfterReleases;
634 ReleasesNotOwnedTy ReleasesNotOwned;
Ted Kremenekdb863712008-04-16 22:32:20 +0000635 LeaksTy Leaks;
Ted Kremenek73c750b2008-03-11 18:14:09 +0000636
Ted Kremenekf3948042008-03-11 19:44:10 +0000637 BindingsPrinter Printer;
638
Ted Kremenek9ed18e62008-04-16 04:28:53 +0000639 Selector RetainSelector;
640 Selector ReleaseSelector;
Ted Kremenek5934cee2008-05-01 02:18:37 +0000641 Selector AutoreleaseSelector;
Ted Kremenek9ed18e62008-04-16 04:28:53 +0000642
Ted Kremenek8dd56462008-04-18 03:39:05 +0000643public:
644
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000645 static RefBindings GetRefBindings(ValueState& StImpl) {
646 return RefBindings((RefBindings::TreeTy*) StImpl.CheckerState);
647 }
Ted Kremenek9ed18e62008-04-16 04:28:53 +0000648
Ted Kremenek8dd56462008-04-18 03:39:05 +0000649private:
650
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000651 static void SetRefBindings(ValueState& StImpl, RefBindings B) {
652 StImpl.CheckerState = B.getRoot();
653 }
Ted Kremenek9ed18e62008-04-16 04:28:53 +0000654
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000655 RefBindings Remove(RefBindings B, SymbolID sym) {
656 return RefBFactory.Remove(B, sym);
657 }
658
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000659 RefBindings Update(RefBindings B, SymbolID sym, RefVal V, ArgEffect E,
Ted Kremenek9ed18e62008-04-16 04:28:53 +0000660 RefVal::Kind& hasErr);
661
Ted Kremenekdb863712008-04-16 22:32:20 +0000662 void ProcessNonLeakError(ExplodedNodeSet<ValueState>& Dst,
663 GRStmtNodeBuilder<ValueState>& Builder,
664 Expr* NodeExpr, Expr* ErrorExpr,
665 ExplodedNode<ValueState>* Pred,
666 ValueState* St,
Ted Kremenek8dd56462008-04-18 03:39:05 +0000667 RefVal::Kind hasErr, SymbolID Sym);
Ted Kremenekdb863712008-04-16 22:32:20 +0000668
669 ValueState* HandleSymbolDeath(ValueStateManager& VMgr, ValueState* St,
670 SymbolID sid, RefVal V, bool& hasLeak);
671
672 ValueState* NukeBinding(ValueStateManager& VMgr, ValueState* St,
673 SymbolID sid);
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000674
675public:
Ted Kremenek13922612008-04-16 20:40:59 +0000676
Ted Kremenek072192b2008-04-30 23:47:44 +0000677 CFRefCount(ASTContext& Ctx, bool gcenabled, const LangOptions& lopts)
Ted Kremenek377e2302008-04-29 05:33:51 +0000678 : Summaries(Ctx, gcenabled),
Ted Kremeneke5c30122008-04-29 05:13:59 +0000679 GCEnabled(gcenabled),
Ted Kremenek072192b2008-04-30 23:47:44 +0000680 LOpts(lopts),
Ted Kremenekb83e02e2008-05-01 18:31:44 +0000681 RetainSelector(GetNullarySelector("retain", Ctx)),
682 ReleaseSelector(GetNullarySelector("release", Ctx)),
683 AutoreleaseSelector(GetNullarySelector("autorelease", Ctx)) {}
Ted Kremenek9ed18e62008-04-16 04:28:53 +0000684
Ted Kremenek8dd56462008-04-18 03:39:05 +0000685 virtual ~CFRefCount() {
686 for (LeaksTy::iterator I = Leaks.begin(), E = Leaks.end(); I!=E; ++I)
687 delete I->second;
688 }
Ted Kremenek05cbe1a2008-04-09 23:49:11 +0000689
690 virtual void RegisterChecks(GRExprEngine& Eng);
Ted Kremenekf3948042008-03-11 19:44:10 +0000691
692 virtual ValueState::CheckerStatePrinter* getCheckerStatePrinter() {
693 return &Printer;
694 }
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000695
Ted Kremenek072192b2008-04-30 23:47:44 +0000696 bool isGCEnabled() const { return GCEnabled; }
697 const LangOptions& getLangOptions() const { return LOpts; }
698
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000699 // Calls.
700
701 virtual void EvalCall(ExplodedNodeSet<ValueState>& Dst,
Ted Kremenek199e1a02008-03-12 21:06:49 +0000702 GRExprEngine& Eng,
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000703 GRStmtNodeBuilder<ValueState>& Builder,
Ted Kremenek186350f2008-04-23 20:12:28 +0000704 CallExpr* CE, RVal L,
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000705 ExplodedNode<ValueState>* Pred);
Ted Kremenekfa34b332008-04-09 01:10:13 +0000706
Ted Kremenek85348202008-04-15 23:44:31 +0000707 virtual void EvalObjCMessageExpr(ExplodedNodeSet<ValueState>& Dst,
708 GRExprEngine& Engine,
709 GRStmtNodeBuilder<ValueState>& Builder,
710 ObjCMessageExpr* ME,
711 ExplodedNode<ValueState>* Pred);
712
713 bool EvalObjCMessageExprAux(ExplodedNodeSet<ValueState>& Dst,
714 GRExprEngine& Engine,
715 GRStmtNodeBuilder<ValueState>& Builder,
716 ObjCMessageExpr* ME,
717 ExplodedNode<ValueState>* Pred);
718
Ted Kremenek13922612008-04-16 20:40:59 +0000719 // Stores.
720
721 virtual void EvalStore(ExplodedNodeSet<ValueState>& Dst,
722 GRExprEngine& Engine,
723 GRStmtNodeBuilder<ValueState>& Builder,
724 Expr* E, ExplodedNode<ValueState>* Pred,
725 ValueState* St, RVal TargetLV, RVal Val);
Ted Kremeneke7bd9c22008-04-11 22:25:11 +0000726 // End-of-path.
727
728 virtual void EvalEndPath(GRExprEngine& Engine,
729 GREndPathNodeBuilder<ValueState>& Builder);
730
Ted Kremenek652adc62008-04-24 23:57:27 +0000731 virtual void EvalDeadSymbols(ExplodedNodeSet<ValueState>& Dst,
732 GRExprEngine& Engine,
733 GRStmtNodeBuilder<ValueState>& Builder,
Ted Kremenek910e9992008-04-25 01:25:15 +0000734 ExplodedNode<ValueState>* Pred,
735 Stmt* S,
Ted Kremenek652adc62008-04-24 23:57:27 +0000736 ValueState* St,
737 const ValueStateManager::DeadSymbolsTy& Dead);
Ted Kremenek4fd88972008-04-17 18:12:53 +0000738 // Return statements.
739
740 virtual void EvalReturn(ExplodedNodeSet<ValueState>& Dst,
741 GRExprEngine& Engine,
742 GRStmtNodeBuilder<ValueState>& Builder,
743 ReturnStmt* S,
744 ExplodedNode<ValueState>* Pred);
Ted Kremenekcb612922008-04-18 19:23:43 +0000745
746 // Assumptions.
747
748 virtual ValueState* EvalAssume(GRExprEngine& Engine, ValueState* St,
749 RVal Cond, bool Assumption, bool& isFeasible);
750
Ted Kremenekfa34b332008-04-09 01:10:13 +0000751 // Error iterators.
752
753 typedef UseAfterReleasesTy::iterator use_after_iterator;
754 typedef ReleasesNotOwnedTy::iterator bad_release_iterator;
Ted Kremenek989d5192008-04-17 23:43:50 +0000755 typedef LeaksTy::iterator leaks_iterator;
Ted Kremenekfa34b332008-04-09 01:10:13 +0000756
Ted Kremenek05cbe1a2008-04-09 23:49:11 +0000757 use_after_iterator use_after_begin() { return UseAfterReleases.begin(); }
758 use_after_iterator use_after_end() { return UseAfterReleases.end(); }
Ted Kremenekfa34b332008-04-09 01:10:13 +0000759
Ted Kremenek05cbe1a2008-04-09 23:49:11 +0000760 bad_release_iterator bad_release_begin() { return ReleasesNotOwned.begin(); }
761 bad_release_iterator bad_release_end() { return ReleasesNotOwned.end(); }
Ted Kremenek989d5192008-04-17 23:43:50 +0000762
763 leaks_iterator leaks_begin() { return Leaks.begin(); }
764 leaks_iterator leaks_end() { return Leaks.end(); }
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000765};
766
767} // end anonymous namespace
768
Ted Kremenek8dd56462008-04-18 03:39:05 +0000769
Ted Kremenek05cbe1a2008-04-09 23:49:11 +0000770
771
Ted Kremenekf3948042008-03-11 19:44:10 +0000772void CFRefCount::BindingsPrinter::PrintCheckerState(std::ostream& Out,
773 void* State, const char* nl,
774 const char* sep) {
775 RefBindings B((RefBindings::TreeTy*) State);
776
777 if (State)
778 Out << sep << nl;
779
780 for (RefBindings::iterator I=B.begin(), E=B.end(); I!=E; ++I) {
781 Out << (*I).first << " : ";
782 (*I).second.print(Out);
783 Out << nl;
784 }
785}
786
Ted Kremenekf9561e52008-04-11 20:23:24 +0000787static inline ArgEffect GetArgE(CFRefSummary* Summ, unsigned idx) {
788 return Summ ? Summ->getArg(idx) : DoNothing;
789}
790
791static inline RetEffect GetRetE(CFRefSummary* Summ) {
792 return Summ ? Summ->getRet() : RetEffect::MakeNoRet();
793}
794
Ted Kremenekdb863712008-04-16 22:32:20 +0000795void CFRefCount::ProcessNonLeakError(ExplodedNodeSet<ValueState>& Dst,
796 GRStmtNodeBuilder<ValueState>& Builder,
797 Expr* NodeExpr, Expr* ErrorExpr,
798 ExplodedNode<ValueState>* Pred,
799 ValueState* St,
Ted Kremenek8dd56462008-04-18 03:39:05 +0000800 RefVal::Kind hasErr, SymbolID Sym) {
Ted Kremenek9ed18e62008-04-16 04:28:53 +0000801 Builder.BuildSinks = true;
802 GRExprEngine::NodeTy* N = Builder.MakeNode(Dst, NodeExpr, Pred, St);
803
804 if (!N) return;
805
806 switch (hasErr) {
807 default: assert(false);
808 case RefVal::ErrorUseAfterRelease:
Ted Kremenek8dd56462008-04-18 03:39:05 +0000809 UseAfterReleases[N] = std::make_pair(ErrorExpr, Sym);
Ted Kremenek9ed18e62008-04-16 04:28:53 +0000810 break;
811
812 case RefVal::ErrorReleaseNotOwned:
Ted Kremenek8dd56462008-04-18 03:39:05 +0000813 ReleasesNotOwned[N] = std::make_pair(ErrorExpr, Sym);
Ted Kremenek9ed18e62008-04-16 04:28:53 +0000814 break;
815 }
816}
817
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000818void CFRefCount::EvalCall(ExplodedNodeSet<ValueState>& Dst,
Ted Kremenek199e1a02008-03-12 21:06:49 +0000819 GRExprEngine& Eng,
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000820 GRStmtNodeBuilder<ValueState>& Builder,
Ted Kremenek186350f2008-04-23 20:12:28 +0000821 CallExpr* CE, RVal L,
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000822 ExplodedNode<ValueState>* Pred) {
823
Ted Kremenek199e1a02008-03-12 21:06:49 +0000824 ValueStateManager& StateMgr = Eng.getStateManager();
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000825
Ted Kremenek7ded73c2008-04-14 17:45:13 +0000826 CFRefSummary* Summ = NULL;
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000827
828 // Get the summary.
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000829
Ted Kremenek7ded73c2008-04-14 17:45:13 +0000830 if (isa<lval::FuncVal>(L)) {
831 lval::FuncVal FV = cast<lval::FuncVal>(L);
832 FunctionDecl* FD = FV.getDecl();
833 Summ = Summaries.getSummary(FD, Eng.getContext());
834 }
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000835
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000836 // Get the state.
837
838 ValueState* St = Builder.GetState(Pred);
839
840 // Evaluate the effects of the call.
841
842 ValueState StVals = *St;
Ted Kremenek9ed18e62008-04-16 04:28:53 +0000843 RefVal::Kind hasErr = (RefVal::Kind) 0;
Ted Kremenekf9561e52008-04-11 20:23:24 +0000844
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000845 // This function has a summary. Evaluate the effect of the arguments.
846
847 unsigned idx = 0;
848
Ted Kremenekbcf50ad2008-04-11 18:40:51 +0000849 Expr* ErrorExpr = NULL;
Ted Kremenek8dd56462008-04-18 03:39:05 +0000850 SymbolID ErrorSym = 0;
Ted Kremenekbcf50ad2008-04-11 18:40:51 +0000851
852 for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end();
853 I != E; ++I, ++idx) {
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000854
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000855 RVal V = StateMgr.GetRVal(St, *I);
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000856
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000857 if (isa<lval::SymbolVal>(V)) {
858 SymbolID Sym = cast<lval::SymbolVal>(V).getSymbol();
Ted Kremenekf9561e52008-04-11 20:23:24 +0000859 RefBindings B = GetRefBindings(StVals);
860
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000861 if (RefBindings::TreeTy* T = B.SlimFind(Sym)) {
Ted Kremenek9ed18e62008-04-16 04:28:53 +0000862 B = Update(B, Sym, T->getValue().second, GetArgE(Summ, idx), hasErr);
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000863 SetRefBindings(StVals, B);
Ted Kremenekbcf50ad2008-04-11 18:40:51 +0000864
Ted Kremenek9ed18e62008-04-16 04:28:53 +0000865 if (hasErr) {
Ted Kremenekbcf50ad2008-04-11 18:40:51 +0000866 ErrorExpr = *I;
Ted Kremenek8dd56462008-04-18 03:39:05 +0000867 ErrorSym = T->getValue().first;
Ted Kremenekbcf50ad2008-04-11 18:40:51 +0000868 break;
869 }
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000870 }
Ted Kremenekb8873552008-04-11 20:51:02 +0000871 }
872 else if (isa<LVal>(V)) { // Nuke all arguments passed by reference.
873
874 // FIXME: This is basically copy-and-paste from GRSimpleVals. We
875 // should compose behavior, not copy it.
Ted Kremenekf9561e52008-04-11 20:23:24 +0000876 StateMgr.Unbind(StVals, cast<LVal>(V));
Ted Kremenekb8873552008-04-11 20:51:02 +0000877 }
Ted Kremeneka5488462008-04-22 21:39:21 +0000878 else if (isa<nonlval::LValAsInteger>(V))
879 StateMgr.Unbind(StVals, cast<nonlval::LValAsInteger>(V).getLVal());
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000880 }
Ted Kremenek9ed18e62008-04-16 04:28:53 +0000881
882 St = StateMgr.getPersistentState(StVals);
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000883
Ted Kremenek9ed18e62008-04-16 04:28:53 +0000884 if (hasErr) {
Ted Kremenek8dd56462008-04-18 03:39:05 +0000885 ProcessNonLeakError(Dst, Builder, CE, ErrorExpr, Pred, St,
886 hasErr, ErrorSym);
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000887 return;
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000888 }
Ted Kremenek9ed18e62008-04-16 04:28:53 +0000889
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000890 // Finally, consult the summary for the return value.
891
Ted Kremenekf9561e52008-04-11 20:23:24 +0000892 RetEffect RE = GetRetE(Summ);
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000893
894 switch (RE.getKind()) {
895 default:
896 assert (false && "Unhandled RetEffect."); break;
897
Ted Kremenek940b1d82008-04-10 23:44:06 +0000898 case RetEffect::NoRet:
Ted Kremenekf9561e52008-04-11 20:23:24 +0000899
900 // Make up a symbol for the return value (not reference counted).
Ted Kremenekb8873552008-04-11 20:51:02 +0000901 // FIXME: This is basically copy-and-paste from GRSimpleVals. We
902 // should compose behavior, not copy it.
Ted Kremenekf9561e52008-04-11 20:23:24 +0000903
904 if (CE->getType() != Eng.getContext().VoidTy) {
905 unsigned Count = Builder.getCurrentBlockCount();
906 SymbolID Sym = Eng.getSymbolManager().getConjuredSymbol(CE, Count);
907
908 RVal X = CE->getType()->isPointerType()
909 ? cast<RVal>(lval::SymbolVal(Sym))
910 : cast<RVal>(nonlval::SymbolVal(Sym));
911
912 St = StateMgr.SetRVal(St, CE, X, Eng.getCFG().isBlkExpr(CE), false);
913 }
914
Ted Kremenek940b1d82008-04-10 23:44:06 +0000915 break;
916
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000917 case RetEffect::Alias: {
918 unsigned idx = RE.getValue();
919 assert (idx < CE->getNumArgs());
920 RVal V = StateMgr.GetRVal(St, CE->getArg(idx));
Ted Kremenek199e1a02008-03-12 21:06:49 +0000921 St = StateMgr.SetRVal(St, CE, V, Eng.getCFG().isBlkExpr(CE), false);
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000922 break;
923 }
924
925 case RetEffect::OwnedSymbol: {
926 unsigned Count = Builder.getCurrentBlockCount();
Ted Kremenek361fa8e2008-03-12 21:45:47 +0000927 SymbolID Sym = Eng.getSymbolManager().getConjuredSymbol(CE, Count);
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000928
929 ValueState StImpl = *St;
930 RefBindings B = GetRefBindings(StImpl);
Ted Kremenek61b9f872008-04-10 23:09:18 +0000931 SetRefBindings(StImpl, RefBFactory.Add(B, Sym, RefVal::makeOwned()));
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000932
933 St = StateMgr.SetRVal(StateMgr.getPersistentState(StImpl),
934 CE, lval::SymbolVal(Sym),
Ted Kremenek199e1a02008-03-12 21:06:49 +0000935 Eng.getCFG().isBlkExpr(CE), false);
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000936
937 break;
938 }
939
940 case RetEffect::NotOwnedSymbol: {
941 unsigned Count = Builder.getCurrentBlockCount();
Ted Kremenek361fa8e2008-03-12 21:45:47 +0000942 SymbolID Sym = Eng.getSymbolManager().getConjuredSymbol(CE, Count);
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000943
944 ValueState StImpl = *St;
945 RefBindings B = GetRefBindings(StImpl);
946 SetRefBindings(StImpl, RefBFactory.Add(B, Sym, RefVal::makeNotOwned()));
947
948 St = StateMgr.SetRVal(StateMgr.getPersistentState(StImpl),
949 CE, lval::SymbolVal(Sym),
Ted Kremenek199e1a02008-03-12 21:06:49 +0000950 Eng.getCFG().isBlkExpr(CE), false);
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000951
952 break;
953 }
954 }
955
Ted Kremenek0e561a32008-03-21 21:30:14 +0000956 Builder.MakeNode(Dst, CE, Pred, St);
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000957}
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000958
Ted Kremenek85348202008-04-15 23:44:31 +0000959
960void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet<ValueState>& Dst,
961 GRExprEngine& Eng,
962 GRStmtNodeBuilder<ValueState>& Builder,
963 ObjCMessageExpr* ME,
964 ExplodedNode<ValueState>* Pred) {
965
Ted Kremenek9040c652008-05-01 21:31:50 +0000966 if (!EvalObjCMessageExprAux(Dst, Eng, Builder, ME, Pred))
967 return;
968
969 // The basic transfer function logic for message expressions does nothing.
970 // We just invalidate all arguments passed in by references.
971
972 ValueStateManager& StateMgr = Eng.getStateManager();
973 ValueState* St = Builder.GetState(Pred);
974 RefBindings B = GetRefBindings(*St);
975
976 for (ObjCMessageExpr::arg_iterator I = ME->arg_begin(), E = ME->arg_end();
977 I != E; ++I) {
978
979 RVal V = StateMgr.GetRVal(St, *I);
980
981 if (isa<LVal>(V)) {
982
983 LVal lv = cast<LVal>(V);
984
985 // Did the lval bind to a symbol?
986 RVal X = StateMgr.GetRVal(St, lv);
987
988 if (isa<lval::SymbolVal>(X)) {
Ted Kremenek529a9bd2008-05-01 23:38:35 +0000989 SymbolID Sym = cast<lval::SymbolVal>(X).getSymbol();
Ted Kremenek9040c652008-05-01 21:31:50 +0000990 B = Remove(B, Sym);
991
992 // Create a new state with the updated bindings.
993 ValueState StVals = *St;
994 SetRefBindings(StVals, B);
995 St = StateMgr.getPersistentState(StVals);
996 }
997
998 St = StateMgr.SetRVal(St, cast<LVal>(V), UnknownVal());
999 }
1000 }
1001
1002 Builder.MakeNode(Dst, ME, Pred, St);
Ted Kremenek85348202008-04-15 23:44:31 +00001003}
1004
1005bool CFRefCount::EvalObjCMessageExprAux(ExplodedNodeSet<ValueState>& Dst,
1006 GRExprEngine& Eng,
1007 GRStmtNodeBuilder<ValueState>& Builder,
1008 ObjCMessageExpr* ME,
1009 ExplodedNode<ValueState>* Pred) {
Ted Kremenek377e2302008-04-29 05:33:51 +00001010
1011 if (GCEnabled)
1012 return true;
1013
Ted Kremenek9ed18e62008-04-16 04:28:53 +00001014 // Handle "toll-free bridging" of calls to "Release" and "Retain".
1015
1016 // FIXME: track the underlying object type associated so that we can
1017 // flag illegal uses of toll-free bridging (or at least handle it
1018 // at casts).
Ted Kremenek85348202008-04-15 23:44:31 +00001019
1020 Selector S = ME->getSelector();
1021
1022 if (!S.isUnarySelector())
1023 return true;
1024
Ted Kremenek9ed18e62008-04-16 04:28:53 +00001025 Expr* Receiver = ME->getReceiver();
1026
1027 if (!Receiver)
1028 return true;
1029
Ted Kremenek5934cee2008-05-01 02:18:37 +00001030 // Check if we are calling "autorelease".
1031
1032 enum { IsRelease, IsRetain, IsAutorelease, IsNone } mode = IsNone;
Ted Kremenek9ed18e62008-04-16 04:28:53 +00001033
Ted Kremenek5934cee2008-05-01 02:18:37 +00001034 if (S == AutoreleaseSelector)
1035 mode = IsAutorelease;
1036 else if (S == RetainSelector)
1037 mode = IsRetain;
1038 else if (S == ReleaseSelector)
1039 mode = IsRelease;
Ted Kremenek9ed18e62008-04-16 04:28:53 +00001040
Ted Kremenek5934cee2008-05-01 02:18:37 +00001041 if (mode == IsNone)
Ted Kremenek9ed18e62008-04-16 04:28:53 +00001042 return true;
1043
Ted Kremenek5934cee2008-05-01 02:18:37 +00001044 // We have "retain", "release", or "autorelease".
Ted Kremenek9ed18e62008-04-16 04:28:53 +00001045 ValueStateManager& StateMgr = Eng.getStateManager();
1046 ValueState* St = Builder.GetState(Pred);
1047 RVal V = StateMgr.GetRVal(St, Receiver);
1048
Ted Kremenek5934cee2008-05-01 02:18:37 +00001049 // Was the argument something we are not tracking?
Ted Kremenek9ed18e62008-04-16 04:28:53 +00001050 if (!isa<lval::SymbolVal>(V))
1051 return true;
1052
Ted Kremenek5934cee2008-05-01 02:18:37 +00001053 // Get the bindings.
Ted Kremenek9ed18e62008-04-16 04:28:53 +00001054 SymbolID Sym = cast<lval::SymbolVal>(V).getSymbol();
1055 RefBindings B = GetRefBindings(*St);
1056
Ted Kremenek5934cee2008-05-01 02:18:37 +00001057 // Find the tracked value.
Ted Kremenek9ed18e62008-04-16 04:28:53 +00001058 RefBindings::TreeTy* T = B.SlimFind(Sym);
Ted Kremenek5934cee2008-05-01 02:18:37 +00001059
Ted Kremenek9ed18e62008-04-16 04:28:53 +00001060 if (!T)
1061 return true;
Ted Kremenek9ed18e62008-04-16 04:28:53 +00001062
Ted Kremenek5934cee2008-05-01 02:18:37 +00001063 RefVal::Kind hasErr = (RefVal::Kind) 0;
Ted Kremenek9ed18e62008-04-16 04:28:53 +00001064
Ted Kremenek5934cee2008-05-01 02:18:37 +00001065 // Update the bindings.
1066 switch (mode) {
1067 case IsNone:
1068 assert(false);
1069
1070 case IsRelease:
1071 B = Update(B, Sym, T->getValue().second, DecRef, hasErr);
1072 break;
1073
1074 case IsRetain:
1075 B = Update(B, Sym, T->getValue().second, IncRef, hasErr);
1076 break;
1077
1078 case IsAutorelease:
1079 // For now we just stop tracking a value if we see
1080 // it sent "autorelease." In the future we can potentially
1081 // track the associated pool.
1082 B = Remove(B, Sym);
1083 break;
1084 }
1085
1086 // Create a new state with the updated bindings.
Ted Kremenek9ed18e62008-04-16 04:28:53 +00001087 ValueState StVals = *St;
1088 SetRefBindings(StVals, B);
Ted Kremenek31593ac2008-05-01 04:02:04 +00001089 St = Eng.SetRVal(StateMgr.getPersistentState(StVals), ME, V);
Ted Kremenek9ed18e62008-04-16 04:28:53 +00001090
Ted Kremenek5934cee2008-05-01 02:18:37 +00001091 // Create an error node if it exists.
Ted Kremenek9ed18e62008-04-16 04:28:53 +00001092 if (hasErr)
Ted Kremenek8dd56462008-04-18 03:39:05 +00001093 ProcessNonLeakError(Dst, Builder, ME, Receiver, Pred, St, hasErr, Sym);
Ted Kremenek9ed18e62008-04-16 04:28:53 +00001094 else
1095 Builder.MakeNode(Dst, ME, Pred, St);
1096
1097 return false;
Ted Kremenek85348202008-04-15 23:44:31 +00001098}
1099
Ted Kremenek13922612008-04-16 20:40:59 +00001100// Stores.
1101
1102void CFRefCount::EvalStore(ExplodedNodeSet<ValueState>& Dst,
1103 GRExprEngine& Eng,
1104 GRStmtNodeBuilder<ValueState>& Builder,
1105 Expr* E, ExplodedNode<ValueState>* Pred,
1106 ValueState* St, RVal TargetLV, RVal Val) {
1107
1108 // Check if we have a binding for "Val" and if we are storing it to something
1109 // we don't understand or otherwise the value "escapes" the function.
1110
1111 if (!isa<lval::SymbolVal>(Val))
1112 return;
1113
1114 // Are we storing to something that causes the value to "escape"?
1115
1116 bool escapes = false;
1117
1118 if (!isa<lval::DeclVal>(TargetLV))
1119 escapes = true;
1120 else
1121 escapes = cast<lval::DeclVal>(TargetLV).getDecl()->hasGlobalStorage();
1122
1123 if (!escapes)
1124 return;
1125
1126 SymbolID Sym = cast<lval::SymbolVal>(Val).getSymbol();
1127 RefBindings B = GetRefBindings(*St);
1128 RefBindings::TreeTy* T = B.SlimFind(Sym);
1129
1130 if (!T)
1131 return;
1132
Ted Kremenekdb863712008-04-16 22:32:20 +00001133 // Nuke the binding.
1134 St = NukeBinding(Eng.getStateManager(), St, Sym);
Ted Kremenek13922612008-04-16 20:40:59 +00001135
1136 // Hand of the remaining logic to the parent implementation.
1137 GRSimpleVals::EvalStore(Dst, Eng, Builder, E, Pred, St, TargetLV, Val);
1138}
1139
Ted Kremenekdb863712008-04-16 22:32:20 +00001140
1141ValueState* CFRefCount::NukeBinding(ValueStateManager& VMgr, ValueState* St,
1142 SymbolID sid) {
1143 ValueState StImpl = *St;
1144 RefBindings B = GetRefBindings(StImpl);
1145 StImpl.CheckerState = RefBFactory.Remove(B, sid).getRoot();
1146 return VMgr.getPersistentState(StImpl);
1147}
1148
Ted Kremeneke7bd9c22008-04-11 22:25:11 +00001149// End-of-path.
1150
Ted Kremenekdb863712008-04-16 22:32:20 +00001151ValueState* CFRefCount::HandleSymbolDeath(ValueStateManager& VMgr,
1152 ValueState* St, SymbolID sid,
1153 RefVal V, bool& hasLeak) {
1154
Ted Kremenek4fd88972008-04-17 18:12:53 +00001155 hasLeak = V.isOwned() ||
1156 ((V.isNotOwned() || V.isReturnedOwned()) && V.getCount() > 0);
Ted Kremenekdb863712008-04-16 22:32:20 +00001157
1158 if (!hasLeak)
1159 return NukeBinding(VMgr, St, sid);
1160
1161 RefBindings B = GetRefBindings(*St);
1162 ValueState StImpl = *St;
1163 StImpl.CheckerState = RefBFactory.Add(B, sid, RefVal::makeLeak()).getRoot();
1164 return VMgr.getPersistentState(StImpl);
1165}
1166
1167void CFRefCount::EvalEndPath(GRExprEngine& Eng,
Ted Kremeneke7bd9c22008-04-11 22:25:11 +00001168 GREndPathNodeBuilder<ValueState>& Builder) {
1169
Ted Kremenekdb863712008-04-16 22:32:20 +00001170 ValueState* St = Builder.getState();
1171 RefBindings B = GetRefBindings(*St);
Ted Kremeneke7bd9c22008-04-11 22:25:11 +00001172
Ted Kremenekdb863712008-04-16 22:32:20 +00001173 llvm::SmallVector<SymbolID, 10> Leaked;
Ted Kremeneke7bd9c22008-04-11 22:25:11 +00001174
Ted Kremenekdb863712008-04-16 22:32:20 +00001175 for (RefBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) {
1176 bool hasLeak = false;
Ted Kremeneke7bd9c22008-04-11 22:25:11 +00001177
Ted Kremenekdb863712008-04-16 22:32:20 +00001178 St = HandleSymbolDeath(Eng.getStateManager(), St,
1179 (*I).first, (*I).second, hasLeak);
1180
1181 if (hasLeak) Leaked.push_back((*I).first);
1182 }
Ted Kremenek652adc62008-04-24 23:57:27 +00001183
1184 if (Leaked.empty())
1185 return;
1186
Ted Kremenek8dd56462008-04-18 03:39:05 +00001187 ExplodedNode<ValueState>* N = Builder.MakeNode(St);
Ted Kremenek4f285152008-04-18 16:30:14 +00001188
Ted Kremenek652adc62008-04-24 23:57:27 +00001189 if (!N)
Ted Kremenek4f285152008-04-18 16:30:14 +00001190 return;
Ted Kremenekcb612922008-04-18 19:23:43 +00001191
Ted Kremenek8dd56462008-04-18 03:39:05 +00001192 std::vector<SymbolID>*& LeaksAtNode = Leaks[N];
1193 assert (!LeaksAtNode);
1194 LeaksAtNode = new std::vector<SymbolID>();
Ted Kremenekdb863712008-04-16 22:32:20 +00001195
1196 for (llvm::SmallVector<SymbolID, 10>::iterator I=Leaked.begin(),
1197 E = Leaked.end(); I != E; ++I)
Ted Kremenek8dd56462008-04-18 03:39:05 +00001198 (*LeaksAtNode).push_back(*I);
Ted Kremeneke7bd9c22008-04-11 22:25:11 +00001199}
1200
Ted Kremenek652adc62008-04-24 23:57:27 +00001201// Dead symbols.
1202
1203void CFRefCount::EvalDeadSymbols(ExplodedNodeSet<ValueState>& Dst,
1204 GRExprEngine& Eng,
1205 GRStmtNodeBuilder<ValueState>& Builder,
Ted Kremenek910e9992008-04-25 01:25:15 +00001206 ExplodedNode<ValueState>* Pred,
1207 Stmt* S,
Ted Kremenek652adc62008-04-24 23:57:27 +00001208 ValueState* St,
1209 const ValueStateManager::DeadSymbolsTy& Dead) {
Ted Kremenek910e9992008-04-25 01:25:15 +00001210
Ted Kremenek652adc62008-04-24 23:57:27 +00001211 // FIXME: a lot of copy-and-paste from EvalEndPath. Refactor.
1212
1213 RefBindings B = GetRefBindings(*St);
1214 llvm::SmallVector<SymbolID, 10> Leaked;
1215
1216 for (ValueStateManager::DeadSymbolsTy::const_iterator
1217 I=Dead.begin(), E=Dead.end(); I!=E; ++I) {
1218
1219 RefBindings::TreeTy* T = B.SlimFind(*I);
1220
1221 if (!T)
1222 continue;
1223
1224 bool hasLeak = false;
1225
1226 St = HandleSymbolDeath(Eng.getStateManager(), St,
1227 *I, T->getValue().second, hasLeak);
1228
1229 if (hasLeak) Leaked.push_back(*I);
1230 }
1231
1232 if (Leaked.empty())
1233 return;
1234
1235 ExplodedNode<ValueState>* N = Builder.MakeNode(Dst, S, Pred, St);
1236
1237 if (!N)
1238 return;
1239
1240 std::vector<SymbolID>*& LeaksAtNode = Leaks[N];
1241 assert (!LeaksAtNode);
1242 LeaksAtNode = new std::vector<SymbolID>();
1243
1244 for (llvm::SmallVector<SymbolID, 10>::iterator I=Leaked.begin(),
1245 E = Leaked.end(); I != E; ++I)
1246 (*LeaksAtNode).push_back(*I);
1247}
1248
Ted Kremenek4fd88972008-04-17 18:12:53 +00001249 // Return statements.
1250
1251void CFRefCount::EvalReturn(ExplodedNodeSet<ValueState>& Dst,
1252 GRExprEngine& Eng,
1253 GRStmtNodeBuilder<ValueState>& Builder,
1254 ReturnStmt* S,
1255 ExplodedNode<ValueState>* Pred) {
1256
1257 Expr* RetE = S->getRetValue();
1258 if (!RetE) return;
1259
1260 ValueStateManager& StateMgr = Eng.getStateManager();
1261 ValueState* St = Builder.GetState(Pred);
1262 RVal V = StateMgr.GetRVal(St, RetE);
1263
1264 if (!isa<lval::SymbolVal>(V))
1265 return;
1266
1267 // Get the reference count binding (if any).
1268 SymbolID Sym = cast<lval::SymbolVal>(V).getSymbol();
1269 RefBindings B = GetRefBindings(*St);
1270 RefBindings::TreeTy* T = B.SlimFind(Sym);
1271
1272 if (!T)
1273 return;
1274
1275 // Change the reference count.
1276
1277 RefVal X = T->getValue().second;
1278
1279 switch (X.getKind()) {
1280
1281 case RefVal::Owned: {
1282 unsigned cnt = X.getCount();
1283 X = RefVal::makeReturnedOwned(cnt);
1284 break;
1285 }
1286
1287 case RefVal::NotOwned: {
1288 unsigned cnt = X.getCount();
1289 X = cnt ? RefVal::makeReturnedOwned(cnt - 1)
1290 : RefVal::makeReturnedNotOwned();
1291 break;
1292 }
1293
1294 default:
Ted Kremenek4fd88972008-04-17 18:12:53 +00001295 return;
1296 }
1297
1298 // Update the binding.
1299
1300 ValueState StImpl = *St;
1301 StImpl.CheckerState = RefBFactory.Add(B, Sym, X).getRoot();
1302 Builder.MakeNode(Dst, S, Pred, StateMgr.getPersistentState(StImpl));
1303}
1304
Ted Kremenekcb612922008-04-18 19:23:43 +00001305// Assumptions.
1306
1307ValueState* CFRefCount::EvalAssume(GRExprEngine& Eng, ValueState* St,
1308 RVal Cond, bool Assumption,
1309 bool& isFeasible) {
1310
1311 // FIXME: We may add to the interface of EvalAssume the list of symbols
1312 // whose assumptions have changed. For now we just iterate through the
1313 // bindings and check if any of the tracked symbols are NULL. This isn't
1314 // too bad since the number of symbols we will track in practice are
1315 // probably small and EvalAssume is only called at branches and a few
1316 // other places.
1317
1318 RefBindings B = GetRefBindings(*St);
1319
1320 if (B.isEmpty())
1321 return St;
1322
1323 bool changed = false;
1324
1325 for (RefBindings::iterator I=B.begin(), E=B.end(); I!=E; ++I) {
1326
1327 // Check if the symbol is null (or equal to any constant).
1328 // If this is the case, stop tracking the symbol.
1329
1330 if (St->getSymVal(I.getKey())) {
1331 changed = true;
1332 B = RefBFactory.Remove(B, I.getKey());
1333 }
1334 }
1335
1336 if (!changed)
1337 return St;
1338
1339 ValueState StImpl = *St;
1340 StImpl.CheckerState = B.getRoot();
1341 return Eng.getStateManager().getPersistentState(StImpl);
1342}
Ted Kremenek6b3a0f72008-03-11 06:39:11 +00001343
1344CFRefCount::RefBindings CFRefCount::Update(RefBindings B, SymbolID sym,
Ted Kremenek1ac08d62008-03-11 17:48:22 +00001345 RefVal V, ArgEffect E,
Ted Kremenek9ed18e62008-04-16 04:28:53 +00001346 RefVal::Kind& hasErr) {
Ted Kremenek6b3a0f72008-03-11 06:39:11 +00001347
Ted Kremenek1ac08d62008-03-11 17:48:22 +00001348 // FIXME: This dispatch can potentially be sped up by unifiying it into
1349 // a single switch statement. Opt for simplicity for now.
Ted Kremenek6b3a0f72008-03-11 06:39:11 +00001350
Ted Kremenek1ac08d62008-03-11 17:48:22 +00001351 switch (E) {
1352 default:
1353 assert (false && "Unhandled CFRef transition.");
1354
1355 case DoNothing:
Ted Kremenek65c91652008-04-29 05:44:10 +00001356 if (!GCEnabled && V.getKind() == RefVal::Released) {
Ted Kremenek00a3a5f2008-03-12 01:21:45 +00001357 V = RefVal::makeUseAfterRelease();
Ted Kremenek9ed18e62008-04-16 04:28:53 +00001358 hasErr = V.getKind();
Ted Kremenek00a3a5f2008-03-12 01:21:45 +00001359 break;
1360 }
1361
Ted Kremenek1ac08d62008-03-11 17:48:22 +00001362 return B;
1363
1364 case IncRef:
1365 switch (V.getKind()) {
1366 default:
1367 assert(false);
1368
1369 case RefVal::Owned:
Ted Kremenek940b1d82008-04-10 23:44:06 +00001370 V = RefVal::makeOwned(V.getCount()+1);
1371 break;
Ted Kremenek61b9f872008-04-10 23:09:18 +00001372
Ted Kremenek1ac08d62008-03-11 17:48:22 +00001373 case RefVal::NotOwned:
Ted Kremenek61b9f872008-04-10 23:09:18 +00001374 V = RefVal::makeNotOwned(V.getCount()+1);
Ted Kremenek1ac08d62008-03-11 17:48:22 +00001375 break;
1376
1377 case RefVal::Released:
Ted Kremenek65c91652008-04-29 05:44:10 +00001378 if (GCEnabled)
1379 V = RefVal::makeOwned();
1380 else {
1381 V = RefVal::makeUseAfterRelease();
1382 hasErr = V.getKind();
1383 }
1384
Ted Kremenek1ac08d62008-03-11 17:48:22 +00001385 break;
1386 }
1387
Ted Kremenek940b1d82008-04-10 23:44:06 +00001388 break;
1389
Ted Kremenek1ac08d62008-03-11 17:48:22 +00001390 case DecRef:
1391 switch (V.getKind()) {
1392 default:
1393 assert (false);
1394
1395 case RefVal::Owned: {
Ted Kremenek4fd88972008-04-17 18:12:53 +00001396 unsigned Count = V.getCount();
1397 V = Count > 0 ? RefVal::makeOwned(Count - 1) : RefVal::makeReleased();
Ted Kremenek1ac08d62008-03-11 17:48:22 +00001398 break;
1399 }
1400
Ted Kremenek61b9f872008-04-10 23:09:18 +00001401 case RefVal::NotOwned: {
Ted Kremenek4fd88972008-04-17 18:12:53 +00001402 unsigned Count = V.getCount();
Ted Kremenek61b9f872008-04-10 23:09:18 +00001403
Ted Kremenek4fd88972008-04-17 18:12:53 +00001404 if (Count > 0)
1405 V = RefVal::makeNotOwned(Count - 1);
Ted Kremenek61b9f872008-04-10 23:09:18 +00001406 else {
1407 V = RefVal::makeReleaseNotOwned();
Ted Kremenek9ed18e62008-04-16 04:28:53 +00001408 hasErr = V.getKind();
Ted Kremenek61b9f872008-04-10 23:09:18 +00001409 }
1410
Ted Kremenek1ac08d62008-03-11 17:48:22 +00001411 break;
1412 }
Ted Kremenek1ac08d62008-03-11 17:48:22 +00001413
1414 case RefVal::Released:
Ted Kremenek1ac08d62008-03-11 17:48:22 +00001415 V = RefVal::makeUseAfterRelease();
Ted Kremenek9ed18e62008-04-16 04:28:53 +00001416 hasErr = V.getKind();
Ted Kremenek1ac08d62008-03-11 17:48:22 +00001417 break;
1418 }
Ted Kremenek940b1d82008-04-10 23:44:06 +00001419
1420 break;
Ted Kremenek1ac08d62008-03-11 17:48:22 +00001421 }
1422
1423 return RefBFactory.Add(B, sym, V);
Ted Kremenek6b3a0f72008-03-11 06:39:11 +00001424}
1425
Ted Kremenekfa34b332008-04-09 01:10:13 +00001426
1427//===----------------------------------------------------------------------===//
Ted Kremenek05cbe1a2008-04-09 23:49:11 +00001428// Error reporting.
Ted Kremenekfa34b332008-04-09 01:10:13 +00001429//===----------------------------------------------------------------------===//
1430
Ted Kremenek8dd56462008-04-18 03:39:05 +00001431namespace {
1432
1433 //===-------------===//
1434 // Bug Descriptions. //
1435 //===-------------===//
1436
Ted Kremenek95cc1ba2008-04-18 20:54:29 +00001437 class VISIBILITY_HIDDEN CFRefBug : public BugTypeCacheLocation {
Ted Kremenek8dd56462008-04-18 03:39:05 +00001438 protected:
1439 CFRefCount& TF;
1440
1441 public:
1442 CFRefBug(CFRefCount& tf) : TF(tf) {}
Ted Kremenek072192b2008-04-30 23:47:44 +00001443
Ted Kremenekbb77e9b2008-05-01 22:50:36 +00001444 CFRefCount& getTF() { return TF; }
1445
Ted Kremenekc9fa2f72008-05-01 23:13:35 +00001446 virtual bool isLeak() const { return false; }
Ted Kremenek8dd56462008-04-18 03:39:05 +00001447 };
1448
1449 class VISIBILITY_HIDDEN UseAfterRelease : public CFRefBug {
1450 public:
1451 UseAfterRelease(CFRefCount& tf) : CFRefBug(tf) {}
1452
1453 virtual const char* getName() const {
Ted Kremenek2cf943a2008-04-18 04:55:01 +00001454 return "Core Foundation: Use-After-Release";
Ted Kremenek8dd56462008-04-18 03:39:05 +00001455 }
1456 virtual const char* getDescription() const {
Ted Kremenek2cf943a2008-04-18 04:55:01 +00001457 return "Reference-counted object is used"
1458 " after it is released.";
Ted Kremenek8dd56462008-04-18 03:39:05 +00001459 }
1460
1461 virtual void EmitWarnings(BugReporter& BR);
Ted Kremenek8dd56462008-04-18 03:39:05 +00001462 };
1463
1464 class VISIBILITY_HIDDEN BadRelease : public CFRefBug {
1465 public:
1466 BadRelease(CFRefCount& tf) : CFRefBug(tf) {}
1467
1468 virtual const char* getName() const {
Ted Kremenek2cf943a2008-04-18 04:55:01 +00001469 return "Core Foundation: Release of non-owned object";
Ted Kremenek8dd56462008-04-18 03:39:05 +00001470 }
1471 virtual const char* getDescription() const {
1472 return "Incorrect decrement of the reference count of a "
Ted Kremenek2cf943a2008-04-18 04:55:01 +00001473 "CoreFoundation object: "
Ted Kremenek8dd56462008-04-18 03:39:05 +00001474 "The object is not owned at this point by the caller.";
1475 }
1476
1477 virtual void EmitWarnings(BugReporter& BR);
1478 };
1479
1480 class VISIBILITY_HIDDEN Leak : public CFRefBug {
1481 public:
1482 Leak(CFRefCount& tf) : CFRefBug(tf) {}
1483
1484 virtual const char* getName() const {
Ted Kremenek2cf943a2008-04-18 04:55:01 +00001485 return "Core Foundation: Memory Leak";
Ted Kremenek8dd56462008-04-18 03:39:05 +00001486 }
1487
1488 virtual const char* getDescription() const {
Ted Kremenek2cf943a2008-04-18 04:55:01 +00001489 return "Object leaked.";
Ted Kremenek8dd56462008-04-18 03:39:05 +00001490 }
1491
1492 virtual void EmitWarnings(BugReporter& BR);
Ted Kremenekbb77e9b2008-05-01 22:50:36 +00001493 virtual void GetErrorNodes(std::vector<ExplodedNode<ValueState>*>& Nodes);
Ted Kremenekc9fa2f72008-05-01 23:13:35 +00001494 virtual bool isLeak() const { return true; }
Ted Kremenek8dd56462008-04-18 03:39:05 +00001495 };
1496
1497 //===---------===//
1498 // Bug Reports. //
1499 //===---------===//
1500
1501 class VISIBILITY_HIDDEN CFRefReport : public RangedBugReport {
1502 SymbolID Sym;
1503 public:
Ted Kremenek072192b2008-04-30 23:47:44 +00001504 CFRefReport(CFRefBug& D, ExplodedNode<ValueState> *n, SymbolID sym)
Ted Kremenek8dd56462008-04-18 03:39:05 +00001505 : RangedBugReport(D, n), Sym(sym) {}
1506
1507 virtual ~CFRefReport() {}
1508
Ted Kremenekbb77e9b2008-05-01 22:50:36 +00001509 CFRefBug& getBugType() {
1510 return (CFRefBug&) RangedBugReport::getBugType();
1511 }
1512 const CFRefBug& getBugType() const {
1513 return (const CFRefBug&) RangedBugReport::getBugType();
1514 }
1515
1516 virtual void getRanges(BugReporter& BR, const SourceRange*& beg,
1517 const SourceRange*& end) {
1518
Ted Kremenekc9fa2f72008-05-01 23:13:35 +00001519 if (getBugType().isLeak())
Ted Kremenekbb77e9b2008-05-01 22:50:36 +00001520 RangedBugReport::getRanges(BR, beg, end);
1521 else {
1522 beg = 0;
1523 end = 0;
1524 }
1525 }
1526
Ted Kremenekc9fa2f72008-05-01 23:13:35 +00001527 virtual PathDiagnosticPiece* getEndPath(BugReporter& BR,
1528 ExplodedNode<ValueState>* N);
1529
Ted Kremenek072192b2008-04-30 23:47:44 +00001530 virtual std::pair<const char**,const char**> getExtraDescriptiveText();
Ted Kremenek8dd56462008-04-18 03:39:05 +00001531
1532 virtual PathDiagnosticPiece* VisitNode(ExplodedNode<ValueState>* N,
1533 ExplodedNode<ValueState>* PrevN,
1534 ExplodedGraph<ValueState>& G,
1535 BugReporter& BR);
1536 };
1537
1538
1539} // end anonymous namespace
1540
1541void CFRefCount::RegisterChecks(GRExprEngine& Eng) {
1542 GRSimpleVals::RegisterChecks(Eng);
1543 Eng.Register(new UseAfterRelease(*this));
1544 Eng.Register(new BadRelease(*this));
1545 Eng.Register(new Leak(*this));
1546}
1547
Ted Kremenek072192b2008-04-30 23:47:44 +00001548
1549static const char* Msgs[] = {
1550 "Code is compiled in garbage collection only mode" // GC only
1551 " (the bug occurs with garbage collection enabled).",
1552
1553 "Code is compiled without garbage collection.", // No GC.
1554
1555 "Code is compiled for use with and without garbage collection (GC)."
1556 " The bug occurs with GC enabled.", // Hybrid, with GC.
1557
1558 "Code is compiled for use with and without garbage collection (GC)."
1559 " The bug occurs in non-GC mode." // Hyrbird, without GC/
1560};
1561
1562std::pair<const char**,const char**> CFRefReport::getExtraDescriptiveText() {
1563 CFRefCount& TF = static_cast<CFRefBug&>(getBugType()).getTF();
1564
1565 switch (TF.getLangOptions().getGCMode()) {
1566 default:
1567 assert(false);
Ted Kremenek31593ac2008-05-01 04:02:04 +00001568
1569 case LangOptions::GCOnly:
1570 assert (TF.isGCEnabled());
1571 return std::make_pair(&Msgs[0], &Msgs[0]+1);
Ted Kremenek072192b2008-04-30 23:47:44 +00001572
1573 case LangOptions::NonGC:
1574 assert (!TF.isGCEnabled());
Ted Kremenek072192b2008-04-30 23:47:44 +00001575 return std::make_pair(&Msgs[1], &Msgs[1]+1);
1576
1577 case LangOptions::HybridGC:
1578 if (TF.isGCEnabled())
1579 return std::make_pair(&Msgs[2], &Msgs[2]+1);
1580 else
1581 return std::make_pair(&Msgs[3], &Msgs[3]+1);
1582 }
1583}
1584
Ted Kremenek8dd56462008-04-18 03:39:05 +00001585PathDiagnosticPiece* CFRefReport::VisitNode(ExplodedNode<ValueState>* N,
1586 ExplodedNode<ValueState>* PrevN,
1587 ExplodedGraph<ValueState>& G,
1588 BugReporter& BR) {
1589
1590 // Check if the type state has changed.
1591
1592 ValueState* PrevSt = PrevN->getState();
1593 ValueState* CurrSt = N->getState();
1594
1595 CFRefCount::RefBindings PrevB = CFRefCount::GetRefBindings(*PrevSt);
1596 CFRefCount::RefBindings CurrB = CFRefCount::GetRefBindings(*CurrSt);
1597
Ted Kremenek2cf943a2008-04-18 04:55:01 +00001598 CFRefCount::RefBindings::TreeTy* PrevT = PrevB.SlimFind(Sym);
1599 CFRefCount::RefBindings::TreeTy* CurrT = CurrB.SlimFind(Sym);
Ted Kremenek8dd56462008-04-18 03:39:05 +00001600
Ted Kremenek2cf943a2008-04-18 04:55:01 +00001601 if (!CurrT)
1602 return NULL;
Ted Kremenek8dd56462008-04-18 03:39:05 +00001603
Ted Kremenek2cf943a2008-04-18 04:55:01 +00001604 const char* Msg = NULL;
1605 RefVal CurrV = CurrB.SlimFind(Sym)->getValue().second;
Ted Kremenek8dd56462008-04-18 03:39:05 +00001606
Ted Kremenek2cf943a2008-04-18 04:55:01 +00001607 if (!PrevT) {
1608
1609 // Check for the point where we start tracking the value.
1610
1611 if (CurrV.isOwned())
1612 Msg = "Function call returns 'Owned' Core Foundation object.";
1613 else {
1614 assert (CurrV.isNotOwned());
1615 Msg = "Function call returns 'Non-Owned' Core Foundation object.";
1616 }
1617
1618 Stmt* S = cast<PostStmt>(N->getLocation()).getStmt();
1619 FullSourceLoc Pos(S->getLocStart(), BR.getContext().getSourceManager());
1620 PathDiagnosticPiece* P = new PathDiagnosticPiece(Pos, Msg);
1621
1622 if (Expr* Exp = dyn_cast<Expr>(S))
1623 P->addRange(Exp->getSourceRange());
1624
1625 return P;
1626 }
1627
1628 // Determine if the typestate has changed.
1629
1630 RefVal PrevV = PrevB.SlimFind(Sym)->getValue().second;
1631
1632 if (PrevV == CurrV)
1633 return NULL;
1634
1635 // The typestate has changed.
1636
1637 std::ostringstream os;
1638
1639 switch (CurrV.getKind()) {
1640 case RefVal::Owned:
1641 case RefVal::NotOwned:
1642 assert (PrevV.getKind() == CurrV.getKind());
1643
1644 if (PrevV.getCount() > CurrV.getCount())
1645 os << "Reference count decremented.";
1646 else
1647 os << "Reference count incremented.";
1648
Ted Kremenek79c140b2008-04-18 05:32:44 +00001649 if (CurrV.getCount()) {
1650 os << " Object has +" << CurrV.getCount();
1651
1652 if (CurrV.getCount() > 1)
1653 os << " reference counts.";
1654 else
1655 os << " reference count.";
1656 }
Ted Kremenek2cf943a2008-04-18 04:55:01 +00001657
1658 Msg = os.str().c_str();
1659
1660 break;
1661
1662 case RefVal::Released:
1663 Msg = "Object released.";
1664 break;
1665
1666 case RefVal::ReturnedOwned:
1667 Msg = "Object returned to caller. "
1668 "Caller gets ownership of object.";
1669 break;
1670
1671 case RefVal::ReturnedNotOwned:
1672 Msg = "Object returned to caller. "
1673 "Caller does not get ownership of object.";
1674 break;
1675
1676 default:
1677 return NULL;
1678 }
1679
1680 Stmt* S = cast<PostStmt>(N->getLocation()).getStmt();
1681 FullSourceLoc Pos(S->getLocStart(), BR.getContext().getSourceManager());
1682 PathDiagnosticPiece* P = new PathDiagnosticPiece(Pos, Msg);
1683
1684 // Add the range by scanning the children of the statement for any bindings
1685 // to Sym.
1686
1687 ValueStateManager& VSM = BR.getEngine().getStateManager();
1688
1689 for (Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I!=E; ++I)
1690 if (Expr* Exp = dyn_cast_or_null<Expr>(*I)) {
1691 RVal X = VSM.GetRVal(CurrSt, Exp);
1692
1693 if (lval::SymbolVal* SV = dyn_cast<lval::SymbolVal>(&X))
1694 if (SV->getSymbol() == Sym) {
1695 P->addRange(Exp->getSourceRange()); break;
1696 }
1697 }
1698
1699 return P;
Ted Kremenek8dd56462008-04-18 03:39:05 +00001700}
1701
Ted Kremenekc9fa2f72008-05-01 23:13:35 +00001702PathDiagnosticPiece* CFRefReport::getEndPath(BugReporter& BR,
1703 ExplodedNode<ValueState>* N) {
1704
1705 if (!getBugType().isLeak())
1706 return RangedBugReport::getEndPath(BR, N);
1707
1708 // We are a leak. Walk up the graph to get to the first node where the
1709 // symbol appeared.
1710
1711 ExplodedNode<ValueState>* Last = N;
1712 typedef CFRefCount::RefBindings RefBindings;
1713
1714 // Find the first node that referred to the tracked symbol.
1715
1716 while (N) {
1717 ValueState* St = N->getState();
1718 RefBindings B = RefBindings((RefBindings::TreeTy*) St->CheckerState);
1719
1720 if (!B.SlimFind(Sym))
1721 break;
1722
1723 Last = N;
1724 N = N->pred_empty() ? NULL : *(N->pred_begin());
1725 }
1726
1727 // Get the location.
1728
1729 assert (Last);
1730 Stmt* FirstStmt = cast<PostStmt>(Last->getLocation()).getStmt();
1731
1732 unsigned Line =
1733 BR.getSourceManager().getLogicalLineNumber(FirstStmt->getLocStart());
1734
1735 // FIXME: Also get the name of the variable.
1736
1737 std::ostringstream os;
1738 os << "Object allocated on line " << Line << " is leaked.";
1739
1740 Stmt* S = getStmt(BR);
1741 assert (S);
1742 FullSourceLoc L(S->getLocStart(), BR.getContext().getSourceManager());
1743 PathDiagnosticPiece* P = new PathDiagnosticPiece(L, os.str());
1744
1745 return P;
1746}
1747
Ted Kremenek05cbe1a2008-04-09 23:49:11 +00001748void UseAfterRelease::EmitWarnings(BugReporter& BR) {
Ted Kremenekfa34b332008-04-09 01:10:13 +00001749
Ted Kremenek05cbe1a2008-04-09 23:49:11 +00001750 for (CFRefCount::use_after_iterator I = TF.use_after_begin(),
1751 E = TF.use_after_end(); I != E; ++I) {
1752
Ted Kremenek8dd56462008-04-18 03:39:05 +00001753 CFRefReport report(*this, I->first, I->second.second);
1754 report.addRange(I->second.first->getSourceRange());
Ted Kremenek75840e12008-04-18 01:56:37 +00001755 BR.EmitWarning(report);
Ted Kremenekfa34b332008-04-09 01:10:13 +00001756 }
Ted Kremenek05cbe1a2008-04-09 23:49:11 +00001757}
1758
1759void BadRelease::EmitWarnings(BugReporter& BR) {
Ted Kremenekfa34b332008-04-09 01:10:13 +00001760
Ted Kremenek05cbe1a2008-04-09 23:49:11 +00001761 for (CFRefCount::bad_release_iterator I = TF.bad_release_begin(),
1762 E = TF.bad_release_end(); I != E; ++I) {
1763
Ted Kremenek8dd56462008-04-18 03:39:05 +00001764 CFRefReport report(*this, I->first, I->second.second);
1765 report.addRange(I->second.first->getSourceRange());
1766 BR.EmitWarning(report);
Ted Kremenek05cbe1a2008-04-09 23:49:11 +00001767 }
1768}
Ted Kremenekfa34b332008-04-09 01:10:13 +00001769
Ted Kremenek989d5192008-04-17 23:43:50 +00001770void Leak::EmitWarnings(BugReporter& BR) {
1771
1772 for (CFRefCount::leaks_iterator I = TF.leaks_begin(),
1773 E = TF.leaks_end(); I != E; ++I) {
1774
Ted Kremenek8dd56462008-04-18 03:39:05 +00001775 std::vector<SymbolID>& SymV = *(I->second);
1776 unsigned n = SymV.size();
1777
1778 for (unsigned i = 0; i < n; ++i) {
1779 CFRefReport report(*this, I->first, SymV[i]);
1780 BR.EmitWarning(report);
1781 }
Ted Kremenek989d5192008-04-17 23:43:50 +00001782 }
1783}
1784
Ted Kremenekcb612922008-04-18 19:23:43 +00001785void Leak::GetErrorNodes(std::vector<ExplodedNode<ValueState>*>& Nodes) {
1786 for (CFRefCount::leaks_iterator I=TF.leaks_begin(), E=TF.leaks_end();
1787 I!=E; ++I)
1788 Nodes.push_back(I->first);
1789}
1790
Ted Kremenek6b3a0f72008-03-11 06:39:11 +00001791//===----------------------------------------------------------------------===//
Ted Kremenekd71ed262008-04-10 22:16:52 +00001792// Transfer function creation for external clients.
Ted Kremenek6b3a0f72008-03-11 06:39:11 +00001793//===----------------------------------------------------------------------===//
1794
Ted Kremenek072192b2008-04-30 23:47:44 +00001795GRTransferFuncs* clang::MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled,
1796 const LangOptions& lopts) {
1797 return new CFRefCount(Ctx, GCEnabled, lopts);
Ted Kremenek3ea0b6a2008-04-10 22:58:08 +00001798}