blob: e51353a61dca37667aa9c11a6e24c269a1e6a2ea [file] [log] [blame]
Ted Kremenek827f93b2008-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 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"
17#include "clang/Basic/Diagnostic.h"
18#include "clang/Analysis/LocalCheckers.h"
Ted Kremeneka7338b42008-03-11 06:39:11 +000019#include "llvm/ADT/DenseMap.h"
20#include "llvm/ADT/FoldingSet.h"
21#include "llvm/ADT/ImmutableMap.h"
Ted Kremenek827f93b2008-03-06 00:08:09 +000022
23using namespace clang;
24
Ted Kremeneka7338b42008-03-11 06:39:11 +000025namespace {
26 enum ArgEffect { IncRef, DecRef, DoNothing };
27 typedef std::vector<ArgEffect> ArgEffects;
28}
Ted Kremenek827f93b2008-03-06 00:08:09 +000029
Ted Kremeneka7338b42008-03-11 06:39:11 +000030namespace llvm {
31 template <> struct FoldingSetTrait<ArgEffects> {
32 static void Profile(const ArgEffects& X, FoldingSetNodeID ID) {
33 for (ArgEffects::const_iterator I = X.begin(), E = X.end(); I!= E; ++I)
34 ID.AddInteger((unsigned) *I);
35 }
36
37 static void Profile(ArgEffects& X, FoldingSetNodeID ID) {
38 Profile(X, ID);
39 }
40 };
41} // end llvm namespace
42
43namespace {
Ted Kremenek827f93b2008-03-06 00:08:09 +000044
Ted Kremeneka7338b42008-03-11 06:39:11 +000045class RetEffect {
46public:
47 enum Kind { Alias = 0x0, OwnedSymbol = 0x1, NotOwnedSymbol = 0x2 };
48
49private:
50 unsigned Data;
51 RetEffect(Kind k, unsigned D) { Data = (Data << 2) | (unsigned) k; }
Ted Kremenek827f93b2008-03-06 00:08:09 +000052
Ted Kremeneka7338b42008-03-11 06:39:11 +000053public:
54
55 Kind getKind() const { return (Kind) (Data & 0x3); }
56
57 unsigned getValue() const {
58 assert(getKind() == Alias);
59 return Data & ~0x3;
60 }
Ted Kremenek827f93b2008-03-06 00:08:09 +000061
Ted Kremeneka7338b42008-03-11 06:39:11 +000062 static RetEffect MakeAlias(unsigned Idx) { return RetEffect(Alias, Idx); }
Ted Kremenek827f93b2008-03-06 00:08:09 +000063
Ted Kremeneka7338b42008-03-11 06:39:11 +000064 static RetEffect MakeOwned() { return RetEffect(OwnedSymbol, 0); }
Ted Kremenek827f93b2008-03-06 00:08:09 +000065
Ted Kremeneka7338b42008-03-11 06:39:11 +000066 static RetEffect MakeNotOwned() { return RetEffect(NotOwnedSymbol, 0); }
67
68 operator Kind() const { return getKind(); }
69
70 void Profile(llvm::FoldingSetNodeID& ID) const { ID.AddInteger(Data); }
71};
72
73
74class CFRefSummary : public llvm::FoldingSetNode {
75 ArgEffects* Args;
76 RetEffect Ret;
77public:
78
79 CFRefSummary(ArgEffects* A, RetEffect R) : Args(A), Ret(R) {}
80
81 unsigned getNumArgs() const { return Args->size(); }
82
Ted Kremenek0d721572008-03-11 17:48:22 +000083 ArgEffect getArg(unsigned idx) const {
84 assert (idx < getNumArgs());
85 return (*Args)[idx];
86 }
87
Ted Kremeneka7338b42008-03-11 06:39:11 +000088 typedef ArgEffects::const_iterator arg_iterator;
89
90 arg_iterator begin_args() const { return Args->begin(); }
91 arg_iterator end_args() const { return Args->end(); }
92
93 static void Profile(llvm::FoldingSetNodeID& ID, ArgEffects* A, RetEffect R) {
94 ID.AddPointer(A);
95 ID.Add(R);
96 }
97
98 void Profile(llvm::FoldingSetNodeID& ID) const {
99 Profile(ID, Args, Ret);
100 }
101};
102
103
104class CFRefSummaryManager {
105 typedef llvm::FoldingSet<llvm::FoldingSetNodeWrapper<ArgEffects> > AESetTy;
106 typedef llvm::FoldingSet<CFRefSummary> SummarySetTy;
107 typedef llvm::DenseMap<FunctionDecl*, CFRefSummary*> SummaryMapTy;
108
109 SummarySetTy SummarySet;
110 SummaryMapTy SummaryMap;
111 AESetTy AESet;
112 llvm::BumpPtrAllocator BPAlloc;
113
114 ArgEffects ScratchArgs;
115
116public:
117 CFRefSummaryManager() {}
118 ~CFRefSummaryManager();
119
120 CFRefSummary* getSummary(FunctionDecl* FD);
121};
122
123} // end anonymous namespace
124
125//===----------------------------------------------------------------------===//
126// Implementation of checker data structures.
127//===----------------------------------------------------------------------===//
128
129CFRefSummaryManager::~CFRefSummaryManager() {
130
131 // FIXME: The ArgEffects could eventually be allocated from BPAlloc,
132 // mitigating the need to do explicit cleanup of the
133 // Argument-Effect summaries.
134
135 for (AESetTy::iterator I = AESet.begin(), E = AESet.end(); I!=E; ++I)
136 I->getValue().~ArgEffects();
Ted Kremenek827f93b2008-03-06 00:08:09 +0000137}
Ted Kremeneka7338b42008-03-11 06:39:11 +0000138
139CFRefSummary* CFRefSummaryManager::getSummary(FunctionDecl* FD) {
Ted Kremenek827f93b2008-03-06 00:08:09 +0000140
Ted Kremeneka7338b42008-03-11 06:39:11 +0000141 { // Look into our cache of summaries to see if we have already computed
142 // a summary for this FunctionDecl.
143
144 SummaryMapTy::iterator I = SummaryMap.find(FD);
145
146 if (I != SummaryMap.end())
147 return I->second;
148 }
149
150 //
151
152
153 return NULL;
Ted Kremenek827f93b2008-03-06 00:08:09 +0000154}
155
Ted Kremeneka7338b42008-03-11 06:39:11 +0000156//===----------------------------------------------------------------------===//
157// Transfer functions.
158//===----------------------------------------------------------------------===//
159
Ted Kremeneka7338b42008-03-11 06:39:11 +0000160namespace {
161
Ted Kremenek0d721572008-03-11 17:48:22 +0000162class RefVal {
163 unsigned Data;
164
165 RefVal(unsigned K, unsigned D) : Data((D << 3) | K) {
166 assert ((K & ~0x5) == 0x0);
167 }
168
169 RefVal(unsigned K) : Data(K) {
170 assert ((K & ~0x5) == 0x0);
171 }
172
173public:
174 enum Kind { Owned = 0, AcqOwned = 1, NotOwned = 2, Released = 3,
175 ErrorUseAfterRelease = 4, ErrorReleaseNotOwned = 5 };
176
177
178 Kind getKind() const { return (Kind) (Data & 0x5); }
179
180 unsigned getCount() const {
181 assert (getKind() == Owned || getKind() == AcqOwned);
182 return Data >> 3;
183 }
184
Ted Kremenek1daa16c2008-03-11 18:14:09 +0000185 static bool isError(Kind k) { return k >= ErrorUseAfterRelease; }
186
Ted Kremenek0d721572008-03-11 17:48:22 +0000187 static RefVal makeOwned(unsigned Count) { return RefVal(Owned, Count); }
188 static RefVal makeAcqOwned(unsigned Count) { return RefVal(AcqOwned, Count); }
189 static RefVal makeNotOwned() { return RefVal(NotOwned); }
190 static RefVal makeReleased() { return RefVal(Released); }
191 static RefVal makeUseAfterRelease() { return RefVal(ErrorUseAfterRelease); }
192 static RefVal makeReleaseNotOwned() { return RefVal(ErrorReleaseNotOwned); }
193
194 bool operator==(const RefVal& X) const { return Data == X.Data; }
195 void Profile(llvm::FoldingSetNodeID& ID) const { ID.AddInteger(Data); }
196};
197
198
Ted Kremeneka7338b42008-03-11 06:39:11 +0000199class CFRefCount : public GRSimpleVals {
Ted Kremenek0d721572008-03-11 17:48:22 +0000200 typedef llvm::ImmutableMap<SymbolID, RefVal> RefBindings;
Ted Kremeneka7338b42008-03-11 06:39:11 +0000201 typedef RefBindings::Factory RefBFactoryTy;
Ted Kremenek1daa16c2008-03-11 18:14:09 +0000202
203 typedef llvm::SmallPtrSet<GRExprEngine::NodeTy*,2> UseAfterReleasesTy;
204 typedef llvm::SmallPtrSet<GRExprEngine::NodeTy*,2> ReleasesNotOwnedTy;
205
Ted Kremeneka7338b42008-03-11 06:39:11 +0000206 CFRefSummaryManager Summaries;
207 RefBFactoryTy RefBFactory;
Ted Kremenek1daa16c2008-03-11 18:14:09 +0000208
209 UseAfterReleasesTy UseAfterReleases;
210 ReleasesNotOwnedTy ReleasesNotOwned;
211
Ted Kremeneka7338b42008-03-11 06:39:11 +0000212
213 static RefBindings GetRefBindings(ValueState& StImpl) {
214 return RefBindings((RefBindings::TreeTy*) StImpl.CheckerState);
215 }
216
217 static void SetRefBindings(ValueState& StImpl, RefBindings B) {
218 StImpl.CheckerState = B.getRoot();
219 }
220
221 RefBindings Remove(RefBindings B, SymbolID sym) {
222 return RefBFactory.Remove(B, sym);
223 }
224
Ted Kremenek0d721572008-03-11 17:48:22 +0000225 RefBindings Update(RefBindings B, SymbolID sym, RefVal V, ArgEffect E,
Ted Kremenek1daa16c2008-03-11 18:14:09 +0000226 RefVal::Kind& hasError);
Ted Kremeneka7338b42008-03-11 06:39:11 +0000227
228public:
229 CFRefCount() {}
230 virtual ~CFRefCount() {}
231
232 // Calls.
233
234 virtual void EvalCall(ExplodedNodeSet<ValueState>& Dst,
235 ValueStateManager& StateMgr,
236 GRStmtNodeBuilder<ValueState>& Builder,
237 BasicValueFactory& BasicVals,
238 CallExpr* CE, LVal L,
239 ExplodedNode<ValueState>* Pred);
240};
241
242} // end anonymous namespace
243
Ted Kremenek827f93b2008-03-06 00:08:09 +0000244void CFRefCount::EvalCall(ExplodedNodeSet<ValueState>& Dst,
245 ValueStateManager& StateMgr,
246 GRStmtNodeBuilder<ValueState>& Builder,
Ted Kremenek8ad19872008-03-07 20:13:31 +0000247 BasicValueFactory& BasicVals,
Ted Kremenek827f93b2008-03-06 00:08:09 +0000248 CallExpr* CE, LVal L,
249 ExplodedNode<ValueState>* Pred) {
250
Ted Kremeneka7338b42008-03-11 06:39:11 +0000251 // FIXME: Support calls to things other than lval::FuncVal. At the very
252 // least we should stop tracking ref-state for ref-counted objects passed
253 // to these functions.
Ted Kremenek827f93b2008-03-06 00:08:09 +0000254
Ted Kremeneka7338b42008-03-11 06:39:11 +0000255 assert (isa<lval::FuncVal>(L) && "Not yet implemented.");
256
257 // Get the summary.
Ted Kremenek827f93b2008-03-06 00:08:09 +0000258
Ted Kremeneka7338b42008-03-11 06:39:11 +0000259 lval::FuncVal FV = cast<lval::FuncVal>(L);
260 FunctionDecl* FD = FV.getDecl();
261 CFRefSummary* Summ = Summaries.getSummary(FD);
Ted Kremenek827f93b2008-03-06 00:08:09 +0000262
Ted Kremeneka7338b42008-03-11 06:39:11 +0000263 // Get the state.
264
265 ValueState* St = Builder.GetState(Pred);
266
267 // Evaluate the effects of the call.
268
269 ValueState StVals = *St;
Ted Kremenek1daa16c2008-03-11 18:14:09 +0000270 RefVal::Kind hasError = (RefVal::Kind) 0;
Ted Kremeneka7338b42008-03-11 06:39:11 +0000271
272 if (!Summ) {
Ted Kremenek827f93b2008-03-06 00:08:09 +0000273
Ted Kremeneka7338b42008-03-11 06:39:11 +0000274 // This function has no summary. Invalidate all reference-count state
275 // for arguments passed to this function, and also nuke the values of
276 // arguments passed-by-reference.
277
278 ValueState StVals = *St;
279
280 for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end();
281 I != E; ++I) {
282
283 RVal V = StateMgr.GetRVal(St, *I);
284
285 if (isa<lval::SymbolVal>(V)) {
286 SymbolID Sym = cast<lval::SymbolVal>(V).getSymbol();
287 RefBindings B = GetRefBindings(StVals);
288 SetRefBindings(StVals, Remove(B, Sym));
289 }
290
291 if (isa<LVal>(V))
292 StateMgr.Unbind(StVals, cast<LVal>(V));
293 }
Ted Kremenek827f93b2008-03-06 00:08:09 +0000294 }
Ted Kremeneka7338b42008-03-11 06:39:11 +0000295 else {
296
297 // This function has a summary. Evaluate the effect of the arguments.
298
299 unsigned idx = 0;
300
301 for (CallExpr::arg_iterator I=CE->arg_begin(), E=CE->arg_end();
302 I!=E; ++I, ++idx) {
303
304 RVal V = StateMgr.GetRVal(St, *I);
305
306 if (isa<lval::SymbolVal>(V)) {
307 SymbolID Sym = cast<lval::SymbolVal>(V).getSymbol();
308 RefBindings B = GetRefBindings(StVals);
Ted Kremenek0d721572008-03-11 17:48:22 +0000309
310 if (RefBindings::TreeTy* T = B.SlimFind(Sym)) {
311 B = Update(B, Sym, T->getValue().second, Summ->getArg(idx), hasError);
312 SetRefBindings(StVals, B);
313 if (hasError) break;
314 }
Ted Kremeneka7338b42008-03-11 06:39:11 +0000315 }
316 }
317 }
318
319 St = StateMgr.getPersistentState(StVals);
Ted Kremenek0d721572008-03-11 17:48:22 +0000320
321 if (hasError) {
Ted Kremenek1daa16c2008-03-11 18:14:09 +0000322 GRExprEngine::NodeTy* N = Builder.generateNode(CE, St, Pred);
323
324 if (N) {
325 N->markAsSink();
326
327 switch (hasError) {
328 default: assert(false);
329 case RefVal::ErrorUseAfterRelease:
330 UseAfterReleases.insert(N);
331 break;
332
333 case RefVal::ErrorReleaseNotOwned:
334 ReleasesNotOwned.insert(N);
335 break;
336 }
337 }
Ted Kremenek0d721572008-03-11 17:48:22 +0000338 }
Ted Kremenek1daa16c2008-03-11 18:14:09 +0000339 else
340 Builder.Nodify(Dst, CE, Pred, St);
Ted Kremenek827f93b2008-03-06 00:08:09 +0000341}
Ted Kremeneka7338b42008-03-11 06:39:11 +0000342
343
344CFRefCount::RefBindings CFRefCount::Update(RefBindings B, SymbolID sym,
Ted Kremenek0d721572008-03-11 17:48:22 +0000345 RefVal V, ArgEffect E,
Ted Kremenek1daa16c2008-03-11 18:14:09 +0000346 RefVal::Kind& hasError) {
Ted Kremeneka7338b42008-03-11 06:39:11 +0000347
Ted Kremenek0d721572008-03-11 17:48:22 +0000348 // FIXME: This dispatch can potentially be sped up by unifiying it into
349 // a single switch statement. Opt for simplicity for now.
Ted Kremeneka7338b42008-03-11 06:39:11 +0000350
Ted Kremenek0d721572008-03-11 17:48:22 +0000351 switch (E) {
352 default:
353 assert (false && "Unhandled CFRef transition.");
354
355 case DoNothing:
356 return B;
357
358 case IncRef:
359 switch (V.getKind()) {
360 default:
361 assert(false);
362
363 case RefVal::Owned:
364 V = RefVal::makeOwned(V.getCount()+1); break;
365
366 case RefVal::AcqOwned:
367 V = RefVal::makeAcqOwned(V.getCount()+1);
368 break;
369
370 case RefVal::NotOwned:
371 V = RefVal::makeAcqOwned(1);
372 break;
373
374 case RefVal::Released:
Ted Kremenek0d721572008-03-11 17:48:22 +0000375 V = RefVal::makeUseAfterRelease();
Ted Kremenek1daa16c2008-03-11 18:14:09 +0000376 hasError = V.getKind();
Ted Kremenek0d721572008-03-11 17:48:22 +0000377 break;
378 }
379
380 case DecRef:
381 switch (V.getKind()) {
382 default:
383 assert (false);
384
385 case RefVal::Owned: {
386 unsigned Count = V.getCount() - 1;
387 V = Count ? RefVal::makeOwned(Count) : RefVal::makeReleased();
388 break;
389 }
390
391 case RefVal::AcqOwned: {
392 unsigned Count = V.getCount() - 1;
393 V = Count ? RefVal::makeAcqOwned(Count) : RefVal::makeNotOwned();
394 break;
395 }
396
397 case RefVal::NotOwned:
Ted Kremenek0d721572008-03-11 17:48:22 +0000398 V = RefVal::makeReleaseNotOwned();
Ted Kremenek1daa16c2008-03-11 18:14:09 +0000399 hasError = V.getKind();
Ted Kremenek0d721572008-03-11 17:48:22 +0000400 break;
401
402 case RefVal::Released:
Ted Kremenek0d721572008-03-11 17:48:22 +0000403 V = RefVal::makeUseAfterRelease();
Ted Kremenek1daa16c2008-03-11 18:14:09 +0000404 hasError = V.getKind();
Ted Kremenek0d721572008-03-11 17:48:22 +0000405 break;
406 }
407 }
408
409 return RefBFactory.Add(B, sym, V);
Ted Kremeneka7338b42008-03-11 06:39:11 +0000410}
411
412//===----------------------------------------------------------------------===//
413// Driver for the CFRefCount Checker.
414//===----------------------------------------------------------------------===//
415
416namespace clang {
417
418 void CheckCFRefCount(CFG& cfg, FunctionDecl& FD, ASTContext& Ctx,
419 Diagnostic& Diag) {
420
421 if (Diag.hasErrorOccurred())
422 return;
423
424 // FIXME: Refactor some day so this becomes a single function invocation.
425
426 GRCoreEngine<GRExprEngine> Engine(cfg, FD, Ctx);
427 GRExprEngine* CS = &Engine.getCheckerState();
428 CFRefCount TF;
429 CS->setTransferFunctions(TF);
430 Engine.ExecuteWorkList(20000);
431
432 }
433
434} // end clang namespace