blob: ea9c8bfd37ef17e3b10c39fd9de837d7be28494d [file] [log] [blame]
Ted Kremenek2fff37e2008-03-06 00:08:09 +00001// CFRefCount.cpp - Transfer functions for tracking simple values -*- C++ -*--
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
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 Kremenek2fff37e2008-03-06 00:08:09 +000016#include "clang/Analysis/PathSensitive/ValueState.h"
17#include "clang/Basic/Diagnostic.h"
18#include "clang/Analysis/LocalCheckers.h"
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000019#include "llvm/ADT/DenseMap.h"
20#include "llvm/ADT/FoldingSet.h"
21#include "llvm/ADT/ImmutableMap.h"
Ted Kremenekf3948042008-03-11 19:44:10 +000022#include <ostream>
Ted Kremenek2fff37e2008-03-06 00:08:09 +000023
24using namespace clang;
25
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000026namespace {
27 enum ArgEffect { IncRef, DecRef, DoNothing };
28 typedef std::vector<ArgEffect> ArgEffects;
29}
Ted Kremenek2fff37e2008-03-06 00:08:09 +000030
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000031namespace llvm {
32 template <> struct FoldingSetTrait<ArgEffects> {
33 static void Profile(const ArgEffects& X, FoldingSetNodeID ID) {
34 for (ArgEffects::const_iterator I = X.begin(), E = X.end(); I!= E; ++I)
35 ID.AddInteger((unsigned) *I);
36 }
37
38 static void Profile(ArgEffects& X, FoldingSetNodeID ID) {
39 Profile(X, ID);
40 }
41 };
42} // end llvm namespace
43
44namespace {
Ted Kremenek2fff37e2008-03-06 00:08:09 +000045
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000046class RetEffect {
47public:
48 enum Kind { Alias = 0x0, OwnedSymbol = 0x1, NotOwnedSymbol = 0x2 };
49
50private:
51 unsigned Data;
52 RetEffect(Kind k, unsigned D) { Data = (Data << 2) | (unsigned) k; }
Ted Kremenek2fff37e2008-03-06 00:08:09 +000053
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000054public:
55
56 Kind getKind() const { return (Kind) (Data & 0x3); }
57
58 unsigned getValue() const {
59 assert(getKind() == Alias);
60 return Data & ~0x3;
61 }
Ted Kremenek2fff37e2008-03-06 00:08:09 +000062
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000063 static RetEffect MakeAlias(unsigned Idx) { return RetEffect(Alias, Idx); }
Ted Kremenek2fff37e2008-03-06 00:08:09 +000064
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000065 static RetEffect MakeOwned() { return RetEffect(OwnedSymbol, 0); }
Ted Kremenek2fff37e2008-03-06 00:08:09 +000066
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000067 static RetEffect MakeNotOwned() { return RetEffect(NotOwnedSymbol, 0); }
68
69 operator Kind() const { return getKind(); }
70
71 void Profile(llvm::FoldingSetNodeID& ID) const { ID.AddInteger(Data); }
72};
73
74
75class CFRefSummary : public llvm::FoldingSetNode {
76 ArgEffects* Args;
77 RetEffect Ret;
78public:
79
80 CFRefSummary(ArgEffects* A, RetEffect R) : Args(A), Ret(R) {}
81
82 unsigned getNumArgs() const { return Args->size(); }
83
Ted Kremenek1ac08d62008-03-11 17:48:22 +000084 ArgEffect getArg(unsigned idx) const {
85 assert (idx < getNumArgs());
86 return (*Args)[idx];
87 }
88
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000089 typedef ArgEffects::const_iterator arg_iterator;
90
91 arg_iterator begin_args() const { return Args->begin(); }
92 arg_iterator end_args() const { return Args->end(); }
93
94 static void Profile(llvm::FoldingSetNodeID& ID, ArgEffects* A, RetEffect R) {
95 ID.AddPointer(A);
96 ID.Add(R);
97 }
98
99 void Profile(llvm::FoldingSetNodeID& ID) const {
100 Profile(ID, Args, Ret);
101 }
102};
103
104
105class CFRefSummaryManager {
106 typedef llvm::FoldingSet<llvm::FoldingSetNodeWrapper<ArgEffects> > AESetTy;
107 typedef llvm::FoldingSet<CFRefSummary> SummarySetTy;
108 typedef llvm::DenseMap<FunctionDecl*, CFRefSummary*> SummaryMapTy;
109
110 SummarySetTy SummarySet;
111 SummaryMapTy SummaryMap;
112 AESetTy AESet;
113 llvm::BumpPtrAllocator BPAlloc;
114
115 ArgEffects ScratchArgs;
116
117public:
118 CFRefSummaryManager() {}
119 ~CFRefSummaryManager();
120
121 CFRefSummary* getSummary(FunctionDecl* FD);
122};
123
124} // end anonymous namespace
125
126//===----------------------------------------------------------------------===//
127// Implementation of checker data structures.
128//===----------------------------------------------------------------------===//
129
130CFRefSummaryManager::~CFRefSummaryManager() {
131
132 // FIXME: The ArgEffects could eventually be allocated from BPAlloc,
133 // mitigating the need to do explicit cleanup of the
134 // Argument-Effect summaries.
135
136 for (AESetTy::iterator I = AESet.begin(), E = AESet.end(); I!=E; ++I)
137 I->getValue().~ArgEffects();
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000138}
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000139
140CFRefSummary* CFRefSummaryManager::getSummary(FunctionDecl* FD) {
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000141
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000142 { // Look into our cache of summaries to see if we have already computed
143 // a summary for this FunctionDecl.
144
145 SummaryMapTy::iterator I = SummaryMap.find(FD);
146
147 if (I != SummaryMap.end())
148 return I->second;
149 }
150
151 //
152
153
154 return NULL;
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000155}
156
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000157//===----------------------------------------------------------------------===//
158// Transfer functions.
159//===----------------------------------------------------------------------===//
160
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000161namespace {
162
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000163class RefVal {
164 unsigned Data;
165
166 RefVal(unsigned K, unsigned D) : Data((D << 3) | K) {
167 assert ((K & ~0x5) == 0x0);
168 }
169
170 RefVal(unsigned K) : Data(K) {
171 assert ((K & ~0x5) == 0x0);
172 }
173
174public:
175 enum Kind { Owned = 0, AcqOwned = 1, NotOwned = 2, Released = 3,
176 ErrorUseAfterRelease = 4, ErrorReleaseNotOwned = 5 };
177
178
179 Kind getKind() const { return (Kind) (Data & 0x5); }
180
181 unsigned getCount() const {
182 assert (getKind() == Owned || getKind() == AcqOwned);
183 return Data >> 3;
184 }
185
Ted Kremenek73c750b2008-03-11 18:14:09 +0000186 static bool isError(Kind k) { return k >= ErrorUseAfterRelease; }
187
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000188 static RefVal makeOwned(unsigned Count) { return RefVal(Owned, Count); }
189 static RefVal makeAcqOwned(unsigned Count) { return RefVal(AcqOwned, Count); }
190 static RefVal makeNotOwned() { return RefVal(NotOwned); }
191 static RefVal makeReleased() { return RefVal(Released); }
192 static RefVal makeUseAfterRelease() { return RefVal(ErrorUseAfterRelease); }
193 static RefVal makeReleaseNotOwned() { return RefVal(ErrorReleaseNotOwned); }
194
195 bool operator==(const RefVal& X) const { return Data == X.Data; }
196 void Profile(llvm::FoldingSetNodeID& ID) const { ID.AddInteger(Data); }
Ted Kremenekf3948042008-03-11 19:44:10 +0000197
198 void print(std::ostream& Out) const;
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000199};
Ted Kremenekf3948042008-03-11 19:44:10 +0000200
201void RefVal::print(std::ostream& Out) const {
202 switch (getKind()) {
203 default: assert(false);
204 case Owned:
205 Out << "Owned(" << getCount() << ")";
206 break;
207
208 case AcqOwned:
209 Out << "Acquired-Owned(" << getCount() << ")";
210 break;
211
212 case NotOwned:
213 Out << "Not-Owned";
214 break;
215
216 case Released:
217 Out << "Released";
218 break;
219
220 case ErrorUseAfterRelease:
221 Out << "Use-After-Release [ERROR]";
222 break;
223
224 case ErrorReleaseNotOwned:
225 Out << "Release of Not-Owned [ERROR]";
226 break;
227 }
228}
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000229
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000230class CFRefCount : public GRSimpleVals {
Ted Kremenekf3948042008-03-11 19:44:10 +0000231
232 // Type definitions.
233
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000234 typedef llvm::ImmutableMap<SymbolID, RefVal> RefBindings;
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000235 typedef RefBindings::Factory RefBFactoryTy;
Ted Kremenek73c750b2008-03-11 18:14:09 +0000236
237 typedef llvm::SmallPtrSet<GRExprEngine::NodeTy*,2> UseAfterReleasesTy;
238 typedef llvm::SmallPtrSet<GRExprEngine::NodeTy*,2> ReleasesNotOwnedTy;
239
Ted Kremenekf3948042008-03-11 19:44:10 +0000240 class BindingsPrinter : public ValueState::CheckerStatePrinter {
241 public:
242 virtual void PrintCheckerState(std::ostream& Out, void* State,
243 const char* nl, const char* sep);
244 };
245
246 // Instance variables.
247
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000248 CFRefSummaryManager Summaries;
249 RefBFactoryTy RefBFactory;
Ted Kremenek73c750b2008-03-11 18:14:09 +0000250
251 UseAfterReleasesTy UseAfterReleases;
252 ReleasesNotOwnedTy ReleasesNotOwned;
253
Ted Kremenekf3948042008-03-11 19:44:10 +0000254 BindingsPrinter Printer;
255
256 // Private methods.
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000257
258 static RefBindings GetRefBindings(ValueState& StImpl) {
259 return RefBindings((RefBindings::TreeTy*) StImpl.CheckerState);
260 }
261
262 static void SetRefBindings(ValueState& StImpl, RefBindings B) {
263 StImpl.CheckerState = B.getRoot();
264 }
265
266 RefBindings Remove(RefBindings B, SymbolID sym) {
267 return RefBFactory.Remove(B, sym);
268 }
269
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000270 RefBindings Update(RefBindings B, SymbolID sym, RefVal V, ArgEffect E,
Ted Kremenek73c750b2008-03-11 18:14:09 +0000271 RefVal::Kind& hasError);
Ted Kremenekf3948042008-03-11 19:44:10 +0000272
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000273
274public:
275 CFRefCount() {}
276 virtual ~CFRefCount() {}
Ted Kremenekf3948042008-03-11 19:44:10 +0000277
278 virtual ValueState::CheckerStatePrinter* getCheckerStatePrinter() {
279 return &Printer;
280 }
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000281
282 // Calls.
283
284 virtual void EvalCall(ExplodedNodeSet<ValueState>& Dst,
285 ValueStateManager& StateMgr,
286 GRStmtNodeBuilder<ValueState>& Builder,
287 BasicValueFactory& BasicVals,
288 CallExpr* CE, LVal L,
289 ExplodedNode<ValueState>* Pred);
290};
291
292} // end anonymous namespace
293
Ted Kremenekf3948042008-03-11 19:44:10 +0000294void CFRefCount::BindingsPrinter::PrintCheckerState(std::ostream& Out,
295 void* State, const char* nl,
296 const char* sep) {
297 RefBindings B((RefBindings::TreeTy*) State);
298
299 if (State)
300 Out << sep << nl;
301
302 for (RefBindings::iterator I=B.begin(), E=B.end(); I!=E; ++I) {
303 Out << (*I).first << " : ";
304 (*I).second.print(Out);
305 Out << nl;
306 }
307}
308
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000309void CFRefCount::EvalCall(ExplodedNodeSet<ValueState>& Dst,
310 ValueStateManager& StateMgr,
311 GRStmtNodeBuilder<ValueState>& Builder,
Ted Kremenek240f1f02008-03-07 20:13:31 +0000312 BasicValueFactory& BasicVals,
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000313 CallExpr* CE, LVal L,
314 ExplodedNode<ValueState>* Pred) {
315
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000316 // FIXME: Support calls to things other than lval::FuncVal. At the very
317 // least we should stop tracking ref-state for ref-counted objects passed
318 // to these functions.
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000319
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000320 assert (isa<lval::FuncVal>(L) && "Not yet implemented.");
321
322 // Get the summary.
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000323
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000324 lval::FuncVal FV = cast<lval::FuncVal>(L);
325 FunctionDecl* FD = FV.getDecl();
326 CFRefSummary* Summ = Summaries.getSummary(FD);
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000327
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000328 // Get the state.
329
330 ValueState* St = Builder.GetState(Pred);
331
332 // Evaluate the effects of the call.
333
334 ValueState StVals = *St;
Ted Kremenek73c750b2008-03-11 18:14:09 +0000335 RefVal::Kind hasError = (RefVal::Kind) 0;
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000336
337 if (!Summ) {
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000338
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000339 // This function has no summary. Invalidate all reference-count state
340 // for arguments passed to this function, and also nuke the values of
341 // arguments passed-by-reference.
342
343 ValueState StVals = *St;
344
345 for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end();
346 I != E; ++I) {
347
348 RVal V = StateMgr.GetRVal(St, *I);
349
350 if (isa<lval::SymbolVal>(V)) {
351 SymbolID Sym = cast<lval::SymbolVal>(V).getSymbol();
352 RefBindings B = GetRefBindings(StVals);
353 SetRefBindings(StVals, Remove(B, Sym));
354 }
355
356 if (isa<LVal>(V))
357 StateMgr.Unbind(StVals, cast<LVal>(V));
358 }
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000359 }
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000360 else {
361
362 // This function has a summary. Evaluate the effect of the arguments.
363
364 unsigned idx = 0;
365
366 for (CallExpr::arg_iterator I=CE->arg_begin(), E=CE->arg_end();
367 I!=E; ++I, ++idx) {
368
369 RVal V = StateMgr.GetRVal(St, *I);
370
371 if (isa<lval::SymbolVal>(V)) {
372 SymbolID Sym = cast<lval::SymbolVal>(V).getSymbol();
373 RefBindings B = GetRefBindings(StVals);
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000374
375 if (RefBindings::TreeTy* T = B.SlimFind(Sym)) {
376 B = Update(B, Sym, T->getValue().second, Summ->getArg(idx), hasError);
377 SetRefBindings(StVals, B);
378 if (hasError) break;
379 }
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000380 }
381 }
382 }
383
384 St = StateMgr.getPersistentState(StVals);
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000385
386 if (hasError) {
Ted Kremenek73c750b2008-03-11 18:14:09 +0000387 GRExprEngine::NodeTy* N = Builder.generateNode(CE, St, Pred);
388
389 if (N) {
390 N->markAsSink();
391
392 switch (hasError) {
393 default: assert(false);
394 case RefVal::ErrorUseAfterRelease:
395 UseAfterReleases.insert(N);
396 break;
397
398 case RefVal::ErrorReleaseNotOwned:
399 ReleasesNotOwned.insert(N);
400 break;
401 }
402 }
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000403 }
Ted Kremenek73c750b2008-03-11 18:14:09 +0000404 else
405 Builder.Nodify(Dst, CE, Pred, St);
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000406}
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000407
408
409CFRefCount::RefBindings CFRefCount::Update(RefBindings B, SymbolID sym,
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000410 RefVal V, ArgEffect E,
Ted Kremenek73c750b2008-03-11 18:14:09 +0000411 RefVal::Kind& hasError) {
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000412
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000413 // FIXME: This dispatch can potentially be sped up by unifiying it into
414 // a single switch statement. Opt for simplicity for now.
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000415
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000416 switch (E) {
417 default:
418 assert (false && "Unhandled CFRef transition.");
419
420 case DoNothing:
421 return B;
422
423 case IncRef:
424 switch (V.getKind()) {
425 default:
426 assert(false);
427
428 case RefVal::Owned:
429 V = RefVal::makeOwned(V.getCount()+1); break;
430
431 case RefVal::AcqOwned:
432 V = RefVal::makeAcqOwned(V.getCount()+1);
433 break;
434
435 case RefVal::NotOwned:
436 V = RefVal::makeAcqOwned(1);
437 break;
438
439 case RefVal::Released:
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000440 V = RefVal::makeUseAfterRelease();
Ted Kremenek73c750b2008-03-11 18:14:09 +0000441 hasError = V.getKind();
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000442 break;
443 }
444
445 case DecRef:
446 switch (V.getKind()) {
447 default:
448 assert (false);
449
450 case RefVal::Owned: {
451 unsigned Count = V.getCount() - 1;
452 V = Count ? RefVal::makeOwned(Count) : RefVal::makeReleased();
453 break;
454 }
455
456 case RefVal::AcqOwned: {
457 unsigned Count = V.getCount() - 1;
458 V = Count ? RefVal::makeAcqOwned(Count) : RefVal::makeNotOwned();
459 break;
460 }
461
462 case RefVal::NotOwned:
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000463 V = RefVal::makeReleaseNotOwned();
Ted Kremenek73c750b2008-03-11 18:14:09 +0000464 hasError = V.getKind();
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000465 break;
466
467 case RefVal::Released:
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000468 V = RefVal::makeUseAfterRelease();
Ted Kremenek73c750b2008-03-11 18:14:09 +0000469 hasError = V.getKind();
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000470 break;
471 }
472 }
473
474 return RefBFactory.Add(B, sym, V);
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000475}
476
477//===----------------------------------------------------------------------===//
478// Driver for the CFRefCount Checker.
479//===----------------------------------------------------------------------===//
480
481namespace clang {
482
483 void CheckCFRefCount(CFG& cfg, FunctionDecl& FD, ASTContext& Ctx,
484 Diagnostic& Diag) {
485
486 if (Diag.hasErrorOccurred())
487 return;
488
489 // FIXME: Refactor some day so this becomes a single function invocation.
490
491 GRCoreEngine<GRExprEngine> Engine(cfg, FD, Ctx);
492 GRExprEngine* CS = &Engine.getCheckerState();
493 CFRefCount TF;
494 CS->setTransferFunctions(TF);
495 Engine.ExecuteWorkList(20000);
496
497 }
498
499} // end clang namespace