UninitializedValues.cpp revision afb10c4bda2ac2c268fa7e6c11141584f57de119
1//==- UninitializedValues.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 <utility>
15#include "llvm/ADT/Optional.h"
16#include "llvm/ADT/SmallVector.h"
17#include "llvm/ADT/BitVector.h"
18#include "llvm/ADT/DenseMap.h"
19#include "clang/AST/Decl.h"
20#include "clang/Analysis/CFG.h"
21#include "clang/Analysis/AnalysisContext.h"
22#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h"
23#include "clang/Analysis/Analyses/UninitializedValues.h"
24#include "clang/Analysis/Support/SaveAndRestore.h"
25
26using namespace clang;
27
28static bool isTrackedVar(const VarDecl *vd, const DeclContext *dc) {
29  return vd->isLocalVarDecl() && !vd->hasGlobalStorage() &&
30         vd->getType()->isScalarType() &&
31         vd->getDeclContext() == dc;
32}
33
34//------------------------------------------------------------------------====//
35// DeclToIndex: a mapping from Decls we track to value indices.
36//====------------------------------------------------------------------------//
37
38namespace {
39class DeclToIndex {
40  llvm::DenseMap<const VarDecl *, unsigned> map;
41public:
42  DeclToIndex() {}
43
44  /// Compute the actual mapping from declarations to bits.
45  void computeMap(const DeclContext &dc);
46
47  /// Return the number of declarations in the map.
48  unsigned size() const { return map.size(); }
49
50  /// Returns the bit vector index for a given declaration.
51  llvm::Optional<unsigned> getValueIndex(const VarDecl *d);
52};
53}
54
55void DeclToIndex::computeMap(const DeclContext &dc) {
56  unsigned count = 0;
57  DeclContext::specific_decl_iterator<VarDecl> I(dc.decls_begin()),
58                                               E(dc.decls_end());
59  for ( ; I != E; ++I) {
60    const VarDecl *vd = *I;
61    if (isTrackedVar(vd, &dc))
62      map[vd] = count++;
63  }
64}
65
66llvm::Optional<unsigned> DeclToIndex::getValueIndex(const VarDecl *d) {
67  llvm::DenseMap<const VarDecl *, unsigned>::iterator I = map.find(d);
68  if (I == map.end())
69    return llvm::Optional<unsigned>();
70  return I->second;
71}
72
73//------------------------------------------------------------------------====//
74// CFGBlockValues: dataflow values for CFG blocks.
75//====------------------------------------------------------------------------//
76
77static const bool Initialized = false;
78static const bool Uninitialized = true;
79
80class ValueVector {
81  llvm::BitVector vec;
82public:
83  ValueVector() {}
84  ValueVector(unsigned size) : vec(size) {}
85  typedef llvm::BitVector::reference reference;
86  void resize(unsigned n) { vec.resize(n); }
87  void merge(const ValueVector &rhs) { vec |= rhs.vec; }
88  bool operator!=(const ValueVector &rhs) const { return vec != rhs.vec; }
89  reference operator[](unsigned idx) { return vec[idx]; }
90  void reset() { vec.reset(); }
91};
92
93typedef std::pair<ValueVector *, ValueVector *> BVPair;
94
95namespace {
96class CFGBlockValues {
97  const CFG &cfg;
98  BVPair *vals;
99  ValueVector scratch;
100  DeclToIndex DeclToIndex;
101
102  ValueVector &lazyCreate(ValueVector *&bv);
103public:
104  CFGBlockValues(const CFG &cfg);
105  ~CFGBlockValues();
106
107  void computeSetOfDeclarations(const DeclContext &dc);
108  ValueVector &getValueVector(const CFGBlock *block,
109                                const CFGBlock *dstBlock);
110
111  BVPair &getValueVectors(const CFGBlock *block, bool shouldLazyCreate);
112
113  void mergeIntoScratch(ValueVector const &source, bool isFirst);
114  bool updateValueVectorWithScratch(const CFGBlock *block);
115  bool updateValueVectors(const CFGBlock *block, const BVPair &newVals);
116
117  bool hasNoDeclarations() const {
118    return DeclToIndex.size() == 0;
119  }
120
121  void resetScratch();
122  ValueVector &getScratch() { return scratch; }
123
124  ValueVector::reference operator[](const VarDecl *vd);
125};
126}
127
128CFGBlockValues::CFGBlockValues(const CFG &c) : cfg(c), vals(0) {
129  unsigned n = cfg.getNumBlockIDs();
130  if (!n)
131    return;
132  vals = new std::pair<ValueVector*, ValueVector*>[n];
133  memset(vals, 0, sizeof(*vals) * n);
134}
135
136CFGBlockValues::~CFGBlockValues() {
137  unsigned n = cfg.getNumBlockIDs();
138  if (n == 0)
139    return;
140  for (unsigned i = 0; i < n; ++i) {
141    delete vals[i].first;
142    delete vals[i].second;
143  }
144  delete [] vals;
145}
146
147void CFGBlockValues::computeSetOfDeclarations(const DeclContext &dc) {
148  DeclToIndex.computeMap(dc);
149  scratch.resize(DeclToIndex.size());
150}
151
152ValueVector &CFGBlockValues::lazyCreate(ValueVector *&bv) {
153  if (!bv)
154    bv = new ValueVector(DeclToIndex.size());
155  return *bv;
156}
157
158/// This function pattern matches for a '&&' or '||' that appears at
159/// the beginning of a CFGBlock that also (1) has a terminator and
160/// (2) has no other elements.  If such an expression is found, it is returned.
161static BinaryOperator *getLogicalOperatorInChain(const CFGBlock *block) {
162  if (block->empty())
163    return 0;
164
165  const CFGStmt *cstmt = block->front().getAs<CFGStmt>();
166  BinaryOperator *b = llvm::dyn_cast_or_null<BinaryOperator>(cstmt->getStmt());
167
168  if (!b || !b->isLogicalOp())
169    return 0;
170
171  if (block->pred_size() == 2 &&
172      ((block->succ_size() == 2 && block->getTerminatorCondition() == b) ||
173       block->size() == 1))
174    return b;
175
176  return 0;
177}
178
179ValueVector &CFGBlockValues::getValueVector(const CFGBlock *block,
180                                            const CFGBlock *dstBlock) {
181  unsigned idx = block->getBlockID();
182  if (dstBlock && getLogicalOperatorInChain(block)) {
183    if (*block->succ_begin() == dstBlock)
184      return lazyCreate(vals[idx].first);
185    assert(*(block->succ_begin()+1) == dstBlock);
186    return lazyCreate(vals[idx].second);
187  }
188
189  assert(vals[idx].second == 0);
190  return lazyCreate(vals[idx].first);
191}
192
193BVPair &CFGBlockValues::getValueVectors(const clang::CFGBlock *block,
194                                        bool shouldLazyCreate) {
195  unsigned idx = block->getBlockID();
196  lazyCreate(vals[idx].first);
197  if (shouldLazyCreate)
198    lazyCreate(vals[idx].second);
199  return vals[idx];
200}
201
202void CFGBlockValues::mergeIntoScratch(ValueVector const &source,
203                                      bool isFirst) {
204  if (isFirst)
205    scratch = source;
206  else
207    scratch.merge(source);
208}
209#if 0
210static void printVector(const CFGBlock *block, ValueVector &bv,
211                        unsigned num) {
212
213  llvm::errs() << block->getBlockID() << " :";
214  for (unsigned i = 0; i < bv.size(); ++i) {
215    llvm::errs() << ' ' << bv[i];
216  }
217  llvm::errs() << " : " << num << '\n';
218}
219#endif
220
221bool CFGBlockValues::updateValueVectorWithScratch(const CFGBlock *block) {
222  ValueVector &dst = getValueVector(block, 0);
223  bool changed = (dst != scratch);
224  if (changed)
225    dst = scratch;
226#if 0
227  printVector(block, scratch, 0);
228#endif
229  return changed;
230}
231
232bool CFGBlockValues::updateValueVectors(const CFGBlock *block,
233                                      const BVPair &newVals) {
234  BVPair &vals = getValueVectors(block, true);
235  bool changed = *newVals.first != *vals.first ||
236                 *newVals.second != *vals.second;
237  *vals.first = *newVals.first;
238  *vals.second = *newVals.second;
239#if 0
240  printVector(block, *vals.first, 1);
241  printVector(block, *vals.second, 2);
242#endif
243  return changed;
244}
245
246void CFGBlockValues::resetScratch() {
247  scratch.reset();
248}
249
250ValueVector::reference CFGBlockValues::operator[](const VarDecl *vd) {
251  const llvm::Optional<unsigned> &idx = DeclToIndex.getValueIndex(vd);
252  assert(idx.hasValue());
253  return scratch[idx.getValue()];
254}
255
256//------------------------------------------------------------------------====//
257// Worklist: worklist for dataflow analysis.
258//====------------------------------------------------------------------------//
259
260namespace {
261class DataflowWorklist {
262  llvm::SmallVector<const CFGBlock *, 20> worklist;
263  ValueVector enqueuedBlocks;
264public:
265  DataflowWorklist(const CFG &cfg) : enqueuedBlocks(cfg.getNumBlockIDs()) {}
266
267  void enqueue(const CFGBlock *block);
268  void enqueueSuccessors(const CFGBlock *block);
269  const CFGBlock *dequeue();
270
271};
272}
273
274void DataflowWorklist::enqueue(const CFGBlock *block) {
275  if (!block)
276    return;
277  unsigned idx = block->getBlockID();
278  if (enqueuedBlocks[idx])
279    return;
280  worklist.push_back(block);
281  enqueuedBlocks[idx] = true;
282}
283
284void DataflowWorklist::enqueueSuccessors(const clang::CFGBlock *block) {
285  for (CFGBlock::const_succ_iterator I = block->succ_begin(),
286       E = block->succ_end(); I != E; ++I) {
287    enqueue(*I);
288  }
289}
290
291const CFGBlock *DataflowWorklist::dequeue() {
292  if (worklist.empty())
293    return 0;
294  const CFGBlock *b = worklist.back();
295  worklist.pop_back();
296  enqueuedBlocks[b->getBlockID()] = false;
297  return b;
298}
299
300//------------------------------------------------------------------------====//
301// Transfer function for uninitialized values analysis.
302//====------------------------------------------------------------------------//
303
304namespace {
305class FindVarResult {
306  const VarDecl *vd;
307  const DeclRefExpr *dr;
308public:
309  FindVarResult(VarDecl *vd, DeclRefExpr *dr) : vd(vd), dr(dr) {}
310
311  const DeclRefExpr *getDeclRefExpr() const { return dr; }
312  const VarDecl *getDecl() const { return vd; }
313};
314
315class TransferFunctions : public CFGRecStmtVisitor<TransferFunctions> {
316  CFGBlockValues &vals;
317  const CFG &cfg;
318  AnalysisContext &ac;
319  UninitVariablesHandler *handler;
320  const DeclRefExpr *currentDR;
321  const Expr *currentVoidCast;
322  const bool flagBlockUses;
323public:
324  TransferFunctions(CFGBlockValues &vals, const CFG &cfg,
325                    AnalysisContext &ac,
326                    UninitVariablesHandler *handler,
327                    bool flagBlockUses)
328    : vals(vals), cfg(cfg), ac(ac), handler(handler), currentDR(0),
329      currentVoidCast(0), flagBlockUses(flagBlockUses) {}
330
331  const CFG &getCFG() { return cfg; }
332  void reportUninit(const DeclRefExpr *ex, const VarDecl *vd);
333
334  void VisitBlockExpr(BlockExpr *be);
335  void VisitDeclStmt(DeclStmt *ds);
336  void VisitDeclRefExpr(DeclRefExpr *dr);
337  void VisitUnaryOperator(UnaryOperator *uo);
338  void VisitBinaryOperator(BinaryOperator *bo);
339  void VisitCastExpr(CastExpr *ce);
340  void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *se);
341  void BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt *fs);
342
343  bool isTrackedVar(const VarDecl *vd) {
344    return ::isTrackedVar(vd, cast<DeclContext>(ac.getDecl()));
345  }
346
347  FindVarResult findBlockVarDecl(Expr *ex);
348};
349}
350
351void TransferFunctions::reportUninit(const DeclRefExpr *ex,
352                                     const VarDecl *vd) {
353  if (handler) handler->handleUseOfUninitVariable(ex, vd);
354}
355
356FindVarResult TransferFunctions::findBlockVarDecl(Expr* ex) {
357  if (DeclRefExpr* dr = dyn_cast<DeclRefExpr>(ex->IgnoreParenCasts()))
358    if (VarDecl *vd = dyn_cast<VarDecl>(dr->getDecl()))
359      if (isTrackedVar(vd))
360        return FindVarResult(vd, dr);
361  return FindVarResult(0, 0);
362}
363
364void TransferFunctions::BlockStmt_VisitObjCForCollectionStmt(
365    ObjCForCollectionStmt *fs) {
366
367  Visit(fs->getCollection());
368
369  // This represents an initialization of the 'element' value.
370  Stmt *element = fs->getElement();
371  const VarDecl* vd = 0;
372
373  if (DeclStmt* ds = dyn_cast<DeclStmt>(element)) {
374    vd = cast<VarDecl>(ds->getSingleDecl());
375    if (!isTrackedVar(vd))
376      vd = 0;
377  }
378  else {
379    // Initialize the value of the reference variable.
380    const FindVarResult &res = findBlockVarDecl(cast<Expr>(element));
381    vd = res.getDecl();
382    if (!vd) {
383      Visit(element);
384      return;
385    }
386  }
387
388  if (vd)
389    vals[vd] = Initialized;
390}
391
392void TransferFunctions::VisitBlockExpr(BlockExpr *be) {
393  if (!flagBlockUses || !handler)
394    return;
395  AnalysisContext::referenced_decls_iterator i, e;
396  llvm::tie(i, e) = ac.getReferencedBlockVars(be->getBlockDecl());
397  for ( ; i != e; ++i) {
398    const VarDecl *vd = *i;
399    if (vd->getAttr<BlocksAttr>() || !vd->hasLocalStorage() ||
400        !isTrackedVar(vd))
401      continue;
402    if (vals[vd] == Uninitialized)
403      handler->handleUseOfUninitVariable(be, vd);
404  }
405}
406
407void TransferFunctions::VisitDeclStmt(DeclStmt *ds) {
408  for (DeclStmt::decl_iterator DI = ds->decl_begin(), DE = ds->decl_end();
409       DI != DE; ++DI) {
410    if (VarDecl *vd = dyn_cast<VarDecl>(*DI)) {
411      if (isTrackedVar(vd)) {
412        vals[vd] = Uninitialized;
413        if (Stmt *init = vd->getInit()) {
414          Visit(init);
415          vals[vd] = Initialized;
416        }
417      }
418      else if (Stmt *init = vd->getInit()) {
419        Visit(init);
420      }
421    }
422  }
423}
424
425void TransferFunctions::VisitDeclRefExpr(DeclRefExpr *dr) {
426  // We assume that DeclRefExprs wrapped in an lvalue-to-rvalue cast
427  // cannot be block-level expressions.  Therefore, we determine if
428  // a DeclRefExpr is involved in a "load" by comparing it to the current
429  // DeclRefExpr found when analyzing the last lvalue-to-rvalue CastExpr.
430  // If a DeclRefExpr is not involved in a load, we are essentially computing
431  // its address, either for assignment to a reference or via the '&' operator.
432  // In such cases, treat the variable as being initialized, since this
433  // analysis isn't powerful enough to do alias tracking.
434  if (dr != currentDR)
435    if (const VarDecl *vd = dyn_cast<VarDecl>(dr->getDecl()))
436      if (isTrackedVar(vd))
437        vals[vd] = Initialized;
438}
439
440void TransferFunctions::VisitBinaryOperator(clang::BinaryOperator *bo) {
441  if (bo->isAssignmentOp()) {
442    const FindVarResult &res = findBlockVarDecl(bo->getLHS());
443    if (const VarDecl* vd = res.getDecl()) {
444      // We assume that DeclRefExprs wrapped in a BinaryOperator "assignment"
445      // cannot be block-level expressions.  Therefore, we determine if
446      // a DeclRefExpr is involved in a "load" by comparing it to the current
447      // DeclRefExpr found when analyzing the last lvalue-to-rvalue CastExpr.
448      SaveAndRestore<const DeclRefExpr*> lastDR(currentDR,
449                                                res.getDeclRefExpr());
450      Visit(bo->getRHS());
451      Visit(bo->getLHS());
452
453      ValueVector::reference bit = vals[vd];
454      if (bit == Uninitialized) {
455        if (bo->getOpcode() != BO_Assign)
456          reportUninit(res.getDeclRefExpr(), vd);
457        bit = Initialized;
458      }
459      return;
460    }
461  }
462  Visit(bo->getRHS());
463  Visit(bo->getLHS());
464}
465
466void TransferFunctions::VisitUnaryOperator(clang::UnaryOperator *uo) {
467  switch (uo->getOpcode()) {
468    case clang::UO_PostDec:
469    case clang::UO_PostInc:
470    case clang::UO_PreDec:
471    case clang::UO_PreInc: {
472      const FindVarResult &res = findBlockVarDecl(uo->getSubExpr());
473      if (const VarDecl *vd = res.getDecl()) {
474        // We assume that DeclRefExprs wrapped in a unary operator ++/--
475        // cannot be block-level expressions.  Therefore, we determine if
476        // a DeclRefExpr is involved in a "load" by comparing it to the current
477        // DeclRefExpr found when analyzing the last lvalue-to-rvalue CastExpr.
478        SaveAndRestore<const DeclRefExpr*> lastDR(currentDR,
479                                                  res.getDeclRefExpr());
480        Visit(uo->getSubExpr());
481
482        ValueVector::reference bit = vals[vd];
483        if (bit == Uninitialized) {
484          reportUninit(res.getDeclRefExpr(), vd);
485          bit = Initialized;
486        }
487        return;
488      }
489      break;
490    }
491    default:
492      break;
493  }
494  Visit(uo->getSubExpr());
495}
496
497void TransferFunctions::VisitCastExpr(clang::CastExpr *ce) {
498  if (ce->getCastKind() == CK_LValueToRValue) {
499    const FindVarResult &res = findBlockVarDecl(ce->getSubExpr());
500    if (const VarDecl *vd = res.getDecl()) {
501      // We assume that DeclRefExprs wrapped in an lvalue-to-rvalue cast
502      // cannot be block-level expressions.  Therefore, we determine if
503      // a DeclRefExpr is involved in a "load" by comparing it to the current
504      // DeclRefExpr found when analyzing the last lvalue-to-rvalue CastExpr.
505      // Here we update 'currentDR' to be the one associated with this
506      // lvalue-to-rvalue cast.  Then, when we analyze the DeclRefExpr, we
507      // will know that we are not computing its lvalue for other purposes
508      // than to perform a load.
509      SaveAndRestore<const DeclRefExpr*> lastDR(currentDR,
510                                                res.getDeclRefExpr());
511      Visit(ce->getSubExpr());
512      if (currentVoidCast != ce && vals[vd] == Uninitialized) {
513        reportUninit(res.getDeclRefExpr(), vd);
514        // Don't cascade warnings.
515        vals[vd] = Initialized;
516      }
517      return;
518    }
519  }
520  else if (CStyleCastExpr *cse = dyn_cast<CStyleCastExpr>(ce)) {
521    if (cse->getType()->isVoidType()) {
522      // e.g. (void) x;
523      SaveAndRestore<const Expr *>
524        lastVoidCast(currentVoidCast, cse->getSubExpr()->IgnoreParens());
525      Visit(cse->getSubExpr());
526      return;
527    }
528  }
529  Visit(ce->getSubExpr());
530}
531
532void TransferFunctions::VisitUnaryExprOrTypeTraitExpr(
533                                          UnaryExprOrTypeTraitExpr *se) {
534  if (se->getKind() == UETT_SizeOf) {
535    if (se->getType()->isConstantSizeType())
536      return;
537    // Handle VLAs.
538    Visit(se->getArgumentExpr());
539  }
540}
541
542//------------------------------------------------------------------------====//
543// High-level "driver" logic for uninitialized values analysis.
544//====------------------------------------------------------------------------//
545
546static bool runOnBlock(const CFGBlock *block, const CFG &cfg,
547                       AnalysisContext &ac, CFGBlockValues &vals,
548                       UninitVariablesHandler *handler = 0,
549                       bool flagBlockUses = false) {
550
551  if (const BinaryOperator *b = getLogicalOperatorInChain(block)) {
552    CFGBlock::const_pred_iterator itr = block->pred_begin();
553    BVPair vA = vals.getValueVectors(*itr, false);
554    ++itr;
555    BVPair vB = vals.getValueVectors(*itr, false);
556
557    BVPair valsAB;
558
559    if (b->getOpcode() == BO_LAnd) {
560      // Merge the 'F' bits from the first and second.
561      vals.mergeIntoScratch(*(vA.second ? vA.second : vA.first), true);
562      vals.mergeIntoScratch(*(vB.second ? vB.second : vB.first), false);
563      valsAB.first = vA.first;
564      valsAB.second = &vals.getScratch();
565    }
566    else {
567      // Merge the 'T' bits from the first and second.
568      assert(b->getOpcode() == BO_LOr);
569      vals.mergeIntoScratch(*vA.first, true);
570      vals.mergeIntoScratch(*vB.first, false);
571      valsAB.first = &vals.getScratch();
572      valsAB.second = vA.second ? vA.second : vA.first;
573    }
574    return vals.updateValueVectors(block, valsAB);
575  }
576
577  // Default behavior: merge in values of predecessor blocks.
578  vals.resetScratch();
579  bool isFirst = true;
580  for (CFGBlock::const_pred_iterator I = block->pred_begin(),
581       E = block->pred_end(); I != E; ++I) {
582    vals.mergeIntoScratch(vals.getValueVector(*I, block), isFirst);
583    isFirst = false;
584  }
585  // Apply the transfer function.
586  TransferFunctions tf(vals, cfg, ac, handler, flagBlockUses);
587  for (CFGBlock::const_iterator I = block->begin(), E = block->end();
588       I != E; ++I) {
589    if (const CFGStmt *cs = dyn_cast<CFGStmt>(&*I)) {
590      tf.BlockStmt_Visit(cs->getStmt());
591    }
592  }
593  return vals.updateValueVectorWithScratch(block);
594}
595
596void clang::runUninitializedVariablesAnalysis(const DeclContext &dc,
597                                              const CFG &cfg,
598                                              AnalysisContext &ac,
599                                              UninitVariablesHandler &handler) {
600  CFGBlockValues vals(cfg);
601  vals.computeSetOfDeclarations(dc);
602  if (vals.hasNoDeclarations())
603    return;
604  DataflowWorklist worklist(cfg);
605  ValueVector previouslyVisited(cfg.getNumBlockIDs());
606
607  worklist.enqueueSuccessors(&cfg.getEntry());
608
609  while (const CFGBlock *block = worklist.dequeue()) {
610    // Did the block change?
611    bool changed = runOnBlock(block, cfg, ac, vals);
612    if (changed || !previouslyVisited[block->getBlockID()])
613      worklist.enqueueSuccessors(block);
614    previouslyVisited[block->getBlockID()] = true;
615  }
616
617  // Run through the blocks one more time, and report uninitialized variabes.
618  for (CFG::const_iterator BI = cfg.begin(), BE = cfg.end(); BI != BE; ++BI) {
619    runOnBlock(*BI, cfg, ac, vals, &handler, /* flagBlockUses */ true);
620  }
621}
622
623UninitVariablesHandler::~UninitVariablesHandler() {}
624
625