1193326Sed//==- UninitializedValues.cpp - Find Uninitialized Values -------*- C++ --*-==//
2193326Sed//
3193326Sed//                     The LLVM Compiler Infrastructure
4193326Sed//
5193326Sed// This file is distributed under the University of Illinois Open Source
6193326Sed// License. See LICENSE.TXT for details.
7193326Sed//
8193326Sed//===----------------------------------------------------------------------===//
9193326Sed//
10221345Sdim// This file implements uninitialized values analysis for source-level CFGs.
11193326Sed//
12193326Sed//===----------------------------------------------------------------------===//
13193326Sed
14239462Sdim#include "clang/AST/ASTContext.h"
15249423Sdim#include "clang/AST/Attr.h"
16221345Sdim#include "clang/AST/Decl.h"
17263508Sdim#include "clang/AST/StmtVisitor.h"
18249423Sdim#include "clang/Analysis/Analyses/PostOrderCFGView.h"
19249423Sdim#include "clang/Analysis/Analyses/UninitializedValues.h"
20249423Sdim#include "clang/Analysis/AnalysisContext.h"
21221345Sdim#include "clang/Analysis/CFG.h"
22249423Sdim#include "clang/Analysis/DomainSpecific/ObjCNoReturn.h"
23249423Sdim#include "llvm/ADT/DenseMap.h"
24249423Sdim#include "llvm/ADT/Optional.h"
25249423Sdim#include "llvm/ADT/PackedVector.h"
26249423Sdim#include "llvm/ADT/SmallBitVector.h"
27249423Sdim#include "llvm/ADT/SmallVector.h"
28234353Sdim#include "llvm/Support/SaveAndRestore.h"
29249423Sdim#include <utility>
30193326Sed
31193326Sedusing namespace clang;
32193326Sed
33239462Sdim#define DEBUG_LOGGING 0
34239462Sdim
35221345Sdimstatic bool isTrackedVar(const VarDecl *vd, const DeclContext *dc) {
36221345Sdim  if (vd->isLocalVarDecl() && !vd->hasGlobalStorage() &&
37221345Sdim      !vd->isExceptionVariable() &&
38221345Sdim      vd->getDeclContext() == dc) {
39221345Sdim    QualType ty = vd->getType();
40221345Sdim    return ty->isScalarType() || ty->isVectorType();
41221345Sdim  }
42221345Sdim  return false;
43221345Sdim}
44193326Sed
45221345Sdim//------------------------------------------------------------------------====//
46221345Sdim// DeclToIndex: a mapping from Decls we track to value indices.
47221345Sdim//====------------------------------------------------------------------------//
48221345Sdim
49193326Sednamespace {
50221345Sdimclass DeclToIndex {
51221345Sdim  llvm::DenseMap<const VarDecl *, unsigned> map;
52221345Sdimpublic:
53221345Sdim  DeclToIndex() {}
54221345Sdim
55221345Sdim  /// Compute the actual mapping from declarations to bits.
56221345Sdim  void computeMap(const DeclContext &dc);
57221345Sdim
58221345Sdim  /// Return the number of declarations in the map.
59221345Sdim  unsigned size() const { return map.size(); }
60221345Sdim
61221345Sdim  /// Returns the bit vector index for a given declaration.
62249423Sdim  Optional<unsigned> getValueIndex(const VarDecl *d) const;
63221345Sdim};
64221345Sdim}
65193326Sed
66221345Sdimvoid DeclToIndex::computeMap(const DeclContext &dc) {
67221345Sdim  unsigned count = 0;
68221345Sdim  DeclContext::specific_decl_iterator<VarDecl> I(dc.decls_begin()),
69221345Sdim                                               E(dc.decls_end());
70221345Sdim  for ( ; I != E; ++I) {
71221345Sdim    const VarDecl *vd = *I;
72221345Sdim    if (isTrackedVar(vd, &dc))
73221345Sdim      map[vd] = count++;
74221345Sdim  }
75221345Sdim}
76193326Sed
77249423SdimOptional<unsigned> DeclToIndex::getValueIndex(const VarDecl *d) const {
78221345Sdim  llvm::DenseMap<const VarDecl *, unsigned>::const_iterator I = map.find(d);
79221345Sdim  if (I == map.end())
80249423Sdim    return None;
81221345Sdim  return I->second;
82221345Sdim}
83198092Srdivacky
84221345Sdim//------------------------------------------------------------------------====//
85221345Sdim// CFGBlockValues: dataflow values for CFG blocks.
86221345Sdim//====------------------------------------------------------------------------//
87198092Srdivacky
88221345Sdim// These values are defined in such a way that a merge can be done using
89221345Sdim// a bitwise OR.
90221345Sdimenum Value { Unknown = 0x0,         /* 00 */
91221345Sdim             Initialized = 0x1,     /* 01 */
92221345Sdim             Uninitialized = 0x2,   /* 10 */
93221345Sdim             MayUninitialized = 0x3 /* 11 */ };
94193326Sed
95221345Sdimstatic bool isUninitialized(const Value v) {
96221345Sdim  return v >= Uninitialized;
97193326Sed}
98221345Sdimstatic bool isAlwaysUninit(const Value v) {
99221345Sdim  return v == Uninitialized;
100221345Sdim}
101193326Sed
102193326Sednamespace {
103198092Srdivacky
104243830Sdimtypedef llvm::PackedVector<Value, 2, llvm::SmallBitVector> ValueVector;
105221345Sdim
106221345Sdimclass CFGBlockValues {
107221345Sdim  const CFG &cfg;
108243830Sdim  SmallVector<ValueVector, 8> vals;
109221345Sdim  ValueVector scratch;
110221345Sdim  DeclToIndex declToIndex;
111193326Sedpublic:
112221345Sdim  CFGBlockValues(const CFG &cfg);
113239462Sdim
114221345Sdim  unsigned getNumEntries() const { return declToIndex.size(); }
115221345Sdim
116221345Sdim  void computeSetOfDeclarations(const DeclContext &dc);
117239462Sdim  ValueVector &getValueVector(const CFGBlock *block) {
118243830Sdim    return vals[block->getBlockID()];
119239462Sdim  }
120198092Srdivacky
121239462Sdim  void setAllScratchValues(Value V);
122221345Sdim  void mergeIntoScratch(ValueVector const &source, bool isFirst);
123221345Sdim  bool updateValueVectorWithScratch(const CFGBlock *block);
124221345Sdim
125221345Sdim  bool hasNoDeclarations() const {
126221345Sdim    return declToIndex.size() == 0;
127193326Sed  }
128226633Sdim
129221345Sdim  void resetScratch();
130221345Sdim
131221345Sdim  ValueVector::reference operator[](const VarDecl *vd);
132239462Sdim
133239462Sdim  Value getValue(const CFGBlock *block, const CFGBlock *dstBlock,
134239462Sdim                 const VarDecl *vd) {
135249423Sdim    const Optional<unsigned> &idx = declToIndex.getValueIndex(vd);
136239462Sdim    assert(idx.hasValue());
137239462Sdim    return getValueVector(block)[idx.getValue()];
138239462Sdim  }
139221345Sdim};
140221345Sdim} // end anonymous namespace
141198092Srdivacky
142239462SdimCFGBlockValues::CFGBlockValues(const CFG &c) : cfg(c), vals(0) {}
143198092Srdivacky
144221345Sdimvoid CFGBlockValues::computeSetOfDeclarations(const DeclContext &dc) {
145221345Sdim  declToIndex.computeMap(dc);
146239462Sdim  unsigned decls = declToIndex.size();
147239462Sdim  scratch.resize(decls);
148239462Sdim  unsigned n = cfg.getNumBlockIDs();
149239462Sdim  if (!n)
150239462Sdim    return;
151239462Sdim  vals.resize(n);
152239462Sdim  for (unsigned i = 0; i < n; ++i)
153243830Sdim    vals[i].resize(decls);
154221345Sdim}
155198092Srdivacky
156239462Sdim#if DEBUG_LOGGING
157221345Sdimstatic void printVector(const CFGBlock *block, ValueVector &bv,
158221345Sdim                        unsigned num) {
159221345Sdim  llvm::errs() << block->getBlockID() << " :";
160221345Sdim  for (unsigned i = 0; i < bv.size(); ++i) {
161221345Sdim    llvm::errs() << ' ' << bv[i];
162221345Sdim  }
163221345Sdim  llvm::errs() << " : " << num << '\n';
164221345Sdim}
165239462Sdim#endif
166226633Sdim
167239462Sdimvoid CFGBlockValues::setAllScratchValues(Value V) {
168239462Sdim  for (unsigned I = 0, E = scratch.size(); I != E; ++I)
169239462Sdim    scratch[I] = V;
170226633Sdim}
171198092Srdivacky
172226633Sdimvoid CFGBlockValues::mergeIntoScratch(ValueVector const &source,
173226633Sdim                                      bool isFirst) {
174226633Sdim  if (isFirst)
175226633Sdim    scratch = source;
176226633Sdim  else
177226633Sdim    scratch |= source;
178226633Sdim}
179226633Sdim
180221345Sdimbool CFGBlockValues::updateValueVectorWithScratch(const CFGBlock *block) {
181239462Sdim  ValueVector &dst = getValueVector(block);
182221345Sdim  bool changed = (dst != scratch);
183221345Sdim  if (changed)
184221345Sdim    dst = scratch;
185239462Sdim#if DEBUG_LOGGING
186221345Sdim  printVector(block, scratch, 0);
187221345Sdim#endif
188221345Sdim  return changed;
189221345Sdim}
190193326Sed
191221345Sdimvoid CFGBlockValues::resetScratch() {
192221345Sdim  scratch.reset();
193221345Sdim}
194193326Sed
195221345SdimValueVector::reference CFGBlockValues::operator[](const VarDecl *vd) {
196249423Sdim  const Optional<unsigned> &idx = declToIndex.getValueIndex(vd);
197221345Sdim  assert(idx.hasValue());
198221345Sdim  return scratch[idx.getValue()];
199221345Sdim}
200193326Sed
201221345Sdim//------------------------------------------------------------------------====//
202221345Sdim// Worklist: worklist for dataflow analysis.
203221345Sdim//====------------------------------------------------------------------------//
204221345Sdim
205221345Sdimnamespace {
206221345Sdimclass DataflowWorklist {
207249423Sdim  PostOrderCFGView::iterator PO_I, PO_E;
208226633Sdim  SmallVector<const CFGBlock *, 20> worklist;
209221345Sdim  llvm::BitVector enqueuedBlocks;
210221345Sdimpublic:
211249423Sdim  DataflowWorklist(const CFG &cfg, PostOrderCFGView &view)
212249423Sdim    : PO_I(view.begin()), PO_E(view.end()),
213249423Sdim      enqueuedBlocks(cfg.getNumBlockIDs(), true) {
214249423Sdim        // Treat the first block as already analyzed.
215249423Sdim        if (PO_I != PO_E) {
216249423Sdim          assert(*PO_I == &cfg.getEntry());
217249423Sdim          enqueuedBlocks[(*PO_I)->getBlockID()] = false;
218249423Sdim          ++PO_I;
219249423Sdim        }
220249423Sdim      }
221221345Sdim
222221345Sdim  void enqueueSuccessors(const CFGBlock *block);
223221345Sdim  const CFGBlock *dequeue();
224221345Sdim};
225193326Sed}
226193326Sed
227221345Sdimvoid DataflowWorklist::enqueueSuccessors(const clang::CFGBlock *block) {
228221345Sdim  for (CFGBlock::const_succ_iterator I = block->succ_begin(),
229221345Sdim       E = block->succ_end(); I != E; ++I) {
230224145Sdim    const CFGBlock *Successor = *I;
231224145Sdim    if (!Successor || enqueuedBlocks[Successor->getBlockID()])
232224145Sdim      continue;
233224145Sdim    worklist.push_back(Successor);
234224145Sdim    enqueuedBlocks[Successor->getBlockID()] = true;
235193326Sed  }
236193326Sed}
237198092Srdivacky
238221345Sdimconst CFGBlock *DataflowWorklist::dequeue() {
239249423Sdim  const CFGBlock *B = 0;
240249423Sdim
241249423Sdim  // First dequeue from the worklist.  This can represent
242249423Sdim  // updates along backedges that we want propagated as quickly as possible.
243263508Sdim  if (!worklist.empty())
244263508Sdim    B = worklist.pop_back_val();
245263508Sdim
246249423Sdim  // Next dequeue from the initial reverse post order.  This is the
247249423Sdim  // theoretical ideal in the presence of no back edges.
248249423Sdim  else if (PO_I != PO_E) {
249249423Sdim    B = *PO_I;
250249423Sdim    ++PO_I;
251249423Sdim  }
252249423Sdim  else {
253221345Sdim    return 0;
254249423Sdim  }
255249423Sdim
256249423Sdim  assert(enqueuedBlocks[B->getBlockID()] == true);
257249423Sdim  enqueuedBlocks[B->getBlockID()] = false;
258249423Sdim  return B;
259193326Sed}
260193326Sed
261221345Sdim//------------------------------------------------------------------------====//
262239462Sdim// Classification of DeclRefExprs as use or initialization.
263221345Sdim//====------------------------------------------------------------------------//
264198092Srdivacky
265221345Sdimnamespace {
266221345Sdimclass FindVarResult {
267221345Sdim  const VarDecl *vd;
268221345Sdim  const DeclRefExpr *dr;
269221345Sdimpublic:
270239462Sdim  FindVarResult(const VarDecl *vd, const DeclRefExpr *dr) : vd(vd), dr(dr) {}
271239462Sdim
272221345Sdim  const DeclRefExpr *getDeclRefExpr() const { return dr; }
273221345Sdim  const VarDecl *getDecl() const { return vd; }
274221345Sdim};
275239462Sdim
276239462Sdimstatic const Expr *stripCasts(ASTContext &C, const Expr *Ex) {
277239462Sdim  while (Ex) {
278239462Sdim    Ex = Ex->IgnoreParenNoopCasts(C);
279239462Sdim    if (const CastExpr *CE = dyn_cast<CastExpr>(Ex)) {
280239462Sdim      if (CE->getCastKind() == CK_LValueBitCast) {
281239462Sdim        Ex = CE->getSubExpr();
282239462Sdim        continue;
283239462Sdim      }
284239462Sdim    }
285239462Sdim    break;
286239462Sdim  }
287239462Sdim  return Ex;
288239462Sdim}
289239462Sdim
290239462Sdim/// If E is an expression comprising a reference to a single variable, find that
291239462Sdim/// variable.
292239462Sdimstatic FindVarResult findVar(const Expr *E, const DeclContext *DC) {
293239462Sdim  if (const DeclRefExpr *DRE =
294239462Sdim        dyn_cast<DeclRefExpr>(stripCasts(DC->getParentASTContext(), E)))
295239462Sdim    if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl()))
296239462Sdim      if (isTrackedVar(VD, DC))
297239462Sdim        return FindVarResult(VD, DRE);
298239462Sdim  return FindVarResult(0, 0);
299239462Sdim}
300239462Sdim
301239462Sdim/// \brief Classify each DeclRefExpr as an initialization or a use. Any
302239462Sdim/// DeclRefExpr which isn't explicitly classified will be assumed to have
303239462Sdim/// escaped the analysis and will be treated as an initialization.
304239462Sdimclass ClassifyRefs : public StmtVisitor<ClassifyRefs> {
305239462Sdimpublic:
306239462Sdim  enum Class {
307239462Sdim    Init,
308239462Sdim    Use,
309239462Sdim    SelfInit,
310239462Sdim    Ignore
311239462Sdim  };
312239462Sdim
313239462Sdimprivate:
314239462Sdim  const DeclContext *DC;
315239462Sdim  llvm::DenseMap<const DeclRefExpr*, Class> Classification;
316239462Sdim
317239462Sdim  bool isTrackedVar(const VarDecl *VD) const {
318239462Sdim    return ::isTrackedVar(VD, DC);
319239462Sdim  }
320239462Sdim
321239462Sdim  void classify(const Expr *E, Class C);
322239462Sdim
323239462Sdimpublic:
324239462Sdim  ClassifyRefs(AnalysisDeclContext &AC) : DC(cast<DeclContext>(AC.getDecl())) {}
325239462Sdim
326239462Sdim  void VisitDeclStmt(DeclStmt *DS);
327239462Sdim  void VisitUnaryOperator(UnaryOperator *UO);
328239462Sdim  void VisitBinaryOperator(BinaryOperator *BO);
329239462Sdim  void VisitCallExpr(CallExpr *CE);
330239462Sdim  void VisitCastExpr(CastExpr *CE);
331239462Sdim
332239462Sdim  void operator()(Stmt *S) { Visit(S); }
333239462Sdim
334239462Sdim  Class get(const DeclRefExpr *DRE) const {
335239462Sdim    llvm::DenseMap<const DeclRefExpr*, Class>::const_iterator I
336239462Sdim        = Classification.find(DRE);
337239462Sdim    if (I != Classification.end())
338239462Sdim      return I->second;
339239462Sdim
340239462Sdim    const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl());
341239462Sdim    if (!VD || !isTrackedVar(VD))
342239462Sdim      return Ignore;
343239462Sdim
344239462Sdim    return Init;
345239462Sdim  }
346239462Sdim};
347239462Sdim}
348239462Sdim
349239462Sdimstatic const DeclRefExpr *getSelfInitExpr(VarDecl *VD) {
350239462Sdim  if (Expr *Init = VD->getInit()) {
351239462Sdim    const DeclRefExpr *DRE
352239462Sdim      = dyn_cast<DeclRefExpr>(stripCasts(VD->getASTContext(), Init));
353239462Sdim    if (DRE && DRE->getDecl() == VD)
354239462Sdim      return DRE;
355239462Sdim  }
356239462Sdim  return 0;
357239462Sdim}
358239462Sdim
359239462Sdimvoid ClassifyRefs::classify(const Expr *E, Class C) {
360249423Sdim  // The result of a ?: could also be an lvalue.
361249423Sdim  E = E->IgnoreParens();
362249423Sdim  if (const ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) {
363249423Sdim    const Expr *TrueExpr = CO->getTrueExpr();
364249423Sdim    if (!isa<OpaqueValueExpr>(TrueExpr))
365249423Sdim      classify(TrueExpr, C);
366249423Sdim    classify(CO->getFalseExpr(), C);
367249423Sdim    return;
368249423Sdim  }
369249423Sdim
370239462Sdim  FindVarResult Var = findVar(E, DC);
371239462Sdim  if (const DeclRefExpr *DRE = Var.getDeclRefExpr())
372239462Sdim    Classification[DRE] = std::max(Classification[DRE], C);
373239462Sdim}
374239462Sdim
375239462Sdimvoid ClassifyRefs::VisitDeclStmt(DeclStmt *DS) {
376239462Sdim  for (DeclStmt::decl_iterator DI = DS->decl_begin(), DE = DS->decl_end();
377239462Sdim       DI != DE; ++DI) {
378239462Sdim    VarDecl *VD = dyn_cast<VarDecl>(*DI);
379239462Sdim    if (VD && isTrackedVar(VD))
380239462Sdim      if (const DeclRefExpr *DRE = getSelfInitExpr(VD))
381239462Sdim        Classification[DRE] = SelfInit;
382239462Sdim  }
383239462Sdim}
384239462Sdim
385239462Sdimvoid ClassifyRefs::VisitBinaryOperator(BinaryOperator *BO) {
386239462Sdim  // Ignore the evaluation of a DeclRefExpr on the LHS of an assignment. If this
387239462Sdim  // is not a compound-assignment, we will treat it as initializing the variable
388239462Sdim  // when TransferFunctions visits it. A compound-assignment does not affect
389239462Sdim  // whether a variable is uninitialized, and there's no point counting it as a
390239462Sdim  // use.
391239462Sdim  if (BO->isCompoundAssignmentOp())
392239462Sdim    classify(BO->getLHS(), Use);
393239462Sdim  else if (BO->getOpcode() == BO_Assign)
394239462Sdim    classify(BO->getLHS(), Ignore);
395239462Sdim}
396239462Sdim
397239462Sdimvoid ClassifyRefs::VisitUnaryOperator(UnaryOperator *UO) {
398239462Sdim  // Increment and decrement are uses despite there being no lvalue-to-rvalue
399239462Sdim  // conversion.
400239462Sdim  if (UO->isIncrementDecrementOp())
401239462Sdim    classify(UO->getSubExpr(), Use);
402239462Sdim}
403239462Sdim
404239462Sdimvoid ClassifyRefs::VisitCallExpr(CallExpr *CE) {
405239462Sdim  // If a value is passed by const reference to a function, we should not assume
406239462Sdim  // that it is initialized by the call, and we conservatively do not assume
407239462Sdim  // that it is used.
408239462Sdim  for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end();
409239462Sdim       I != E; ++I)
410239462Sdim    if ((*I)->getType().isConstQualified() && (*I)->isGLValue())
411239462Sdim      classify(*I, Ignore);
412239462Sdim}
413239462Sdim
414239462Sdimvoid ClassifyRefs::VisitCastExpr(CastExpr *CE) {
415239462Sdim  if (CE->getCastKind() == CK_LValueToRValue)
416239462Sdim    classify(CE->getSubExpr(), Use);
417239462Sdim  else if (CStyleCastExpr *CSE = dyn_cast<CStyleCastExpr>(CE)) {
418239462Sdim    if (CSE->getType()->isVoidType()) {
419239462Sdim      // Squelch any detected load of an uninitialized value if
420239462Sdim      // we cast it to void.
421239462Sdim      // e.g. (void) x;
422239462Sdim      classify(CSE->getSubExpr(), Ignore);
423239462Sdim    }
424239462Sdim  }
425239462Sdim}
426239462Sdim
427239462Sdim//------------------------------------------------------------------------====//
428239462Sdim// Transfer function for uninitialized values analysis.
429239462Sdim//====------------------------------------------------------------------------//
430239462Sdim
431239462Sdimnamespace {
432226633Sdimclass TransferFunctions : public StmtVisitor<TransferFunctions> {
433221345Sdim  CFGBlockValues &vals;
434221345Sdim  const CFG &cfg;
435239462Sdim  const CFGBlock *block;
436234353Sdim  AnalysisDeclContext &ac;
437239462Sdim  const ClassifyRefs &classification;
438243830Sdim  ObjCNoReturn objCNoRet;
439249423Sdim  UninitVariablesHandler &handler;
440239462Sdim
441221345Sdimpublic:
442221345Sdim  TransferFunctions(CFGBlockValues &vals, const CFG &cfg,
443239462Sdim                    const CFGBlock *block, AnalysisDeclContext &ac,
444239462Sdim                    const ClassifyRefs &classification,
445249423Sdim                    UninitVariablesHandler &handler)
446239462Sdim    : vals(vals), cfg(cfg), block(block), ac(ac),
447243830Sdim      classification(classification), objCNoRet(ac.getASTContext()),
448243830Sdim      handler(handler) {}
449221345Sdim
450239462Sdim  void reportUse(const Expr *ex, const VarDecl *vd);
451239462Sdim
452243830Sdim  void VisitBinaryOperator(BinaryOperator *bo);
453221345Sdim  void VisitBlockExpr(BlockExpr *be);
454239462Sdim  void VisitCallExpr(CallExpr *ce);
455243830Sdim  void VisitDeclRefExpr(DeclRefExpr *dr);
456221345Sdim  void VisitDeclStmt(DeclStmt *ds);
457243830Sdim  void VisitObjCForCollectionStmt(ObjCForCollectionStmt *FS);
458243830Sdim  void VisitObjCMessageExpr(ObjCMessageExpr *ME);
459239462Sdim
460221345Sdim  bool isTrackedVar(const VarDecl *vd) {
461221345Sdim    return ::isTrackedVar(vd, cast<DeclContext>(ac.getDecl()));
462193326Sed  }
463193326Sed
464239462Sdim  FindVarResult findVar(const Expr *ex) {
465239462Sdim    return ::findVar(ex, cast<DeclContext>(ac.getDecl()));
466239462Sdim  }
467239462Sdim
468239462Sdim  UninitUse getUninitUse(const Expr *ex, const VarDecl *vd, Value v) {
469239462Sdim    UninitUse Use(ex, isAlwaysUninit(v));
470239462Sdim
471239462Sdim    assert(isUninitialized(v));
472239462Sdim    if (Use.getKind() == UninitUse::Always)
473239462Sdim      return Use;
474239462Sdim
475239462Sdim    // If an edge which leads unconditionally to this use did not initialize
476239462Sdim    // the variable, we can say something stronger than 'may be uninitialized':
477239462Sdim    // we can say 'either it's used uninitialized or you have dead code'.
478239462Sdim    //
479239462Sdim    // We track the number of successors of a node which have been visited, and
480239462Sdim    // visit a node once we have visited all of its successors. Only edges where
481239462Sdim    // the variable might still be uninitialized are followed. Since a variable
482239462Sdim    // can't transfer from being initialized to being uninitialized, this will
483239462Sdim    // trace out the subgraph which inevitably leads to the use and does not
484239462Sdim    // initialize the variable. We do not want to skip past loops, since their
485239462Sdim    // non-termination might be correlated with the initialization condition.
486239462Sdim    //
487239462Sdim    // For example:
488239462Sdim    //
489239462Sdim    //         void f(bool a, bool b) {
490239462Sdim    // block1:   int n;
491239462Sdim    //           if (a) {
492239462Sdim    // block2:     if (b)
493239462Sdim    // block3:       n = 1;
494239462Sdim    // block4:   } else if (b) {
495239462Sdim    // block5:     while (!a) {
496239462Sdim    // block6:       do_work(&a);
497239462Sdim    //               n = 2;
498239462Sdim    //             }
499239462Sdim    //           }
500239462Sdim    // block7:   if (a)
501239462Sdim    // block8:     g();
502239462Sdim    // block9:   return n;
503239462Sdim    //         }
504239462Sdim    //
505239462Sdim    // Starting from the maybe-uninitialized use in block 9:
506239462Sdim    //  * Block 7 is not visited because we have only visited one of its two
507239462Sdim    //    successors.
508239462Sdim    //  * Block 8 is visited because we've visited its only successor.
509239462Sdim    // From block 8:
510239462Sdim    //  * Block 7 is visited because we've now visited both of its successors.
511239462Sdim    // From block 7:
512239462Sdim    //  * Blocks 1, 2, 4, 5, and 6 are not visited because we didn't visit all
513239462Sdim    //    of their successors (we didn't visit 4, 3, 5, 6, and 5, respectively).
514239462Sdim    //  * Block 3 is not visited because it initializes 'n'.
515239462Sdim    // Now the algorithm terminates, having visited blocks 7 and 8, and having
516239462Sdim    // found the frontier is blocks 2, 4, and 5.
517239462Sdim    //
518239462Sdim    // 'n' is definitely uninitialized for two edges into block 7 (from blocks 2
519239462Sdim    // and 4), so we report that any time either of those edges is taken (in
520239462Sdim    // each case when 'b == false'), 'n' is used uninitialized.
521249423Sdim    SmallVector<const CFGBlock*, 32> Queue;
522249423Sdim    SmallVector<unsigned, 32> SuccsVisited(cfg.getNumBlockIDs(), 0);
523239462Sdim    Queue.push_back(block);
524239462Sdim    // Specify that we've already visited all successors of the starting block.
525239462Sdim    // This has the dual purpose of ensuring we never add it to the queue, and
526239462Sdim    // of marking it as not being a candidate element of the frontier.
527239462Sdim    SuccsVisited[block->getBlockID()] = block->succ_size();
528239462Sdim    while (!Queue.empty()) {
529263508Sdim      const CFGBlock *B = Queue.pop_back_val();
530263508Sdim
531263508Sdim      // If the use is always reached from the entry block, make a note of that.
532263508Sdim      if (B == &cfg.getEntry())
533263508Sdim        Use.setUninitAfterCall();
534263508Sdim
535239462Sdim      for (CFGBlock::const_pred_iterator I = B->pred_begin(), E = B->pred_end();
536239462Sdim           I != E; ++I) {
537239462Sdim        const CFGBlock *Pred = *I;
538263508Sdim        Value AtPredExit = vals.getValue(Pred, B, vd);
539263508Sdim        if (AtPredExit == Initialized)
540239462Sdim          // This block initializes the variable.
541239462Sdim          continue;
542263508Sdim        if (AtPredExit == MayUninitialized &&
543263508Sdim            vals.getValue(B, 0, vd) == Uninitialized) {
544263508Sdim          // This block declares the variable (uninitialized), and is reachable
545263508Sdim          // from a block that initializes the variable. We can't guarantee to
546263508Sdim          // give an earlier location for the diagnostic (and it appears that
547263508Sdim          // this code is intended to be reachable) so give a diagnostic here
548263508Sdim          // and go no further down this path.
549263508Sdim          Use.setUninitAfterDecl();
550263508Sdim          continue;
551263508Sdim        }
552239462Sdim
553239462Sdim        unsigned &SV = SuccsVisited[Pred->getBlockID()];
554239462Sdim        if (!SV) {
555239462Sdim          // When visiting the first successor of a block, mark all NULL
556239462Sdim          // successors as having been visited.
557239462Sdim          for (CFGBlock::const_succ_iterator SI = Pred->succ_begin(),
558239462Sdim                                             SE = Pred->succ_end();
559239462Sdim               SI != SE; ++SI)
560239462Sdim            if (!*SI)
561239462Sdim              ++SV;
562239462Sdim        }
563239462Sdim
564239462Sdim        if (++SV == Pred->succ_size())
565239462Sdim          // All paths from this block lead to the use and don't initialize the
566239462Sdim          // variable.
567239462Sdim          Queue.push_back(Pred);
568226633Sdim      }
569226633Sdim    }
570239462Sdim
571239462Sdim    // Scan the frontier, looking for blocks where the variable was
572239462Sdim    // uninitialized.
573239462Sdim    for (CFG::const_iterator BI = cfg.begin(), BE = cfg.end(); BI != BE; ++BI) {
574239462Sdim      const CFGBlock *Block = *BI;
575239462Sdim      unsigned BlockID = Block->getBlockID();
576239462Sdim      const Stmt *Term = Block->getTerminator();
577239462Sdim      if (SuccsVisited[BlockID] && SuccsVisited[BlockID] < Block->succ_size() &&
578239462Sdim          Term) {
579239462Sdim        // This block inevitably leads to the use. If we have an edge from here
580239462Sdim        // to a post-dominator block, and the variable is uninitialized on that
581239462Sdim        // edge, we have found a bug.
582239462Sdim        for (CFGBlock::const_succ_iterator I = Block->succ_begin(),
583239462Sdim             E = Block->succ_end(); I != E; ++I) {
584239462Sdim          const CFGBlock *Succ = *I;
585239462Sdim          if (Succ && SuccsVisited[Succ->getBlockID()] >= Succ->succ_size() &&
586239462Sdim              vals.getValue(Block, Succ, vd) == Uninitialized) {
587239462Sdim            // Switch cases are a special case: report the label to the caller
588239462Sdim            // as the 'terminator', not the switch statement itself. Suppress
589239462Sdim            // situations where no label matched: we can't be sure that's
590239462Sdim            // possible.
591239462Sdim            if (isa<SwitchStmt>(Term)) {
592239462Sdim              const Stmt *Label = Succ->getLabel();
593239462Sdim              if (!Label || !isa<SwitchCase>(Label))
594239462Sdim                // Might not be possible.
595239462Sdim                continue;
596239462Sdim              UninitUse::Branch Branch;
597239462Sdim              Branch.Terminator = Label;
598239462Sdim              Branch.Output = 0; // Ignored.
599239462Sdim              Use.addUninitBranch(Branch);
600239462Sdim            } else {
601239462Sdim              UninitUse::Branch Branch;
602239462Sdim              Branch.Terminator = Term;
603239462Sdim              Branch.Output = I - Block->succ_begin();
604239462Sdim              Use.addUninitBranch(Branch);
605239462Sdim            }
606239462Sdim          }
607239462Sdim        }
608239462Sdim      }
609239462Sdim    }
610239462Sdim
611239462Sdim    return Use;
612226633Sdim  }
613239462Sdim};
614226633Sdim}
615226633Sdim
616239462Sdimvoid TransferFunctions::reportUse(const Expr *ex, const VarDecl *vd) {
617239462Sdim  Value v = vals[vd];
618239462Sdim  if (isUninitialized(v))
619249423Sdim    handler.handleUseOfUninitVariable(vd, getUninitUse(ex, vd, v));
620193326Sed}
621198092Srdivacky
622239462Sdimvoid TransferFunctions::VisitObjCForCollectionStmt(ObjCForCollectionStmt *FS) {
623193326Sed  // This represents an initialization of the 'element' value.
624239462Sdim  if (DeclStmt *DS = dyn_cast<DeclStmt>(FS->getElement())) {
625239462Sdim    const VarDecl *VD = cast<VarDecl>(DS->getSingleDecl());
626239462Sdim    if (isTrackedVar(VD))
627239462Sdim      vals[VD] = Initialized;
628193326Sed  }
629221345Sdim}
630198092Srdivacky
631221345Sdimvoid TransferFunctions::VisitBlockExpr(BlockExpr *be) {
632221345Sdim  const BlockDecl *bd = be->getBlockDecl();
633221345Sdim  for (BlockDecl::capture_const_iterator i = bd->capture_begin(),
634221345Sdim        e = bd->capture_end() ; i != e; ++i) {
635221345Sdim    const VarDecl *vd = i->getVariable();
636221345Sdim    if (!isTrackedVar(vd))
637221345Sdim      continue;
638221345Sdim    if (i->isByRef()) {
639221345Sdim      vals[vd] = Initialized;
640221345Sdim      continue;
641221345Sdim    }
642239462Sdim    reportUse(be, vd);
643221345Sdim  }
644193326Sed}
645198092Srdivacky
646239462Sdimvoid TransferFunctions::VisitCallExpr(CallExpr *ce) {
647243830Sdim  if (Decl *Callee = ce->getCalleeDecl()) {
648243830Sdim    if (Callee->hasAttr<ReturnsTwiceAttr>()) {
649243830Sdim      // After a call to a function like setjmp or vfork, any variable which is
650243830Sdim      // initialized anywhere within this function may now be initialized. For
651243830Sdim      // now, just assume such a call initializes all variables.  FIXME: Only
652243830Sdim      // mark variables as initialized if they have an initializer which is
653243830Sdim      // reachable from here.
654243830Sdim      vals.setAllScratchValues(Initialized);
655243830Sdim    }
656243830Sdim    else if (Callee->hasAttr<AnalyzerNoReturnAttr>()) {
657243830Sdim      // Functions labeled like "analyzer_noreturn" are often used to denote
658243830Sdim      // "panic" functions that in special debug situations can still return,
659243830Sdim      // but for the most part should not be treated as returning.  This is a
660243830Sdim      // useful annotation borrowed from the static analyzer that is useful for
661243830Sdim      // suppressing branch-specific false positives when we call one of these
662243830Sdim      // functions but keep pretending the path continues (when in reality the
663243830Sdim      // user doesn't care).
664243830Sdim      vals.setAllScratchValues(Unknown);
665243830Sdim    }
666243830Sdim  }
667226633Sdim}
668226633Sdim
669239462Sdimvoid TransferFunctions::VisitDeclRefExpr(DeclRefExpr *dr) {
670239462Sdim  switch (classification.get(dr)) {
671239462Sdim  case ClassifyRefs::Ignore:
672239462Sdim    break;
673239462Sdim  case ClassifyRefs::Use:
674239462Sdim    reportUse(dr, cast<VarDecl>(dr->getDecl()));
675239462Sdim    break;
676239462Sdim  case ClassifyRefs::Init:
677239462Sdim    vals[cast<VarDecl>(dr->getDecl())] = Initialized;
678239462Sdim    break;
679239462Sdim  case ClassifyRefs::SelfInit:
680249423Sdim      handler.handleSelfInit(cast<VarDecl>(dr->getDecl()));
681239462Sdim    break;
682221345Sdim  }
683221345Sdim}
684193326Sed
685239462Sdimvoid TransferFunctions::VisitBinaryOperator(BinaryOperator *BO) {
686239462Sdim  if (BO->getOpcode() == BO_Assign) {
687239462Sdim    FindVarResult Var = findVar(BO->getLHS());
688239462Sdim    if (const VarDecl *VD = Var.getDecl())
689239462Sdim      vals[VD] = Initialized;
690221345Sdim  }
691221345Sdim}
692198092Srdivacky
693239462Sdimvoid TransferFunctions::VisitDeclStmt(DeclStmt *DS) {
694239462Sdim  for (DeclStmt::decl_iterator DI = DS->decl_begin(), DE = DS->decl_end();
695239462Sdim       DI != DE; ++DI) {
696239462Sdim    VarDecl *VD = dyn_cast<VarDecl>(*DI);
697239462Sdim    if (VD && isTrackedVar(VD)) {
698239462Sdim      if (getSelfInitExpr(VD)) {
699239462Sdim        // If the initializer consists solely of a reference to itself, we
700239462Sdim        // explicitly mark the variable as uninitialized. This allows code
701239462Sdim        // like the following:
702239462Sdim        //
703239462Sdim        //   int x = x;
704239462Sdim        //
705239462Sdim        // to deliberately leave a variable uninitialized. Different analysis
706239462Sdim        // clients can detect this pattern and adjust their reporting
707239462Sdim        // appropriately, but we need to continue to analyze subsequent uses
708239462Sdim        // of the variable.
709239462Sdim        vals[VD] = Uninitialized;
710239462Sdim      } else if (VD->getInit()) {
711239462Sdim        // Treat the new variable as initialized.
712239462Sdim        vals[VD] = Initialized;
713239462Sdim      } else {
714239462Sdim        // No initializer: the variable is now uninitialized. This matters
715239462Sdim        // for cases like:
716239462Sdim        //   while (...) {
717239462Sdim        //     int n;
718239462Sdim        //     use(n);
719239462Sdim        //     n = 0;
720239462Sdim        //   }
721239462Sdim        // FIXME: Mark the variable as uninitialized whenever its scope is
722239462Sdim        // left, since its scope could be re-entered by a jump over the
723239462Sdim        // declaration.
724239462Sdim        vals[VD] = Uninitialized;
725221345Sdim      }
726221345Sdim    }
727221345Sdim  }
728193326Sed}
729198092Srdivacky
730243830Sdimvoid TransferFunctions::VisitObjCMessageExpr(ObjCMessageExpr *ME) {
731243830Sdim  // If the Objective-C message expression is an implicit no-return that
732243830Sdim  // is not modeled in the CFG, set the tracked dataflow values to Unknown.
733243830Sdim  if (objCNoRet.isImplicitNoReturn(ME)) {
734243830Sdim    vals.setAllScratchValues(Unknown);
735243830Sdim  }
736243830Sdim}
737243830Sdim
738221345Sdim//------------------------------------------------------------------------====//
739221345Sdim// High-level "driver" logic for uninitialized values analysis.
740221345Sdim//====------------------------------------------------------------------------//
741193326Sed
742221345Sdimstatic bool runOnBlock(const CFGBlock *block, const CFG &cfg,
743234353Sdim                       AnalysisDeclContext &ac, CFGBlockValues &vals,
744239462Sdim                       const ClassifyRefs &classification,
745221345Sdim                       llvm::BitVector &wasAnalyzed,
746249423Sdim                       UninitVariablesHandler &handler) {
747221345Sdim  wasAnalyzed[block->getBlockID()] = true;
748221345Sdim  vals.resetScratch();
749239462Sdim  // Merge in values of predecessor blocks.
750221345Sdim  bool isFirst = true;
751221345Sdim  for (CFGBlock::const_pred_iterator I = block->pred_begin(),
752221345Sdim       E = block->pred_end(); I != E; ++I) {
753226633Sdim    const CFGBlock *pred = *I;
754226633Sdim    if (wasAnalyzed[pred->getBlockID()]) {
755239462Sdim      vals.mergeIntoScratch(vals.getValueVector(pred), isFirst);
756226633Sdim      isFirst = false;
757226633Sdim    }
758221345Sdim  }
759221345Sdim  // Apply the transfer function.
760239462Sdim  TransferFunctions tf(vals, cfg, block, ac, classification, handler);
761221345Sdim  for (CFGBlock::const_iterator I = block->begin(), E = block->end();
762221345Sdim       I != E; ++I) {
763249423Sdim    if (Optional<CFGStmt> cs = I->getAs<CFGStmt>())
764226633Sdim      tf.Visit(const_cast<Stmt*>(cs->getStmt()));
765221345Sdim  }
766221345Sdim  return vals.updateValueVectorWithScratch(block);
767221345Sdim}
768198092Srdivacky
769249423Sdim/// PruneBlocksHandler is a special UninitVariablesHandler that is used
770249423Sdim/// to detect when a CFGBlock has any *potential* use of an uninitialized
771249423Sdim/// variable.  It is mainly used to prune out work during the final
772249423Sdim/// reporting pass.
773249423Sdimnamespace {
774249423Sdimstruct PruneBlocksHandler : public UninitVariablesHandler {
775249423Sdim  PruneBlocksHandler(unsigned numBlocks)
776249423Sdim    : hadUse(numBlocks, false), hadAnyUse(false),
777249423Sdim      currentBlock(0) {}
778249423Sdim
779249423Sdim  virtual ~PruneBlocksHandler() {}
780249423Sdim
781249423Sdim  /// Records if a CFGBlock had a potential use of an uninitialized variable.
782249423Sdim  llvm::BitVector hadUse;
783249423Sdim
784249423Sdim  /// Records if any CFGBlock had a potential use of an uninitialized variable.
785249423Sdim  bool hadAnyUse;
786249423Sdim
787249423Sdim  /// The current block to scribble use information.
788249423Sdim  unsigned currentBlock;
789249423Sdim
790249423Sdim  virtual void handleUseOfUninitVariable(const VarDecl *vd,
791249423Sdim                                         const UninitUse &use) {
792249423Sdim    hadUse[currentBlock] = true;
793249423Sdim    hadAnyUse = true;
794249423Sdim  }
795249423Sdim
796249423Sdim  /// Called when the uninitialized variable analysis detects the
797249423Sdim  /// idiom 'int x = x'.  All other uses of 'x' within the initializer
798249423Sdim  /// are handled by handleUseOfUninitVariable.
799249423Sdim  virtual void handleSelfInit(const VarDecl *vd) {
800249423Sdim    hadUse[currentBlock] = true;
801249423Sdim    hadAnyUse = true;
802249423Sdim  }
803249423Sdim};
804249423Sdim}
805249423Sdim
806224145Sdimvoid clang::runUninitializedVariablesAnalysis(
807224145Sdim    const DeclContext &dc,
808224145Sdim    const CFG &cfg,
809234353Sdim    AnalysisDeclContext &ac,
810224145Sdim    UninitVariablesHandler &handler,
811224145Sdim    UninitVariablesAnalysisStats &stats) {
812221345Sdim  CFGBlockValues vals(cfg);
813221345Sdim  vals.computeSetOfDeclarations(dc);
814221345Sdim  if (vals.hasNoDeclarations())
815221345Sdim    return;
816198092Srdivacky
817224145Sdim  stats.NumVariablesAnalyzed = vals.getNumEntries();
818224145Sdim
819239462Sdim  // Precompute which expressions are uses and which are initializations.
820239462Sdim  ClassifyRefs classification(ac);
821239462Sdim  cfg.VisitBlockStmts(classification);
822239462Sdim
823221345Sdim  // Mark all variables uninitialized at the entry.
824221345Sdim  const CFGBlock &entry = cfg.getEntry();
825239462Sdim  ValueVector &vec = vals.getValueVector(&entry);
826239462Sdim  const unsigned n = vals.getNumEntries();
827239462Sdim  for (unsigned j = 0; j < n ; ++j) {
828239462Sdim    vec[j] = Uninitialized;
829221345Sdim  }
830193326Sed
831221345Sdim  // Proceed with the workist.
832249423Sdim  DataflowWorklist worklist(cfg, *ac.getAnalysis<PostOrderCFGView>());
833221345Sdim  llvm::BitVector previouslyVisited(cfg.getNumBlockIDs());
834221345Sdim  worklist.enqueueSuccessors(&cfg.getEntry());
835221345Sdim  llvm::BitVector wasAnalyzed(cfg.getNumBlockIDs(), false);
836226633Sdim  wasAnalyzed[cfg.getEntry().getBlockID()] = true;
837249423Sdim  PruneBlocksHandler PBH(cfg.getNumBlockIDs());
838198092Srdivacky
839221345Sdim  while (const CFGBlock *block = worklist.dequeue()) {
840249423Sdim    PBH.currentBlock = block->getBlockID();
841249423Sdim
842221345Sdim    // Did the block change?
843239462Sdim    bool changed = runOnBlock(block, cfg, ac, vals,
844249423Sdim                              classification, wasAnalyzed, PBH);
845224145Sdim    ++stats.NumBlockVisits;
846221345Sdim    if (changed || !previouslyVisited[block->getBlockID()])
847221345Sdim      worklist.enqueueSuccessors(block);
848221345Sdim    previouslyVisited[block->getBlockID()] = true;
849193326Sed  }
850249423Sdim
851249423Sdim  if (!PBH.hadAnyUse)
852249423Sdim    return;
853249423Sdim
854249423Sdim  // Run through the blocks one more time, and report uninitialized variables.
855221345Sdim  for (CFG::const_iterator BI = cfg.begin(), BE = cfg.end(); BI != BE; ++BI) {
856226633Sdim    const CFGBlock *block = *BI;
857249423Sdim    if (PBH.hadUse[block->getBlockID()]) {
858249423Sdim      runOnBlock(block, cfg, ac, vals, classification, wasAnalyzed, handler);
859224145Sdim      ++stats.NumBlockVisits;
860224145Sdim    }
861221345Sdim  }
862221345Sdim}
863193326Sed
864221345SdimUninitVariablesHandler::~UninitVariablesHandler() {}
865