blob: 209b18c045e3254b0ad79f7bcd85d3e8113f8791 [file] [log] [blame]
Ted Kremenek610068c2011-01-15 02:58:47 +00001//==- UninitializedValuesV2.cpp - Find Uninitialized 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//
10// This file implements uninitialized values analysis for source-level CFGs.
11//
12//===----------------------------------------------------------------------===//
13
14#include "llvm/ADT/Optional.h"
15#include "llvm/ADT/SmallVector.h"
16#include "llvm/ADT/BitVector.h"
17#include "llvm/ADT/DenseMap.h"
18#include "clang/AST/Decl.h"
19#include "clang/Analysis/CFG.h"
20#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h"
21#include "clang/Analysis/Analyses/UninitializedValuesV2.h"
22
23using namespace clang;
24
25//------------------------------------------------------------------------====//
26// DeclToBit: a mapping from Decls we track to bitvector indices.
27//====------------------------------------------------------------------------//
28
29namespace {
30class DeclToBit {
31 llvm::DenseMap<const VarDecl *, unsigned> map;
32public:
33 DeclToBit() {}
34
35 /// Compute the actual mapping from declarations to bits.
36 void computeMap(const DeclContext &dc);
37
38 /// Return the number of declarations in the map.
39 unsigned size() const { return map.size(); }
40
41 /// Returns the bit vector index for a given declaration.
42 llvm::Optional<unsigned> getBitVectorIndex(const VarDecl *d);
43};
44}
45
46void DeclToBit::computeMap(const DeclContext &dc) {
47 unsigned count = 0;
48 DeclContext::specific_decl_iterator<VarDecl> I(dc.decls_begin()),
49 E(dc.decls_end());
50 for ( ; I != E; ++I) {
51 const VarDecl *vd = *I;
52 if (vd->isLocalVarDecl() && !vd->hasGlobalStorage())
53 map[vd] = count++;
54 }
55}
56
57llvm::Optional<unsigned> DeclToBit::getBitVectorIndex(const VarDecl *d) {
58 llvm::DenseMap<const VarDecl *, unsigned>::iterator I = map.find(d);
59 if (I == map.end())
60 return llvm::Optional<unsigned>();
61 return I->second;
62}
63
64//------------------------------------------------------------------------====//
65// CFGBlockValues: dataflow values for CFG blocks.
66//====------------------------------------------------------------------------//
67
68namespace {
69class CFGBlockValues {
70 const CFG &cfg;
71 llvm::BitVector **vals;
72 llvm::BitVector scratch;
73 DeclToBit declToBit;
74public:
75 CFGBlockValues(const CFG &cfg);
76 ~CFGBlockValues();
77
78 void computeSetOfDeclarations(const DeclContext &dc);
79 llvm::BitVector &getBitVector(const CFGBlock *block);
80 void mergeIntoScratch(llvm::BitVector const &source, bool isFirst);
81 bool updateBitVectorWithScratch(const CFGBlock *block);
82
83 bool hasNoDeclarations() const {
84 return declToBit.size() == 0;
85 }
86
87 void resetScratch();
88 llvm::BitVector::reference operator[](const VarDecl *vd);
89};
90}
91
92CFGBlockValues::CFGBlockValues(const CFG &c) : cfg(c), vals(0) {
93 unsigned n = cfg.getNumBlockIDs();
94 if (!n)
95 return;
96 vals = new llvm::BitVector*[n];
Francois Pichet2d78c372011-01-15 13:27:47 +000097 memset(vals, 0, sizeof(*vals) * n);
Ted Kremenek610068c2011-01-15 02:58:47 +000098}
99
100CFGBlockValues::~CFGBlockValues() {
101 unsigned n = cfg.getNumBlockIDs();
102 if (n == 0)
103 return;
104 for (unsigned i = 0; i < n; ++i)
105 delete vals[i];
106 delete [] vals;
107}
108
109void CFGBlockValues::computeSetOfDeclarations(const DeclContext &dc) {
110 declToBit.computeMap(dc);
111 scratch.resize(declToBit.size());
112}
113
114llvm::BitVector &CFGBlockValues::getBitVector(const CFGBlock *block) {
115 unsigned idx = block->getBlockID();
116 llvm::BitVector *bv = vals[idx];
117 if (!bv) {
118 bv = new llvm::BitVector(declToBit.size());
119 vals[idx] = bv;
120 }
121 return *bv;
122}
123
124void CFGBlockValues::mergeIntoScratch(llvm::BitVector const &source,
125 bool isFirst) {
126 if (isFirst)
127 scratch = source;
128 else
129 scratch &= source;
130}
131
132bool CFGBlockValues::updateBitVectorWithScratch(const CFGBlock *block) {
133 llvm::BitVector &dst = getBitVector(block);
134 bool changed = (dst != scratch);
135 if (changed)
136 dst = scratch;
137 return changed;
138}
139
140void CFGBlockValues::resetScratch() {
141 scratch.reset();
142}
143
144llvm::BitVector::reference CFGBlockValues::operator[](const VarDecl *vd) {
145 const llvm::Optional<unsigned> &idx = declToBit.getBitVectorIndex(vd);
146 assert(idx.hasValue());
147 return scratch[idx.getValue()];
148}
149
150//------------------------------------------------------------------------====//
151// Worklist: worklist for dataflow analysis.
152//====------------------------------------------------------------------------//
153
154namespace {
155class DataflowWorklist {
156 llvm::SmallVector<const CFGBlock *, 20> worklist;
157 llvm::BitVector enqueuedBlocks;
158public:
159 DataflowWorklist(const CFG &cfg) : enqueuedBlocks(cfg.getNumBlockIDs()) {}
160
161 void enqueue(const CFGBlock *block);
162 void enqueueSuccessors(const CFGBlock *block);
163 const CFGBlock *dequeue();
164
165};
166}
167
168void DataflowWorklist::enqueue(const CFGBlock *block) {
169 unsigned idx = block->getBlockID();
170 if (enqueuedBlocks[idx])
171 return;
172 worklist.push_back(block);
173 enqueuedBlocks[idx] = true;
174}
175
176void DataflowWorklist::enqueueSuccessors(const clang::CFGBlock *block) {
177 for (CFGBlock::const_succ_iterator I = block->succ_begin(),
178 E = block->succ_end(); I != E; ++I) {
179 enqueue(*I);
180 }
181}
182
183const CFGBlock *DataflowWorklist::dequeue() {
184 if (worklist.empty())
185 return 0;
186 const CFGBlock *b = worklist.back();
187 worklist.pop_back();
188 enqueuedBlocks[b->getBlockID()] = false;
189 return b;
190}
191
192//------------------------------------------------------------------------====//
193// Transfer function for uninitialized values analysis.
194//====------------------------------------------------------------------------//
195
196static const bool Initialized = true;
197static const bool Uninitialized = false;
198
199namespace {
200class FindVarResult {
201 const VarDecl *vd;
202 const DeclRefExpr *dr;
203public:
204 FindVarResult(VarDecl *vd, DeclRefExpr *dr) : vd(vd), dr(dr) {}
205
206 const DeclRefExpr *getDeclRefExpr() const { return dr; }
207 const VarDecl *getDecl() const { return vd; }
208};
209
210class TransferFunctions : public CFGRecStmtVisitor<TransferFunctions> {
211 CFGBlockValues &vals;
212 const CFG &cfg;
213 UninitVariablesHandler *handler;
214public:
215 TransferFunctions(CFGBlockValues &vals, const CFG &cfg,
216 UninitVariablesHandler *handler)
217 : vals(vals), cfg(cfg), handler(handler) {}
218
219 const CFG &getCFG() { return cfg; }
220 void reportUninit(const DeclRefExpr *ex, const VarDecl *vd);
221
222 void VisitDeclStmt(DeclStmt *ds);
223 void VisitUnaryOperator(UnaryOperator *uo);
224 void VisitBinaryOperator(BinaryOperator *bo);
225 void VisitCastExpr(CastExpr *ce);
226};
227}
228
229void TransferFunctions::reportUninit(const DeclRefExpr *ex,
230 const VarDecl *vd) {
231 if (handler) handler->handleUseOfUninitVariable(ex, vd);
232}
233
234void TransferFunctions::VisitDeclStmt(DeclStmt *ds) {
235 for (DeclStmt::decl_iterator DI = ds->decl_begin(), DE = ds->decl_end();
236 DI != DE; ++DI) {
237 if (VarDecl *vd = dyn_cast<VarDecl>(*DI)) {
238 if (vd->isLocalVarDecl() && !vd->hasGlobalStorage()) {
239 if (Stmt *init = vd->getInit()) {
240 vals[vd] = Initialized;
241 Visit(init);
242 }
243 }
244 }
245 }
246}
247
248static FindVarResult findBlockVarDecl(Expr* ex) {
249 if (DeclRefExpr* dr = dyn_cast<DeclRefExpr>(ex->IgnoreParenCasts()))
250 if (VarDecl *vd = dyn_cast<VarDecl>(dr->getDecl()))
251 if (vd->isLocalVarDecl() && !vd->hasGlobalStorage())
252 return FindVarResult(vd, dr);
253
254 return FindVarResult(0, 0);
255}
256
257void TransferFunctions::VisitBinaryOperator(clang::BinaryOperator *bo) {
258 Visit(bo->getRHS());
259 Visit(bo->getLHS());
260 if (bo->isAssignmentOp()) {
261 const FindVarResult &res = findBlockVarDecl(bo->getLHS());
262 if (const VarDecl* vd = res.getDecl()) {
263 llvm::BitVector::reference bit = vals[vd];
264 if (bit == Uninitialized) {
265 if (bo->getOpcode() != BO_Assign)
266 reportUninit(res.getDeclRefExpr(), vd);
267 bit = Initialized;
268 }
269 }
270 }
271}
272
273void TransferFunctions::VisitUnaryOperator(clang::UnaryOperator *uo) {
274 Visit(uo->getSubExpr());
275 switch (uo->getOpcode()) {
276 case clang::UO_AddrOf:
277 if (const VarDecl *vd = findBlockVarDecl(uo->getSubExpr()).getDecl())
278 vals[vd] = Initialized;
279 break;
280 case clang::UO_PostDec:
281 case clang::UO_PostInc:
282 case clang::UO_PreDec:
283 case clang::UO_PreInc: {
284 const FindVarResult &res = findBlockVarDecl(uo->getSubExpr());
285 if (const VarDecl *vd = res.getDecl()) {
286 llvm::BitVector::reference bit = vals[vd];
287 if (bit == Uninitialized) {
288 reportUninit(res.getDeclRefExpr(), vd);
289 bit = Initialized;
290 }
291 }
292 break;
293 }
294 default:
295 break;
296 }
297}
298
299void TransferFunctions::VisitCastExpr(clang::CastExpr *ce) {
300 Visit(ce->getSubExpr());
301 if (ce->getCastKind() == CK_LValueToRValue) {
302 const FindVarResult &res = findBlockVarDecl(ce->getSubExpr());
303 if (const VarDecl *vd = res.getDecl())
304 if (vals[vd] == Uninitialized)
305 reportUninit(res.getDeclRefExpr(), vd);
306 }
307}
308
309//------------------------------------------------------------------------====//
310// High-level "driver" logic for uninitialized values analysis.
311//====------------------------------------------------------------------------//
312
313static void runOnBlock(const CFGBlock *block, const CFG &cfg,
314 CFGBlockValues &vals,
315 UninitVariablesHandler *handler = 0) {
316 // Merge in values of predecessor blocks.
317 vals.resetScratch();
318 bool isFirst = true;
319 for (CFGBlock::const_pred_iterator I = block->pred_begin(),
320 E = block->pred_end(); I != E; ++I) {
321 vals.mergeIntoScratch(vals.getBitVector(*I), isFirst);
322 isFirst = false;
323 }
324 // Apply the transfer function.
325 TransferFunctions tf(vals, cfg, handler);
326 for (CFGBlock::const_iterator I = block->begin(), E = block->end();
327 I != E; ++I) {
328 if (const CFGStmt *cs = dyn_cast<CFGStmt>(&*I)) {
329 tf.BlockStmt_Visit(cs->getStmt());
330 }
331 }
332}
333
334void clang::runUninitializedVariablesAnalysis(const DeclContext &dc,
335 const CFG &cfg,
336 UninitVariablesHandler &handler) {
337 CFGBlockValues vals(cfg);
338 vals.computeSetOfDeclarations(dc);
339 if (vals.hasNoDeclarations())
340 return;
341 DataflowWorklist worklist(cfg);
342 llvm::BitVector previouslyVisited(cfg.getNumBlockIDs());
343
344 worklist.enqueueSuccessors(&cfg.getEntry());
345
346 while (const CFGBlock *block = worklist.dequeue()) {
347 runOnBlock(block, cfg, vals);
348 // Did the block change?
349 bool changed = vals.updateBitVectorWithScratch(block);
350 if (changed || !previouslyVisited[block->getBlockID()])
351 worklist.enqueueSuccessors(block);
352 previouslyVisited[block->getBlockID()] = true;
353 }
354
355 // Run through the blocks one more time, and report uninitialized variabes.
356 for (CFG::const_iterator BI = cfg.begin(), BE = cfg.end(); BI != BE; ++BI) {
357 runOnBlock(*BI, cfg, vals, &handler);
358 }
359}
360
361UninitVariablesHandler::~UninitVariablesHandler() {}
362