blob: c5f582fdbe7f170a9fa68ba897075a1b1a9e9a8e [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 Kremenek2fff37e2008-03-06 00:08:09 +000017#include "clang/Analysis/PathSensitive/ValueState.h"
Ted Kremenek4dc41cc2008-03-31 18:26:32 +000018#include "clang/Analysis/PathDiagnostic.h"
Ted Kremenek2fff37e2008-03-06 00:08:09 +000019#include "clang/Analysis/LocalCheckers.h"
Ted Kremenekfa34b332008-04-09 01:10:13 +000020#include "clang/Analysis/PathDiagnostic.h"
21#include "clang/Analysis/PathSensitive/BugReporter.h"
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000022#include "llvm/ADT/DenseMap.h"
23#include "llvm/ADT/FoldingSet.h"
24#include "llvm/ADT/ImmutableMap.h"
Ted Kremenekfa34b332008-04-09 01:10:13 +000025#include "llvm/Support/Compiler.h"
Ted Kremenekf3948042008-03-11 19:44:10 +000026#include <ostream>
Ted Kremenek2cf943a2008-04-18 04:55:01 +000027#include <sstream>
Ted Kremenek2fff37e2008-03-06 00:08:09 +000028
29using namespace clang;
30
Ted Kremenek05cbe1a2008-04-09 23:49:11 +000031//===----------------------------------------------------------------------===//
Ted Kremenek4fd88972008-04-17 18:12:53 +000032// Utility functions.
33//===----------------------------------------------------------------------===//
34
35static inline Selector GetUnarySelector(const char* name, ASTContext& Ctx) {
36 IdentifierInfo* II = &Ctx.Idents.get(name);
37 return Ctx.Selectors.getSelector(0, &II);
38}
39
40//===----------------------------------------------------------------------===//
Ted Kremenek05cbe1a2008-04-09 23:49:11 +000041// Symbolic Evaluation of Reference Counting Logic
42//===----------------------------------------------------------------------===//
43
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000044namespace {
45 enum ArgEffect { IncRef, DecRef, DoNothing };
Ted Kremenek891d5cc2008-04-24 17:22:33 +000046 typedef std::vector<std::pair<unsigned,ArgEffect> > ArgEffects;
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000047}
Ted Kremenek2fff37e2008-03-06 00:08:09 +000048
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000049namespace llvm {
50 template <> struct FoldingSetTrait<ArgEffects> {
Ted Kremenek3ea0b6a2008-04-10 22:58:08 +000051 static void Profile(const ArgEffects& X, FoldingSetNodeID& ID) {
Ted Kremenek891d5cc2008-04-24 17:22:33 +000052 for (ArgEffects::const_iterator I = X.begin(), E = X.end(); I!= E; ++I) {
53 ID.AddInteger(I->first);
54 ID.AddInteger((unsigned) I->second);
55 }
Ted Kremenek3ea0b6a2008-04-10 22:58:08 +000056 }
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000057 };
58} // end llvm namespace
59
60namespace {
Ted Kremenek2fff37e2008-03-06 00:08:09 +000061
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000062class RetEffect {
63public:
Ted Kremenek940b1d82008-04-10 23:44:06 +000064 enum Kind { NoRet = 0x0, Alias = 0x1, OwnedSymbol = 0x2,
65 NotOwnedSymbol = 0x3 };
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000066
67private:
68 unsigned Data;
Ted Kremenek3ea0b6a2008-04-10 22:58:08 +000069 RetEffect(Kind k, unsigned D) { Data = (D << 2) | (unsigned) k; }
Ted Kremenek2fff37e2008-03-06 00:08:09 +000070
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000071public:
72
73 Kind getKind() const { return (Kind) (Data & 0x3); }
74
75 unsigned getValue() const {
76 assert(getKind() == Alias);
Ted Kremenek3ea0b6a2008-04-10 22:58:08 +000077 return Data >> 2;
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000078 }
Ted Kremeneke7bd9c22008-04-11 22:25:11 +000079
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000080 static RetEffect MakeAlias(unsigned Idx) { return RetEffect(Alias, Idx); }
Ted Kremenek2fff37e2008-03-06 00:08:09 +000081
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000082 static RetEffect MakeOwned() { return RetEffect(OwnedSymbol, 0); }
Ted Kremenek2fff37e2008-03-06 00:08:09 +000083
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000084 static RetEffect MakeNotOwned() { return RetEffect(NotOwnedSymbol, 0); }
85
Ted Kremenek940b1d82008-04-10 23:44:06 +000086 static RetEffect MakeNoRet() { return RetEffect(NoRet, 0); }
87
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000088 operator Kind() const { return getKind(); }
89
90 void Profile(llvm::FoldingSetNodeID& ID) const { ID.AddInteger(Data); }
91};
92
93
94class CFRefSummary : public llvm::FoldingSetNode {
95 ArgEffects* Args;
96 RetEffect Ret;
97public:
98
99 CFRefSummary(ArgEffects* A, RetEffect R) : Args(A), Ret(R) {}
100
101 unsigned getNumArgs() const { return Args->size(); }
102
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000103 ArgEffect getArg(unsigned idx) const {
Ted Kremenek891d5cc2008-04-24 17:22:33 +0000104 if (!Args)
105 return DoNothing;
106
107 // If Args is present, it is likely to contain only 1 element.
108 // Just do a linear search. Do it from the back because functions with
109 // large numbers of arguments will be tail heavy with respect to which
110 // argument they actually modify with respect to the reference count.
111
112 for (ArgEffects::reverse_iterator I=Args->rbegin(), E=Args->rend();
113 I!=E; ++I) {
114
115 if (idx > I->first)
116 return DoNothing;
117
118 if (idx == I->first)
119 return I->second;
120 }
121
122 return DoNothing;
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000123 }
124
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000125 RetEffect getRet() const {
126 return Ret;
127 }
128
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000129 typedef ArgEffects::const_iterator arg_iterator;
130
131 arg_iterator begin_args() const { return Args->begin(); }
132 arg_iterator end_args() const { return Args->end(); }
133
134 static void Profile(llvm::FoldingSetNodeID& ID, ArgEffects* A, RetEffect R) {
135 ID.AddPointer(A);
136 ID.Add(R);
137 }
138
139 void Profile(llvm::FoldingSetNodeID& ID) const {
140 Profile(ID, Args, Ret);
141 }
142};
143
144
145class CFRefSummaryManager {
146 typedef llvm::FoldingSet<llvm::FoldingSetNodeWrapper<ArgEffects> > AESetTy;
147 typedef llvm::FoldingSet<CFRefSummary> SummarySetTy;
148 typedef llvm::DenseMap<FunctionDecl*, CFRefSummary*> SummaryMapTy;
149
Ted Kremenek377e2302008-04-29 05:33:51 +0000150 ASTContext& Ctx;
151 const bool GCEnabled;
152
Ted Kremenek3ea0b6a2008-04-10 22:58:08 +0000153 SummarySetTy SummarySet;
154 SummaryMapTy SummaryMap;
155 AESetTy AESet;
156 llvm::BumpPtrAllocator BPAlloc;
Ted Kremenek891d5cc2008-04-24 17:22:33 +0000157 ArgEffects ScratchArgs;
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000158
159 ArgEffects* getArgEffects();
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000160
Ted Kremenek377e2302008-04-29 05:33:51 +0000161 enum CFUnaryFunc { cfretain, cfrelease, cfmakecollectable };
162 CFRefSummary* getUnaryCFSummary(FunctionTypeProto* FT, CFUnaryFunc func);
163
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000164 CFRefSummary* getCFSummary(FunctionDecl* FD, const char* FName);
165
166 CFRefSummary* getCFSummaryCreateRule(FunctionTypeProto* FT);
167 CFRefSummary* getCFSummaryGetRule(FunctionTypeProto* FT);
168
169 CFRefSummary* getPersistentSummary(ArgEffects* AE, RetEffect RE);
Ted Kremenek891d5cc2008-04-24 17:22:33 +0000170
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000171public:
Ted Kremenek377e2302008-04-29 05:33:51 +0000172 CFRefSummaryManager(ASTContext& ctx, bool gcenabled)
173 : Ctx(ctx), GCEnabled(gcenabled) {}
174
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000175 ~CFRefSummaryManager();
176
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000177 CFRefSummary* getSummary(FunctionDecl* FD, ASTContext& Ctx);
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000178};
179
180} // end anonymous namespace
181
182//===----------------------------------------------------------------------===//
183// Implementation of checker data structures.
184//===----------------------------------------------------------------------===//
185
186CFRefSummaryManager::~CFRefSummaryManager() {
187
188 // FIXME: The ArgEffects could eventually be allocated from BPAlloc,
189 // mitigating the need to do explicit cleanup of the
190 // Argument-Effect summaries.
191
192 for (AESetTy::iterator I = AESet.begin(), E = AESet.end(); I!=E; ++I)
193 I->getValue().~ArgEffects();
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000194}
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000195
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000196ArgEffects* CFRefSummaryManager::getArgEffects() {
197
Ted Kremenek891d5cc2008-04-24 17:22:33 +0000198 if (ScratchArgs.empty())
199 return NULL;
200
201 // Compute a profile for a non-empty ScratchArgs.
202
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000203 llvm::FoldingSetNodeID profile;
Ted Kremenek891d5cc2008-04-24 17:22:33 +0000204
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000205 profile.Add(ScratchArgs);
206 void* InsertPos;
207
Ted Kremenek891d5cc2008-04-24 17:22:33 +0000208 // Look up the uniqued copy, or create a new one.
209
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000210 llvm::FoldingSetNodeWrapper<ArgEffects>* E =
211 AESet.FindNodeOrInsertPos(profile, InsertPos);
212
Ted Kremenek891d5cc2008-04-24 17:22:33 +0000213 if (E) {
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000214 ScratchArgs.clear();
215 return &E->getValue();
216 }
217
218 E = (llvm::FoldingSetNodeWrapper<ArgEffects>*)
219 BPAlloc.Allocate<llvm::FoldingSetNodeWrapper<ArgEffects> >();
220
221 new (E) llvm::FoldingSetNodeWrapper<ArgEffects>(ScratchArgs);
222 AESet.InsertNode(E, InsertPos);
223
224 ScratchArgs.clear();
225 return &E->getValue();
226}
227
228CFRefSummary* CFRefSummaryManager::getPersistentSummary(ArgEffects* AE,
229 RetEffect RE) {
230
Ted Kremenek891d5cc2008-04-24 17:22:33 +0000231 // Generate a profile for the summary.
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000232 llvm::FoldingSetNodeID profile;
233 CFRefSummary::Profile(profile, AE, RE);
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000234
Ted Kremenek891d5cc2008-04-24 17:22:33 +0000235 // Look up the uniqued summary, or create one if it doesn't exist.
236 void* InsertPos;
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000237 CFRefSummary* Summ = SummarySet.FindNodeOrInsertPos(profile, InsertPos);
238
239 if (Summ)
240 return Summ;
241
Ted Kremenek891d5cc2008-04-24 17:22:33 +0000242 // Create the summary and return it.
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000243 Summ = (CFRefSummary*) BPAlloc.Allocate<CFRefSummary>();
244 new (Summ) CFRefSummary(AE, RE);
245 SummarySet.InsertNode(Summ, InsertPos);
246
247 return Summ;
248}
249
250
251CFRefSummary* CFRefSummaryManager::getSummary(FunctionDecl* FD,
252 ASTContext& Ctx) {
253
254 SourceLocation Loc = FD->getLocation();
255
256 if (!Loc.isFileID())
257 return NULL;
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000258
Ted Kremenek891d5cc2008-04-24 17:22:33 +0000259
260 // Look up a summary in our cache of FunctionDecls -> Summaries.
261 SummaryMapTy::iterator I = SummaryMap.find(FD);
262
263 if (I != SummaryMap.end())
264 return I->second;
265
266 // No summary. Generate one.
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000267 const char* FName = FD->getIdentifier()->getName();
268
269 if (FName[0] == 'C' && FName[1] == 'F') {
270 CFRefSummary* S = getCFSummary(FD, FName);
271 SummaryMap[FD] = S;
272 return S;
273 }
Ted Kremenek891d5cc2008-04-24 17:22:33 +0000274
275 // Function has no ref-count effects. Return the NULL summary.
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000276 return NULL;
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000277}
278
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000279CFRefSummary* CFRefSummaryManager::getCFSummary(FunctionDecl* FD,
280 const char* FName) {
281
282 // For now, only generate summaries for functions that have a prototype.
283
284 FunctionTypeProto* FT =
285 dyn_cast<FunctionTypeProto>(FD->getType().getTypePtr());
286
287 if (!FT)
288 return NULL;
289
290 FName += 2;
291
292 if (strcmp(FName, "Retain") == 0)
Ted Kremenek377e2302008-04-29 05:33:51 +0000293 return getUnaryCFSummary(FT, cfretain);
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000294
295 if (strcmp(FName, "Release") == 0)
Ted Kremenek377e2302008-04-29 05:33:51 +0000296 return getUnaryCFSummary(FT, cfrelease);
297
298 if (strcmp(FName, "MakeCollectable") == 0)
299 return getUnaryCFSummary(FT, cfmakecollectable);
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000300
301 assert (ScratchArgs.empty());
302 bool usesCreateRule = false;
303
304 if (strstr(FName, "Create"))
305 usesCreateRule = true;
306
307 if (!usesCreateRule && strstr(FName, "Copy"))
308 usesCreateRule = true;
309
310 if (usesCreateRule)
311 return getCFSummaryCreateRule(FT);
312
313 if (strstr(FName, "Get"))
314 return getCFSummaryGetRule(FT);
315
316 return NULL;
317}
318
Ted Kremenek377e2302008-04-29 05:33:51 +0000319CFRefSummary*
320CFRefSummaryManager::getUnaryCFSummary(FunctionTypeProto* FT, CFUnaryFunc func) {
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000321
322 if (FT->getNumArgs() != 1)
323 return NULL;
324
325 TypedefType* ArgT = dyn_cast<TypedefType>(FT->getArgType(0).getTypePtr());
326
327 if (!ArgT)
328 return NULL;
329
330 // For CFRetain/CFRelease, the first (and only) argument is of type
331 // "CFTypeRef".
332
333 const char* TDName = ArgT->getDecl()->getIdentifier()->getName();
334 assert (TDName);
335
Ted Kremenek3ea0b6a2008-04-10 22:58:08 +0000336 if (strcmp("CFTypeRef", TDName) != 0)
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000337 return NULL;
338
Ted Kremenekc0c3f5d2008-04-30 20:17:27 +0000339 if (!ArgT->isPointerType())
340 return NULL;
Ted Kremenek3ea0b6a2008-04-10 22:58:08 +0000341
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000342 QualType RetTy = FT->getResultType();
343
Ted Kremenek377e2302008-04-29 05:33:51 +0000344 switch (func) {
345 case cfretain: {
346
347 // CFRetain: the return type should also be "CFTypeRef".
348 if (RetTy.getTypePtr() != ArgT)
349 return NULL;
350
351 // The function's interface checks out. Generate a canned summary.
352 assert (ScratchArgs.empty());
353 ScratchArgs.push_back(std::make_pair(0, IncRef));
354 return getPersistentSummary(getArgEffects(), RetEffect::MakeAlias(0));
355 }
356
357 case cfrelease: {
358
359 // CFRelease: the return type should be void.
360
361 if (RetTy != Ctx.VoidTy)
362 return NULL;
363
364 assert (ScratchArgs.empty());
365 ScratchArgs.push_back(std::make_pair(0, DecRef));
366 return getPersistentSummary(getArgEffects(), RetEffect::MakeNoRet());
367 }
368
369 case cfmakecollectable: {
370
371 // CFRetain: the return type should also be "CFTypeRef".
372 if (RetTy.getTypePtr() != ArgT)
373 return NULL;
374
375 // The function's interface checks out. Generate a canned summary.
376 assert (ScratchArgs.empty());
377
378 if (GCEnabled)
379 ScratchArgs.push_back(std::make_pair(0, DecRef));
380
381 return getPersistentSummary(getArgEffects(), RetEffect::MakeAlias(0));
382
383
384 }
385
386 default:
387 assert (false && "Not a support unary function.");
Ted Kremenek940b1d82008-04-10 23:44:06 +0000388 }
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000389}
390
391static bool isCFRefType(QualType T) {
392
393 if (!T->isPointerType())
394 return false;
395
396 // Check the typedef for the name "CF" and the substring "Ref".
397
398 TypedefType* TD = dyn_cast<TypedefType>(T.getTypePtr());
399
400 if (!TD)
401 return false;
402
403 const char* TDName = TD->getDecl()->getIdentifier()->getName();
404 assert (TDName);
405
406 if (TDName[0] != 'C' || TDName[1] != 'F')
407 return false;
408
409 if (strstr(TDName, "Ref") == 0)
410 return false;
411
412 return true;
413}
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000414
415CFRefSummary*
416CFRefSummaryManager::getCFSummaryCreateRule(FunctionTypeProto* FT) {
417
418 if (!isCFRefType(FT->getResultType()))
Ted Kremeneka0df99f2008-04-11 20:11:19 +0000419 return NULL;
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000420
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000421 // FIXME: Add special-cases for functions that retain/release. For now
422 // just handle the default case.
Ted Kremenek891d5cc2008-04-24 17:22:33 +0000423
424 assert (ScratchArgs.empty());
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000425 return getPersistentSummary(getArgEffects(), RetEffect::MakeOwned());
426}
427
428CFRefSummary*
429CFRefSummaryManager::getCFSummaryGetRule(FunctionTypeProto* FT) {
430
Ted Kremeneka0df99f2008-04-11 20:11:19 +0000431 QualType RetTy = FT->getResultType();
432
433 // FIXME: For now we assume that all pointer types returned are referenced
434 // counted. Since this is the "Get" rule, we assume non-ownership, which
435 // works fine for things that are not reference counted. We do this because
436 // some generic data structures return "void*". We need something better
437 // in the future.
438
439 if (!isCFRefType(RetTy) && !RetTy->isPointerType())
440 return NULL;
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000441
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000442 // FIXME: Add special-cases for functions that retain/release. For now
443 // just handle the default case.
444
Ted Kremenek891d5cc2008-04-24 17:22:33 +0000445 assert (ScratchArgs.empty());
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000446 return getPersistentSummary(getArgEffects(), RetEffect::MakeNotOwned());
447}
448
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000449//===----------------------------------------------------------------------===//
Ted Kremenek13922612008-04-16 20:40:59 +0000450// Reference-counting logic (typestate + counts).
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000451//===----------------------------------------------------------------------===//
452
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000453namespace {
454
Ted Kremenek05cbe1a2008-04-09 23:49:11 +0000455class VISIBILITY_HIDDEN RefVal {
Ted Kremenek4fd88972008-04-17 18:12:53 +0000456public:
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000457
Ted Kremenek4fd88972008-04-17 18:12:53 +0000458 enum Kind {
459 Owned = 0, // Owning reference.
460 NotOwned, // Reference is not owned by still valid (not freed).
461 Released, // Object has been released.
462 ReturnedOwned, // Returned object passes ownership to caller.
463 ReturnedNotOwned, // Return object does not pass ownership to caller.
464 ErrorUseAfterRelease, // Object used after released.
465 ErrorReleaseNotOwned, // Release of an object that was not owned.
466 ErrorLeak // A memory leak due to excessive reference counts.
467 };
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000468
Ted Kremenek4fd88972008-04-17 18:12:53 +0000469private:
470
471 Kind kind;
472 unsigned Cnt;
473
474 RefVal(Kind k, unsigned cnt) : kind(k), Cnt(cnt) {}
475
476 RefVal(Kind k) : kind(k), Cnt(0) {}
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000477
478public:
Ted Kremenekdb863712008-04-16 22:32:20 +0000479
Ted Kremenek4fd88972008-04-17 18:12:53 +0000480 Kind getKind() const { return kind; }
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000481
Ted Kremenek4fd88972008-04-17 18:12:53 +0000482 unsigned getCount() const { return Cnt; }
483
484 // Useful predicates.
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000485
Ted Kremenek73c750b2008-03-11 18:14:09 +0000486 static bool isError(Kind k) { return k >= ErrorUseAfterRelease; }
487
Ted Kremenekdb863712008-04-16 22:32:20 +0000488 static bool isLeak(Kind k) { return k == ErrorLeak; }
489
Ted Kremeneke7bd9c22008-04-11 22:25:11 +0000490 bool isOwned() const {
491 return getKind() == Owned;
492 }
493
Ted Kremenekdb863712008-04-16 22:32:20 +0000494 bool isNotOwned() const {
495 return getKind() == NotOwned;
496 }
497
Ted Kremenek4fd88972008-04-17 18:12:53 +0000498 bool isReturnedOwned() const {
499 return getKind() == ReturnedOwned;
500 }
501
502 bool isReturnedNotOwned() const {
503 return getKind() == ReturnedNotOwned;
504 }
505
506 bool isNonLeakError() const {
507 Kind k = getKind();
508 return isError(k) && !isLeak(k);
509 }
510
511 // State creation: normal state.
512
Ted Kremenek61b9f872008-04-10 23:09:18 +0000513 static RefVal makeOwned(unsigned Count = 0) {
514 return RefVal(Owned, Count);
515 }
516
517 static RefVal makeNotOwned(unsigned Count = 0) {
518 return RefVal(NotOwned, Count);
519 }
Ted Kremenek4fd88972008-04-17 18:12:53 +0000520
521 static RefVal makeReturnedOwned(unsigned Count) {
522 return RefVal(ReturnedOwned, Count);
523 }
524
525 static RefVal makeReturnedNotOwned() {
526 return RefVal(ReturnedNotOwned);
527 }
528
529 // State creation: errors.
Ted Kremenek61b9f872008-04-10 23:09:18 +0000530
Ted Kremenekdb863712008-04-16 22:32:20 +0000531 static RefVal makeLeak() { return RefVal(ErrorLeak); }
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000532 static RefVal makeReleased() { return RefVal(Released); }
533 static RefVal makeUseAfterRelease() { return RefVal(ErrorUseAfterRelease); }
534 static RefVal makeReleaseNotOwned() { return RefVal(ErrorReleaseNotOwned); }
Ted Kremenek4fd88972008-04-17 18:12:53 +0000535
536 // Comparison, profiling, and pretty-printing.
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000537
Ted Kremenek4fd88972008-04-17 18:12:53 +0000538 bool operator==(const RefVal& X) const {
539 return kind == X.kind && Cnt == X.Cnt;
540 }
Ted Kremenekf3948042008-03-11 19:44:10 +0000541
Ted Kremenek4fd88972008-04-17 18:12:53 +0000542 void Profile(llvm::FoldingSetNodeID& ID) const {
543 ID.AddInteger((unsigned) kind);
544 ID.AddInteger(Cnt);
545 }
546
Ted Kremenekf3948042008-03-11 19:44:10 +0000547 void print(std::ostream& Out) const;
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000548};
Ted Kremenekf3948042008-03-11 19:44:10 +0000549
550void RefVal::print(std::ostream& Out) const {
551 switch (getKind()) {
552 default: assert(false);
Ted Kremenek61b9f872008-04-10 23:09:18 +0000553 case Owned: {
554 Out << "Owned";
555 unsigned cnt = getCount();
556 if (cnt) Out << " (+ " << cnt << ")";
Ted Kremenekf3948042008-03-11 19:44:10 +0000557 break;
Ted Kremenek61b9f872008-04-10 23:09:18 +0000558 }
Ted Kremenekf3948042008-03-11 19:44:10 +0000559
Ted Kremenek61b9f872008-04-10 23:09:18 +0000560 case NotOwned: {
Ted Kremenek4fd88972008-04-17 18:12:53 +0000561 Out << "NotOwned";
Ted Kremenek61b9f872008-04-10 23:09:18 +0000562 unsigned cnt = getCount();
563 if (cnt) Out << " (+ " << cnt << ")";
Ted Kremenekf3948042008-03-11 19:44:10 +0000564 break;
Ted Kremenek61b9f872008-04-10 23:09:18 +0000565 }
Ted Kremenekf3948042008-03-11 19:44:10 +0000566
Ted Kremenek4fd88972008-04-17 18:12:53 +0000567 case ReturnedOwned: {
568 Out << "ReturnedOwned";
569 unsigned cnt = getCount();
570 if (cnt) Out << " (+ " << cnt << ")";
571 break;
572 }
573
574 case ReturnedNotOwned: {
575 Out << "ReturnedNotOwned";
576 unsigned cnt = getCount();
577 if (cnt) Out << " (+ " << cnt << ")";
578 break;
579 }
580
Ted Kremenekf3948042008-03-11 19:44:10 +0000581 case Released:
582 Out << "Released";
583 break;
584
Ted Kremenekdb863712008-04-16 22:32:20 +0000585 case ErrorLeak:
586 Out << "Leaked";
587 break;
588
Ted Kremenekf3948042008-03-11 19:44:10 +0000589 case ErrorUseAfterRelease:
590 Out << "Use-After-Release [ERROR]";
591 break;
592
593 case ErrorReleaseNotOwned:
594 Out << "Release of Not-Owned [ERROR]";
595 break;
596 }
597}
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000598
Ted Kremenek13922612008-04-16 20:40:59 +0000599//===----------------------------------------------------------------------===//
600// Transfer functions.
601//===----------------------------------------------------------------------===//
602
Ted Kremenek05cbe1a2008-04-09 23:49:11 +0000603class VISIBILITY_HIDDEN CFRefCount : public GRSimpleVals {
Ted Kremenek8dd56462008-04-18 03:39:05 +0000604public:
Ted Kremenekf3948042008-03-11 19:44:10 +0000605 // Type definitions.
606
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000607 typedef llvm::ImmutableMap<SymbolID, RefVal> RefBindings;
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000608 typedef RefBindings::Factory RefBFactoryTy;
Ted Kremenek73c750b2008-03-11 18:14:09 +0000609
Ted Kremenek8dd56462008-04-18 03:39:05 +0000610 typedef llvm::DenseMap<GRExprEngine::NodeTy*,std::pair<Expr*, SymbolID> >
611 ReleasesNotOwnedTy;
612
613 typedef ReleasesNotOwnedTy UseAfterReleasesTy;
614
615 typedef llvm::DenseMap<GRExprEngine::NodeTy*, std::vector<SymbolID>*>
Ted Kremenekdb863712008-04-16 22:32:20 +0000616 LeaksTy;
Ted Kremenek8dd56462008-04-18 03:39:05 +0000617
Ted Kremenekf3948042008-03-11 19:44:10 +0000618 class BindingsPrinter : public ValueState::CheckerStatePrinter {
619 public:
620 virtual void PrintCheckerState(std::ostream& Out, void* State,
621 const char* nl, const char* sep);
622 };
Ted Kremenek8dd56462008-04-18 03:39:05 +0000623
624private:
Ted Kremenekf3948042008-03-11 19:44:10 +0000625 // Instance variables.
626
Ted Kremeneke5c30122008-04-29 05:13:59 +0000627 CFRefSummaryManager Summaries;
Ted Kremenek072192b2008-04-30 23:47:44 +0000628 const bool GCEnabled;
629 const LangOptions& LOpts;
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000630 RefBFactoryTy RefBFactory;
631
Ted Kremenek73c750b2008-03-11 18:14:09 +0000632 UseAfterReleasesTy UseAfterReleases;
633 ReleasesNotOwnedTy ReleasesNotOwned;
Ted Kremenekdb863712008-04-16 22:32:20 +0000634 LeaksTy Leaks;
Ted Kremenek73c750b2008-03-11 18:14:09 +0000635
Ted Kremenekf3948042008-03-11 19:44:10 +0000636 BindingsPrinter Printer;
637
Ted Kremenek9ed18e62008-04-16 04:28:53 +0000638 Selector RetainSelector;
639 Selector ReleaseSelector;
640
Ted Kremenek8dd56462008-04-18 03:39:05 +0000641public:
642
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000643 static RefBindings GetRefBindings(ValueState& StImpl) {
644 return RefBindings((RefBindings::TreeTy*) StImpl.CheckerState);
645 }
Ted Kremenek9ed18e62008-04-16 04:28:53 +0000646
Ted Kremenek8dd56462008-04-18 03:39:05 +0000647private:
648
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000649 static void SetRefBindings(ValueState& StImpl, RefBindings B) {
650 StImpl.CheckerState = B.getRoot();
651 }
Ted Kremenek9ed18e62008-04-16 04:28:53 +0000652
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000653 RefBindings Remove(RefBindings B, SymbolID sym) {
654 return RefBFactory.Remove(B, sym);
655 }
656
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000657 RefBindings Update(RefBindings B, SymbolID sym, RefVal V, ArgEffect E,
Ted Kremenek9ed18e62008-04-16 04:28:53 +0000658 RefVal::Kind& hasErr);
659
Ted Kremenekdb863712008-04-16 22:32:20 +0000660 void ProcessNonLeakError(ExplodedNodeSet<ValueState>& Dst,
661 GRStmtNodeBuilder<ValueState>& Builder,
662 Expr* NodeExpr, Expr* ErrorExpr,
663 ExplodedNode<ValueState>* Pred,
664 ValueState* St,
Ted Kremenek8dd56462008-04-18 03:39:05 +0000665 RefVal::Kind hasErr, SymbolID Sym);
Ted Kremenekdb863712008-04-16 22:32:20 +0000666
667 ValueState* HandleSymbolDeath(ValueStateManager& VMgr, ValueState* St,
668 SymbolID sid, RefVal V, bool& hasLeak);
669
670 ValueState* NukeBinding(ValueStateManager& VMgr, ValueState* St,
671 SymbolID sid);
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000672
673public:
Ted Kremenek13922612008-04-16 20:40:59 +0000674
Ted Kremenek072192b2008-04-30 23:47:44 +0000675 CFRefCount(ASTContext& Ctx, bool gcenabled, const LangOptions& lopts)
Ted Kremenek377e2302008-04-29 05:33:51 +0000676 : Summaries(Ctx, gcenabled),
Ted Kremeneke5c30122008-04-29 05:13:59 +0000677 GCEnabled(gcenabled),
Ted Kremenek072192b2008-04-30 23:47:44 +0000678 LOpts(lopts),
Ted Kremenek9ed18e62008-04-16 04:28:53 +0000679 RetainSelector(GetUnarySelector("retain", Ctx)),
680 ReleaseSelector(GetUnarySelector("release", Ctx)) {}
681
Ted Kremenek8dd56462008-04-18 03:39:05 +0000682 virtual ~CFRefCount() {
683 for (LeaksTy::iterator I = Leaks.begin(), E = Leaks.end(); I!=E; ++I)
684 delete I->second;
685 }
Ted Kremenek05cbe1a2008-04-09 23:49:11 +0000686
687 virtual void RegisterChecks(GRExprEngine& Eng);
Ted Kremenekf3948042008-03-11 19:44:10 +0000688
689 virtual ValueState::CheckerStatePrinter* getCheckerStatePrinter() {
690 return &Printer;
691 }
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000692
Ted Kremenek072192b2008-04-30 23:47:44 +0000693 bool isGCEnabled() const { return GCEnabled; }
694 const LangOptions& getLangOptions() const { return LOpts; }
695
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000696 // Calls.
697
698 virtual void EvalCall(ExplodedNodeSet<ValueState>& Dst,
Ted Kremenek199e1a02008-03-12 21:06:49 +0000699 GRExprEngine& Eng,
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000700 GRStmtNodeBuilder<ValueState>& Builder,
Ted Kremenek186350f2008-04-23 20:12:28 +0000701 CallExpr* CE, RVal L,
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000702 ExplodedNode<ValueState>* Pred);
Ted Kremenekfa34b332008-04-09 01:10:13 +0000703
Ted Kremenek85348202008-04-15 23:44:31 +0000704 virtual void EvalObjCMessageExpr(ExplodedNodeSet<ValueState>& Dst,
705 GRExprEngine& Engine,
706 GRStmtNodeBuilder<ValueState>& Builder,
707 ObjCMessageExpr* ME,
708 ExplodedNode<ValueState>* Pred);
709
710 bool EvalObjCMessageExprAux(ExplodedNodeSet<ValueState>& Dst,
711 GRExprEngine& Engine,
712 GRStmtNodeBuilder<ValueState>& Builder,
713 ObjCMessageExpr* ME,
714 ExplodedNode<ValueState>* Pred);
715
Ted Kremenek13922612008-04-16 20:40:59 +0000716 // Stores.
717
718 virtual void EvalStore(ExplodedNodeSet<ValueState>& Dst,
719 GRExprEngine& Engine,
720 GRStmtNodeBuilder<ValueState>& Builder,
721 Expr* E, ExplodedNode<ValueState>* Pred,
722 ValueState* St, RVal TargetLV, RVal Val);
Ted Kremeneke7bd9c22008-04-11 22:25:11 +0000723 // End-of-path.
724
725 virtual void EvalEndPath(GRExprEngine& Engine,
726 GREndPathNodeBuilder<ValueState>& Builder);
727
Ted Kremenek652adc62008-04-24 23:57:27 +0000728 virtual void EvalDeadSymbols(ExplodedNodeSet<ValueState>& Dst,
729 GRExprEngine& Engine,
730 GRStmtNodeBuilder<ValueState>& Builder,
Ted Kremenek910e9992008-04-25 01:25:15 +0000731 ExplodedNode<ValueState>* Pred,
732 Stmt* S,
Ted Kremenek652adc62008-04-24 23:57:27 +0000733 ValueState* St,
734 const ValueStateManager::DeadSymbolsTy& Dead);
Ted Kremenek4fd88972008-04-17 18:12:53 +0000735 // Return statements.
736
737 virtual void EvalReturn(ExplodedNodeSet<ValueState>& Dst,
738 GRExprEngine& Engine,
739 GRStmtNodeBuilder<ValueState>& Builder,
740 ReturnStmt* S,
741 ExplodedNode<ValueState>* Pred);
Ted Kremenekcb612922008-04-18 19:23:43 +0000742
743 // Assumptions.
744
745 virtual ValueState* EvalAssume(GRExprEngine& Engine, ValueState* St,
746 RVal Cond, bool Assumption, bool& isFeasible);
747
Ted Kremenekfa34b332008-04-09 01:10:13 +0000748 // Error iterators.
749
750 typedef UseAfterReleasesTy::iterator use_after_iterator;
751 typedef ReleasesNotOwnedTy::iterator bad_release_iterator;
Ted Kremenek989d5192008-04-17 23:43:50 +0000752 typedef LeaksTy::iterator leaks_iterator;
Ted Kremenekfa34b332008-04-09 01:10:13 +0000753
Ted Kremenek05cbe1a2008-04-09 23:49:11 +0000754 use_after_iterator use_after_begin() { return UseAfterReleases.begin(); }
755 use_after_iterator use_after_end() { return UseAfterReleases.end(); }
Ted Kremenekfa34b332008-04-09 01:10:13 +0000756
Ted Kremenek05cbe1a2008-04-09 23:49:11 +0000757 bad_release_iterator bad_release_begin() { return ReleasesNotOwned.begin(); }
758 bad_release_iterator bad_release_end() { return ReleasesNotOwned.end(); }
Ted Kremenek989d5192008-04-17 23:43:50 +0000759
760 leaks_iterator leaks_begin() { return Leaks.begin(); }
761 leaks_iterator leaks_end() { return Leaks.end(); }
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000762};
763
764} // end anonymous namespace
765
Ted Kremenek8dd56462008-04-18 03:39:05 +0000766
Ted Kremenek05cbe1a2008-04-09 23:49:11 +0000767
768
Ted Kremenekf3948042008-03-11 19:44:10 +0000769void CFRefCount::BindingsPrinter::PrintCheckerState(std::ostream& Out,
770 void* State, const char* nl,
771 const char* sep) {
772 RefBindings B((RefBindings::TreeTy*) State);
773
774 if (State)
775 Out << sep << nl;
776
777 for (RefBindings::iterator I=B.begin(), E=B.end(); I!=E; ++I) {
778 Out << (*I).first << " : ";
779 (*I).second.print(Out);
780 Out << nl;
781 }
782}
783
Ted Kremenekf9561e52008-04-11 20:23:24 +0000784static inline ArgEffect GetArgE(CFRefSummary* Summ, unsigned idx) {
785 return Summ ? Summ->getArg(idx) : DoNothing;
786}
787
788static inline RetEffect GetRetE(CFRefSummary* Summ) {
789 return Summ ? Summ->getRet() : RetEffect::MakeNoRet();
790}
791
Ted Kremenekdb863712008-04-16 22:32:20 +0000792void CFRefCount::ProcessNonLeakError(ExplodedNodeSet<ValueState>& Dst,
793 GRStmtNodeBuilder<ValueState>& Builder,
794 Expr* NodeExpr, Expr* ErrorExpr,
795 ExplodedNode<ValueState>* Pred,
796 ValueState* St,
Ted Kremenek8dd56462008-04-18 03:39:05 +0000797 RefVal::Kind hasErr, SymbolID Sym) {
Ted Kremenek9ed18e62008-04-16 04:28:53 +0000798 Builder.BuildSinks = true;
799 GRExprEngine::NodeTy* N = Builder.MakeNode(Dst, NodeExpr, Pred, St);
800
801 if (!N) return;
802
803 switch (hasErr) {
804 default: assert(false);
805 case RefVal::ErrorUseAfterRelease:
Ted Kremenek8dd56462008-04-18 03:39:05 +0000806 UseAfterReleases[N] = std::make_pair(ErrorExpr, Sym);
Ted Kremenek9ed18e62008-04-16 04:28:53 +0000807 break;
808
809 case RefVal::ErrorReleaseNotOwned:
Ted Kremenek8dd56462008-04-18 03:39:05 +0000810 ReleasesNotOwned[N] = std::make_pair(ErrorExpr, Sym);
Ted Kremenek9ed18e62008-04-16 04:28:53 +0000811 break;
812 }
813}
814
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000815void CFRefCount::EvalCall(ExplodedNodeSet<ValueState>& Dst,
Ted Kremenek199e1a02008-03-12 21:06:49 +0000816 GRExprEngine& Eng,
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000817 GRStmtNodeBuilder<ValueState>& Builder,
Ted Kremenek186350f2008-04-23 20:12:28 +0000818 CallExpr* CE, RVal L,
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000819 ExplodedNode<ValueState>* Pred) {
820
Ted Kremenek199e1a02008-03-12 21:06:49 +0000821 ValueStateManager& StateMgr = Eng.getStateManager();
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000822
Ted Kremenek7ded73c2008-04-14 17:45:13 +0000823 CFRefSummary* Summ = NULL;
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000824
825 // Get the summary.
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000826
Ted Kremenek7ded73c2008-04-14 17:45:13 +0000827 if (isa<lval::FuncVal>(L)) {
828 lval::FuncVal FV = cast<lval::FuncVal>(L);
829 FunctionDecl* FD = FV.getDecl();
830 Summ = Summaries.getSummary(FD, Eng.getContext());
831 }
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000832
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000833 // Get the state.
834
835 ValueState* St = Builder.GetState(Pred);
836
837 // Evaluate the effects of the call.
838
839 ValueState StVals = *St;
Ted Kremenek9ed18e62008-04-16 04:28:53 +0000840 RefVal::Kind hasErr = (RefVal::Kind) 0;
Ted Kremenekf9561e52008-04-11 20:23:24 +0000841
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000842 // This function has a summary. Evaluate the effect of the arguments.
843
844 unsigned idx = 0;
845
Ted Kremenekbcf50ad2008-04-11 18:40:51 +0000846 Expr* ErrorExpr = NULL;
Ted Kremenek8dd56462008-04-18 03:39:05 +0000847 SymbolID ErrorSym = 0;
Ted Kremenekbcf50ad2008-04-11 18:40:51 +0000848
849 for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end();
850 I != E; ++I, ++idx) {
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000851
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000852 RVal V = StateMgr.GetRVal(St, *I);
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000853
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000854 if (isa<lval::SymbolVal>(V)) {
855 SymbolID Sym = cast<lval::SymbolVal>(V).getSymbol();
Ted Kremenekf9561e52008-04-11 20:23:24 +0000856 RefBindings B = GetRefBindings(StVals);
857
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000858 if (RefBindings::TreeTy* T = B.SlimFind(Sym)) {
Ted Kremenek9ed18e62008-04-16 04:28:53 +0000859 B = Update(B, Sym, T->getValue().second, GetArgE(Summ, idx), hasErr);
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000860 SetRefBindings(StVals, B);
Ted Kremenekbcf50ad2008-04-11 18:40:51 +0000861
Ted Kremenek9ed18e62008-04-16 04:28:53 +0000862 if (hasErr) {
Ted Kremenekbcf50ad2008-04-11 18:40:51 +0000863 ErrorExpr = *I;
Ted Kremenek8dd56462008-04-18 03:39:05 +0000864 ErrorSym = T->getValue().first;
Ted Kremenekbcf50ad2008-04-11 18:40:51 +0000865 break;
866 }
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000867 }
Ted Kremenekb8873552008-04-11 20:51:02 +0000868 }
869 else if (isa<LVal>(V)) { // Nuke all arguments passed by reference.
870
871 // FIXME: This is basically copy-and-paste from GRSimpleVals. We
872 // should compose behavior, not copy it.
Ted Kremenekf9561e52008-04-11 20:23:24 +0000873 StateMgr.Unbind(StVals, cast<LVal>(V));
Ted Kremenekb8873552008-04-11 20:51:02 +0000874 }
Ted Kremeneka5488462008-04-22 21:39:21 +0000875 else if (isa<nonlval::LValAsInteger>(V))
876 StateMgr.Unbind(StVals, cast<nonlval::LValAsInteger>(V).getLVal());
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000877 }
Ted Kremenek9ed18e62008-04-16 04:28:53 +0000878
879 St = StateMgr.getPersistentState(StVals);
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000880
Ted Kremenek9ed18e62008-04-16 04:28:53 +0000881 if (hasErr) {
Ted Kremenek8dd56462008-04-18 03:39:05 +0000882 ProcessNonLeakError(Dst, Builder, CE, ErrorExpr, Pred, St,
883 hasErr, ErrorSym);
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000884 return;
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000885 }
Ted Kremenek9ed18e62008-04-16 04:28:53 +0000886
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000887 // Finally, consult the summary for the return value.
888
Ted Kremenekf9561e52008-04-11 20:23:24 +0000889 RetEffect RE = GetRetE(Summ);
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000890
891 switch (RE.getKind()) {
892 default:
893 assert (false && "Unhandled RetEffect."); break;
894
Ted Kremenek940b1d82008-04-10 23:44:06 +0000895 case RetEffect::NoRet:
Ted Kremenekf9561e52008-04-11 20:23:24 +0000896
897 // Make up a symbol for the return value (not reference counted).
Ted Kremenekb8873552008-04-11 20:51:02 +0000898 // FIXME: This is basically copy-and-paste from GRSimpleVals. We
899 // should compose behavior, not copy it.
Ted Kremenekf9561e52008-04-11 20:23:24 +0000900
901 if (CE->getType() != Eng.getContext().VoidTy) {
902 unsigned Count = Builder.getCurrentBlockCount();
903 SymbolID Sym = Eng.getSymbolManager().getConjuredSymbol(CE, Count);
904
905 RVal X = CE->getType()->isPointerType()
906 ? cast<RVal>(lval::SymbolVal(Sym))
907 : cast<RVal>(nonlval::SymbolVal(Sym));
908
909 St = StateMgr.SetRVal(St, CE, X, Eng.getCFG().isBlkExpr(CE), false);
910 }
911
Ted Kremenek940b1d82008-04-10 23:44:06 +0000912 break;
913
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000914 case RetEffect::Alias: {
915 unsigned idx = RE.getValue();
916 assert (idx < CE->getNumArgs());
917 RVal V = StateMgr.GetRVal(St, CE->getArg(idx));
Ted Kremenek199e1a02008-03-12 21:06:49 +0000918 St = StateMgr.SetRVal(St, CE, V, Eng.getCFG().isBlkExpr(CE), false);
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000919 break;
920 }
921
922 case RetEffect::OwnedSymbol: {
923 unsigned Count = Builder.getCurrentBlockCount();
Ted Kremenek361fa8e2008-03-12 21:45:47 +0000924 SymbolID Sym = Eng.getSymbolManager().getConjuredSymbol(CE, Count);
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000925
926 ValueState StImpl = *St;
927 RefBindings B = GetRefBindings(StImpl);
Ted Kremenek61b9f872008-04-10 23:09:18 +0000928 SetRefBindings(StImpl, RefBFactory.Add(B, Sym, RefVal::makeOwned()));
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000929
930 St = StateMgr.SetRVal(StateMgr.getPersistentState(StImpl),
931 CE, lval::SymbolVal(Sym),
Ted Kremenek199e1a02008-03-12 21:06:49 +0000932 Eng.getCFG().isBlkExpr(CE), false);
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000933
934 break;
935 }
936
937 case RetEffect::NotOwnedSymbol: {
938 unsigned Count = Builder.getCurrentBlockCount();
Ted Kremenek361fa8e2008-03-12 21:45:47 +0000939 SymbolID Sym = Eng.getSymbolManager().getConjuredSymbol(CE, Count);
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000940
941 ValueState StImpl = *St;
942 RefBindings B = GetRefBindings(StImpl);
943 SetRefBindings(StImpl, RefBFactory.Add(B, Sym, RefVal::makeNotOwned()));
944
945 St = StateMgr.SetRVal(StateMgr.getPersistentState(StImpl),
946 CE, lval::SymbolVal(Sym),
Ted Kremenek199e1a02008-03-12 21:06:49 +0000947 Eng.getCFG().isBlkExpr(CE), false);
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000948
949 break;
950 }
951 }
952
Ted Kremenek0e561a32008-03-21 21:30:14 +0000953 Builder.MakeNode(Dst, CE, Pred, St);
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000954}
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000955
Ted Kremenek85348202008-04-15 23:44:31 +0000956
957void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet<ValueState>& Dst,
958 GRExprEngine& Eng,
959 GRStmtNodeBuilder<ValueState>& Builder,
960 ObjCMessageExpr* ME,
961 ExplodedNode<ValueState>* Pred) {
962
963 if (EvalObjCMessageExprAux(Dst, Eng, Builder, ME, Pred))
964 GRSimpleVals::EvalObjCMessageExpr(Dst, Eng, Builder, ME, Pred);
965}
966
967bool CFRefCount::EvalObjCMessageExprAux(ExplodedNodeSet<ValueState>& Dst,
968 GRExprEngine& Eng,
969 GRStmtNodeBuilder<ValueState>& Builder,
970 ObjCMessageExpr* ME,
971 ExplodedNode<ValueState>* Pred) {
Ted Kremenek377e2302008-04-29 05:33:51 +0000972
973 if (GCEnabled)
974 return true;
975
Ted Kremenek9ed18e62008-04-16 04:28:53 +0000976 // Handle "toll-free bridging" of calls to "Release" and "Retain".
977
978 // FIXME: track the underlying object type associated so that we can
979 // flag illegal uses of toll-free bridging (or at least handle it
980 // at casts).
Ted Kremenek85348202008-04-15 23:44:31 +0000981
982 Selector S = ME->getSelector();
983
984 if (!S.isUnarySelector())
985 return true;
986
Ted Kremenek9ed18e62008-04-16 04:28:53 +0000987 Expr* Receiver = ME->getReceiver();
988
989 if (!Receiver)
990 return true;
991
992 // Check if we are calling "Retain" or "Release".
993
994 bool isRetain = false;
995
996 if (S == RetainSelector)
997 isRetain = true;
998 else if (S != ReleaseSelector)
999 return true;
1000
1001 // We have "Retain" or "Release". Get the reference binding.
1002
1003 ValueStateManager& StateMgr = Eng.getStateManager();
1004 ValueState* St = Builder.GetState(Pred);
1005 RVal V = StateMgr.GetRVal(St, Receiver);
1006
1007 if (!isa<lval::SymbolVal>(V))
1008 return true;
1009
1010 SymbolID Sym = cast<lval::SymbolVal>(V).getSymbol();
1011 RefBindings B = GetRefBindings(*St);
1012
1013 RefBindings::TreeTy* T = B.SlimFind(Sym);
1014
1015 if (!T)
1016 return true;
1017
1018 RefVal::Kind hasErr = (RefVal::Kind) 0;
1019 B = Update(B, Sym, T->getValue().second, isRetain ? IncRef : DecRef, hasErr);
1020
1021 // Create a new state with the updated bindings.
1022
1023 ValueState StVals = *St;
1024 SetRefBindings(StVals, B);
1025 St = StateMgr.getPersistentState(StVals);
1026
1027 // Create an error node if it exists.
1028
1029 if (hasErr)
Ted Kremenek8dd56462008-04-18 03:39:05 +00001030 ProcessNonLeakError(Dst, Builder, ME, Receiver, Pred, St, hasErr, Sym);
Ted Kremenek9ed18e62008-04-16 04:28:53 +00001031 else
1032 Builder.MakeNode(Dst, ME, Pred, St);
1033
1034 return false;
Ted Kremenek85348202008-04-15 23:44:31 +00001035}
1036
Ted Kremenek13922612008-04-16 20:40:59 +00001037// Stores.
1038
1039void CFRefCount::EvalStore(ExplodedNodeSet<ValueState>& Dst,
1040 GRExprEngine& Eng,
1041 GRStmtNodeBuilder<ValueState>& Builder,
1042 Expr* E, ExplodedNode<ValueState>* Pred,
1043 ValueState* St, RVal TargetLV, RVal Val) {
1044
1045 // Check if we have a binding for "Val" and if we are storing it to something
1046 // we don't understand or otherwise the value "escapes" the function.
1047
1048 if (!isa<lval::SymbolVal>(Val))
1049 return;
1050
1051 // Are we storing to something that causes the value to "escape"?
1052
1053 bool escapes = false;
1054
1055 if (!isa<lval::DeclVal>(TargetLV))
1056 escapes = true;
1057 else
1058 escapes = cast<lval::DeclVal>(TargetLV).getDecl()->hasGlobalStorage();
1059
1060 if (!escapes)
1061 return;
1062
1063 SymbolID Sym = cast<lval::SymbolVal>(Val).getSymbol();
1064 RefBindings B = GetRefBindings(*St);
1065 RefBindings::TreeTy* T = B.SlimFind(Sym);
1066
1067 if (!T)
1068 return;
1069
Ted Kremenekdb863712008-04-16 22:32:20 +00001070 // Nuke the binding.
1071 St = NukeBinding(Eng.getStateManager(), St, Sym);
Ted Kremenek13922612008-04-16 20:40:59 +00001072
1073 // Hand of the remaining logic to the parent implementation.
1074 GRSimpleVals::EvalStore(Dst, Eng, Builder, E, Pred, St, TargetLV, Val);
1075}
1076
Ted Kremenekdb863712008-04-16 22:32:20 +00001077
1078ValueState* CFRefCount::NukeBinding(ValueStateManager& VMgr, ValueState* St,
1079 SymbolID sid) {
1080 ValueState StImpl = *St;
1081 RefBindings B = GetRefBindings(StImpl);
1082 StImpl.CheckerState = RefBFactory.Remove(B, sid).getRoot();
1083 return VMgr.getPersistentState(StImpl);
1084}
1085
Ted Kremeneke7bd9c22008-04-11 22:25:11 +00001086// End-of-path.
1087
Ted Kremenekdb863712008-04-16 22:32:20 +00001088ValueState* CFRefCount::HandleSymbolDeath(ValueStateManager& VMgr,
1089 ValueState* St, SymbolID sid,
1090 RefVal V, bool& hasLeak) {
1091
Ted Kremenek4fd88972008-04-17 18:12:53 +00001092 hasLeak = V.isOwned() ||
1093 ((V.isNotOwned() || V.isReturnedOwned()) && V.getCount() > 0);
Ted Kremenekdb863712008-04-16 22:32:20 +00001094
1095 if (!hasLeak)
1096 return NukeBinding(VMgr, St, sid);
1097
1098 RefBindings B = GetRefBindings(*St);
1099 ValueState StImpl = *St;
1100 StImpl.CheckerState = RefBFactory.Add(B, sid, RefVal::makeLeak()).getRoot();
1101 return VMgr.getPersistentState(StImpl);
1102}
1103
1104void CFRefCount::EvalEndPath(GRExprEngine& Eng,
Ted Kremeneke7bd9c22008-04-11 22:25:11 +00001105 GREndPathNodeBuilder<ValueState>& Builder) {
1106
Ted Kremenekdb863712008-04-16 22:32:20 +00001107 ValueState* St = Builder.getState();
1108 RefBindings B = GetRefBindings(*St);
Ted Kremeneke7bd9c22008-04-11 22:25:11 +00001109
Ted Kremenekdb863712008-04-16 22:32:20 +00001110 llvm::SmallVector<SymbolID, 10> Leaked;
Ted Kremeneke7bd9c22008-04-11 22:25:11 +00001111
Ted Kremenekdb863712008-04-16 22:32:20 +00001112 for (RefBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) {
1113 bool hasLeak = false;
Ted Kremeneke7bd9c22008-04-11 22:25:11 +00001114
Ted Kremenekdb863712008-04-16 22:32:20 +00001115 St = HandleSymbolDeath(Eng.getStateManager(), St,
1116 (*I).first, (*I).second, hasLeak);
1117
1118 if (hasLeak) Leaked.push_back((*I).first);
1119 }
Ted Kremenek652adc62008-04-24 23:57:27 +00001120
1121 if (Leaked.empty())
1122 return;
1123
Ted Kremenek8dd56462008-04-18 03:39:05 +00001124 ExplodedNode<ValueState>* N = Builder.MakeNode(St);
Ted Kremenek4f285152008-04-18 16:30:14 +00001125
Ted Kremenek652adc62008-04-24 23:57:27 +00001126 if (!N)
Ted Kremenek4f285152008-04-18 16:30:14 +00001127 return;
Ted Kremenekcb612922008-04-18 19:23:43 +00001128
Ted Kremenek8dd56462008-04-18 03:39:05 +00001129 std::vector<SymbolID>*& LeaksAtNode = Leaks[N];
1130 assert (!LeaksAtNode);
1131 LeaksAtNode = new std::vector<SymbolID>();
Ted Kremenekdb863712008-04-16 22:32:20 +00001132
1133 for (llvm::SmallVector<SymbolID, 10>::iterator I=Leaked.begin(),
1134 E = Leaked.end(); I != E; ++I)
Ted Kremenek8dd56462008-04-18 03:39:05 +00001135 (*LeaksAtNode).push_back(*I);
Ted Kremeneke7bd9c22008-04-11 22:25:11 +00001136}
1137
Ted Kremenek652adc62008-04-24 23:57:27 +00001138// Dead symbols.
1139
1140void CFRefCount::EvalDeadSymbols(ExplodedNodeSet<ValueState>& Dst,
1141 GRExprEngine& Eng,
1142 GRStmtNodeBuilder<ValueState>& Builder,
Ted Kremenek910e9992008-04-25 01:25:15 +00001143 ExplodedNode<ValueState>* Pred,
1144 Stmt* S,
Ted Kremenek652adc62008-04-24 23:57:27 +00001145 ValueState* St,
1146 const ValueStateManager::DeadSymbolsTy& Dead) {
Ted Kremenek910e9992008-04-25 01:25:15 +00001147
Ted Kremenek652adc62008-04-24 23:57:27 +00001148 // FIXME: a lot of copy-and-paste from EvalEndPath. Refactor.
1149
1150 RefBindings B = GetRefBindings(*St);
1151 llvm::SmallVector<SymbolID, 10> Leaked;
1152
1153 for (ValueStateManager::DeadSymbolsTy::const_iterator
1154 I=Dead.begin(), E=Dead.end(); I!=E; ++I) {
1155
1156 RefBindings::TreeTy* T = B.SlimFind(*I);
1157
1158 if (!T)
1159 continue;
1160
1161 bool hasLeak = false;
1162
1163 St = HandleSymbolDeath(Eng.getStateManager(), St,
1164 *I, T->getValue().second, hasLeak);
1165
1166 if (hasLeak) Leaked.push_back(*I);
1167 }
1168
1169 if (Leaked.empty())
1170 return;
1171
1172 ExplodedNode<ValueState>* N = Builder.MakeNode(Dst, S, Pred, St);
1173
1174 if (!N)
1175 return;
1176
1177 std::vector<SymbolID>*& LeaksAtNode = Leaks[N];
1178 assert (!LeaksAtNode);
1179 LeaksAtNode = new std::vector<SymbolID>();
1180
1181 for (llvm::SmallVector<SymbolID, 10>::iterator I=Leaked.begin(),
1182 E = Leaked.end(); I != E; ++I)
1183 (*LeaksAtNode).push_back(*I);
1184}
1185
Ted Kremenek4fd88972008-04-17 18:12:53 +00001186 // Return statements.
1187
1188void CFRefCount::EvalReturn(ExplodedNodeSet<ValueState>& Dst,
1189 GRExprEngine& Eng,
1190 GRStmtNodeBuilder<ValueState>& Builder,
1191 ReturnStmt* S,
1192 ExplodedNode<ValueState>* Pred) {
1193
1194 Expr* RetE = S->getRetValue();
1195 if (!RetE) return;
1196
1197 ValueStateManager& StateMgr = Eng.getStateManager();
1198 ValueState* St = Builder.GetState(Pred);
1199 RVal V = StateMgr.GetRVal(St, RetE);
1200
1201 if (!isa<lval::SymbolVal>(V))
1202 return;
1203
1204 // Get the reference count binding (if any).
1205 SymbolID Sym = cast<lval::SymbolVal>(V).getSymbol();
1206 RefBindings B = GetRefBindings(*St);
1207 RefBindings::TreeTy* T = B.SlimFind(Sym);
1208
1209 if (!T)
1210 return;
1211
1212 // Change the reference count.
1213
1214 RefVal X = T->getValue().second;
1215
1216 switch (X.getKind()) {
1217
1218 case RefVal::Owned: {
1219 unsigned cnt = X.getCount();
1220 X = RefVal::makeReturnedOwned(cnt);
1221 break;
1222 }
1223
1224 case RefVal::NotOwned: {
1225 unsigned cnt = X.getCount();
1226 X = cnt ? RefVal::makeReturnedOwned(cnt - 1)
1227 : RefVal::makeReturnedNotOwned();
1228 break;
1229 }
1230
1231 default:
1232 // None of the error states should be possible at this point.
1233 // A symbol could not have been leaked (yet) if we are returning it
1234 // (and thus it is still live), and the other errors are hard errors.
1235 assert(false);
1236 return;
1237 }
1238
1239 // Update the binding.
1240
1241 ValueState StImpl = *St;
1242 StImpl.CheckerState = RefBFactory.Add(B, Sym, X).getRoot();
1243 Builder.MakeNode(Dst, S, Pred, StateMgr.getPersistentState(StImpl));
1244}
1245
Ted Kremenekcb612922008-04-18 19:23:43 +00001246// Assumptions.
1247
1248ValueState* CFRefCount::EvalAssume(GRExprEngine& Eng, ValueState* St,
1249 RVal Cond, bool Assumption,
1250 bool& isFeasible) {
1251
1252 // FIXME: We may add to the interface of EvalAssume the list of symbols
1253 // whose assumptions have changed. For now we just iterate through the
1254 // bindings and check if any of the tracked symbols are NULL. This isn't
1255 // too bad since the number of symbols we will track in practice are
1256 // probably small and EvalAssume is only called at branches and a few
1257 // other places.
1258
1259 RefBindings B = GetRefBindings(*St);
1260
1261 if (B.isEmpty())
1262 return St;
1263
1264 bool changed = false;
1265
1266 for (RefBindings::iterator I=B.begin(), E=B.end(); I!=E; ++I) {
1267
1268 // Check if the symbol is null (or equal to any constant).
1269 // If this is the case, stop tracking the symbol.
1270
1271 if (St->getSymVal(I.getKey())) {
1272 changed = true;
1273 B = RefBFactory.Remove(B, I.getKey());
1274 }
1275 }
1276
1277 if (!changed)
1278 return St;
1279
1280 ValueState StImpl = *St;
1281 StImpl.CheckerState = B.getRoot();
1282 return Eng.getStateManager().getPersistentState(StImpl);
1283}
Ted Kremenek6b3a0f72008-03-11 06:39:11 +00001284
1285CFRefCount::RefBindings CFRefCount::Update(RefBindings B, SymbolID sym,
Ted Kremenek1ac08d62008-03-11 17:48:22 +00001286 RefVal V, ArgEffect E,
Ted Kremenek9ed18e62008-04-16 04:28:53 +00001287 RefVal::Kind& hasErr) {
Ted Kremenek6b3a0f72008-03-11 06:39:11 +00001288
Ted Kremenek1ac08d62008-03-11 17:48:22 +00001289 // FIXME: This dispatch can potentially be sped up by unifiying it into
1290 // a single switch statement. Opt for simplicity for now.
Ted Kremenek6b3a0f72008-03-11 06:39:11 +00001291
Ted Kremenek1ac08d62008-03-11 17:48:22 +00001292 switch (E) {
1293 default:
1294 assert (false && "Unhandled CFRef transition.");
1295
1296 case DoNothing:
Ted Kremenek65c91652008-04-29 05:44:10 +00001297 if (!GCEnabled && V.getKind() == RefVal::Released) {
Ted Kremenek00a3a5f2008-03-12 01:21:45 +00001298 V = RefVal::makeUseAfterRelease();
Ted Kremenek9ed18e62008-04-16 04:28:53 +00001299 hasErr = V.getKind();
Ted Kremenek00a3a5f2008-03-12 01:21:45 +00001300 break;
1301 }
1302
Ted Kremenek1ac08d62008-03-11 17:48:22 +00001303 return B;
1304
1305 case IncRef:
1306 switch (V.getKind()) {
1307 default:
1308 assert(false);
1309
1310 case RefVal::Owned:
Ted Kremenek940b1d82008-04-10 23:44:06 +00001311 V = RefVal::makeOwned(V.getCount()+1);
1312 break;
Ted Kremenek61b9f872008-04-10 23:09:18 +00001313
Ted Kremenek1ac08d62008-03-11 17:48:22 +00001314 case RefVal::NotOwned:
Ted Kremenek61b9f872008-04-10 23:09:18 +00001315 V = RefVal::makeNotOwned(V.getCount()+1);
Ted Kremenek1ac08d62008-03-11 17:48:22 +00001316 break;
1317
1318 case RefVal::Released:
Ted Kremenek65c91652008-04-29 05:44:10 +00001319 if (GCEnabled)
1320 V = RefVal::makeOwned();
1321 else {
1322 V = RefVal::makeUseAfterRelease();
1323 hasErr = V.getKind();
1324 }
1325
Ted Kremenek1ac08d62008-03-11 17:48:22 +00001326 break;
1327 }
1328
Ted Kremenek940b1d82008-04-10 23:44:06 +00001329 break;
1330
Ted Kremenek1ac08d62008-03-11 17:48:22 +00001331 case DecRef:
1332 switch (V.getKind()) {
1333 default:
1334 assert (false);
1335
1336 case RefVal::Owned: {
Ted Kremenek4fd88972008-04-17 18:12:53 +00001337 unsigned Count = V.getCount();
1338 V = Count > 0 ? RefVal::makeOwned(Count - 1) : RefVal::makeReleased();
Ted Kremenek1ac08d62008-03-11 17:48:22 +00001339 break;
1340 }
1341
Ted Kremenek61b9f872008-04-10 23:09:18 +00001342 case RefVal::NotOwned: {
Ted Kremenek4fd88972008-04-17 18:12:53 +00001343 unsigned Count = V.getCount();
Ted Kremenek61b9f872008-04-10 23:09:18 +00001344
Ted Kremenek4fd88972008-04-17 18:12:53 +00001345 if (Count > 0)
1346 V = RefVal::makeNotOwned(Count - 1);
Ted Kremenek61b9f872008-04-10 23:09:18 +00001347 else {
1348 V = RefVal::makeReleaseNotOwned();
Ted Kremenek9ed18e62008-04-16 04:28:53 +00001349 hasErr = V.getKind();
Ted Kremenek61b9f872008-04-10 23:09:18 +00001350 }
1351
Ted Kremenek1ac08d62008-03-11 17:48:22 +00001352 break;
1353 }
Ted Kremenek1ac08d62008-03-11 17:48:22 +00001354
1355 case RefVal::Released:
Ted Kremenek1ac08d62008-03-11 17:48:22 +00001356 V = RefVal::makeUseAfterRelease();
Ted Kremenek9ed18e62008-04-16 04:28:53 +00001357 hasErr = V.getKind();
Ted Kremenek1ac08d62008-03-11 17:48:22 +00001358 break;
1359 }
Ted Kremenek940b1d82008-04-10 23:44:06 +00001360
1361 break;
Ted Kremenek1ac08d62008-03-11 17:48:22 +00001362 }
1363
1364 return RefBFactory.Add(B, sym, V);
Ted Kremenek6b3a0f72008-03-11 06:39:11 +00001365}
1366
Ted Kremenekfa34b332008-04-09 01:10:13 +00001367
1368//===----------------------------------------------------------------------===//
Ted Kremenek05cbe1a2008-04-09 23:49:11 +00001369// Error reporting.
Ted Kremenekfa34b332008-04-09 01:10:13 +00001370//===----------------------------------------------------------------------===//
1371
Ted Kremenek8dd56462008-04-18 03:39:05 +00001372namespace {
1373
1374 //===-------------===//
1375 // Bug Descriptions. //
1376 //===-------------===//
1377
Ted Kremenek95cc1ba2008-04-18 20:54:29 +00001378 class VISIBILITY_HIDDEN CFRefBug : public BugTypeCacheLocation {
Ted Kremenek8dd56462008-04-18 03:39:05 +00001379 protected:
1380 CFRefCount& TF;
1381
1382 public:
1383 CFRefBug(CFRefCount& tf) : TF(tf) {}
Ted Kremenek072192b2008-04-30 23:47:44 +00001384
1385 CFRefCount& getTF() { return TF; }
Ted Kremenek8dd56462008-04-18 03:39:05 +00001386 };
1387
1388 class VISIBILITY_HIDDEN UseAfterRelease : public CFRefBug {
1389 public:
1390 UseAfterRelease(CFRefCount& tf) : CFRefBug(tf) {}
1391
1392 virtual const char* getName() const {
Ted Kremenek2cf943a2008-04-18 04:55:01 +00001393 return "Core Foundation: Use-After-Release";
Ted Kremenek8dd56462008-04-18 03:39:05 +00001394 }
1395 virtual const char* getDescription() const {
Ted Kremenek2cf943a2008-04-18 04:55:01 +00001396 return "Reference-counted object is used"
1397 " after it is released.";
Ted Kremenek8dd56462008-04-18 03:39:05 +00001398 }
1399
1400 virtual void EmitWarnings(BugReporter& BR);
Ted Kremenek8dd56462008-04-18 03:39:05 +00001401 };
1402
1403 class VISIBILITY_HIDDEN BadRelease : public CFRefBug {
1404 public:
1405 BadRelease(CFRefCount& tf) : CFRefBug(tf) {}
1406
1407 virtual const char* getName() const {
Ted Kremenek2cf943a2008-04-18 04:55:01 +00001408 return "Core Foundation: Release of non-owned object";
Ted Kremenek8dd56462008-04-18 03:39:05 +00001409 }
1410 virtual const char* getDescription() const {
1411 return "Incorrect decrement of the reference count of a "
Ted Kremenek2cf943a2008-04-18 04:55:01 +00001412 "CoreFoundation object: "
Ted Kremenek8dd56462008-04-18 03:39:05 +00001413 "The object is not owned at this point by the caller.";
1414 }
1415
1416 virtual void EmitWarnings(BugReporter& BR);
1417 };
1418
1419 class VISIBILITY_HIDDEN Leak : public CFRefBug {
1420 public:
1421 Leak(CFRefCount& tf) : CFRefBug(tf) {}
1422
1423 virtual const char* getName() const {
Ted Kremenek2cf943a2008-04-18 04:55:01 +00001424 return "Core Foundation: Memory Leak";
Ted Kremenek8dd56462008-04-18 03:39:05 +00001425 }
1426
1427 virtual const char* getDescription() const {
Ted Kremenek2cf943a2008-04-18 04:55:01 +00001428 return "Object leaked.";
Ted Kremenek8dd56462008-04-18 03:39:05 +00001429 }
1430
1431 virtual void EmitWarnings(BugReporter& BR);
Ted Kremenekcb612922008-04-18 19:23:43 +00001432 virtual void GetErrorNodes(std::vector<ExplodedNode<ValueState>*>& Nodes);
Ted Kremenek8dd56462008-04-18 03:39:05 +00001433 };
1434
1435 //===---------===//
1436 // Bug Reports. //
1437 //===---------===//
1438
1439 class VISIBILITY_HIDDEN CFRefReport : public RangedBugReport {
1440 SymbolID Sym;
1441 public:
Ted Kremenek072192b2008-04-30 23:47:44 +00001442 CFRefReport(CFRefBug& D, ExplodedNode<ValueState> *n, SymbolID sym)
Ted Kremenek8dd56462008-04-18 03:39:05 +00001443 : RangedBugReport(D, n), Sym(sym) {}
1444
1445 virtual ~CFRefReport() {}
1446
Ted Kremenek072192b2008-04-30 23:47:44 +00001447 virtual std::pair<const char**,const char**> getExtraDescriptiveText();
Ted Kremenek8dd56462008-04-18 03:39:05 +00001448
1449 virtual PathDiagnosticPiece* VisitNode(ExplodedNode<ValueState>* N,
1450 ExplodedNode<ValueState>* PrevN,
1451 ExplodedGraph<ValueState>& G,
1452 BugReporter& BR);
1453 };
1454
1455
1456} // end anonymous namespace
1457
1458void CFRefCount::RegisterChecks(GRExprEngine& Eng) {
1459 GRSimpleVals::RegisterChecks(Eng);
1460 Eng.Register(new UseAfterRelease(*this));
1461 Eng.Register(new BadRelease(*this));
1462 Eng.Register(new Leak(*this));
1463}
1464
Ted Kremenek072192b2008-04-30 23:47:44 +00001465
1466static const char* Msgs[] = {
1467 "Code is compiled in garbage collection only mode" // GC only
1468 " (the bug occurs with garbage collection enabled).",
1469
1470 "Code is compiled without garbage collection.", // No GC.
1471
1472 "Code is compiled for use with and without garbage collection (GC)."
1473 " The bug occurs with GC enabled.", // Hybrid, with GC.
1474
1475 "Code is compiled for use with and without garbage collection (GC)."
1476 " The bug occurs in non-GC mode." // Hyrbird, without GC/
1477};
1478
1479std::pair<const char**,const char**> CFRefReport::getExtraDescriptiveText() {
1480 CFRefCount& TF = static_cast<CFRefBug&>(getBugType()).getTF();
1481
1482 switch (TF.getLangOptions().getGCMode()) {
1483 default:
1484 assert(false);
1485
1486 case LangOptions::NonGC:
1487 assert (!TF.isGCEnabled());
1488 return std::make_pair(&Msgs[0], &Msgs[0]+1);
1489
1490 case LangOptions::GCOnly:
1491 assert (TF.isGCEnabled());
1492 return std::make_pair(&Msgs[1], &Msgs[1]+1);
1493
1494 case LangOptions::HybridGC:
1495 if (TF.isGCEnabled())
1496 return std::make_pair(&Msgs[2], &Msgs[2]+1);
1497 else
1498 return std::make_pair(&Msgs[3], &Msgs[3]+1);
1499 }
1500}
1501
Ted Kremenek8dd56462008-04-18 03:39:05 +00001502PathDiagnosticPiece* CFRefReport::VisitNode(ExplodedNode<ValueState>* N,
1503 ExplodedNode<ValueState>* PrevN,
1504 ExplodedGraph<ValueState>& G,
1505 BugReporter& BR) {
1506
1507 // Check if the type state has changed.
1508
1509 ValueState* PrevSt = PrevN->getState();
1510 ValueState* CurrSt = N->getState();
1511
1512 CFRefCount::RefBindings PrevB = CFRefCount::GetRefBindings(*PrevSt);
1513 CFRefCount::RefBindings CurrB = CFRefCount::GetRefBindings(*CurrSt);
1514
Ted Kremenek2cf943a2008-04-18 04:55:01 +00001515 CFRefCount::RefBindings::TreeTy* PrevT = PrevB.SlimFind(Sym);
1516 CFRefCount::RefBindings::TreeTy* CurrT = CurrB.SlimFind(Sym);
Ted Kremenek8dd56462008-04-18 03:39:05 +00001517
Ted Kremenek2cf943a2008-04-18 04:55:01 +00001518 if (!CurrT)
1519 return NULL;
Ted Kremenek8dd56462008-04-18 03:39:05 +00001520
Ted Kremenek2cf943a2008-04-18 04:55:01 +00001521 const char* Msg = NULL;
1522 RefVal CurrV = CurrB.SlimFind(Sym)->getValue().second;
Ted Kremenek8dd56462008-04-18 03:39:05 +00001523
Ted Kremenek2cf943a2008-04-18 04:55:01 +00001524 if (!PrevT) {
1525
1526 // Check for the point where we start tracking the value.
1527
1528 if (CurrV.isOwned())
1529 Msg = "Function call returns 'Owned' Core Foundation object.";
1530 else {
1531 assert (CurrV.isNotOwned());
1532 Msg = "Function call returns 'Non-Owned' Core Foundation object.";
1533 }
1534
1535 Stmt* S = cast<PostStmt>(N->getLocation()).getStmt();
1536 FullSourceLoc Pos(S->getLocStart(), BR.getContext().getSourceManager());
1537 PathDiagnosticPiece* P = new PathDiagnosticPiece(Pos, Msg);
1538
1539 if (Expr* Exp = dyn_cast<Expr>(S))
1540 P->addRange(Exp->getSourceRange());
1541
1542 return P;
1543 }
1544
1545 // Determine if the typestate has changed.
1546
1547 RefVal PrevV = PrevB.SlimFind(Sym)->getValue().second;
1548
1549 if (PrevV == CurrV)
1550 return NULL;
1551
1552 // The typestate has changed.
1553
1554 std::ostringstream os;
1555
1556 switch (CurrV.getKind()) {
1557 case RefVal::Owned:
1558 case RefVal::NotOwned:
1559 assert (PrevV.getKind() == CurrV.getKind());
1560
1561 if (PrevV.getCount() > CurrV.getCount())
1562 os << "Reference count decremented.";
1563 else
1564 os << "Reference count incremented.";
1565
Ted Kremenek79c140b2008-04-18 05:32:44 +00001566 if (CurrV.getCount()) {
1567 os << " Object has +" << CurrV.getCount();
1568
1569 if (CurrV.getCount() > 1)
1570 os << " reference counts.";
1571 else
1572 os << " reference count.";
1573 }
Ted Kremenek2cf943a2008-04-18 04:55:01 +00001574
1575 Msg = os.str().c_str();
1576
1577 break;
1578
1579 case RefVal::Released:
1580 Msg = "Object released.";
1581 break;
1582
1583 case RefVal::ReturnedOwned:
1584 Msg = "Object returned to caller. "
1585 "Caller gets ownership of object.";
1586 break;
1587
1588 case RefVal::ReturnedNotOwned:
1589 Msg = "Object returned to caller. "
1590 "Caller does not get ownership of object.";
1591 break;
1592
1593 default:
1594 return NULL;
1595 }
1596
1597 Stmt* S = cast<PostStmt>(N->getLocation()).getStmt();
1598 FullSourceLoc Pos(S->getLocStart(), BR.getContext().getSourceManager());
1599 PathDiagnosticPiece* P = new PathDiagnosticPiece(Pos, Msg);
1600
1601 // Add the range by scanning the children of the statement for any bindings
1602 // to Sym.
1603
1604 ValueStateManager& VSM = BR.getEngine().getStateManager();
1605
1606 for (Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I!=E; ++I)
1607 if (Expr* Exp = dyn_cast_or_null<Expr>(*I)) {
1608 RVal X = VSM.GetRVal(CurrSt, Exp);
1609
1610 if (lval::SymbolVal* SV = dyn_cast<lval::SymbolVal>(&X))
1611 if (SV->getSymbol() == Sym) {
1612 P->addRange(Exp->getSourceRange()); break;
1613 }
1614 }
1615
1616 return P;
Ted Kremenek8dd56462008-04-18 03:39:05 +00001617}
1618
Ted Kremenek05cbe1a2008-04-09 23:49:11 +00001619void UseAfterRelease::EmitWarnings(BugReporter& BR) {
Ted Kremenekfa34b332008-04-09 01:10:13 +00001620
Ted Kremenek05cbe1a2008-04-09 23:49:11 +00001621 for (CFRefCount::use_after_iterator I = TF.use_after_begin(),
1622 E = TF.use_after_end(); I != E; ++I) {
1623
Ted Kremenek8dd56462008-04-18 03:39:05 +00001624 CFRefReport report(*this, I->first, I->second.second);
1625 report.addRange(I->second.first->getSourceRange());
Ted Kremenek75840e12008-04-18 01:56:37 +00001626 BR.EmitWarning(report);
Ted Kremenekfa34b332008-04-09 01:10:13 +00001627 }
Ted Kremenek05cbe1a2008-04-09 23:49:11 +00001628}
1629
1630void BadRelease::EmitWarnings(BugReporter& BR) {
Ted Kremenekfa34b332008-04-09 01:10:13 +00001631
Ted Kremenek05cbe1a2008-04-09 23:49:11 +00001632 for (CFRefCount::bad_release_iterator I = TF.bad_release_begin(),
1633 E = TF.bad_release_end(); I != E; ++I) {
1634
Ted Kremenek8dd56462008-04-18 03:39:05 +00001635 CFRefReport report(*this, I->first, I->second.second);
1636 report.addRange(I->second.first->getSourceRange());
1637 BR.EmitWarning(report);
Ted Kremenek05cbe1a2008-04-09 23:49:11 +00001638 }
1639}
Ted Kremenekfa34b332008-04-09 01:10:13 +00001640
Ted Kremenek989d5192008-04-17 23:43:50 +00001641void Leak::EmitWarnings(BugReporter& BR) {
1642
1643 for (CFRefCount::leaks_iterator I = TF.leaks_begin(),
1644 E = TF.leaks_end(); I != E; ++I) {
1645
Ted Kremenek8dd56462008-04-18 03:39:05 +00001646 std::vector<SymbolID>& SymV = *(I->second);
1647 unsigned n = SymV.size();
1648
1649 for (unsigned i = 0; i < n; ++i) {
1650 CFRefReport report(*this, I->first, SymV[i]);
1651 BR.EmitWarning(report);
1652 }
Ted Kremenek989d5192008-04-17 23:43:50 +00001653 }
1654}
1655
Ted Kremenekcb612922008-04-18 19:23:43 +00001656void Leak::GetErrorNodes(std::vector<ExplodedNode<ValueState>*>& Nodes) {
1657 for (CFRefCount::leaks_iterator I=TF.leaks_begin(), E=TF.leaks_end();
1658 I!=E; ++I)
1659 Nodes.push_back(I->first);
1660}
1661
Ted Kremenek6b3a0f72008-03-11 06:39:11 +00001662//===----------------------------------------------------------------------===//
Ted Kremenekd71ed262008-04-10 22:16:52 +00001663// Transfer function creation for external clients.
Ted Kremenek6b3a0f72008-03-11 06:39:11 +00001664//===----------------------------------------------------------------------===//
1665
Ted Kremenek072192b2008-04-30 23:47:44 +00001666GRTransferFuncs* clang::MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled,
1667 const LangOptions& lopts) {
1668 return new CFRefCount(Ctx, GCEnabled, lopts);
Ted Kremenek3ea0b6a2008-04-10 22:58:08 +00001669}