blob: 93de1dcfd16786e1b0bef100aec32fa92a3a78ed [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
83 typedef ArgEffects::const_iterator arg_iterator;
84
85 arg_iterator begin_args() const { return Args->begin(); }
86 arg_iterator end_args() const { return Args->end(); }
87
88 static void Profile(llvm::FoldingSetNodeID& ID, ArgEffects* A, RetEffect R) {
89 ID.AddPointer(A);
90 ID.Add(R);
91 }
92
93 void Profile(llvm::FoldingSetNodeID& ID) const {
94 Profile(ID, Args, Ret);
95 }
96};
97
98
99class CFRefSummaryManager {
100 typedef llvm::FoldingSet<llvm::FoldingSetNodeWrapper<ArgEffects> > AESetTy;
101 typedef llvm::FoldingSet<CFRefSummary> SummarySetTy;
102 typedef llvm::DenseMap<FunctionDecl*, CFRefSummary*> SummaryMapTy;
103
104 SummarySetTy SummarySet;
105 SummaryMapTy SummaryMap;
106 AESetTy AESet;
107 llvm::BumpPtrAllocator BPAlloc;
108
109 ArgEffects ScratchArgs;
110
111public:
112 CFRefSummaryManager() {}
113 ~CFRefSummaryManager();
114
115 CFRefSummary* getSummary(FunctionDecl* FD);
116};
117
118} // end anonymous namespace
119
120//===----------------------------------------------------------------------===//
121// Implementation of checker data structures.
122//===----------------------------------------------------------------------===//
123
124CFRefSummaryManager::~CFRefSummaryManager() {
125
126 // FIXME: The ArgEffects could eventually be allocated from BPAlloc,
127 // mitigating the need to do explicit cleanup of the
128 // Argument-Effect summaries.
129
130 for (AESetTy::iterator I = AESet.begin(), E = AESet.end(); I!=E; ++I)
131 I->getValue().~ArgEffects();
Ted Kremenek827f93b2008-03-06 00:08:09 +0000132}
Ted Kremeneka7338b42008-03-11 06:39:11 +0000133
134CFRefSummary* CFRefSummaryManager::getSummary(FunctionDecl* FD) {
Ted Kremenek827f93b2008-03-06 00:08:09 +0000135
Ted Kremeneka7338b42008-03-11 06:39:11 +0000136 { // Look into our cache of summaries to see if we have already computed
137 // a summary for this FunctionDecl.
138
139 SummaryMapTy::iterator I = SummaryMap.find(FD);
140
141 if (I != SummaryMap.end())
142 return I->second;
143 }
144
145 //
146
147
148 return NULL;
Ted Kremenek827f93b2008-03-06 00:08:09 +0000149}
150
Ted Kremeneka7338b42008-03-11 06:39:11 +0000151//===----------------------------------------------------------------------===//
152// Transfer functions.
153//===----------------------------------------------------------------------===//
154
155typedef unsigned RefState; // FIXME
156
157namespace {
158
159class CFRefCount : public GRSimpleVals {
160 typedef llvm::ImmutableMap<SymbolID, RefState> RefBindings;
161 typedef RefBindings::Factory RefBFactoryTy;
162
163 CFRefSummaryManager Summaries;
164 RefBFactoryTy RefBFactory;
165
166 static RefBindings GetRefBindings(ValueState& StImpl) {
167 return RefBindings((RefBindings::TreeTy*) StImpl.CheckerState);
168 }
169
170 static void SetRefBindings(ValueState& StImpl, RefBindings B) {
171 StImpl.CheckerState = B.getRoot();
172 }
173
174 RefBindings Remove(RefBindings B, SymbolID sym) {
175 return RefBFactory.Remove(B, sym);
176 }
177
178 RefBindings Update(RefBindings B, SymbolID sym,
179 CFRefSummary* Summ, unsigned ArgIdx);
180
181public:
182 CFRefCount() {}
183 virtual ~CFRefCount() {}
184
185 // Calls.
186
187 virtual void EvalCall(ExplodedNodeSet<ValueState>& Dst,
188 ValueStateManager& StateMgr,
189 GRStmtNodeBuilder<ValueState>& Builder,
190 BasicValueFactory& BasicVals,
191 CallExpr* CE, LVal L,
192 ExplodedNode<ValueState>* Pred);
193};
194
195} // end anonymous namespace
196
Ted Kremenek827f93b2008-03-06 00:08:09 +0000197void CFRefCount::EvalCall(ExplodedNodeSet<ValueState>& Dst,
198 ValueStateManager& StateMgr,
199 GRStmtNodeBuilder<ValueState>& Builder,
Ted Kremenek8ad19872008-03-07 20:13:31 +0000200 BasicValueFactory& BasicVals,
Ted Kremenek827f93b2008-03-06 00:08:09 +0000201 CallExpr* CE, LVal L,
202 ExplodedNode<ValueState>* Pred) {
203
Ted Kremeneka7338b42008-03-11 06:39:11 +0000204 // FIXME: Support calls to things other than lval::FuncVal. At the very
205 // least we should stop tracking ref-state for ref-counted objects passed
206 // to these functions.
Ted Kremenek827f93b2008-03-06 00:08:09 +0000207
Ted Kremeneka7338b42008-03-11 06:39:11 +0000208 assert (isa<lval::FuncVal>(L) && "Not yet implemented.");
209
210 // Get the summary.
Ted Kremenek827f93b2008-03-06 00:08:09 +0000211
Ted Kremeneka7338b42008-03-11 06:39:11 +0000212 lval::FuncVal FV = cast<lval::FuncVal>(L);
213 FunctionDecl* FD = FV.getDecl();
214 CFRefSummary* Summ = Summaries.getSummary(FD);
Ted Kremenek827f93b2008-03-06 00:08:09 +0000215
Ted Kremeneka7338b42008-03-11 06:39:11 +0000216 // Get the state.
217
218 ValueState* St = Builder.GetState(Pred);
219
220 // Evaluate the effects of the call.
221
222 ValueState StVals = *St;
223
224 if (!Summ) {
Ted Kremenek827f93b2008-03-06 00:08:09 +0000225
Ted Kremeneka7338b42008-03-11 06:39:11 +0000226 // This function has no summary. Invalidate all reference-count state
227 // for arguments passed to this function, and also nuke the values of
228 // arguments passed-by-reference.
229
230 ValueState StVals = *St;
231
232 for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end();
233 I != E; ++I) {
234
235 RVal V = StateMgr.GetRVal(St, *I);
236
237 if (isa<lval::SymbolVal>(V)) {
238 SymbolID Sym = cast<lval::SymbolVal>(V).getSymbol();
239 RefBindings B = GetRefBindings(StVals);
240 SetRefBindings(StVals, Remove(B, Sym));
241 }
242
243 if (isa<LVal>(V))
244 StateMgr.Unbind(StVals, cast<LVal>(V));
245 }
Ted Kremenek827f93b2008-03-06 00:08:09 +0000246 }
Ted Kremeneka7338b42008-03-11 06:39:11 +0000247 else {
248
249 // This function has a summary. Evaluate the effect of the arguments.
250
251 unsigned idx = 0;
252
253 for (CallExpr::arg_iterator I=CE->arg_begin(), E=CE->arg_end();
254 I!=E; ++I, ++idx) {
255
256 RVal V = StateMgr.GetRVal(St, *I);
257
258 if (isa<lval::SymbolVal>(V)) {
259 SymbolID Sym = cast<lval::SymbolVal>(V).getSymbol();
260 RefBindings B = GetRefBindings(StVals);
261 SetRefBindings(StVals, Update(B, Sym, Summ, idx));
262 }
263 }
264 }
265
266 St = StateMgr.getPersistentState(StVals);
Ted Kremenek827f93b2008-03-06 00:08:09 +0000267
268 Builder.Nodify(Dst, CE, Pred, St);
269}
Ted Kremeneka7338b42008-03-11 06:39:11 +0000270
271
272CFRefCount::RefBindings CFRefCount::Update(RefBindings B, SymbolID sym,
273 CFRefSummary* Summ, unsigned ArgIdx){
274
275 assert (Summ);
276
277 // FIXME: Implement.
278
279 return B;
280}
281
282//===----------------------------------------------------------------------===//
283// Driver for the CFRefCount Checker.
284//===----------------------------------------------------------------------===//
285
286namespace clang {
287
288 void CheckCFRefCount(CFG& cfg, FunctionDecl& FD, ASTContext& Ctx,
289 Diagnostic& Diag) {
290
291 if (Diag.hasErrorOccurred())
292 return;
293
294 // FIXME: Refactor some day so this becomes a single function invocation.
295
296 GRCoreEngine<GRExprEngine> Engine(cfg, FD, Ctx);
297 GRExprEngine* CS = &Engine.getCheckerState();
298 CFRefCount TF;
299 CS->setTransferFunctions(TF);
300 Engine.ExecuteWorkList(20000);
301
302 }
303
304} // end clang namespace