blob: d9de2cf2b5f69d0c740d629fee209c19519e56f1 [file] [log] [blame]
Chris Lattnerbe1a7a02008-03-15 23:59:48 +00001// CFRefCount.cpp - Transfer functions for tracking simple values -*- C++ -*--//
Ted Kremenek827f93b2008-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 Greif2224fcb2008-03-06 10:40:09 +000010// This file defines the methods for CFRefCount, which implements
Ted Kremenek827f93b2008-03-06 00:08:09 +000011// a reference count checker for Core Foundation (Mac OS X).
12//
13//===----------------------------------------------------------------------===//
14
Ted Kremeneka7338b42008-03-11 06:39:11 +000015#include "GRSimpleVals.h"
Ted Kremenek827f93b2008-03-06 00:08:09 +000016#include "clang/Analysis/PathSensitive/ValueState.h"
Ted Kremenekdd0126b2008-03-31 18:26:32 +000017#include "clang/Analysis/PathDiagnostic.h"
Ted Kremenek827f93b2008-03-06 00:08:09 +000018#include "clang/Analysis/LocalCheckers.h"
Ted Kremenek10fe66d2008-04-09 01:10:13 +000019#include "clang/Analysis/PathDiagnostic.h"
20#include "clang/Analysis/PathSensitive/BugReporter.h"
Ted Kremeneka7338b42008-03-11 06:39:11 +000021#include "llvm/ADT/DenseMap.h"
22#include "llvm/ADT/FoldingSet.h"
23#include "llvm/ADT/ImmutableMap.h"
Ted Kremenek10fe66d2008-04-09 01:10:13 +000024#include "llvm/Support/Compiler.h"
Ted Kremenek3b11f7a2008-03-11 19:44:10 +000025#include <ostream>
Ted Kremenek827f93b2008-03-06 00:08:09 +000026
27using namespace clang;
28
Ted Kremenek7d421f32008-04-09 23:49:11 +000029//===----------------------------------------------------------------------===//
30// Symbolic Evaluation of Reference Counting Logic
31//===----------------------------------------------------------------------===//
32
Ted Kremeneka7338b42008-03-11 06:39:11 +000033namespace {
34 enum ArgEffect { IncRef, DecRef, DoNothing };
35 typedef std::vector<ArgEffect> ArgEffects;
36}
Ted Kremenek827f93b2008-03-06 00:08:09 +000037
Ted Kremeneka7338b42008-03-11 06:39:11 +000038namespace llvm {
39 template <> struct FoldingSetTrait<ArgEffects> {
Ted Kremeneka4c74292008-04-10 22:58:08 +000040 static void Profile(const ArgEffects& X, FoldingSetNodeID& ID) {
Ted Kremeneka7338b42008-03-11 06:39:11 +000041 for (ArgEffects::const_iterator I = X.begin(), E = X.end(); I!= E; ++I)
42 ID.AddInteger((unsigned) *I);
Ted Kremeneka4c74292008-04-10 22:58:08 +000043 }
Ted Kremeneka7338b42008-03-11 06:39:11 +000044 };
45} // end llvm namespace
46
47namespace {
Ted Kremenek827f93b2008-03-06 00:08:09 +000048
Ted Kremeneka7338b42008-03-11 06:39:11 +000049class RetEffect {
50public:
51 enum Kind { Alias = 0x0, OwnedSymbol = 0x1, NotOwnedSymbol = 0x2 };
52
53private:
54 unsigned Data;
Ted Kremeneka4c74292008-04-10 22:58:08 +000055 RetEffect(Kind k, unsigned D) { Data = (D << 2) | (unsigned) k; }
Ted Kremenek827f93b2008-03-06 00:08:09 +000056
Ted Kremeneka7338b42008-03-11 06:39:11 +000057public:
58
59 Kind getKind() const { return (Kind) (Data & 0x3); }
60
61 unsigned getValue() const {
62 assert(getKind() == Alias);
Ted Kremeneka4c74292008-04-10 22:58:08 +000063 return Data >> 2;
Ted Kremeneka7338b42008-03-11 06:39:11 +000064 }
Ted Kremenek827f93b2008-03-06 00:08:09 +000065
Ted Kremeneka7338b42008-03-11 06:39:11 +000066 static RetEffect MakeAlias(unsigned Idx) { return RetEffect(Alias, Idx); }
Ted Kremenek827f93b2008-03-06 00:08:09 +000067
Ted Kremeneka7338b42008-03-11 06:39:11 +000068 static RetEffect MakeOwned() { return RetEffect(OwnedSymbol, 0); }
Ted Kremenek827f93b2008-03-06 00:08:09 +000069
Ted Kremeneka7338b42008-03-11 06:39:11 +000070 static RetEffect MakeNotOwned() { return RetEffect(NotOwnedSymbol, 0); }
71
72 operator Kind() const { return getKind(); }
73
74 void Profile(llvm::FoldingSetNodeID& ID) const { ID.AddInteger(Data); }
75};
76
77
78class CFRefSummary : public llvm::FoldingSetNode {
79 ArgEffects* Args;
80 RetEffect Ret;
81public:
82
83 CFRefSummary(ArgEffects* A, RetEffect R) : Args(A), Ret(R) {}
84
85 unsigned getNumArgs() const { return Args->size(); }
86
Ted Kremenek0d721572008-03-11 17:48:22 +000087 ArgEffect getArg(unsigned idx) const {
88 assert (idx < getNumArgs());
89 return (*Args)[idx];
90 }
91
Ted Kremenekce3ed1e2008-03-12 01:21:45 +000092 RetEffect getRet() const {
93 return Ret;
94 }
95
Ted Kremeneka7338b42008-03-11 06:39:11 +000096 typedef ArgEffects::const_iterator arg_iterator;
97
98 arg_iterator begin_args() const { return Args->begin(); }
99 arg_iterator end_args() const { return Args->end(); }
100
101 static void Profile(llvm::FoldingSetNodeID& ID, ArgEffects* A, RetEffect R) {
102 ID.AddPointer(A);
103 ID.Add(R);
104 }
105
106 void Profile(llvm::FoldingSetNodeID& ID) const {
107 Profile(ID, Args, Ret);
108 }
109};
110
111
112class CFRefSummaryManager {
113 typedef llvm::FoldingSet<llvm::FoldingSetNodeWrapper<ArgEffects> > AESetTy;
114 typedef llvm::FoldingSet<CFRefSummary> SummarySetTy;
115 typedef llvm::DenseMap<FunctionDecl*, CFRefSummary*> SummaryMapTy;
116
Ted Kremeneka4c74292008-04-10 22:58:08 +0000117 ASTContext& Ctx;
118 SummarySetTy SummarySet;
119 SummaryMapTy SummaryMap;
120 AESetTy AESet;
121 llvm::BumpPtrAllocator BPAlloc;
122 ArgEffects ScratchArgs;
Ted Kremenekce3ed1e2008-03-12 01:21:45 +0000123
124
125 ArgEffects* getArgEffects();
Ted Kremeneka7338b42008-03-11 06:39:11 +0000126
Ted Kremenekce3ed1e2008-03-12 01:21:45 +0000127 CFRefSummary* getCannedCFSummary(FunctionTypeProto* FT, bool isRetain);
128
129 CFRefSummary* getCFSummary(FunctionDecl* FD, const char* FName);
130
131 CFRefSummary* getCFSummaryCreateRule(FunctionTypeProto* FT);
132 CFRefSummary* getCFSummaryGetRule(FunctionTypeProto* FT);
133
134 CFRefSummary* getPersistentSummary(ArgEffects* AE, RetEffect RE);
135
Ted Kremeneka7338b42008-03-11 06:39:11 +0000136public:
Ted Kremeneka4c74292008-04-10 22:58:08 +0000137 CFRefSummaryManager(ASTContext& ctx) : Ctx(ctx) {}
Ted Kremeneka7338b42008-03-11 06:39:11 +0000138 ~CFRefSummaryManager();
139
Ted Kremenekce3ed1e2008-03-12 01:21:45 +0000140 CFRefSummary* getSummary(FunctionDecl* FD, ASTContext& Ctx);
Ted Kremeneka7338b42008-03-11 06:39:11 +0000141};
142
143} // end anonymous namespace
144
145//===----------------------------------------------------------------------===//
146// Implementation of checker data structures.
147//===----------------------------------------------------------------------===//
148
149CFRefSummaryManager::~CFRefSummaryManager() {
150
151 // FIXME: The ArgEffects could eventually be allocated from BPAlloc,
152 // mitigating the need to do explicit cleanup of the
153 // Argument-Effect summaries.
154
155 for (AESetTy::iterator I = AESet.begin(), E = AESet.end(); I!=E; ++I)
156 I->getValue().~ArgEffects();
Ted Kremenek827f93b2008-03-06 00:08:09 +0000157}
Ted Kremeneka7338b42008-03-11 06:39:11 +0000158
Ted Kremenekce3ed1e2008-03-12 01:21:45 +0000159ArgEffects* CFRefSummaryManager::getArgEffects() {
160
161 assert (!ScratchArgs.empty());
162
163 llvm::FoldingSetNodeID profile;
164 profile.Add(ScratchArgs);
165 void* InsertPos;
166
167 llvm::FoldingSetNodeWrapper<ArgEffects>* E =
168 AESet.FindNodeOrInsertPos(profile, InsertPos);
169
170 if (E) {
171 ScratchArgs.clear();
172 return &E->getValue();
173 }
174
175 E = (llvm::FoldingSetNodeWrapper<ArgEffects>*)
176 BPAlloc.Allocate<llvm::FoldingSetNodeWrapper<ArgEffects> >();
177
178 new (E) llvm::FoldingSetNodeWrapper<ArgEffects>(ScratchArgs);
179 AESet.InsertNode(E, InsertPos);
180
181 ScratchArgs.clear();
182 return &E->getValue();
183}
184
185CFRefSummary* CFRefSummaryManager::getPersistentSummary(ArgEffects* AE,
186 RetEffect RE) {
187
188 llvm::FoldingSetNodeID profile;
189 CFRefSummary::Profile(profile, AE, RE);
190 void* InsertPos;
191
192 CFRefSummary* Summ = SummarySet.FindNodeOrInsertPos(profile, InsertPos);
193
194 if (Summ)
195 return Summ;
196
197 Summ = (CFRefSummary*) BPAlloc.Allocate<CFRefSummary>();
198 new (Summ) CFRefSummary(AE, RE);
199 SummarySet.InsertNode(Summ, InsertPos);
200
201 return Summ;
202}
203
204
205CFRefSummary* CFRefSummaryManager::getSummary(FunctionDecl* FD,
206 ASTContext& Ctx) {
207
208 SourceLocation Loc = FD->getLocation();
209
210 if (!Loc.isFileID())
211 return NULL;
Ted Kremenek827f93b2008-03-06 00:08:09 +0000212
Ted Kremeneka7338b42008-03-11 06:39:11 +0000213 { // Look into our cache of summaries to see if we have already computed
214 // a summary for this FunctionDecl.
215
216 SummaryMapTy::iterator I = SummaryMap.find(FD);
217
218 if (I != SummaryMap.end())
219 return I->second;
220 }
221
Ted Kremenekce3ed1e2008-03-12 01:21:45 +0000222#if 0
223 SourceManager& SrcMgr = Ctx.getSourceManager();
224 unsigned fid = Loc.getFileID();
225 const FileEntry* FE = SrcMgr.getFileEntryForID(fid);
Ted Kremeneka7338b42008-03-11 06:39:11 +0000226
Ted Kremenekce3ed1e2008-03-12 01:21:45 +0000227 if (!FE)
228 return NULL;
229
230 const char* DirName = FE->getDir()->getName();
231 assert (DirName);
232 assert (strlen(DirName) > 0);
233
234 if (!strstr(DirName, "CoreFoundation")) {
235 SummaryMap[FD] = NULL;
236 return NULL;
237 }
238#endif
239
240 const char* FName = FD->getIdentifier()->getName();
241
242 if (FName[0] == 'C' && FName[1] == 'F') {
243 CFRefSummary* S = getCFSummary(FD, FName);
244 SummaryMap[FD] = S;
245 return S;
246 }
Ted Kremeneka7338b42008-03-11 06:39:11 +0000247
248 return NULL;
Ted Kremenek827f93b2008-03-06 00:08:09 +0000249}
250
Ted Kremenekce3ed1e2008-03-12 01:21:45 +0000251CFRefSummary* CFRefSummaryManager::getCFSummary(FunctionDecl* FD,
252 const char* FName) {
253
254 // For now, only generate summaries for functions that have a prototype.
255
256 FunctionTypeProto* FT =
257 dyn_cast<FunctionTypeProto>(FD->getType().getTypePtr());
258
259 if (!FT)
260 return NULL;
261
262 FName += 2;
263
264 if (strcmp(FName, "Retain") == 0)
265 return getCannedCFSummary(FT, true);
266
267 if (strcmp(FName, "Release") == 0)
268 return getCannedCFSummary(FT, false);
269
270 assert (ScratchArgs.empty());
271 bool usesCreateRule = false;
272
273 if (strstr(FName, "Create"))
274 usesCreateRule = true;
275
276 if (!usesCreateRule && strstr(FName, "Copy"))
277 usesCreateRule = true;
278
279 if (usesCreateRule)
280 return getCFSummaryCreateRule(FT);
281
282 if (strstr(FName, "Get"))
283 return getCFSummaryGetRule(FT);
284
285 return NULL;
286}
287
288CFRefSummary* CFRefSummaryManager::getCannedCFSummary(FunctionTypeProto* FT,
289 bool isRetain) {
290
291 if (FT->getNumArgs() != 1)
292 return NULL;
293
294 TypedefType* ArgT = dyn_cast<TypedefType>(FT->getArgType(0).getTypePtr());
295
296 if (!ArgT)
297 return NULL;
298
299 // For CFRetain/CFRelease, the first (and only) argument is of type
300 // "CFTypeRef".
301
302 const char* TDName = ArgT->getDecl()->getIdentifier()->getName();
303 assert (TDName);
304
Ted Kremeneka4c74292008-04-10 22:58:08 +0000305 if (strcmp("CFTypeRef", TDName) != 0)
Ted Kremenekce3ed1e2008-03-12 01:21:45 +0000306 return NULL;
307
308 if (!ArgT->isPointerType())
309 return NULL;
Ted Kremeneka4c74292008-04-10 22:58:08 +0000310
Ted Kremenekce3ed1e2008-03-12 01:21:45 +0000311 QualType RetTy = FT->getResultType();
312
Ted Kremeneka4c74292008-04-10 22:58:08 +0000313 if (isRetain) {
314 // CFRetain: the return type should also be "CFTypeRef".
315 if (RetTy.getTypePtr() != ArgT)
316 return NULL;
317 }
318 else {
319 // CFRelease: the return type should be void.
320
321 if (RetTy != Ctx.VoidTy)
322 return NULL;
323 }
324
Ted Kremenekce3ed1e2008-03-12 01:21:45 +0000325 // The function's interface checks out. Generate a canned summary.
326
327 assert (ScratchArgs.empty());
328 ScratchArgs.push_back(isRetain ? IncRef : DecRef);
329
330 return getPersistentSummary(getArgEffects(), RetEffect::MakeAlias(0));
331}
332
333static bool isCFRefType(QualType T) {
334
335 if (!T->isPointerType())
336 return false;
337
338 // Check the typedef for the name "CF" and the substring "Ref".
339
340 TypedefType* TD = dyn_cast<TypedefType>(T.getTypePtr());
341
342 if (!TD)
343 return false;
344
345 const char* TDName = TD->getDecl()->getIdentifier()->getName();
346 assert (TDName);
347
348 if (TDName[0] != 'C' || TDName[1] != 'F')
349 return false;
350
351 if (strstr(TDName, "Ref") == 0)
352 return false;
353
354 return true;
355}
356
357
358CFRefSummary*
359CFRefSummaryManager::getCFSummaryCreateRule(FunctionTypeProto* FT) {
360
361 if (!isCFRefType(FT->getResultType()))
362 return NULL;
363
364 assert (ScratchArgs.empty());
365
366 // FIXME: Add special-cases for functions that retain/release. For now
367 // just handle the default case.
368
369 for (unsigned i = 0, n = FT->getNumArgs(); i != n; ++i)
370 ScratchArgs.push_back(DoNothing);
371
372 return getPersistentSummary(getArgEffects(), RetEffect::MakeOwned());
373}
374
375CFRefSummary*
376CFRefSummaryManager::getCFSummaryGetRule(FunctionTypeProto* FT) {
377
378 if (!isCFRefType(FT->getResultType()))
379 return NULL;
380
381 assert (ScratchArgs.empty());
382
383 // FIXME: Add special-cases for functions that retain/release. For now
384 // just handle the default case.
385
386 for (unsigned i = 0, n = FT->getNumArgs(); i != n; ++i)
387 ScratchArgs.push_back(DoNothing);
388
389 return getPersistentSummary(getArgEffects(), RetEffect::MakeNotOwned());
390}
391
Ted Kremeneka7338b42008-03-11 06:39:11 +0000392//===----------------------------------------------------------------------===//
Ted Kremenek7d421f32008-04-09 23:49:11 +0000393// Bug Descriptions.
394//===----------------------------------------------------------------------===//
395
396namespace {
397
398 class CFRefCount;
399
400 class VISIBILITY_HIDDEN CFRefBug : public BugType {
401 protected:
402 CFRefCount& TF;
403
404 public:
405 CFRefBug(CFRefCount& tf) : TF(tf) {}
406 };
407
408 class VISIBILITY_HIDDEN UseAfterRelease : public CFRefBug {
409 public:
410 UseAfterRelease(CFRefCount& tf) : CFRefBug(tf) {}
411
412 virtual const char* getName() const {
413 return "(CoreFoundation) use-after-release";
414 }
415 virtual const char* getDescription() const {
416 return "(CoreFoundation) Reference-counted object is used"
417 " after it is released.";
418 }
419
420 virtual void EmitWarnings(BugReporter& BR);
421
422 };
423
424 class VISIBILITY_HIDDEN BadRelease : public CFRefBug {
425 public:
426 BadRelease(CFRefCount& tf) : CFRefBug(tf) {}
427
428 virtual const char* getName() const {
429 return "(CoreFoundation) release of non-owned object";
430 }
431 virtual const char* getDescription() const {
432 return "Incorrect decrement of the reference count of a "
433 "CoreFoundation object:\n"
434 "The object is not owned at this point by the caller.";
435 }
436
437 virtual void EmitWarnings(BugReporter& BR);
438 };
439
440} // end anonymous namespace
441
442//===----------------------------------------------------------------------===//
Ted Kremeneka7338b42008-03-11 06:39:11 +0000443// Transfer functions.
444//===----------------------------------------------------------------------===//
445
Ted Kremeneka7338b42008-03-11 06:39:11 +0000446namespace {
447
Ted Kremenek7d421f32008-04-09 23:49:11 +0000448class VISIBILITY_HIDDEN RefVal {
Ted Kremenek0d721572008-03-11 17:48:22 +0000449 unsigned Data;
450
451 RefVal(unsigned K, unsigned D) : Data((D << 3) | K) {
Ted Kremeneka4c74292008-04-10 22:58:08 +0000452 assert ((K & ~0x7) == 0x0);
Ted Kremenek0d721572008-03-11 17:48:22 +0000453 }
454
455 RefVal(unsigned K) : Data(K) {
Ted Kremeneka4c74292008-04-10 22:58:08 +0000456 assert ((K & ~0x7) == 0x0);
Ted Kremenek0d721572008-03-11 17:48:22 +0000457 }
458
459public:
Ted Kremenekc4f81022008-04-10 23:09:18 +0000460 enum Kind { Owned = 0, NotOwned = 1, Released = 2,
461 ErrorUseAfterRelease = 3, ErrorReleaseNotOwned = 4 };
Ted Kremenek0d721572008-03-11 17:48:22 +0000462
463
Ted Kremenekc4f81022008-04-10 23:09:18 +0000464 Kind getKind() const { return (Kind) (Data & 0x7); }
Ted Kremenek0d721572008-03-11 17:48:22 +0000465
466 unsigned getCount() const {
Ted Kremenekc4f81022008-04-10 23:09:18 +0000467 assert (getKind() == Owned || getKind() == NotOwned);
Ted Kremenek0d721572008-03-11 17:48:22 +0000468 return Data >> 3;
469 }
470
Ted Kremenek1daa16c2008-03-11 18:14:09 +0000471 static bool isError(Kind k) { return k >= ErrorUseAfterRelease; }
472
Ted Kremenekc4f81022008-04-10 23:09:18 +0000473 static RefVal makeOwned(unsigned Count = 0) {
474 return RefVal(Owned, Count);
475 }
476
477 static RefVal makeNotOwned(unsigned Count = 0) {
478 return RefVal(NotOwned, Count);
479 }
480
Ted Kremenek0d721572008-03-11 17:48:22 +0000481 static RefVal makeReleased() { return RefVal(Released); }
482 static RefVal makeUseAfterRelease() { return RefVal(ErrorUseAfterRelease); }
483 static RefVal makeReleaseNotOwned() { return RefVal(ErrorReleaseNotOwned); }
484
485 bool operator==(const RefVal& X) const { return Data == X.Data; }
486 void Profile(llvm::FoldingSetNodeID& ID) const { ID.AddInteger(Data); }
Ted Kremenek3b11f7a2008-03-11 19:44:10 +0000487
488 void print(std::ostream& Out) const;
Ted Kremenek0d721572008-03-11 17:48:22 +0000489};
Ted Kremenek3b11f7a2008-03-11 19:44:10 +0000490
491void RefVal::print(std::ostream& Out) const {
492 switch (getKind()) {
493 default: assert(false);
Ted Kremenekc4f81022008-04-10 23:09:18 +0000494 case Owned: {
495 Out << "Owned";
496 unsigned cnt = getCount();
497 if (cnt) Out << " (+ " << cnt << ")";
Ted Kremenek3b11f7a2008-03-11 19:44:10 +0000498 break;
Ted Kremenekc4f81022008-04-10 23:09:18 +0000499 }
Ted Kremenek3b11f7a2008-03-11 19:44:10 +0000500
Ted Kremenekc4f81022008-04-10 23:09:18 +0000501 case NotOwned: {
Ted Kremenek3b11f7a2008-03-11 19:44:10 +0000502 Out << "Not-Owned";
Ted Kremenekc4f81022008-04-10 23:09:18 +0000503 unsigned cnt = getCount();
504 if (cnt) Out << " (+ " << cnt << ")";
Ted Kremenek3b11f7a2008-03-11 19:44:10 +0000505 break;
Ted Kremenekc4f81022008-04-10 23:09:18 +0000506 }
Ted Kremenek3b11f7a2008-03-11 19:44:10 +0000507
508 case Released:
509 Out << "Released";
510 break;
511
512 case ErrorUseAfterRelease:
513 Out << "Use-After-Release [ERROR]";
514 break;
515
516 case ErrorReleaseNotOwned:
517 Out << "Release of Not-Owned [ERROR]";
518 break;
519 }
520}
Ted Kremenek0d721572008-03-11 17:48:22 +0000521
Ted Kremenek7d421f32008-04-09 23:49:11 +0000522class VISIBILITY_HIDDEN CFRefCount : public GRSimpleVals {
Ted Kremenek3b11f7a2008-03-11 19:44:10 +0000523
524 // Type definitions.
525
Ted Kremenek0d721572008-03-11 17:48:22 +0000526 typedef llvm::ImmutableMap<SymbolID, RefVal> RefBindings;
Ted Kremeneka7338b42008-03-11 06:39:11 +0000527 typedef RefBindings::Factory RefBFactoryTy;
Ted Kremenek1daa16c2008-03-11 18:14:09 +0000528
529 typedef llvm::SmallPtrSet<GRExprEngine::NodeTy*,2> UseAfterReleasesTy;
530 typedef llvm::SmallPtrSet<GRExprEngine::NodeTy*,2> ReleasesNotOwnedTy;
531
Ted Kremenek3b11f7a2008-03-11 19:44:10 +0000532 class BindingsPrinter : public ValueState::CheckerStatePrinter {
533 public:
534 virtual void PrintCheckerState(std::ostream& Out, void* State,
535 const char* nl, const char* sep);
536 };
537
538 // Instance variables.
539
Ted Kremeneka7338b42008-03-11 06:39:11 +0000540 CFRefSummaryManager Summaries;
Ted Kremenekce3ed1e2008-03-12 01:21:45 +0000541 RefBFactoryTy RefBFactory;
542
Ted Kremenek1daa16c2008-03-11 18:14:09 +0000543 UseAfterReleasesTy UseAfterReleases;
544 ReleasesNotOwnedTy ReleasesNotOwned;
545
Ted Kremenek3b11f7a2008-03-11 19:44:10 +0000546 BindingsPrinter Printer;
547
548 // Private methods.
Ted Kremeneka7338b42008-03-11 06:39:11 +0000549
550 static RefBindings GetRefBindings(ValueState& StImpl) {
551 return RefBindings((RefBindings::TreeTy*) StImpl.CheckerState);
552 }
553
554 static void SetRefBindings(ValueState& StImpl, RefBindings B) {
555 StImpl.CheckerState = B.getRoot();
556 }
557
558 RefBindings Remove(RefBindings B, SymbolID sym) {
559 return RefBFactory.Remove(B, sym);
560 }
561
Ted Kremenek0d721572008-03-11 17:48:22 +0000562 RefBindings Update(RefBindings B, SymbolID sym, RefVal V, ArgEffect E,
Ted Kremenek1daa16c2008-03-11 18:14:09 +0000563 RefVal::Kind& hasError);
Ted Kremenek3b11f7a2008-03-11 19:44:10 +0000564
Ted Kremeneka7338b42008-03-11 06:39:11 +0000565
566public:
Ted Kremeneka4c74292008-04-10 22:58:08 +0000567 CFRefCount(ASTContext& Ctx) : Summaries(Ctx) {}
Ted Kremeneka7338b42008-03-11 06:39:11 +0000568 virtual ~CFRefCount() {}
Ted Kremenek7d421f32008-04-09 23:49:11 +0000569
570 virtual void RegisterChecks(GRExprEngine& Eng);
Ted Kremenek3b11f7a2008-03-11 19:44:10 +0000571
572 virtual ValueState::CheckerStatePrinter* getCheckerStatePrinter() {
573 return &Printer;
574 }
Ted Kremeneka7338b42008-03-11 06:39:11 +0000575
576 // Calls.
577
578 virtual void EvalCall(ExplodedNodeSet<ValueState>& Dst,
Ted Kremenekce0767f2008-03-12 21:06:49 +0000579 GRExprEngine& Eng,
Ted Kremeneka7338b42008-03-11 06:39:11 +0000580 GRStmtNodeBuilder<ValueState>& Builder,
Ted Kremeneka7338b42008-03-11 06:39:11 +0000581 CallExpr* CE, LVal L,
582 ExplodedNode<ValueState>* Pred);
Ted Kremenek10fe66d2008-04-09 01:10:13 +0000583
584 // Error iterators.
585
586 typedef UseAfterReleasesTy::iterator use_after_iterator;
587 typedef ReleasesNotOwnedTy::iterator bad_release_iterator;
588
Ted Kremenek7d421f32008-04-09 23:49:11 +0000589 use_after_iterator use_after_begin() { return UseAfterReleases.begin(); }
590 use_after_iterator use_after_end() { return UseAfterReleases.end(); }
Ted Kremenek10fe66d2008-04-09 01:10:13 +0000591
Ted Kremenek7d421f32008-04-09 23:49:11 +0000592 bad_release_iterator bad_release_begin() { return ReleasesNotOwned.begin(); }
593 bad_release_iterator bad_release_end() { return ReleasesNotOwned.end(); }
Ted Kremeneka7338b42008-03-11 06:39:11 +0000594};
595
596} // end anonymous namespace
597
Ted Kremenek7d421f32008-04-09 23:49:11 +0000598void CFRefCount::RegisterChecks(GRExprEngine& Eng) {
599 GRSimpleVals::RegisterChecks(Eng);
600 Eng.Register(new UseAfterRelease(*this));
601 Eng.Register(new BadRelease(*this));
602}
603
604
Ted Kremenek3b11f7a2008-03-11 19:44:10 +0000605void CFRefCount::BindingsPrinter::PrintCheckerState(std::ostream& Out,
606 void* State, const char* nl,
607 const char* sep) {
608 RefBindings B((RefBindings::TreeTy*) State);
609
610 if (State)
611 Out << sep << nl;
612
613 for (RefBindings::iterator I=B.begin(), E=B.end(); I!=E; ++I) {
614 Out << (*I).first << " : ";
615 (*I).second.print(Out);
616 Out << nl;
617 }
618}
619
Ted Kremenek827f93b2008-03-06 00:08:09 +0000620void CFRefCount::EvalCall(ExplodedNodeSet<ValueState>& Dst,
Ted Kremenekce0767f2008-03-12 21:06:49 +0000621 GRExprEngine& Eng,
Ted Kremenekce3ed1e2008-03-12 01:21:45 +0000622 GRStmtNodeBuilder<ValueState>& Builder,
623 CallExpr* CE, LVal L,
624 ExplodedNode<ValueState>* Pred) {
625
Ted Kremenekce0767f2008-03-12 21:06:49 +0000626 ValueStateManager& StateMgr = Eng.getStateManager();
Ted Kremenek827f93b2008-03-06 00:08:09 +0000627
Ted Kremeneka7338b42008-03-11 06:39:11 +0000628 // FIXME: Support calls to things other than lval::FuncVal. At the very
629 // least we should stop tracking ref-state for ref-counted objects passed
630 // to these functions.
Ted Kremenek827f93b2008-03-06 00:08:09 +0000631
Ted Kremeneka7338b42008-03-11 06:39:11 +0000632 assert (isa<lval::FuncVal>(L) && "Not yet implemented.");
633
634 // Get the summary.
Ted Kremenek827f93b2008-03-06 00:08:09 +0000635
Ted Kremeneka7338b42008-03-11 06:39:11 +0000636 lval::FuncVal FV = cast<lval::FuncVal>(L);
637 FunctionDecl* FD = FV.getDecl();
Ted Kremenekce0767f2008-03-12 21:06:49 +0000638 CFRefSummary* Summ = Summaries.getSummary(FD, Eng.getContext());
Ted Kremenek827f93b2008-03-06 00:08:09 +0000639
Ted Kremeneka7338b42008-03-11 06:39:11 +0000640 // Get the state.
641
642 ValueState* St = Builder.GetState(Pred);
643
644 // Evaluate the effects of the call.
645
646 ValueState StVals = *St;
Ted Kremenek1daa16c2008-03-11 18:14:09 +0000647 RefVal::Kind hasError = (RefVal::Kind) 0;
Ted Kremeneka7338b42008-03-11 06:39:11 +0000648
649 if (!Summ) {
Ted Kremenek827f93b2008-03-06 00:08:09 +0000650
Ted Kremeneka7338b42008-03-11 06:39:11 +0000651 // This function has no summary. Invalidate all reference-count state
652 // for arguments passed to this function, and also nuke the values of
653 // arguments passed-by-reference.
654
655 ValueState StVals = *St;
656
657 for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end();
658 I != E; ++I) {
659
660 RVal V = StateMgr.GetRVal(St, *I);
661
662 if (isa<lval::SymbolVal>(V)) {
663 SymbolID Sym = cast<lval::SymbolVal>(V).getSymbol();
664 RefBindings B = GetRefBindings(StVals);
665 SetRefBindings(StVals, Remove(B, Sym));
666 }
667
668 if (isa<LVal>(V))
669 StateMgr.Unbind(StVals, cast<LVal>(V));
Ted Kremenekce3ed1e2008-03-12 01:21:45 +0000670 }
671
672 St = StateMgr.getPersistentState(StVals);
Ted Kremenekce0767f2008-03-12 21:06:49 +0000673
674 // Make up a symbol for the return value of this function.
675
676 if (CE->getType() != Eng.getContext().VoidTy) {
677 unsigned Count = Builder.getCurrentBlockCount();
Ted Kremenekd4676512008-03-12 21:45:47 +0000678 SymbolID Sym = Eng.getSymbolManager().getConjuredSymbol(CE, Count);
Ted Kremenekce0767f2008-03-12 21:06:49 +0000679
680 RVal X = CE->getType()->isPointerType()
681 ? cast<RVal>(lval::SymbolVal(Sym))
682 : cast<RVal>(nonlval::SymbolVal(Sym));
683
684 St = StateMgr.SetRVal(St, CE, X, Eng.getCFG().isBlkExpr(CE), false);
685 }
686
Ted Kremenekf10f2882008-03-21 21:30:14 +0000687 Builder.MakeNode(Dst, CE, Pred, St);
Ted Kremenekce3ed1e2008-03-12 01:21:45 +0000688 return;
Ted Kremenek827f93b2008-03-06 00:08:09 +0000689 }
Ted Kremenekce3ed1e2008-03-12 01:21:45 +0000690
691 // This function has a summary. Evaluate the effect of the arguments.
692
693 unsigned idx = 0;
694
695 for (CallExpr::arg_iterator I=CE->arg_begin(), E=CE->arg_end();
696 I!=E; ++I, ++idx) {
Ted Kremeneka7338b42008-03-11 06:39:11 +0000697
Ted Kremenekce3ed1e2008-03-12 01:21:45 +0000698 RVal V = StateMgr.GetRVal(St, *I);
Ted Kremeneka7338b42008-03-11 06:39:11 +0000699
Ted Kremenekce3ed1e2008-03-12 01:21:45 +0000700 if (isa<lval::SymbolVal>(V)) {
701 SymbolID Sym = cast<lval::SymbolVal>(V).getSymbol();
702 RefBindings B = GetRefBindings(StVals);
Ted Kremenek0d721572008-03-11 17:48:22 +0000703
Ted Kremenekce3ed1e2008-03-12 01:21:45 +0000704 if (RefBindings::TreeTy* T = B.SlimFind(Sym)) {
705 B = Update(B, Sym, T->getValue().second, Summ->getArg(idx), hasError);
706 SetRefBindings(StVals, B);
707 if (hasError) break;
Ted Kremeneka7338b42008-03-11 06:39:11 +0000708 }
Ted Kremenekce3ed1e2008-03-12 01:21:45 +0000709 }
710 }
711
Ted Kremenek0d721572008-03-11 17:48:22 +0000712 if (hasError) {
Ted Kremenekce3ed1e2008-03-12 01:21:45 +0000713 St = StateMgr.getPersistentState(StVals);
Ted Kremenek1daa16c2008-03-11 18:14:09 +0000714 GRExprEngine::NodeTy* N = Builder.generateNode(CE, St, Pred);
715
716 if (N) {
717 N->markAsSink();
718
719 switch (hasError) {
720 default: assert(false);
721 case RefVal::ErrorUseAfterRelease:
722 UseAfterReleases.insert(N);
723 break;
724
725 case RefVal::ErrorReleaseNotOwned:
726 ReleasesNotOwned.insert(N);
727 break;
728 }
Ted Kremenekce3ed1e2008-03-12 01:21:45 +0000729 }
730
731 return;
Ted Kremenek0d721572008-03-11 17:48:22 +0000732 }
Ted Kremenekce3ed1e2008-03-12 01:21:45 +0000733
734 // Finally, consult the summary for the return value.
735
736 RetEffect RE = Summ->getRet();
737 St = StateMgr.getPersistentState(StVals);
738
739
740 switch (RE.getKind()) {
741 default:
742 assert (false && "Unhandled RetEffect."); break;
743
744 case RetEffect::Alias: {
745 unsigned idx = RE.getValue();
746 assert (idx < CE->getNumArgs());
747 RVal V = StateMgr.GetRVal(St, CE->getArg(idx));
Ted Kremenekce0767f2008-03-12 21:06:49 +0000748 St = StateMgr.SetRVal(St, CE, V, Eng.getCFG().isBlkExpr(CE), false);
Ted Kremenekce3ed1e2008-03-12 01:21:45 +0000749 break;
750 }
751
752 case RetEffect::OwnedSymbol: {
753 unsigned Count = Builder.getCurrentBlockCount();
Ted Kremenekd4676512008-03-12 21:45:47 +0000754 SymbolID Sym = Eng.getSymbolManager().getConjuredSymbol(CE, Count);
Ted Kremenekce3ed1e2008-03-12 01:21:45 +0000755
756 ValueState StImpl = *St;
757 RefBindings B = GetRefBindings(StImpl);
Ted Kremenekc4f81022008-04-10 23:09:18 +0000758 SetRefBindings(StImpl, RefBFactory.Add(B, Sym, RefVal::makeOwned()));
Ted Kremenekce3ed1e2008-03-12 01:21:45 +0000759
760 St = StateMgr.SetRVal(StateMgr.getPersistentState(StImpl),
761 CE, lval::SymbolVal(Sym),
Ted Kremenekce0767f2008-03-12 21:06:49 +0000762 Eng.getCFG().isBlkExpr(CE), false);
Ted Kremenekce3ed1e2008-03-12 01:21:45 +0000763
764 break;
765 }
766
767 case RetEffect::NotOwnedSymbol: {
768 unsigned Count = Builder.getCurrentBlockCount();
Ted Kremenekd4676512008-03-12 21:45:47 +0000769 SymbolID Sym = Eng.getSymbolManager().getConjuredSymbol(CE, Count);
Ted Kremenekce3ed1e2008-03-12 01:21:45 +0000770
771 ValueState StImpl = *St;
772 RefBindings B = GetRefBindings(StImpl);
773 SetRefBindings(StImpl, RefBFactory.Add(B, Sym, RefVal::makeNotOwned()));
774
775 St = StateMgr.SetRVal(StateMgr.getPersistentState(StImpl),
776 CE, lval::SymbolVal(Sym),
Ted Kremenekce0767f2008-03-12 21:06:49 +0000777 Eng.getCFG().isBlkExpr(CE), false);
Ted Kremenekce3ed1e2008-03-12 01:21:45 +0000778
779 break;
780 }
781 }
782
Ted Kremenekf10f2882008-03-21 21:30:14 +0000783 Builder.MakeNode(Dst, CE, Pred, St);
Ted Kremenek827f93b2008-03-06 00:08:09 +0000784}
Ted Kremeneka7338b42008-03-11 06:39:11 +0000785
786
787CFRefCount::RefBindings CFRefCount::Update(RefBindings B, SymbolID sym,
Ted Kremenek0d721572008-03-11 17:48:22 +0000788 RefVal V, ArgEffect E,
Ted Kremenek1daa16c2008-03-11 18:14:09 +0000789 RefVal::Kind& hasError) {
Ted Kremeneka7338b42008-03-11 06:39:11 +0000790
Ted Kremenek0d721572008-03-11 17:48:22 +0000791 // FIXME: This dispatch can potentially be sped up by unifiying it into
792 // a single switch statement. Opt for simplicity for now.
Ted Kremeneka7338b42008-03-11 06:39:11 +0000793
Ted Kremenek0d721572008-03-11 17:48:22 +0000794 switch (E) {
795 default:
796 assert (false && "Unhandled CFRef transition.");
797
798 case DoNothing:
Ted Kremenekce3ed1e2008-03-12 01:21:45 +0000799 if (V.getKind() == RefVal::Released) {
800 V = RefVal::makeUseAfterRelease();
801 hasError = V.getKind();
802 break;
803 }
804
Ted Kremenek0d721572008-03-11 17:48:22 +0000805 return B;
806
807 case IncRef:
808 switch (V.getKind()) {
809 default:
810 assert(false);
811
812 case RefVal::Owned:
813 V = RefVal::makeOwned(V.getCount()+1); break;
Ted Kremenekc4f81022008-04-10 23:09:18 +0000814
Ted Kremenek0d721572008-03-11 17:48:22 +0000815 case RefVal::NotOwned:
Ted Kremenekc4f81022008-04-10 23:09:18 +0000816 V = RefVal::makeNotOwned(V.getCount()+1);
Ted Kremenek0d721572008-03-11 17:48:22 +0000817 break;
818
819 case RefVal::Released:
Ted Kremenek0d721572008-03-11 17:48:22 +0000820 V = RefVal::makeUseAfterRelease();
Ted Kremenek1daa16c2008-03-11 18:14:09 +0000821 hasError = V.getKind();
Ted Kremenek0d721572008-03-11 17:48:22 +0000822 break;
823 }
824
825 case DecRef:
826 switch (V.getKind()) {
827 default:
828 assert (false);
829
830 case RefVal::Owned: {
Ted Kremenekc4f81022008-04-10 23:09:18 +0000831 signed Count = ((signed) V.getCount()) - 1;
832 V = Count >= 0 ? RefVal::makeOwned(Count) : RefVal::makeReleased();
Ted Kremenek0d721572008-03-11 17:48:22 +0000833 break;
834 }
835
Ted Kremenekc4f81022008-04-10 23:09:18 +0000836 case RefVal::NotOwned: {
837 signed Count = ((signed) V.getCount()) - 1;
838
839 if (Count >= 0)
840 V = RefVal::makeNotOwned(Count);
841 else {
842 V = RefVal::makeReleaseNotOwned();
843 hasError = V.getKind();
844 }
845
Ted Kremenek0d721572008-03-11 17:48:22 +0000846 break;
847 }
Ted Kremenek0d721572008-03-11 17:48:22 +0000848
849 case RefVal::Released:
Ted Kremenek0d721572008-03-11 17:48:22 +0000850 V = RefVal::makeUseAfterRelease();
Ted Kremenek1daa16c2008-03-11 18:14:09 +0000851 hasError = V.getKind();
Ted Kremenek0d721572008-03-11 17:48:22 +0000852 break;
853 }
854 }
855
856 return RefBFactory.Add(B, sym, V);
Ted Kremeneka7338b42008-03-11 06:39:11 +0000857}
858
Ted Kremenek10fe66d2008-04-09 01:10:13 +0000859
860//===----------------------------------------------------------------------===//
Ted Kremenek7d421f32008-04-09 23:49:11 +0000861// Error reporting.
Ted Kremenek10fe66d2008-04-09 01:10:13 +0000862//===----------------------------------------------------------------------===//
863
Ted Kremenek7d421f32008-04-09 23:49:11 +0000864void UseAfterRelease::EmitWarnings(BugReporter& BR) {
Ted Kremenek10fe66d2008-04-09 01:10:13 +0000865
Ted Kremenek7d421f32008-04-09 23:49:11 +0000866 for (CFRefCount::use_after_iterator I = TF.use_after_begin(),
867 E = TF.use_after_end(); I != E; ++I) {
868
869 BugReport report(*this);
870 BR.EmitPathWarning(report, *I);
Ted Kremenek10fe66d2008-04-09 01:10:13 +0000871 }
Ted Kremenek7d421f32008-04-09 23:49:11 +0000872}
873
874void BadRelease::EmitWarnings(BugReporter& BR) {
Ted Kremenek10fe66d2008-04-09 01:10:13 +0000875
Ted Kremenek7d421f32008-04-09 23:49:11 +0000876 for (CFRefCount::bad_release_iterator I = TF.bad_release_begin(),
877 E = TF.bad_release_end(); I != E; ++I) {
878
879 BugReport report(*this);
880 BR.EmitPathWarning(report, *I);
881 }
882}
Ted Kremenek10fe66d2008-04-09 01:10:13 +0000883
Ted Kremeneka7338b42008-03-11 06:39:11 +0000884//===----------------------------------------------------------------------===//
Ted Kremenekb1983ba2008-04-10 22:16:52 +0000885// Transfer function creation for external clients.
Ted Kremeneka7338b42008-03-11 06:39:11 +0000886//===----------------------------------------------------------------------===//
887
Ted Kremeneka4c74292008-04-10 22:58:08 +0000888GRTransferFuncs* clang::MakeCFRefCountTF(ASTContext& Ctx) {
889 return new CFRefCount(Ctx);
890}