blob: 6bb8e0dbb155de4e26674b562b861f029e119450 [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"
Ted Kremenekc21fed32011-01-18 21:18:58 +000022#include "clang/Analysis/Support/SaveAndRestore.h"
Ted Kremenek610068c2011-01-15 02:58:47 +000023
24using namespace clang;
25
Ted Kremenekc104e532011-01-18 04:53:25 +000026static bool isTrackedVar(const VarDecl *vd) {
27 return vd->isLocalVarDecl() && !vd->hasGlobalStorage() &&
28 vd->getType()->isScalarType();
29}
30
Ted Kremenek610068c2011-01-15 02:58:47 +000031//------------------------------------------------------------------------====//
32// DeclToBit: a mapping from Decls we track to bitvector indices.
33//====------------------------------------------------------------------------//
34
35namespace {
36class DeclToBit {
37 llvm::DenseMap<const VarDecl *, unsigned> map;
38public:
39 DeclToBit() {}
40
41 /// Compute the actual mapping from declarations to bits.
42 void computeMap(const DeclContext &dc);
43
44 /// Return the number of declarations in the map.
45 unsigned size() const { return map.size(); }
46
47 /// Returns the bit vector index for a given declaration.
48 llvm::Optional<unsigned> getBitVectorIndex(const VarDecl *d);
49};
50}
51
52void DeclToBit::computeMap(const DeclContext &dc) {
53 unsigned count = 0;
54 DeclContext::specific_decl_iterator<VarDecl> I(dc.decls_begin()),
55 E(dc.decls_end());
56 for ( ; I != E; ++I) {
57 const VarDecl *vd = *I;
Ted Kremenekc104e532011-01-18 04:53:25 +000058 if (isTrackedVar(vd))
Ted Kremenek610068c2011-01-15 02:58:47 +000059 map[vd] = count++;
60 }
61}
62
63llvm::Optional<unsigned> DeclToBit::getBitVectorIndex(const VarDecl *d) {
64 llvm::DenseMap<const VarDecl *, unsigned>::iterator I = map.find(d);
65 if (I == map.end())
66 return llvm::Optional<unsigned>();
67 return I->second;
68}
69
70//------------------------------------------------------------------------====//
71// CFGBlockValues: dataflow values for CFG blocks.
72//====------------------------------------------------------------------------//
73
74namespace {
75class CFGBlockValues {
76 const CFG &cfg;
77 llvm::BitVector **vals;
78 llvm::BitVector scratch;
79 DeclToBit declToBit;
80public:
81 CFGBlockValues(const CFG &cfg);
82 ~CFGBlockValues();
83
84 void computeSetOfDeclarations(const DeclContext &dc);
85 llvm::BitVector &getBitVector(const CFGBlock *block);
86 void mergeIntoScratch(llvm::BitVector const &source, bool isFirst);
87 bool updateBitVectorWithScratch(const CFGBlock *block);
88
89 bool hasNoDeclarations() const {
90 return declToBit.size() == 0;
91 }
92
93 void resetScratch();
94 llvm::BitVector::reference operator[](const VarDecl *vd);
95};
96}
97
98CFGBlockValues::CFGBlockValues(const CFG &c) : cfg(c), vals(0) {
99 unsigned n = cfg.getNumBlockIDs();
100 if (!n)
101 return;
102 vals = new llvm::BitVector*[n];
Francois Pichet2d78c372011-01-15 13:27:47 +0000103 memset(vals, 0, sizeof(*vals) * n);
Ted Kremenek610068c2011-01-15 02:58:47 +0000104}
105
106CFGBlockValues::~CFGBlockValues() {
107 unsigned n = cfg.getNumBlockIDs();
108 if (n == 0)
109 return;
110 for (unsigned i = 0; i < n; ++i)
111 delete vals[i];
112 delete [] vals;
113}
114
115void CFGBlockValues::computeSetOfDeclarations(const DeclContext &dc) {
116 declToBit.computeMap(dc);
117 scratch.resize(declToBit.size());
118}
119
120llvm::BitVector &CFGBlockValues::getBitVector(const CFGBlock *block) {
121 unsigned idx = block->getBlockID();
122 llvm::BitVector *bv = vals[idx];
123 if (!bv) {
124 bv = new llvm::BitVector(declToBit.size());
125 vals[idx] = bv;
126 }
127 return *bv;
128}
129
130void CFGBlockValues::mergeIntoScratch(llvm::BitVector const &source,
131 bool isFirst) {
132 if (isFirst)
133 scratch = source;
134 else
Ted Kremenekc104e532011-01-18 04:53:25 +0000135 scratch |= source;
Ted Kremenek610068c2011-01-15 02:58:47 +0000136}
137
138bool CFGBlockValues::updateBitVectorWithScratch(const CFGBlock *block) {
139 llvm::BitVector &dst = getBitVector(block);
140 bool changed = (dst != scratch);
141 if (changed)
142 dst = scratch;
143 return changed;
144}
145
146void CFGBlockValues::resetScratch() {
147 scratch.reset();
148}
149
150llvm::BitVector::reference CFGBlockValues::operator[](const VarDecl *vd) {
151 const llvm::Optional<unsigned> &idx = declToBit.getBitVectorIndex(vd);
152 assert(idx.hasValue());
153 return scratch[idx.getValue()];
154}
155
156//------------------------------------------------------------------------====//
157// Worklist: worklist for dataflow analysis.
158//====------------------------------------------------------------------------//
159
160namespace {
161class DataflowWorklist {
162 llvm::SmallVector<const CFGBlock *, 20> worklist;
163 llvm::BitVector enqueuedBlocks;
164public:
165 DataflowWorklist(const CFG &cfg) : enqueuedBlocks(cfg.getNumBlockIDs()) {}
166
167 void enqueue(const CFGBlock *block);
168 void enqueueSuccessors(const CFGBlock *block);
169 const CFGBlock *dequeue();
170
171};
172}
173
174void DataflowWorklist::enqueue(const CFGBlock *block) {
Ted Kremenekc104e532011-01-18 04:53:25 +0000175 if (!block)
176 return;
Ted Kremenek610068c2011-01-15 02:58:47 +0000177 unsigned idx = block->getBlockID();
178 if (enqueuedBlocks[idx])
179 return;
180 worklist.push_back(block);
181 enqueuedBlocks[idx] = true;
182}
183
184void DataflowWorklist::enqueueSuccessors(const clang::CFGBlock *block) {
185 for (CFGBlock::const_succ_iterator I = block->succ_begin(),
186 E = block->succ_end(); I != E; ++I) {
187 enqueue(*I);
188 }
189}
190
191const CFGBlock *DataflowWorklist::dequeue() {
192 if (worklist.empty())
193 return 0;
194 const CFGBlock *b = worklist.back();
195 worklist.pop_back();
196 enqueuedBlocks[b->getBlockID()] = false;
197 return b;
198}
199
200//------------------------------------------------------------------------====//
201// Transfer function for uninitialized values analysis.
202//====------------------------------------------------------------------------//
203
Ted Kremenekc104e532011-01-18 04:53:25 +0000204static const bool Initialized = false;
205static const bool Uninitialized = true;
Ted Kremenek610068c2011-01-15 02:58:47 +0000206
207namespace {
208class FindVarResult {
209 const VarDecl *vd;
210 const DeclRefExpr *dr;
211public:
212 FindVarResult(VarDecl *vd, DeclRefExpr *dr) : vd(vd), dr(dr) {}
213
214 const DeclRefExpr *getDeclRefExpr() const { return dr; }
215 const VarDecl *getDecl() const { return vd; }
216};
217
218class TransferFunctions : public CFGRecStmtVisitor<TransferFunctions> {
219 CFGBlockValues &vals;
220 const CFG &cfg;
221 UninitVariablesHandler *handler;
Ted Kremenekc21fed32011-01-18 21:18:58 +0000222 const DeclRefExpr *currentDR;
Ted Kremenek610068c2011-01-15 02:58:47 +0000223public:
224 TransferFunctions(CFGBlockValues &vals, const CFG &cfg,
225 UninitVariablesHandler *handler)
Ted Kremenekc21fed32011-01-18 21:18:58 +0000226 : vals(vals), cfg(cfg), handler(handler), currentDR(0) {}
Ted Kremenek610068c2011-01-15 02:58:47 +0000227
228 const CFG &getCFG() { return cfg; }
229 void reportUninit(const DeclRefExpr *ex, const VarDecl *vd);
230
231 void VisitDeclStmt(DeclStmt *ds);
Ted Kremenekc21fed32011-01-18 21:18:58 +0000232 void VisitDeclRefExpr(DeclRefExpr *dr);
Ted Kremenek610068c2011-01-15 02:58:47 +0000233 void VisitUnaryOperator(UnaryOperator *uo);
234 void VisitBinaryOperator(BinaryOperator *bo);
235 void VisitCastExpr(CastExpr *ce);
236};
237}
238
239void TransferFunctions::reportUninit(const DeclRefExpr *ex,
240 const VarDecl *vd) {
241 if (handler) handler->handleUseOfUninitVariable(ex, vd);
242}
243
244void TransferFunctions::VisitDeclStmt(DeclStmt *ds) {
245 for (DeclStmt::decl_iterator DI = ds->decl_begin(), DE = ds->decl_end();
246 DI != DE; ++DI) {
247 if (VarDecl *vd = dyn_cast<VarDecl>(*DI)) {
Ted Kremenek4dccb902011-01-18 05:00:42 +0000248 if (isTrackedVar(vd)) {
249 vals[vd] = Uninitialized;
Ted Kremenek610068c2011-01-15 02:58:47 +0000250 if (Stmt *init = vd->getInit()) {
Ted Kremenek610068c2011-01-15 02:58:47 +0000251 Visit(init);
Ted Kremenekc104e532011-01-18 04:53:25 +0000252 vals[vd] = Initialized;
Ted Kremenek610068c2011-01-15 02:58:47 +0000253 }
Ted Kremenek4dccb902011-01-18 05:00:42 +0000254 }
Ted Kremenekc21fed32011-01-18 21:18:58 +0000255 else if (Stmt *init = vd->getInit()) {
256 Visit(init);
257 }
Ted Kremenek610068c2011-01-15 02:58:47 +0000258 }
259 }
260}
261
Ted Kremenekc21fed32011-01-18 21:18:58 +0000262void TransferFunctions::VisitDeclRefExpr(DeclRefExpr *dr) {
263 // We assume that DeclRefExprs wrapped in an lvalue-to-rvalue cast
264 // cannot be block-level expressions. Therefore, we determine if
265 // a DeclRefExpr is involved in a "load" by comparing it to the current
266 // DeclRefExpr found when analyzing the last lvalue-to-rvalue CastExpr.
267 // If a DeclRefExpr is not involved in a load, we are essentially computing
268 // its address, either for assignment to a reference or via the '&' operator.
269 // In such cases, treat the variable as being initialized, since this
270 // analysis isn't powerful enough to do alias tracking.
271 if (dr != currentDR)
272 if (const VarDecl *vd = dyn_cast<VarDecl>(dr->getDecl()))
273 if (isTrackedVar(vd))
274 vals[vd] = Initialized;
275}
276
Ted Kremenek610068c2011-01-15 02:58:47 +0000277static FindVarResult findBlockVarDecl(Expr* ex) {
278 if (DeclRefExpr* dr = dyn_cast<DeclRefExpr>(ex->IgnoreParenCasts()))
279 if (VarDecl *vd = dyn_cast<VarDecl>(dr->getDecl()))
Ted Kremenekc104e532011-01-18 04:53:25 +0000280 if (isTrackedVar(vd))
Ted Kremenek610068c2011-01-15 02:58:47 +0000281 return FindVarResult(vd, dr);
282
283 return FindVarResult(0, 0);
284}
285
286void TransferFunctions::VisitBinaryOperator(clang::BinaryOperator *bo) {
Ted Kremenek610068c2011-01-15 02:58:47 +0000287 if (bo->isAssignmentOp()) {
288 const FindVarResult &res = findBlockVarDecl(bo->getLHS());
289 if (const VarDecl* vd = res.getDecl()) {
Ted Kremenekc21fed32011-01-18 21:18:58 +0000290 // We assume that DeclRefExprs wrapped in a BinaryOperator "assignment"
291 // cannot be block-level expressions. Therefore, we determine if
292 // a DeclRefExpr is involved in a "load" by comparing it to the current
293 // DeclRefExpr found when analyzing the last lvalue-to-rvalue CastExpr.
294 SaveAndRestore<const DeclRefExpr*> lastDR(currentDR,
295 res.getDeclRefExpr());
296 Visit(bo->getRHS());
297 Visit(bo->getLHS());
298
Ted Kremenek610068c2011-01-15 02:58:47 +0000299 llvm::BitVector::reference bit = vals[vd];
300 if (bit == Uninitialized) {
301 if (bo->getOpcode() != BO_Assign)
302 reportUninit(res.getDeclRefExpr(), vd);
303 bit = Initialized;
304 }
Ted Kremenekc21fed32011-01-18 21:18:58 +0000305 return;
Ted Kremenek610068c2011-01-15 02:58:47 +0000306 }
307 }
Ted Kremenekc21fed32011-01-18 21:18:58 +0000308 Visit(bo->getRHS());
309 Visit(bo->getLHS());
Ted Kremenek610068c2011-01-15 02:58:47 +0000310}
311
312void TransferFunctions::VisitUnaryOperator(clang::UnaryOperator *uo) {
Ted Kremenek610068c2011-01-15 02:58:47 +0000313 switch (uo->getOpcode()) {
Ted Kremenek610068c2011-01-15 02:58:47 +0000314 case clang::UO_PostDec:
315 case clang::UO_PostInc:
316 case clang::UO_PreDec:
317 case clang::UO_PreInc: {
318 const FindVarResult &res = findBlockVarDecl(uo->getSubExpr());
319 if (const VarDecl *vd = res.getDecl()) {
Ted Kremenekc21fed32011-01-18 21:18:58 +0000320 // We assume that DeclRefExprs wrapped in a unary operator ++/--
321 // cannot be block-level expressions. Therefore, we determine if
322 // a DeclRefExpr is involved in a "load" by comparing it to the current
323 // DeclRefExpr found when analyzing the last lvalue-to-rvalue CastExpr.
324 SaveAndRestore<const DeclRefExpr*> lastDR(currentDR,
325 res.getDeclRefExpr());
326 Visit(uo->getSubExpr());
327
Ted Kremenek610068c2011-01-15 02:58:47 +0000328 llvm::BitVector::reference bit = vals[vd];
329 if (bit == Uninitialized) {
330 reportUninit(res.getDeclRefExpr(), vd);
331 bit = Initialized;
332 }
Ted Kremenekc21fed32011-01-18 21:18:58 +0000333 return;
Ted Kremenek610068c2011-01-15 02:58:47 +0000334 }
335 break;
336 }
337 default:
338 break;
339 }
Ted Kremenekc21fed32011-01-18 21:18:58 +0000340 Visit(uo->getSubExpr());
Ted Kremenek610068c2011-01-15 02:58:47 +0000341}
342
343void TransferFunctions::VisitCastExpr(clang::CastExpr *ce) {
Ted Kremenek610068c2011-01-15 02:58:47 +0000344 if (ce->getCastKind() == CK_LValueToRValue) {
345 const FindVarResult &res = findBlockVarDecl(ce->getSubExpr());
Ted Kremenekc21fed32011-01-18 21:18:58 +0000346 if (const VarDecl *vd = res.getDecl()) {
347 // We assume that DeclRefExprs wrapped in an lvalue-to-rvalue cast
348 // cannot be block-level expressions. Therefore, we determine if
349 // a DeclRefExpr is involved in a "load" by comparing it to the current
350 // DeclRefExpr found when analyzing the last lvalue-to-rvalue CastExpr.
351 // Here we update 'currentDR' to be the one associated with this
352 // lvalue-to-rvalue cast. Then, when we analyze the DeclRefExpr, we
353 // will know that we are not computing its lvalue for other purposes
354 // than to perform a load.
355 SaveAndRestore<const DeclRefExpr*> lastDR(currentDR,
356 res.getDeclRefExpr());
357 Visit(ce->getSubExpr());
358 if (vals[vd] == Uninitialized) {
Ted Kremenek610068c2011-01-15 02:58:47 +0000359 reportUninit(res.getDeclRefExpr(), vd);
Ted Kremenekc21fed32011-01-18 21:18:58 +0000360 // Don't cascade warnings.
361 vals[vd] = Initialized;
362 }
363 return;
364 }
365 }
366 Visit(ce->getSubExpr());
Ted Kremenek610068c2011-01-15 02:58:47 +0000367}
368
369//------------------------------------------------------------------------====//
370// High-level "driver" logic for uninitialized values analysis.
371//====------------------------------------------------------------------------//
372
373static void runOnBlock(const CFGBlock *block, const CFG &cfg,
374 CFGBlockValues &vals,
375 UninitVariablesHandler *handler = 0) {
376 // Merge in values of predecessor blocks.
377 vals.resetScratch();
378 bool isFirst = true;
379 for (CFGBlock::const_pred_iterator I = block->pred_begin(),
380 E = block->pred_end(); I != E; ++I) {
381 vals.mergeIntoScratch(vals.getBitVector(*I), isFirst);
382 isFirst = false;
383 }
384 // Apply the transfer function.
385 TransferFunctions tf(vals, cfg, handler);
386 for (CFGBlock::const_iterator I = block->begin(), E = block->end();
387 I != E; ++I) {
388 if (const CFGStmt *cs = dyn_cast<CFGStmt>(&*I)) {
389 tf.BlockStmt_Visit(cs->getStmt());
390 }
391 }
392}
393
394void clang::runUninitializedVariablesAnalysis(const DeclContext &dc,
395 const CFG &cfg,
396 UninitVariablesHandler &handler) {
397 CFGBlockValues vals(cfg);
398 vals.computeSetOfDeclarations(dc);
399 if (vals.hasNoDeclarations())
400 return;
401 DataflowWorklist worklist(cfg);
402 llvm::BitVector previouslyVisited(cfg.getNumBlockIDs());
403
404 worklist.enqueueSuccessors(&cfg.getEntry());
405
406 while (const CFGBlock *block = worklist.dequeue()) {
407 runOnBlock(block, cfg, vals);
408 // Did the block change?
409 bool changed = vals.updateBitVectorWithScratch(block);
410 if (changed || !previouslyVisited[block->getBlockID()])
411 worklist.enqueueSuccessors(block);
412 previouslyVisited[block->getBlockID()] = true;
413 }
414
415 // Run through the blocks one more time, and report uninitialized variabes.
416 for (CFG::const_iterator BI = cfg.begin(), BE = cfg.end(); BI != BE; ++BI) {
417 runOnBlock(*BI, cfg, vals, &handler);
418 }
419}
420
421UninitVariablesHandler::~UninitVariablesHandler() {}
422