blob: c3da51bd125071efec54af84f9703ec03b58662e [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 Kremenek9f741612008-05-02 18:01:49 +0000629 const bool GCEnabled;
630 const bool EmitStandardWarnings;
Ted Kremenek072192b2008-04-30 23:47:44 +0000631 const LangOptions& LOpts;
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000632 RefBFactoryTy RefBFactory;
633
Ted Kremenek73c750b2008-03-11 18:14:09 +0000634 UseAfterReleasesTy UseAfterReleases;
635 ReleasesNotOwnedTy ReleasesNotOwned;
Ted Kremenekdb863712008-04-16 22:32:20 +0000636 LeaksTy Leaks;
Ted Kremenek73c750b2008-03-11 18:14:09 +0000637
Ted Kremenekf3948042008-03-11 19:44:10 +0000638 BindingsPrinter Printer;
639
Ted Kremenek9ed18e62008-04-16 04:28:53 +0000640 Selector RetainSelector;
641 Selector ReleaseSelector;
Ted Kremenek5934cee2008-05-01 02:18:37 +0000642 Selector AutoreleaseSelector;
Ted Kremenek9ed18e62008-04-16 04:28:53 +0000643
Ted Kremenek8dd56462008-04-18 03:39:05 +0000644public:
645
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000646 static RefBindings GetRefBindings(ValueState& StImpl) {
647 return RefBindings((RefBindings::TreeTy*) StImpl.CheckerState);
648 }
Ted Kremenek9ed18e62008-04-16 04:28:53 +0000649
Ted Kremenek8dd56462008-04-18 03:39:05 +0000650private:
651
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000652 static void SetRefBindings(ValueState& StImpl, RefBindings B) {
653 StImpl.CheckerState = B.getRoot();
654 }
Ted Kremenek9ed18e62008-04-16 04:28:53 +0000655
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000656 RefBindings Remove(RefBindings B, SymbolID sym) {
657 return RefBFactory.Remove(B, sym);
658 }
659
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000660 RefBindings Update(RefBindings B, SymbolID sym, RefVal V, ArgEffect E,
Ted Kremenek9ed18e62008-04-16 04:28:53 +0000661 RefVal::Kind& hasErr);
662
Ted Kremenekdb863712008-04-16 22:32:20 +0000663 void ProcessNonLeakError(ExplodedNodeSet<ValueState>& Dst,
664 GRStmtNodeBuilder<ValueState>& Builder,
665 Expr* NodeExpr, Expr* ErrorExpr,
666 ExplodedNode<ValueState>* Pred,
667 ValueState* St,
Ted Kremenek8dd56462008-04-18 03:39:05 +0000668 RefVal::Kind hasErr, SymbolID Sym);
Ted Kremenekdb863712008-04-16 22:32:20 +0000669
670 ValueState* HandleSymbolDeath(ValueStateManager& VMgr, ValueState* St,
671 SymbolID sid, RefVal V, bool& hasLeak);
672
673 ValueState* NukeBinding(ValueStateManager& VMgr, ValueState* St,
674 SymbolID sid);
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000675
676public:
Ted Kremenek13922612008-04-16 20:40:59 +0000677
Ted Kremenek9f741612008-05-02 18:01:49 +0000678 CFRefCount(ASTContext& Ctx, bool gcenabled, bool StandardWarnings,
679 const LangOptions& lopts)
Ted Kremenek377e2302008-04-29 05:33:51 +0000680 : Summaries(Ctx, gcenabled),
Ted Kremeneke5c30122008-04-29 05:13:59 +0000681 GCEnabled(gcenabled),
Ted Kremenek9f741612008-05-02 18:01:49 +0000682 EmitStandardWarnings(StandardWarnings),
Ted Kremenek072192b2008-04-30 23:47:44 +0000683 LOpts(lopts),
Ted Kremenekb83e02e2008-05-01 18:31:44 +0000684 RetainSelector(GetNullarySelector("retain", Ctx)),
685 ReleaseSelector(GetNullarySelector("release", Ctx)),
686 AutoreleaseSelector(GetNullarySelector("autorelease", Ctx)) {}
Ted Kremenek9ed18e62008-04-16 04:28:53 +0000687
Ted Kremenek8dd56462008-04-18 03:39:05 +0000688 virtual ~CFRefCount() {
689 for (LeaksTy::iterator I = Leaks.begin(), E = Leaks.end(); I!=E; ++I)
690 delete I->second;
691 }
Ted Kremenek05cbe1a2008-04-09 23:49:11 +0000692
693 virtual void RegisterChecks(GRExprEngine& Eng);
Ted Kremenekf3948042008-03-11 19:44:10 +0000694
695 virtual ValueState::CheckerStatePrinter* getCheckerStatePrinter() {
696 return &Printer;
697 }
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000698
Ted Kremenek072192b2008-04-30 23:47:44 +0000699 bool isGCEnabled() const { return GCEnabled; }
700 const LangOptions& getLangOptions() const { return LOpts; }
701
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000702 // Calls.
703
704 virtual void EvalCall(ExplodedNodeSet<ValueState>& Dst,
Ted Kremenek199e1a02008-03-12 21:06:49 +0000705 GRExprEngine& Eng,
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000706 GRStmtNodeBuilder<ValueState>& Builder,
Ted Kremenek186350f2008-04-23 20:12:28 +0000707 CallExpr* CE, RVal L,
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000708 ExplodedNode<ValueState>* Pred);
Ted Kremenekfa34b332008-04-09 01:10:13 +0000709
Ted Kremenek85348202008-04-15 23:44:31 +0000710 virtual void EvalObjCMessageExpr(ExplodedNodeSet<ValueState>& Dst,
711 GRExprEngine& Engine,
712 GRStmtNodeBuilder<ValueState>& Builder,
713 ObjCMessageExpr* ME,
714 ExplodedNode<ValueState>* Pred);
715
716 bool EvalObjCMessageExprAux(ExplodedNodeSet<ValueState>& Dst,
717 GRExprEngine& Engine,
718 GRStmtNodeBuilder<ValueState>& Builder,
719 ObjCMessageExpr* ME,
720 ExplodedNode<ValueState>* Pred);
721
Ted Kremenek13922612008-04-16 20:40:59 +0000722 // Stores.
723
724 virtual void EvalStore(ExplodedNodeSet<ValueState>& Dst,
725 GRExprEngine& Engine,
726 GRStmtNodeBuilder<ValueState>& Builder,
727 Expr* E, ExplodedNode<ValueState>* Pred,
728 ValueState* St, RVal TargetLV, RVal Val);
Ted Kremeneke7bd9c22008-04-11 22:25:11 +0000729 // End-of-path.
730
731 virtual void EvalEndPath(GRExprEngine& Engine,
732 GREndPathNodeBuilder<ValueState>& Builder);
733
Ted Kremenek652adc62008-04-24 23:57:27 +0000734 virtual void EvalDeadSymbols(ExplodedNodeSet<ValueState>& Dst,
735 GRExprEngine& Engine,
736 GRStmtNodeBuilder<ValueState>& Builder,
Ted Kremenek910e9992008-04-25 01:25:15 +0000737 ExplodedNode<ValueState>* Pred,
738 Stmt* S,
Ted Kremenek652adc62008-04-24 23:57:27 +0000739 ValueState* St,
740 const ValueStateManager::DeadSymbolsTy& Dead);
Ted Kremenek4fd88972008-04-17 18:12:53 +0000741 // Return statements.
742
743 virtual void EvalReturn(ExplodedNodeSet<ValueState>& Dst,
744 GRExprEngine& Engine,
745 GRStmtNodeBuilder<ValueState>& Builder,
746 ReturnStmt* S,
747 ExplodedNode<ValueState>* Pred);
Ted Kremenekcb612922008-04-18 19:23:43 +0000748
749 // Assumptions.
750
751 virtual ValueState* EvalAssume(GRExprEngine& Engine, ValueState* St,
752 RVal Cond, bool Assumption, bool& isFeasible);
753
Ted Kremenekfa34b332008-04-09 01:10:13 +0000754 // Error iterators.
755
756 typedef UseAfterReleasesTy::iterator use_after_iterator;
757 typedef ReleasesNotOwnedTy::iterator bad_release_iterator;
Ted Kremenek989d5192008-04-17 23:43:50 +0000758 typedef LeaksTy::iterator leaks_iterator;
Ted Kremenekfa34b332008-04-09 01:10:13 +0000759
Ted Kremenek05cbe1a2008-04-09 23:49:11 +0000760 use_after_iterator use_after_begin() { return UseAfterReleases.begin(); }
761 use_after_iterator use_after_end() { return UseAfterReleases.end(); }
Ted Kremenekfa34b332008-04-09 01:10:13 +0000762
Ted Kremenek05cbe1a2008-04-09 23:49:11 +0000763 bad_release_iterator bad_release_begin() { return ReleasesNotOwned.begin(); }
764 bad_release_iterator bad_release_end() { return ReleasesNotOwned.end(); }
Ted Kremenek989d5192008-04-17 23:43:50 +0000765
766 leaks_iterator leaks_begin() { return Leaks.begin(); }
767 leaks_iterator leaks_end() { return Leaks.end(); }
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000768};
769
770} // end anonymous namespace
771
Ted Kremenek8dd56462008-04-18 03:39:05 +0000772
Ted Kremenek05cbe1a2008-04-09 23:49:11 +0000773
774
Ted Kremenekf3948042008-03-11 19:44:10 +0000775void CFRefCount::BindingsPrinter::PrintCheckerState(std::ostream& Out,
776 void* State, const char* nl,
777 const char* sep) {
778 RefBindings B((RefBindings::TreeTy*) State);
779
780 if (State)
781 Out << sep << nl;
782
783 for (RefBindings::iterator I=B.begin(), E=B.end(); I!=E; ++I) {
784 Out << (*I).first << " : ";
785 (*I).second.print(Out);
786 Out << nl;
787 }
788}
789
Ted Kremenekf9561e52008-04-11 20:23:24 +0000790static inline ArgEffect GetArgE(CFRefSummary* Summ, unsigned idx) {
791 return Summ ? Summ->getArg(idx) : DoNothing;
792}
793
794static inline RetEffect GetRetE(CFRefSummary* Summ) {
795 return Summ ? Summ->getRet() : RetEffect::MakeNoRet();
796}
797
Ted Kremenekdb863712008-04-16 22:32:20 +0000798void CFRefCount::ProcessNonLeakError(ExplodedNodeSet<ValueState>& Dst,
799 GRStmtNodeBuilder<ValueState>& Builder,
800 Expr* NodeExpr, Expr* ErrorExpr,
801 ExplodedNode<ValueState>* Pred,
802 ValueState* St,
Ted Kremenek8dd56462008-04-18 03:39:05 +0000803 RefVal::Kind hasErr, SymbolID Sym) {
Ted Kremenek9ed18e62008-04-16 04:28:53 +0000804 Builder.BuildSinks = true;
805 GRExprEngine::NodeTy* N = Builder.MakeNode(Dst, NodeExpr, Pred, St);
806
807 if (!N) return;
808
809 switch (hasErr) {
810 default: assert(false);
811 case RefVal::ErrorUseAfterRelease:
Ted Kremenek8dd56462008-04-18 03:39:05 +0000812 UseAfterReleases[N] = std::make_pair(ErrorExpr, Sym);
Ted Kremenek9ed18e62008-04-16 04:28:53 +0000813 break;
814
815 case RefVal::ErrorReleaseNotOwned:
Ted Kremenek8dd56462008-04-18 03:39:05 +0000816 ReleasesNotOwned[N] = std::make_pair(ErrorExpr, Sym);
Ted Kremenek9ed18e62008-04-16 04:28:53 +0000817 break;
818 }
819}
820
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000821void CFRefCount::EvalCall(ExplodedNodeSet<ValueState>& Dst,
Ted Kremenek199e1a02008-03-12 21:06:49 +0000822 GRExprEngine& Eng,
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000823 GRStmtNodeBuilder<ValueState>& Builder,
Ted Kremenek186350f2008-04-23 20:12:28 +0000824 CallExpr* CE, RVal L,
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000825 ExplodedNode<ValueState>* Pred) {
826
Ted Kremenek199e1a02008-03-12 21:06:49 +0000827 ValueStateManager& StateMgr = Eng.getStateManager();
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000828
Ted Kremenek7ded73c2008-04-14 17:45:13 +0000829 CFRefSummary* Summ = NULL;
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000830
831 // Get the summary.
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000832
Ted Kremenek7ded73c2008-04-14 17:45:13 +0000833 if (isa<lval::FuncVal>(L)) {
834 lval::FuncVal FV = cast<lval::FuncVal>(L);
835 FunctionDecl* FD = FV.getDecl();
836 Summ = Summaries.getSummary(FD, Eng.getContext());
837 }
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000838
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000839 // Get the state.
840
841 ValueState* St = Builder.GetState(Pred);
842
843 // Evaluate the effects of the call.
844
845 ValueState StVals = *St;
Ted Kremenek9ed18e62008-04-16 04:28:53 +0000846 RefVal::Kind hasErr = (RefVal::Kind) 0;
Ted Kremenekf9561e52008-04-11 20:23:24 +0000847
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000848 // This function has a summary. Evaluate the effect of the arguments.
849
850 unsigned idx = 0;
851
Ted Kremenekbcf50ad2008-04-11 18:40:51 +0000852 Expr* ErrorExpr = NULL;
Ted Kremenek8dd56462008-04-18 03:39:05 +0000853 SymbolID ErrorSym = 0;
Ted Kremenekbcf50ad2008-04-11 18:40:51 +0000854
855 for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end();
856 I != E; ++I, ++idx) {
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000857
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000858 RVal V = StateMgr.GetRVal(St, *I);
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000859
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000860 if (isa<lval::SymbolVal>(V)) {
861 SymbolID Sym = cast<lval::SymbolVal>(V).getSymbol();
Ted Kremenekf9561e52008-04-11 20:23:24 +0000862 RefBindings B = GetRefBindings(StVals);
863
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000864 if (RefBindings::TreeTy* T = B.SlimFind(Sym)) {
Ted Kremenek9ed18e62008-04-16 04:28:53 +0000865 B = Update(B, Sym, T->getValue().second, GetArgE(Summ, idx), hasErr);
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000866 SetRefBindings(StVals, B);
Ted Kremenekbcf50ad2008-04-11 18:40:51 +0000867
Ted Kremenek9ed18e62008-04-16 04:28:53 +0000868 if (hasErr) {
Ted Kremenekbcf50ad2008-04-11 18:40:51 +0000869 ErrorExpr = *I;
Ted Kremenek8dd56462008-04-18 03:39:05 +0000870 ErrorSym = T->getValue().first;
Ted Kremenekbcf50ad2008-04-11 18:40:51 +0000871 break;
872 }
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000873 }
Ted Kremenekb8873552008-04-11 20:51:02 +0000874 }
875 else if (isa<LVal>(V)) { // Nuke all arguments passed by reference.
876
877 // FIXME: This is basically copy-and-paste from GRSimpleVals. We
878 // should compose behavior, not copy it.
Ted Kremenekf9561e52008-04-11 20:23:24 +0000879 StateMgr.Unbind(StVals, cast<LVal>(V));
Ted Kremenekb8873552008-04-11 20:51:02 +0000880 }
Ted Kremeneka5488462008-04-22 21:39:21 +0000881 else if (isa<nonlval::LValAsInteger>(V))
882 StateMgr.Unbind(StVals, cast<nonlval::LValAsInteger>(V).getLVal());
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000883 }
Ted Kremenek9ed18e62008-04-16 04:28:53 +0000884
885 St = StateMgr.getPersistentState(StVals);
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000886
Ted Kremenek9ed18e62008-04-16 04:28:53 +0000887 if (hasErr) {
Ted Kremenek8dd56462008-04-18 03:39:05 +0000888 ProcessNonLeakError(Dst, Builder, CE, ErrorExpr, Pred, St,
889 hasErr, ErrorSym);
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000890 return;
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000891 }
Ted Kremenek9ed18e62008-04-16 04:28:53 +0000892
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000893 // Finally, consult the summary for the return value.
894
Ted Kremenekf9561e52008-04-11 20:23:24 +0000895 RetEffect RE = GetRetE(Summ);
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000896
897 switch (RE.getKind()) {
898 default:
899 assert (false && "Unhandled RetEffect."); break;
900
Ted Kremenek940b1d82008-04-10 23:44:06 +0000901 case RetEffect::NoRet:
Ted Kremenekf9561e52008-04-11 20:23:24 +0000902
903 // Make up a symbol for the return value (not reference counted).
Ted Kremenekb8873552008-04-11 20:51:02 +0000904 // FIXME: This is basically copy-and-paste from GRSimpleVals. We
905 // should compose behavior, not copy it.
Ted Kremenekf9561e52008-04-11 20:23:24 +0000906
907 if (CE->getType() != Eng.getContext().VoidTy) {
908 unsigned Count = Builder.getCurrentBlockCount();
909 SymbolID Sym = Eng.getSymbolManager().getConjuredSymbol(CE, Count);
910
911 RVal X = CE->getType()->isPointerType()
912 ? cast<RVal>(lval::SymbolVal(Sym))
913 : cast<RVal>(nonlval::SymbolVal(Sym));
914
915 St = StateMgr.SetRVal(St, CE, X, Eng.getCFG().isBlkExpr(CE), false);
916 }
917
Ted Kremenek940b1d82008-04-10 23:44:06 +0000918 break;
919
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000920 case RetEffect::Alias: {
921 unsigned idx = RE.getValue();
922 assert (idx < CE->getNumArgs());
923 RVal V = StateMgr.GetRVal(St, CE->getArg(idx));
Ted Kremenek199e1a02008-03-12 21:06:49 +0000924 St = StateMgr.SetRVal(St, CE, V, Eng.getCFG().isBlkExpr(CE), false);
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000925 break;
926 }
927
928 case RetEffect::OwnedSymbol: {
929 unsigned Count = Builder.getCurrentBlockCount();
Ted Kremenek361fa8e2008-03-12 21:45:47 +0000930 SymbolID Sym = Eng.getSymbolManager().getConjuredSymbol(CE, Count);
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000931
932 ValueState StImpl = *St;
933 RefBindings B = GetRefBindings(StImpl);
Ted Kremenek61b9f872008-04-10 23:09:18 +0000934 SetRefBindings(StImpl, RefBFactory.Add(B, Sym, RefVal::makeOwned()));
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000935
936 St = StateMgr.SetRVal(StateMgr.getPersistentState(StImpl),
937 CE, lval::SymbolVal(Sym),
Ted Kremenek199e1a02008-03-12 21:06:49 +0000938 Eng.getCFG().isBlkExpr(CE), false);
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000939
940 break;
941 }
942
943 case RetEffect::NotOwnedSymbol: {
944 unsigned Count = Builder.getCurrentBlockCount();
Ted Kremenek361fa8e2008-03-12 21:45:47 +0000945 SymbolID Sym = Eng.getSymbolManager().getConjuredSymbol(CE, Count);
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000946
947 ValueState StImpl = *St;
948 RefBindings B = GetRefBindings(StImpl);
949 SetRefBindings(StImpl, RefBFactory.Add(B, Sym, RefVal::makeNotOwned()));
950
951 St = StateMgr.SetRVal(StateMgr.getPersistentState(StImpl),
952 CE, lval::SymbolVal(Sym),
Ted Kremenek199e1a02008-03-12 21:06:49 +0000953 Eng.getCFG().isBlkExpr(CE), false);
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000954
955 break;
956 }
957 }
958
Ted Kremenek0e561a32008-03-21 21:30:14 +0000959 Builder.MakeNode(Dst, CE, Pred, St);
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000960}
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000961
Ted Kremenek85348202008-04-15 23:44:31 +0000962
963void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet<ValueState>& Dst,
964 GRExprEngine& Eng,
965 GRStmtNodeBuilder<ValueState>& Builder,
966 ObjCMessageExpr* ME,
967 ExplodedNode<ValueState>* Pred) {
968
Ted Kremenek9040c652008-05-01 21:31:50 +0000969 if (!EvalObjCMessageExprAux(Dst, Eng, Builder, ME, Pred))
970 return;
971
972 // The basic transfer function logic for message expressions does nothing.
973 // We just invalidate all arguments passed in by references.
974
975 ValueStateManager& StateMgr = Eng.getStateManager();
976 ValueState* St = Builder.GetState(Pred);
977 RefBindings B = GetRefBindings(*St);
978
979 for (ObjCMessageExpr::arg_iterator I = ME->arg_begin(), E = ME->arg_end();
980 I != E; ++I) {
981
982 RVal V = StateMgr.GetRVal(St, *I);
983
984 if (isa<LVal>(V)) {
985
986 LVal lv = cast<LVal>(V);
987
988 // Did the lval bind to a symbol?
989 RVal X = StateMgr.GetRVal(St, lv);
990
991 if (isa<lval::SymbolVal>(X)) {
Ted Kremenek529a9bd2008-05-01 23:38:35 +0000992 SymbolID Sym = cast<lval::SymbolVal>(X).getSymbol();
Ted Kremenek9040c652008-05-01 21:31:50 +0000993 B = Remove(B, Sym);
994
995 // Create a new state with the updated bindings.
996 ValueState StVals = *St;
997 SetRefBindings(StVals, B);
998 St = StateMgr.getPersistentState(StVals);
999 }
1000
1001 St = StateMgr.SetRVal(St, cast<LVal>(V), UnknownVal());
1002 }
1003 }
1004
1005 Builder.MakeNode(Dst, ME, Pred, St);
Ted Kremenek85348202008-04-15 23:44:31 +00001006}
1007
1008bool CFRefCount::EvalObjCMessageExprAux(ExplodedNodeSet<ValueState>& Dst,
1009 GRExprEngine& Eng,
1010 GRStmtNodeBuilder<ValueState>& Builder,
1011 ObjCMessageExpr* ME,
1012 ExplodedNode<ValueState>* Pred) {
Ted Kremenek377e2302008-04-29 05:33:51 +00001013
1014 if (GCEnabled)
1015 return true;
1016
Ted Kremenek9ed18e62008-04-16 04:28:53 +00001017 // Handle "toll-free bridging" of calls to "Release" and "Retain".
1018
1019 // FIXME: track the underlying object type associated so that we can
1020 // flag illegal uses of toll-free bridging (or at least handle it
1021 // at casts).
Ted Kremenek85348202008-04-15 23:44:31 +00001022
1023 Selector S = ME->getSelector();
1024
1025 if (!S.isUnarySelector())
1026 return true;
1027
Ted Kremenek9ed18e62008-04-16 04:28:53 +00001028 Expr* Receiver = ME->getReceiver();
1029
1030 if (!Receiver)
1031 return true;
1032
Ted Kremenek5934cee2008-05-01 02:18:37 +00001033 // Check if we are calling "autorelease".
1034
1035 enum { IsRelease, IsRetain, IsAutorelease, IsNone } mode = IsNone;
Ted Kremenek9ed18e62008-04-16 04:28:53 +00001036
Ted Kremenek5934cee2008-05-01 02:18:37 +00001037 if (S == AutoreleaseSelector)
1038 mode = IsAutorelease;
1039 else if (S == RetainSelector)
1040 mode = IsRetain;
1041 else if (S == ReleaseSelector)
1042 mode = IsRelease;
Ted Kremenek9ed18e62008-04-16 04:28:53 +00001043
Ted Kremenek5934cee2008-05-01 02:18:37 +00001044 if (mode == IsNone)
Ted Kremenek9ed18e62008-04-16 04:28:53 +00001045 return true;
1046
Ted Kremenek5934cee2008-05-01 02:18:37 +00001047 // We have "retain", "release", or "autorelease".
Ted Kremenek9ed18e62008-04-16 04:28:53 +00001048 ValueStateManager& StateMgr = Eng.getStateManager();
1049 ValueState* St = Builder.GetState(Pred);
1050 RVal V = StateMgr.GetRVal(St, Receiver);
1051
Ted Kremenek5934cee2008-05-01 02:18:37 +00001052 // Was the argument something we are not tracking?
Ted Kremenek9ed18e62008-04-16 04:28:53 +00001053 if (!isa<lval::SymbolVal>(V))
1054 return true;
1055
Ted Kremenek5934cee2008-05-01 02:18:37 +00001056 // Get the bindings.
Ted Kremenek9ed18e62008-04-16 04:28:53 +00001057 SymbolID Sym = cast<lval::SymbolVal>(V).getSymbol();
1058 RefBindings B = GetRefBindings(*St);
1059
Ted Kremenek5934cee2008-05-01 02:18:37 +00001060 // Find the tracked value.
Ted Kremenek9ed18e62008-04-16 04:28:53 +00001061 RefBindings::TreeTy* T = B.SlimFind(Sym);
Ted Kremenek5934cee2008-05-01 02:18:37 +00001062
Ted Kremenek9ed18e62008-04-16 04:28:53 +00001063 if (!T)
1064 return true;
Ted Kremenek9ed18e62008-04-16 04:28:53 +00001065
Ted Kremenek5934cee2008-05-01 02:18:37 +00001066 RefVal::Kind hasErr = (RefVal::Kind) 0;
Ted Kremenek9ed18e62008-04-16 04:28:53 +00001067
Ted Kremenek5934cee2008-05-01 02:18:37 +00001068 // Update the bindings.
1069 switch (mode) {
1070 case IsNone:
1071 assert(false);
1072
1073 case IsRelease:
1074 B = Update(B, Sym, T->getValue().second, DecRef, hasErr);
1075 break;
1076
1077 case IsRetain:
1078 B = Update(B, Sym, T->getValue().second, IncRef, hasErr);
1079 break;
1080
1081 case IsAutorelease:
1082 // For now we just stop tracking a value if we see
1083 // it sent "autorelease." In the future we can potentially
1084 // track the associated pool.
1085 B = Remove(B, Sym);
1086 break;
1087 }
1088
1089 // Create a new state with the updated bindings.
Ted Kremenek9ed18e62008-04-16 04:28:53 +00001090 ValueState StVals = *St;
1091 SetRefBindings(StVals, B);
Ted Kremenek31593ac2008-05-01 04:02:04 +00001092 St = Eng.SetRVal(StateMgr.getPersistentState(StVals), ME, V);
Ted Kremenek9ed18e62008-04-16 04:28:53 +00001093
Ted Kremenek5934cee2008-05-01 02:18:37 +00001094 // Create an error node if it exists.
Ted Kremenek9ed18e62008-04-16 04:28:53 +00001095 if (hasErr)
Ted Kremenek8dd56462008-04-18 03:39:05 +00001096 ProcessNonLeakError(Dst, Builder, ME, Receiver, Pred, St, hasErr, Sym);
Ted Kremenek9ed18e62008-04-16 04:28:53 +00001097 else
1098 Builder.MakeNode(Dst, ME, Pred, St);
1099
1100 return false;
Ted Kremenek85348202008-04-15 23:44:31 +00001101}
1102
Ted Kremenek13922612008-04-16 20:40:59 +00001103// Stores.
1104
1105void CFRefCount::EvalStore(ExplodedNodeSet<ValueState>& Dst,
1106 GRExprEngine& Eng,
1107 GRStmtNodeBuilder<ValueState>& Builder,
1108 Expr* E, ExplodedNode<ValueState>* Pred,
1109 ValueState* St, RVal TargetLV, RVal Val) {
1110
1111 // Check if we have a binding for "Val" and if we are storing it to something
1112 // we don't understand or otherwise the value "escapes" the function.
1113
1114 if (!isa<lval::SymbolVal>(Val))
1115 return;
1116
1117 // Are we storing to something that causes the value to "escape"?
1118
1119 bool escapes = false;
1120
1121 if (!isa<lval::DeclVal>(TargetLV))
1122 escapes = true;
1123 else
1124 escapes = cast<lval::DeclVal>(TargetLV).getDecl()->hasGlobalStorage();
1125
1126 if (!escapes)
1127 return;
1128
1129 SymbolID Sym = cast<lval::SymbolVal>(Val).getSymbol();
1130 RefBindings B = GetRefBindings(*St);
1131 RefBindings::TreeTy* T = B.SlimFind(Sym);
1132
1133 if (!T)
1134 return;
1135
Ted Kremenekdb863712008-04-16 22:32:20 +00001136 // Nuke the binding.
1137 St = NukeBinding(Eng.getStateManager(), St, Sym);
Ted Kremenek13922612008-04-16 20:40:59 +00001138
1139 // Hand of the remaining logic to the parent implementation.
1140 GRSimpleVals::EvalStore(Dst, Eng, Builder, E, Pred, St, TargetLV, Val);
1141}
1142
Ted Kremenekdb863712008-04-16 22:32:20 +00001143
1144ValueState* CFRefCount::NukeBinding(ValueStateManager& VMgr, ValueState* St,
1145 SymbolID sid) {
1146 ValueState StImpl = *St;
1147 RefBindings B = GetRefBindings(StImpl);
1148 StImpl.CheckerState = RefBFactory.Remove(B, sid).getRoot();
1149 return VMgr.getPersistentState(StImpl);
1150}
1151
Ted Kremeneke7bd9c22008-04-11 22:25:11 +00001152// End-of-path.
1153
Ted Kremenekdb863712008-04-16 22:32:20 +00001154ValueState* CFRefCount::HandleSymbolDeath(ValueStateManager& VMgr,
1155 ValueState* St, SymbolID sid,
1156 RefVal V, bool& hasLeak) {
1157
Ted Kremenek4fd88972008-04-17 18:12:53 +00001158 hasLeak = V.isOwned() ||
1159 ((V.isNotOwned() || V.isReturnedOwned()) && V.getCount() > 0);
Ted Kremenekdb863712008-04-16 22:32:20 +00001160
1161 if (!hasLeak)
1162 return NukeBinding(VMgr, St, sid);
1163
1164 RefBindings B = GetRefBindings(*St);
1165 ValueState StImpl = *St;
1166 StImpl.CheckerState = RefBFactory.Add(B, sid, RefVal::makeLeak()).getRoot();
1167 return VMgr.getPersistentState(StImpl);
1168}
1169
1170void CFRefCount::EvalEndPath(GRExprEngine& Eng,
Ted Kremeneke7bd9c22008-04-11 22:25:11 +00001171 GREndPathNodeBuilder<ValueState>& Builder) {
1172
Ted Kremenekdb863712008-04-16 22:32:20 +00001173 ValueState* St = Builder.getState();
1174 RefBindings B = GetRefBindings(*St);
Ted Kremeneke7bd9c22008-04-11 22:25:11 +00001175
Ted Kremenekdb863712008-04-16 22:32:20 +00001176 llvm::SmallVector<SymbolID, 10> Leaked;
Ted Kremeneke7bd9c22008-04-11 22:25:11 +00001177
Ted Kremenekdb863712008-04-16 22:32:20 +00001178 for (RefBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) {
1179 bool hasLeak = false;
Ted Kremeneke7bd9c22008-04-11 22:25:11 +00001180
Ted Kremenekdb863712008-04-16 22:32:20 +00001181 St = HandleSymbolDeath(Eng.getStateManager(), St,
1182 (*I).first, (*I).second, hasLeak);
1183
1184 if (hasLeak) Leaked.push_back((*I).first);
1185 }
Ted Kremenek652adc62008-04-24 23:57:27 +00001186
1187 if (Leaked.empty())
1188 return;
1189
Ted Kremenek8dd56462008-04-18 03:39:05 +00001190 ExplodedNode<ValueState>* N = Builder.MakeNode(St);
Ted Kremenek4f285152008-04-18 16:30:14 +00001191
Ted Kremenek652adc62008-04-24 23:57:27 +00001192 if (!N)
Ted Kremenek4f285152008-04-18 16:30:14 +00001193 return;
Ted Kremenekcb612922008-04-18 19:23:43 +00001194
Ted Kremenek8dd56462008-04-18 03:39:05 +00001195 std::vector<SymbolID>*& LeaksAtNode = Leaks[N];
1196 assert (!LeaksAtNode);
1197 LeaksAtNode = new std::vector<SymbolID>();
Ted Kremenekdb863712008-04-16 22:32:20 +00001198
1199 for (llvm::SmallVector<SymbolID, 10>::iterator I=Leaked.begin(),
1200 E = Leaked.end(); I != E; ++I)
Ted Kremenek8dd56462008-04-18 03:39:05 +00001201 (*LeaksAtNode).push_back(*I);
Ted Kremeneke7bd9c22008-04-11 22:25:11 +00001202}
1203
Ted Kremenek652adc62008-04-24 23:57:27 +00001204// Dead symbols.
1205
1206void CFRefCount::EvalDeadSymbols(ExplodedNodeSet<ValueState>& Dst,
1207 GRExprEngine& Eng,
1208 GRStmtNodeBuilder<ValueState>& Builder,
Ted Kremenek910e9992008-04-25 01:25:15 +00001209 ExplodedNode<ValueState>* Pred,
1210 Stmt* S,
Ted Kremenek652adc62008-04-24 23:57:27 +00001211 ValueState* St,
1212 const ValueStateManager::DeadSymbolsTy& Dead) {
Ted Kremenek910e9992008-04-25 01:25:15 +00001213
Ted Kremenek652adc62008-04-24 23:57:27 +00001214 // FIXME: a lot of copy-and-paste from EvalEndPath. Refactor.
1215
1216 RefBindings B = GetRefBindings(*St);
1217 llvm::SmallVector<SymbolID, 10> Leaked;
1218
1219 for (ValueStateManager::DeadSymbolsTy::const_iterator
1220 I=Dead.begin(), E=Dead.end(); I!=E; ++I) {
1221
1222 RefBindings::TreeTy* T = B.SlimFind(*I);
1223
1224 if (!T)
1225 continue;
1226
1227 bool hasLeak = false;
1228
1229 St = HandleSymbolDeath(Eng.getStateManager(), St,
1230 *I, T->getValue().second, hasLeak);
1231
1232 if (hasLeak) Leaked.push_back(*I);
1233 }
1234
1235 if (Leaked.empty())
1236 return;
1237
1238 ExplodedNode<ValueState>* N = Builder.MakeNode(Dst, S, Pred, St);
1239
1240 if (!N)
1241 return;
1242
1243 std::vector<SymbolID>*& LeaksAtNode = Leaks[N];
1244 assert (!LeaksAtNode);
1245 LeaksAtNode = new std::vector<SymbolID>();
1246
1247 for (llvm::SmallVector<SymbolID, 10>::iterator I=Leaked.begin(),
1248 E = Leaked.end(); I != E; ++I)
1249 (*LeaksAtNode).push_back(*I);
1250}
1251
Ted Kremenek4fd88972008-04-17 18:12:53 +00001252 // Return statements.
1253
1254void CFRefCount::EvalReturn(ExplodedNodeSet<ValueState>& Dst,
1255 GRExprEngine& Eng,
1256 GRStmtNodeBuilder<ValueState>& Builder,
1257 ReturnStmt* S,
1258 ExplodedNode<ValueState>* Pred) {
1259
1260 Expr* RetE = S->getRetValue();
1261 if (!RetE) return;
1262
1263 ValueStateManager& StateMgr = Eng.getStateManager();
1264 ValueState* St = Builder.GetState(Pred);
1265 RVal V = StateMgr.GetRVal(St, RetE);
1266
1267 if (!isa<lval::SymbolVal>(V))
1268 return;
1269
1270 // Get the reference count binding (if any).
1271 SymbolID Sym = cast<lval::SymbolVal>(V).getSymbol();
1272 RefBindings B = GetRefBindings(*St);
1273 RefBindings::TreeTy* T = B.SlimFind(Sym);
1274
1275 if (!T)
1276 return;
1277
1278 // Change the reference count.
1279
1280 RefVal X = T->getValue().second;
1281
1282 switch (X.getKind()) {
1283
1284 case RefVal::Owned: {
1285 unsigned cnt = X.getCount();
1286 X = RefVal::makeReturnedOwned(cnt);
1287 break;
1288 }
1289
1290 case RefVal::NotOwned: {
1291 unsigned cnt = X.getCount();
1292 X = cnt ? RefVal::makeReturnedOwned(cnt - 1)
1293 : RefVal::makeReturnedNotOwned();
1294 break;
1295 }
1296
1297 default:
Ted Kremenek4fd88972008-04-17 18:12:53 +00001298 return;
1299 }
1300
1301 // Update the binding.
1302
1303 ValueState StImpl = *St;
1304 StImpl.CheckerState = RefBFactory.Add(B, Sym, X).getRoot();
1305 Builder.MakeNode(Dst, S, Pred, StateMgr.getPersistentState(StImpl));
1306}
1307
Ted Kremenekcb612922008-04-18 19:23:43 +00001308// Assumptions.
1309
1310ValueState* CFRefCount::EvalAssume(GRExprEngine& Eng, ValueState* St,
1311 RVal Cond, bool Assumption,
1312 bool& isFeasible) {
1313
1314 // FIXME: We may add to the interface of EvalAssume the list of symbols
1315 // whose assumptions have changed. For now we just iterate through the
1316 // bindings and check if any of the tracked symbols are NULL. This isn't
1317 // too bad since the number of symbols we will track in practice are
1318 // probably small and EvalAssume is only called at branches and a few
1319 // other places.
1320
1321 RefBindings B = GetRefBindings(*St);
1322
1323 if (B.isEmpty())
1324 return St;
1325
1326 bool changed = false;
1327
1328 for (RefBindings::iterator I=B.begin(), E=B.end(); I!=E; ++I) {
1329
1330 // Check if the symbol is null (or equal to any constant).
1331 // If this is the case, stop tracking the symbol.
1332
1333 if (St->getSymVal(I.getKey())) {
1334 changed = true;
1335 B = RefBFactory.Remove(B, I.getKey());
1336 }
1337 }
1338
1339 if (!changed)
1340 return St;
1341
1342 ValueState StImpl = *St;
1343 StImpl.CheckerState = B.getRoot();
1344 return Eng.getStateManager().getPersistentState(StImpl);
1345}
Ted Kremenek6b3a0f72008-03-11 06:39:11 +00001346
1347CFRefCount::RefBindings CFRefCount::Update(RefBindings B, SymbolID sym,
Ted Kremenek1ac08d62008-03-11 17:48:22 +00001348 RefVal V, ArgEffect E,
Ted Kremenek9ed18e62008-04-16 04:28:53 +00001349 RefVal::Kind& hasErr) {
Ted Kremenek6b3a0f72008-03-11 06:39:11 +00001350
Ted Kremenek1ac08d62008-03-11 17:48:22 +00001351 // FIXME: This dispatch can potentially be sped up by unifiying it into
1352 // a single switch statement. Opt for simplicity for now.
Ted Kremenek6b3a0f72008-03-11 06:39:11 +00001353
Ted Kremenek1ac08d62008-03-11 17:48:22 +00001354 switch (E) {
1355 default:
1356 assert (false && "Unhandled CFRef transition.");
1357
1358 case DoNothing:
Ted Kremenek65c91652008-04-29 05:44:10 +00001359 if (!GCEnabled && V.getKind() == RefVal::Released) {
Ted Kremenek00a3a5f2008-03-12 01:21:45 +00001360 V = RefVal::makeUseAfterRelease();
Ted Kremenek9ed18e62008-04-16 04:28:53 +00001361 hasErr = V.getKind();
Ted Kremenek00a3a5f2008-03-12 01:21:45 +00001362 break;
1363 }
1364
Ted Kremenek1ac08d62008-03-11 17:48:22 +00001365 return B;
1366
1367 case IncRef:
1368 switch (V.getKind()) {
1369 default:
1370 assert(false);
1371
1372 case RefVal::Owned:
Ted Kremenek940b1d82008-04-10 23:44:06 +00001373 V = RefVal::makeOwned(V.getCount()+1);
1374 break;
Ted Kremenek61b9f872008-04-10 23:09:18 +00001375
Ted Kremenek1ac08d62008-03-11 17:48:22 +00001376 case RefVal::NotOwned:
Ted Kremenek61b9f872008-04-10 23:09:18 +00001377 V = RefVal::makeNotOwned(V.getCount()+1);
Ted Kremenek1ac08d62008-03-11 17:48:22 +00001378 break;
1379
1380 case RefVal::Released:
Ted Kremenek65c91652008-04-29 05:44:10 +00001381 if (GCEnabled)
1382 V = RefVal::makeOwned();
1383 else {
1384 V = RefVal::makeUseAfterRelease();
1385 hasErr = V.getKind();
1386 }
1387
Ted Kremenek1ac08d62008-03-11 17:48:22 +00001388 break;
1389 }
1390
Ted Kremenek940b1d82008-04-10 23:44:06 +00001391 break;
1392
Ted Kremenek1ac08d62008-03-11 17:48:22 +00001393 case DecRef:
1394 switch (V.getKind()) {
1395 default:
1396 assert (false);
1397
1398 case RefVal::Owned: {
Ted Kremenek4fd88972008-04-17 18:12:53 +00001399 unsigned Count = V.getCount();
1400 V = Count > 0 ? RefVal::makeOwned(Count - 1) : RefVal::makeReleased();
Ted Kremenek1ac08d62008-03-11 17:48:22 +00001401 break;
1402 }
1403
Ted Kremenek61b9f872008-04-10 23:09:18 +00001404 case RefVal::NotOwned: {
Ted Kremenek4fd88972008-04-17 18:12:53 +00001405 unsigned Count = V.getCount();
Ted Kremenek61b9f872008-04-10 23:09:18 +00001406
Ted Kremenek4fd88972008-04-17 18:12:53 +00001407 if (Count > 0)
1408 V = RefVal::makeNotOwned(Count - 1);
Ted Kremenek61b9f872008-04-10 23:09:18 +00001409 else {
1410 V = RefVal::makeReleaseNotOwned();
Ted Kremenek9ed18e62008-04-16 04:28:53 +00001411 hasErr = V.getKind();
Ted Kremenek61b9f872008-04-10 23:09:18 +00001412 }
1413
Ted Kremenek1ac08d62008-03-11 17:48:22 +00001414 break;
1415 }
Ted Kremenek1ac08d62008-03-11 17:48:22 +00001416
1417 case RefVal::Released:
Ted Kremenek1ac08d62008-03-11 17:48:22 +00001418 V = RefVal::makeUseAfterRelease();
Ted Kremenek9ed18e62008-04-16 04:28:53 +00001419 hasErr = V.getKind();
Ted Kremenek1ac08d62008-03-11 17:48:22 +00001420 break;
1421 }
Ted Kremenek940b1d82008-04-10 23:44:06 +00001422
1423 break;
Ted Kremenek1ac08d62008-03-11 17:48:22 +00001424 }
1425
1426 return RefBFactory.Add(B, sym, V);
Ted Kremenek6b3a0f72008-03-11 06:39:11 +00001427}
1428
Ted Kremenekfa34b332008-04-09 01:10:13 +00001429
1430//===----------------------------------------------------------------------===//
Ted Kremenek05cbe1a2008-04-09 23:49:11 +00001431// Error reporting.
Ted Kremenekfa34b332008-04-09 01:10:13 +00001432//===----------------------------------------------------------------------===//
1433
Ted Kremenek8dd56462008-04-18 03:39:05 +00001434namespace {
1435
1436 //===-------------===//
1437 // Bug Descriptions. //
1438 //===-------------===//
1439
Ted Kremenek95cc1ba2008-04-18 20:54:29 +00001440 class VISIBILITY_HIDDEN CFRefBug : public BugTypeCacheLocation {
Ted Kremenek8dd56462008-04-18 03:39:05 +00001441 protected:
1442 CFRefCount& TF;
1443
1444 public:
1445 CFRefBug(CFRefCount& tf) : TF(tf) {}
Ted Kremenek072192b2008-04-30 23:47:44 +00001446
Ted Kremenekbb77e9b2008-05-01 22:50:36 +00001447 CFRefCount& getTF() { return TF; }
1448
Ted Kremenekc9fa2f72008-05-01 23:13:35 +00001449 virtual bool isLeak() const { return false; }
Ted Kremenek8dd56462008-04-18 03:39:05 +00001450 };
1451
1452 class VISIBILITY_HIDDEN UseAfterRelease : public CFRefBug {
1453 public:
1454 UseAfterRelease(CFRefCount& tf) : CFRefBug(tf) {}
1455
1456 virtual const char* getName() const {
Ted Kremenek2cf943a2008-04-18 04:55:01 +00001457 return "Core Foundation: Use-After-Release";
Ted Kremenek8dd56462008-04-18 03:39:05 +00001458 }
1459 virtual const char* getDescription() const {
Ted Kremenek2cf943a2008-04-18 04:55:01 +00001460 return "Reference-counted object is used"
1461 " after it is released.";
Ted Kremenek8dd56462008-04-18 03:39:05 +00001462 }
1463
1464 virtual void EmitWarnings(BugReporter& BR);
Ted Kremenek8dd56462008-04-18 03:39:05 +00001465 };
1466
1467 class VISIBILITY_HIDDEN BadRelease : public CFRefBug {
1468 public:
1469 BadRelease(CFRefCount& tf) : CFRefBug(tf) {}
1470
1471 virtual const char* getName() const {
Ted Kremenek2cf943a2008-04-18 04:55:01 +00001472 return "Core Foundation: Release of non-owned object";
Ted Kremenek8dd56462008-04-18 03:39:05 +00001473 }
1474 virtual const char* getDescription() const {
1475 return "Incorrect decrement of the reference count of a "
Ted Kremenek2cf943a2008-04-18 04:55:01 +00001476 "CoreFoundation object: "
Ted Kremenek8dd56462008-04-18 03:39:05 +00001477 "The object is not owned at this point by the caller.";
1478 }
1479
1480 virtual void EmitWarnings(BugReporter& BR);
1481 };
1482
1483 class VISIBILITY_HIDDEN Leak : public CFRefBug {
1484 public:
1485 Leak(CFRefCount& tf) : CFRefBug(tf) {}
1486
1487 virtual const char* getName() const {
Ted Kremenek2cf943a2008-04-18 04:55:01 +00001488 return "Core Foundation: Memory Leak";
Ted Kremenek8dd56462008-04-18 03:39:05 +00001489 }
1490
1491 virtual const char* getDescription() const {
Ted Kremenek2cf943a2008-04-18 04:55:01 +00001492 return "Object leaked.";
Ted Kremenek8dd56462008-04-18 03:39:05 +00001493 }
1494
1495 virtual void EmitWarnings(BugReporter& BR);
Ted Kremenekbb77e9b2008-05-01 22:50:36 +00001496 virtual void GetErrorNodes(std::vector<ExplodedNode<ValueState>*>& Nodes);
Ted Kremenekc9fa2f72008-05-01 23:13:35 +00001497 virtual bool isLeak() const { return true; }
Ted Kremenek8dd56462008-04-18 03:39:05 +00001498 };
1499
1500 //===---------===//
1501 // Bug Reports. //
1502 //===---------===//
1503
1504 class VISIBILITY_HIDDEN CFRefReport : public RangedBugReport {
1505 SymbolID Sym;
1506 public:
Ted Kremenek072192b2008-04-30 23:47:44 +00001507 CFRefReport(CFRefBug& D, ExplodedNode<ValueState> *n, SymbolID sym)
Ted Kremenek8dd56462008-04-18 03:39:05 +00001508 : RangedBugReport(D, n), Sym(sym) {}
1509
1510 virtual ~CFRefReport() {}
1511
Ted Kremenekbb77e9b2008-05-01 22:50:36 +00001512 CFRefBug& getBugType() {
1513 return (CFRefBug&) RangedBugReport::getBugType();
1514 }
1515 const CFRefBug& getBugType() const {
1516 return (const CFRefBug&) RangedBugReport::getBugType();
1517 }
1518
1519 virtual void getRanges(BugReporter& BR, const SourceRange*& beg,
1520 const SourceRange*& end) {
1521
Ted Kremenekc9fa2f72008-05-01 23:13:35 +00001522 if (getBugType().isLeak())
Ted Kremenekbb77e9b2008-05-01 22:50:36 +00001523 RangedBugReport::getRanges(BR, beg, end);
1524 else {
1525 beg = 0;
1526 end = 0;
1527 }
1528 }
1529
Ted Kremenekc9fa2f72008-05-01 23:13:35 +00001530 virtual PathDiagnosticPiece* getEndPath(BugReporter& BR,
1531 ExplodedNode<ValueState>* N);
1532
Ted Kremenek072192b2008-04-30 23:47:44 +00001533 virtual std::pair<const char**,const char**> getExtraDescriptiveText();
Ted Kremenek8dd56462008-04-18 03:39:05 +00001534
1535 virtual PathDiagnosticPiece* VisitNode(ExplodedNode<ValueState>* N,
1536 ExplodedNode<ValueState>* PrevN,
1537 ExplodedGraph<ValueState>& G,
1538 BugReporter& BR);
1539 };
1540
1541
1542} // end anonymous namespace
1543
1544void CFRefCount::RegisterChecks(GRExprEngine& Eng) {
Ted Kremenek9f741612008-05-02 18:01:49 +00001545 if (EmitStandardWarnings) GRSimpleVals::RegisterChecks(Eng);
Ted Kremenek8dd56462008-04-18 03:39:05 +00001546 Eng.Register(new UseAfterRelease(*this));
1547 Eng.Register(new BadRelease(*this));
1548 Eng.Register(new Leak(*this));
1549}
1550
Ted Kremenek072192b2008-04-30 23:47:44 +00001551
1552static const char* Msgs[] = {
1553 "Code is compiled in garbage collection only mode" // GC only
1554 " (the bug occurs with garbage collection enabled).",
1555
1556 "Code is compiled without garbage collection.", // No GC.
1557
1558 "Code is compiled for use with and without garbage collection (GC)."
1559 " The bug occurs with GC enabled.", // Hybrid, with GC.
1560
1561 "Code is compiled for use with and without garbage collection (GC)."
1562 " The bug occurs in non-GC mode." // Hyrbird, without GC/
1563};
1564
1565std::pair<const char**,const char**> CFRefReport::getExtraDescriptiveText() {
1566 CFRefCount& TF = static_cast<CFRefBug&>(getBugType()).getTF();
1567
1568 switch (TF.getLangOptions().getGCMode()) {
1569 default:
1570 assert(false);
Ted Kremenek31593ac2008-05-01 04:02:04 +00001571
1572 case LangOptions::GCOnly:
1573 assert (TF.isGCEnabled());
1574 return std::make_pair(&Msgs[0], &Msgs[0]+1);
Ted Kremenek072192b2008-04-30 23:47:44 +00001575
1576 case LangOptions::NonGC:
1577 assert (!TF.isGCEnabled());
Ted Kremenek072192b2008-04-30 23:47:44 +00001578 return std::make_pair(&Msgs[1], &Msgs[1]+1);
1579
1580 case LangOptions::HybridGC:
1581 if (TF.isGCEnabled())
1582 return std::make_pair(&Msgs[2], &Msgs[2]+1);
1583 else
1584 return std::make_pair(&Msgs[3], &Msgs[3]+1);
1585 }
1586}
1587
Ted Kremenek8dd56462008-04-18 03:39:05 +00001588PathDiagnosticPiece* CFRefReport::VisitNode(ExplodedNode<ValueState>* N,
1589 ExplodedNode<ValueState>* PrevN,
1590 ExplodedGraph<ValueState>& G,
1591 BugReporter& BR) {
1592
1593 // Check if the type state has changed.
1594
1595 ValueState* PrevSt = PrevN->getState();
1596 ValueState* CurrSt = N->getState();
1597
1598 CFRefCount::RefBindings PrevB = CFRefCount::GetRefBindings(*PrevSt);
1599 CFRefCount::RefBindings CurrB = CFRefCount::GetRefBindings(*CurrSt);
1600
Ted Kremenek2cf943a2008-04-18 04:55:01 +00001601 CFRefCount::RefBindings::TreeTy* PrevT = PrevB.SlimFind(Sym);
1602 CFRefCount::RefBindings::TreeTy* CurrT = CurrB.SlimFind(Sym);
Ted Kremenek8dd56462008-04-18 03:39:05 +00001603
Ted Kremenek2cf943a2008-04-18 04:55:01 +00001604 if (!CurrT)
1605 return NULL;
Ted Kremenek8dd56462008-04-18 03:39:05 +00001606
Ted Kremenek2cf943a2008-04-18 04:55:01 +00001607 const char* Msg = NULL;
1608 RefVal CurrV = CurrB.SlimFind(Sym)->getValue().second;
Ted Kremenek8dd56462008-04-18 03:39:05 +00001609
Ted Kremenek2cf943a2008-04-18 04:55:01 +00001610 if (!PrevT) {
1611
1612 // Check for the point where we start tracking the value.
1613
1614 if (CurrV.isOwned())
1615 Msg = "Function call returns 'Owned' Core Foundation object.";
1616 else {
1617 assert (CurrV.isNotOwned());
1618 Msg = "Function call returns 'Non-Owned' Core Foundation object.";
1619 }
1620
1621 Stmt* S = cast<PostStmt>(N->getLocation()).getStmt();
1622 FullSourceLoc Pos(S->getLocStart(), BR.getContext().getSourceManager());
1623 PathDiagnosticPiece* P = new PathDiagnosticPiece(Pos, Msg);
1624
1625 if (Expr* Exp = dyn_cast<Expr>(S))
1626 P->addRange(Exp->getSourceRange());
1627
1628 return P;
1629 }
1630
1631 // Determine if the typestate has changed.
1632
1633 RefVal PrevV = PrevB.SlimFind(Sym)->getValue().second;
1634
1635 if (PrevV == CurrV)
1636 return NULL;
1637
1638 // The typestate has changed.
1639
1640 std::ostringstream os;
1641
1642 switch (CurrV.getKind()) {
1643 case RefVal::Owned:
1644 case RefVal::NotOwned:
1645 assert (PrevV.getKind() == CurrV.getKind());
1646
1647 if (PrevV.getCount() > CurrV.getCount())
1648 os << "Reference count decremented.";
1649 else
1650 os << "Reference count incremented.";
1651
Ted Kremenek79c140b2008-04-18 05:32:44 +00001652 if (CurrV.getCount()) {
1653 os << " Object has +" << CurrV.getCount();
1654
1655 if (CurrV.getCount() > 1)
1656 os << " reference counts.";
1657 else
1658 os << " reference count.";
1659 }
Ted Kremenek2cf943a2008-04-18 04:55:01 +00001660
1661 Msg = os.str().c_str();
1662
1663 break;
1664
1665 case RefVal::Released:
1666 Msg = "Object released.";
1667 break;
1668
1669 case RefVal::ReturnedOwned:
1670 Msg = "Object returned to caller. "
1671 "Caller gets ownership of object.";
1672 break;
1673
1674 case RefVal::ReturnedNotOwned:
1675 Msg = "Object returned to caller. "
1676 "Caller does not get ownership of object.";
1677 break;
1678
1679 default:
1680 return NULL;
1681 }
1682
1683 Stmt* S = cast<PostStmt>(N->getLocation()).getStmt();
1684 FullSourceLoc Pos(S->getLocStart(), BR.getContext().getSourceManager());
1685 PathDiagnosticPiece* P = new PathDiagnosticPiece(Pos, Msg);
1686
1687 // Add the range by scanning the children of the statement for any bindings
1688 // to Sym.
1689
1690 ValueStateManager& VSM = BR.getEngine().getStateManager();
1691
1692 for (Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I!=E; ++I)
1693 if (Expr* Exp = dyn_cast_or_null<Expr>(*I)) {
1694 RVal X = VSM.GetRVal(CurrSt, Exp);
1695
1696 if (lval::SymbolVal* SV = dyn_cast<lval::SymbolVal>(&X))
1697 if (SV->getSymbol() == Sym) {
1698 P->addRange(Exp->getSourceRange()); break;
1699 }
1700 }
1701
1702 return P;
Ted Kremenek8dd56462008-04-18 03:39:05 +00001703}
1704
Ted Kremenekc9fa2f72008-05-01 23:13:35 +00001705PathDiagnosticPiece* CFRefReport::getEndPath(BugReporter& BR,
1706 ExplodedNode<ValueState>* N) {
1707
1708 if (!getBugType().isLeak())
1709 return RangedBugReport::getEndPath(BR, N);
1710
1711 // We are a leak. Walk up the graph to get to the first node where the
1712 // symbol appeared.
1713
1714 ExplodedNode<ValueState>* Last = N;
1715 typedef CFRefCount::RefBindings RefBindings;
1716
1717 // Find the first node that referred to the tracked symbol.
1718
1719 while (N) {
1720 ValueState* St = N->getState();
1721 RefBindings B = RefBindings((RefBindings::TreeTy*) St->CheckerState);
1722
1723 if (!B.SlimFind(Sym))
1724 break;
1725
1726 Last = N;
1727 N = N->pred_empty() ? NULL : *(N->pred_begin());
1728 }
1729
1730 // Get the location.
1731
1732 assert (Last);
1733 Stmt* FirstStmt = cast<PostStmt>(Last->getLocation()).getStmt();
1734
1735 unsigned Line =
1736 BR.getSourceManager().getLogicalLineNumber(FirstStmt->getLocStart());
1737
1738 // FIXME: Also get the name of the variable.
1739
1740 std::ostringstream os;
1741 os << "Object allocated on line " << Line << " is leaked.";
1742
1743 Stmt* S = getStmt(BR);
1744 assert (S);
1745 FullSourceLoc L(S->getLocStart(), BR.getContext().getSourceManager());
1746 PathDiagnosticPiece* P = new PathDiagnosticPiece(L, os.str());
1747
1748 return P;
1749}
1750
Ted Kremenek05cbe1a2008-04-09 23:49:11 +00001751void UseAfterRelease::EmitWarnings(BugReporter& BR) {
Ted Kremenekfa34b332008-04-09 01:10:13 +00001752
Ted Kremenek05cbe1a2008-04-09 23:49:11 +00001753 for (CFRefCount::use_after_iterator I = TF.use_after_begin(),
1754 E = TF.use_after_end(); I != E; ++I) {
1755
Ted Kremenek8dd56462008-04-18 03:39:05 +00001756 CFRefReport report(*this, I->first, I->second.second);
1757 report.addRange(I->second.first->getSourceRange());
Ted Kremenek75840e12008-04-18 01:56:37 +00001758 BR.EmitWarning(report);
Ted Kremenekfa34b332008-04-09 01:10:13 +00001759 }
Ted Kremenek05cbe1a2008-04-09 23:49:11 +00001760}
1761
1762void BadRelease::EmitWarnings(BugReporter& BR) {
Ted Kremenekfa34b332008-04-09 01:10:13 +00001763
Ted Kremenek05cbe1a2008-04-09 23:49:11 +00001764 for (CFRefCount::bad_release_iterator I = TF.bad_release_begin(),
1765 E = TF.bad_release_end(); I != E; ++I) {
1766
Ted Kremenek8dd56462008-04-18 03:39:05 +00001767 CFRefReport report(*this, I->first, I->second.second);
1768 report.addRange(I->second.first->getSourceRange());
1769 BR.EmitWarning(report);
Ted Kremenek05cbe1a2008-04-09 23:49:11 +00001770 }
1771}
Ted Kremenekfa34b332008-04-09 01:10:13 +00001772
Ted Kremenek989d5192008-04-17 23:43:50 +00001773void Leak::EmitWarnings(BugReporter& BR) {
1774
1775 for (CFRefCount::leaks_iterator I = TF.leaks_begin(),
1776 E = TF.leaks_end(); I != E; ++I) {
1777
Ted Kremenek8dd56462008-04-18 03:39:05 +00001778 std::vector<SymbolID>& SymV = *(I->second);
1779 unsigned n = SymV.size();
1780
1781 for (unsigned i = 0; i < n; ++i) {
1782 CFRefReport report(*this, I->first, SymV[i]);
1783 BR.EmitWarning(report);
1784 }
Ted Kremenek989d5192008-04-17 23:43:50 +00001785 }
1786}
1787
Ted Kremenekcb612922008-04-18 19:23:43 +00001788void Leak::GetErrorNodes(std::vector<ExplodedNode<ValueState>*>& Nodes) {
1789 for (CFRefCount::leaks_iterator I=TF.leaks_begin(), E=TF.leaks_end();
1790 I!=E; ++I)
1791 Nodes.push_back(I->first);
1792}
1793
Ted Kremenek6b3a0f72008-03-11 06:39:11 +00001794//===----------------------------------------------------------------------===//
Ted Kremenekd71ed262008-04-10 22:16:52 +00001795// Transfer function creation for external clients.
Ted Kremenek6b3a0f72008-03-11 06:39:11 +00001796//===----------------------------------------------------------------------===//
1797
Ted Kremenek072192b2008-04-30 23:47:44 +00001798GRTransferFuncs* clang::MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled,
Ted Kremenek9f741612008-05-02 18:01:49 +00001799 bool StandardWarnings,
Ted Kremenek072192b2008-04-30 23:47:44 +00001800 const LangOptions& lopts) {
Ted Kremenek9f741612008-05-02 18:01:49 +00001801 return new CFRefCount(Ctx, GCEnabled, StandardWarnings, lopts);
Ted Kremenek3ea0b6a2008-04-10 22:58:08 +00001802}