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"
17288943Sdim#include "clang/AST/DeclCXX.h"
18261991Sdim#include "clang/AST/StmtVisitor.h"
19249423Sdim#include "clang/Analysis/Analyses/PostOrderCFGView.h"
20249423Sdim#include "clang/Analysis/Analyses/UninitializedValues.h"
21249423Sdim#include "clang/Analysis/AnalysisContext.h"
22221345Sdim#include "clang/Analysis/CFG.h"
23249423Sdim#include "clang/Analysis/DomainSpecific/ObjCNoReturn.h"
24249423Sdim#include "llvm/ADT/DenseMap.h"
25249423Sdim#include "llvm/ADT/Optional.h"
26249423Sdim#include "llvm/ADT/PackedVector.h"
27249423Sdim#include "llvm/ADT/SmallBitVector.h"
28249423Sdim#include "llvm/ADT/SmallVector.h"
29234353Sdim#include "llvm/Support/SaveAndRestore.h"
30249423Sdim#include <utility>
31193326Sed
32193326Sedusing namespace clang;
33193326Sed
34239462Sdim#define DEBUG_LOGGING 0
35239462Sdim
36221345Sdimstatic bool isTrackedVar(const VarDecl *vd, const DeclContext *dc) {
37221345Sdim  if (vd->isLocalVarDecl() && !vd->hasGlobalStorage() &&
38276479Sdim      !vd->isExceptionVariable() && !vd->isInitCapture() &&
39288943Sdim      !vd->isImplicit() && vd->getDeclContext() == dc) {
40221345Sdim    QualType ty = vd->getType();
41288943Sdim    return ty->isScalarType() || ty->isVectorType() || ty->isRecordType();
42221345Sdim  }
43221345Sdim  return false;
44221345Sdim}
45193326Sed
46221345Sdim//------------------------------------------------------------------------====//
47221345Sdim// DeclToIndex: a mapping from Decls we track to value indices.
48221345Sdim//====------------------------------------------------------------------------//
49221345Sdim
50193326Sednamespace {
51221345Sdimclass DeclToIndex {
52221345Sdim  llvm::DenseMap<const VarDecl *, unsigned> map;
53221345Sdimpublic:
54221345Sdim  DeclToIndex() {}
55221345Sdim
56221345Sdim  /// Compute the actual mapping from declarations to bits.
57221345Sdim  void computeMap(const DeclContext &dc);
58221345Sdim
59221345Sdim  /// Return the number of declarations in the map.
60221345Sdim  unsigned size() const { return map.size(); }
61221345Sdim
62221345Sdim  /// Returns the bit vector index for a given declaration.
63249423Sdim  Optional<unsigned> getValueIndex(const VarDecl *d) const;
64221345Sdim};
65221345Sdim}
66193326Sed
67221345Sdimvoid DeclToIndex::computeMap(const DeclContext &dc) {
68221345Sdim  unsigned count = 0;
69221345Sdim  DeclContext::specific_decl_iterator<VarDecl> I(dc.decls_begin()),
70221345Sdim                                               E(dc.decls_end());
71221345Sdim  for ( ; I != E; ++I) {
72221345Sdim    const VarDecl *vd = *I;
73221345Sdim    if (isTrackedVar(vd, &dc))
74221345Sdim      map[vd] = count++;
75221345Sdim  }
76221345Sdim}
77193326Sed
78249423SdimOptional<unsigned> DeclToIndex::getValueIndex(const VarDecl *d) const {
79221345Sdim  llvm::DenseMap<const VarDecl *, unsigned>::const_iterator I = map.find(d);
80221345Sdim  if (I == map.end())
81249423Sdim    return None;
82221345Sdim  return I->second;
83221345Sdim}
84198092Srdivacky
85221345Sdim//------------------------------------------------------------------------====//
86221345Sdim// CFGBlockValues: dataflow values for CFG blocks.
87221345Sdim//====------------------------------------------------------------------------//
88198092Srdivacky
89221345Sdim// These values are defined in such a way that a merge can be done using
90221345Sdim// a bitwise OR.
91221345Sdimenum Value { Unknown = 0x0,         /* 00 */
92221345Sdim             Initialized = 0x1,     /* 01 */
93221345Sdim             Uninitialized = 0x2,   /* 10 */
94221345Sdim             MayUninitialized = 0x3 /* 11 */ };
95193326Sed
96221345Sdimstatic bool isUninitialized(const Value v) {
97221345Sdim  return v >= Uninitialized;
98193326Sed}
99221345Sdimstatic bool isAlwaysUninit(const Value v) {
100221345Sdim  return v == Uninitialized;
101221345Sdim}
102193326Sed
103193326Sednamespace {
104198092Srdivacky
105243830Sdimtypedef llvm::PackedVector<Value, 2, llvm::SmallBitVector> ValueVector;
106221345Sdim
107221345Sdimclass CFGBlockValues {
108221345Sdim  const CFG &cfg;
109243830Sdim  SmallVector<ValueVector, 8> vals;
110221345Sdim  ValueVector scratch;
111221345Sdim  DeclToIndex declToIndex;
112193326Sedpublic:
113221345Sdim  CFGBlockValues(const CFG &cfg);
114239462Sdim
115221345Sdim  unsigned getNumEntries() const { return declToIndex.size(); }
116221345Sdim
117221345Sdim  void computeSetOfDeclarations(const DeclContext &dc);
118239462Sdim  ValueVector &getValueVector(const CFGBlock *block) {
119243830Sdim    return vals[block->getBlockID()];
120239462Sdim  }
121198092Srdivacky
122239462Sdim  void setAllScratchValues(Value V);
123221345Sdim  void mergeIntoScratch(ValueVector const &source, bool isFirst);
124221345Sdim  bool updateValueVectorWithScratch(const CFGBlock *block);
125221345Sdim
126221345Sdim  bool hasNoDeclarations() const {
127221345Sdim    return declToIndex.size() == 0;
128193326Sed  }
129226633Sdim
130221345Sdim  void resetScratch();
131221345Sdim
132221345Sdim  ValueVector::reference operator[](const VarDecl *vd);
133239462Sdim
134239462Sdim  Value getValue(const CFGBlock *block, const CFGBlock *dstBlock,
135239462Sdim                 const VarDecl *vd) {
136249423Sdim    const Optional<unsigned> &idx = declToIndex.getValueIndex(vd);
137239462Sdim    assert(idx.hasValue());
138239462Sdim    return getValueVector(block)[idx.getValue()];
139239462Sdim  }
140221345Sdim};
141221345Sdim} // end anonymous namespace
142198092Srdivacky
143239462SdimCFGBlockValues::CFGBlockValues(const CFG &c) : cfg(c), vals(0) {}
144198092Srdivacky
145221345Sdimvoid CFGBlockValues::computeSetOfDeclarations(const DeclContext &dc) {
146221345Sdim  declToIndex.computeMap(dc);
147239462Sdim  unsigned decls = declToIndex.size();
148239462Sdim  scratch.resize(decls);
149239462Sdim  unsigned n = cfg.getNumBlockIDs();
150239462Sdim  if (!n)
151239462Sdim    return;
152239462Sdim  vals.resize(n);
153239462Sdim  for (unsigned i = 0; i < n; ++i)
154243830Sdim    vals[i].resize(decls);
155221345Sdim}
156198092Srdivacky
157239462Sdim#if DEBUG_LOGGING
158221345Sdimstatic void printVector(const CFGBlock *block, ValueVector &bv,
159221345Sdim                        unsigned num) {
160221345Sdim  llvm::errs() << block->getBlockID() << " :";
161221345Sdim  for (unsigned i = 0; i < bv.size(); ++i) {
162221345Sdim    llvm::errs() << ' ' << bv[i];
163221345Sdim  }
164221345Sdim  llvm::errs() << " : " << num << '\n';
165221345Sdim}
166239462Sdim#endif
167226633Sdim
168239462Sdimvoid CFGBlockValues::setAllScratchValues(Value V) {
169239462Sdim  for (unsigned I = 0, E = scratch.size(); I != E; ++I)
170239462Sdim    scratch[I] = V;
171226633Sdim}
172198092Srdivacky
173226633Sdimvoid CFGBlockValues::mergeIntoScratch(ValueVector const &source,
174226633Sdim                                      bool isFirst) {
175226633Sdim  if (isFirst)
176226633Sdim    scratch = source;
177226633Sdim  else
178226633Sdim    scratch |= source;
179226633Sdim}
180226633Sdim
181221345Sdimbool CFGBlockValues::updateValueVectorWithScratch(const CFGBlock *block) {
182239462Sdim  ValueVector &dst = getValueVector(block);
183221345Sdim  bool changed = (dst != scratch);
184221345Sdim  if (changed)
185221345Sdim    dst = scratch;
186239462Sdim#if DEBUG_LOGGING
187221345Sdim  printVector(block, scratch, 0);
188221345Sdim#endif
189221345Sdim  return changed;
190221345Sdim}
191193326Sed
192221345Sdimvoid CFGBlockValues::resetScratch() {
193221345Sdim  scratch.reset();
194221345Sdim}
195193326Sed
196221345SdimValueVector::reference CFGBlockValues::operator[](const VarDecl *vd) {
197249423Sdim  const Optional<unsigned> &idx = declToIndex.getValueIndex(vd);
198221345Sdim  assert(idx.hasValue());
199221345Sdim  return scratch[idx.getValue()];
200221345Sdim}
201193326Sed
202221345Sdim//------------------------------------------------------------------------====//
203221345Sdim// Worklist: worklist for dataflow analysis.
204221345Sdim//====------------------------------------------------------------------------//
205221345Sdim
206221345Sdimnamespace {
207221345Sdimclass DataflowWorklist {
208249423Sdim  PostOrderCFGView::iterator PO_I, PO_E;
209226633Sdim  SmallVector<const CFGBlock *, 20> worklist;
210221345Sdim  llvm::BitVector enqueuedBlocks;
211221345Sdimpublic:
212249423Sdim  DataflowWorklist(const CFG &cfg, PostOrderCFGView &view)
213249423Sdim    : PO_I(view.begin()), PO_E(view.end()),
214249423Sdim      enqueuedBlocks(cfg.getNumBlockIDs(), true) {
215249423Sdim        // Treat the first block as already analyzed.
216249423Sdim        if (PO_I != PO_E) {
217249423Sdim          assert(*PO_I == &cfg.getEntry());
218249423Sdim          enqueuedBlocks[(*PO_I)->getBlockID()] = false;
219249423Sdim          ++PO_I;
220249423Sdim        }
221249423Sdim      }
222221345Sdim
223221345Sdim  void enqueueSuccessors(const CFGBlock *block);
224221345Sdim  const CFGBlock *dequeue();
225221345Sdim};
226193326Sed}
227193326Sed
228221345Sdimvoid DataflowWorklist::enqueueSuccessors(const clang::CFGBlock *block) {
229221345Sdim  for (CFGBlock::const_succ_iterator I = block->succ_begin(),
230221345Sdim       E = block->succ_end(); I != E; ++I) {
231224145Sdim    const CFGBlock *Successor = *I;
232224145Sdim    if (!Successor || enqueuedBlocks[Successor->getBlockID()])
233224145Sdim      continue;
234224145Sdim    worklist.push_back(Successor);
235224145Sdim    enqueuedBlocks[Successor->getBlockID()] = true;
236193326Sed  }
237193326Sed}
238198092Srdivacky
239221345Sdimconst CFGBlock *DataflowWorklist::dequeue() {
240276479Sdim  const CFGBlock *B = nullptr;
241249423Sdim
242249423Sdim  // First dequeue from the worklist.  This can represent
243249423Sdim  // updates along backedges that we want propagated as quickly as possible.
244261991Sdim  if (!worklist.empty())
245261991Sdim    B = worklist.pop_back_val();
246261991Sdim
247249423Sdim  // Next dequeue from the initial reverse post order.  This is the
248249423Sdim  // theoretical ideal in the presence of no back edges.
249249423Sdim  else if (PO_I != PO_E) {
250249423Sdim    B = *PO_I;
251249423Sdim    ++PO_I;
252249423Sdim  }
253249423Sdim  else {
254276479Sdim    return nullptr;
255249423Sdim  }
256249423Sdim
257249423Sdim  assert(enqueuedBlocks[B->getBlockID()] == true);
258249423Sdim  enqueuedBlocks[B->getBlockID()] = false;
259249423Sdim  return B;
260193326Sed}
261193326Sed
262221345Sdim//------------------------------------------------------------------------====//
263239462Sdim// Classification of DeclRefExprs as use or initialization.
264221345Sdim//====------------------------------------------------------------------------//
265198092Srdivacky
266221345Sdimnamespace {
267221345Sdimclass FindVarResult {
268221345Sdim  const VarDecl *vd;
269221345Sdim  const DeclRefExpr *dr;
270221345Sdimpublic:
271239462Sdim  FindVarResult(const VarDecl *vd, const DeclRefExpr *dr) : vd(vd), dr(dr) {}
272239462Sdim
273221345Sdim  const DeclRefExpr *getDeclRefExpr() const { return dr; }
274221345Sdim  const VarDecl *getDecl() const { return vd; }
275221345Sdim};
276239462Sdim
277239462Sdimstatic const Expr *stripCasts(ASTContext &C, const Expr *Ex) {
278239462Sdim  while (Ex) {
279239462Sdim    Ex = Ex->IgnoreParenNoopCasts(C);
280239462Sdim    if (const CastExpr *CE = dyn_cast<CastExpr>(Ex)) {
281239462Sdim      if (CE->getCastKind() == CK_LValueBitCast) {
282239462Sdim        Ex = CE->getSubExpr();
283239462Sdim        continue;
284239462Sdim      }
285239462Sdim    }
286239462Sdim    break;
287239462Sdim  }
288239462Sdim  return Ex;
289239462Sdim}
290239462Sdim
291239462Sdim/// If E is an expression comprising a reference to a single variable, find that
292239462Sdim/// variable.
293239462Sdimstatic FindVarResult findVar(const Expr *E, const DeclContext *DC) {
294239462Sdim  if (const DeclRefExpr *DRE =
295239462Sdim        dyn_cast<DeclRefExpr>(stripCasts(DC->getParentASTContext(), E)))
296239462Sdim    if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl()))
297239462Sdim      if (isTrackedVar(VD, DC))
298239462Sdim        return FindVarResult(VD, DRE);
299276479Sdim  return FindVarResult(nullptr, nullptr);
300239462Sdim}
301239462Sdim
302239462Sdim/// \brief Classify each DeclRefExpr as an initialization or a use. Any
303239462Sdim/// DeclRefExpr which isn't explicitly classified will be assumed to have
304239462Sdim/// escaped the analysis and will be treated as an initialization.
305239462Sdimclass ClassifyRefs : public StmtVisitor<ClassifyRefs> {
306239462Sdimpublic:
307239462Sdim  enum Class {
308239462Sdim    Init,
309239462Sdim    Use,
310239462Sdim    SelfInit,
311239462Sdim    Ignore
312239462Sdim  };
313239462Sdim
314239462Sdimprivate:
315239462Sdim  const DeclContext *DC;
316239462Sdim  llvm::DenseMap<const DeclRefExpr*, Class> Classification;
317239462Sdim
318239462Sdim  bool isTrackedVar(const VarDecl *VD) const {
319239462Sdim    return ::isTrackedVar(VD, DC);
320239462Sdim  }
321239462Sdim
322239462Sdim  void classify(const Expr *E, Class C);
323239462Sdim
324239462Sdimpublic:
325239462Sdim  ClassifyRefs(AnalysisDeclContext &AC) : DC(cast<DeclContext>(AC.getDecl())) {}
326239462Sdim
327239462Sdim  void VisitDeclStmt(DeclStmt *DS);
328239462Sdim  void VisitUnaryOperator(UnaryOperator *UO);
329239462Sdim  void VisitBinaryOperator(BinaryOperator *BO);
330239462Sdim  void VisitCallExpr(CallExpr *CE);
331239462Sdim  void VisitCastExpr(CastExpr *CE);
332239462Sdim
333239462Sdim  void operator()(Stmt *S) { Visit(S); }
334239462Sdim
335239462Sdim  Class get(const DeclRefExpr *DRE) const {
336239462Sdim    llvm::DenseMap<const DeclRefExpr*, Class>::const_iterator I
337239462Sdim        = Classification.find(DRE);
338239462Sdim    if (I != Classification.end())
339239462Sdim      return I->second;
340239462Sdim
341239462Sdim    const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl());
342239462Sdim    if (!VD || !isTrackedVar(VD))
343239462Sdim      return Ignore;
344239462Sdim
345239462Sdim    return Init;
346239462Sdim  }
347239462Sdim};
348239462Sdim}
349239462Sdim
350239462Sdimstatic const DeclRefExpr *getSelfInitExpr(VarDecl *VD) {
351288943Sdim  if (VD->getType()->isRecordType()) return nullptr;
352239462Sdim  if (Expr *Init = VD->getInit()) {
353239462Sdim    const DeclRefExpr *DRE
354239462Sdim      = dyn_cast<DeclRefExpr>(stripCasts(VD->getASTContext(), Init));
355239462Sdim    if (DRE && DRE->getDecl() == VD)
356239462Sdim      return DRE;
357239462Sdim  }
358276479Sdim  return nullptr;
359239462Sdim}
360239462Sdim
361239462Sdimvoid ClassifyRefs::classify(const Expr *E, Class C) {
362249423Sdim  // The result of a ?: could also be an lvalue.
363249423Sdim  E = E->IgnoreParens();
364249423Sdim  if (const ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) {
365280031Sdim    classify(CO->getTrueExpr(), C);
366249423Sdim    classify(CO->getFalseExpr(), C);
367249423Sdim    return;
368249423Sdim  }
369249423Sdim
370280031Sdim  if (const BinaryConditionalOperator *BCO =
371280031Sdim          dyn_cast<BinaryConditionalOperator>(E)) {
372280031Sdim    classify(BCO->getFalseExpr(), C);
373280031Sdim    return;
374280031Sdim  }
375280031Sdim
376280031Sdim  if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(E)) {
377280031Sdim    classify(OVE->getSourceExpr(), C);
378280031Sdim    return;
379280031Sdim  }
380280031Sdim
381288943Sdim  if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
382288943Sdim    if (VarDecl *VD = dyn_cast<VarDecl>(ME->getMemberDecl())) {
383288943Sdim      if (!VD->isStaticDataMember())
384288943Sdim        classify(ME->getBase(), C);
385288943Sdim    }
386288943Sdim    return;
387288943Sdim  }
388288943Sdim
389280031Sdim  if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
390288943Sdim    switch (BO->getOpcode()) {
391288943Sdim    case BO_PtrMemD:
392288943Sdim    case BO_PtrMemI:
393288943Sdim      classify(BO->getLHS(), C);
394288943Sdim      return;
395288943Sdim    case BO_Comma:
396280031Sdim      classify(BO->getRHS(), C);
397288943Sdim      return;
398288943Sdim    default:
399288943Sdim      return;
400288943Sdim    }
401280031Sdim  }
402280031Sdim
403239462Sdim  FindVarResult Var = findVar(E, DC);
404239462Sdim  if (const DeclRefExpr *DRE = Var.getDeclRefExpr())
405239462Sdim    Classification[DRE] = std::max(Classification[DRE], C);
406239462Sdim}
407239462Sdim
408239462Sdimvoid ClassifyRefs::VisitDeclStmt(DeclStmt *DS) {
409276479Sdim  for (auto *DI : DS->decls()) {
410276479Sdim    VarDecl *VD = dyn_cast<VarDecl>(DI);
411239462Sdim    if (VD && isTrackedVar(VD))
412239462Sdim      if (const DeclRefExpr *DRE = getSelfInitExpr(VD))
413239462Sdim        Classification[DRE] = SelfInit;
414239462Sdim  }
415239462Sdim}
416239462Sdim
417239462Sdimvoid ClassifyRefs::VisitBinaryOperator(BinaryOperator *BO) {
418239462Sdim  // Ignore the evaluation of a DeclRefExpr on the LHS of an assignment. If this
419239462Sdim  // is not a compound-assignment, we will treat it as initializing the variable
420239462Sdim  // when TransferFunctions visits it. A compound-assignment does not affect
421239462Sdim  // whether a variable is uninitialized, and there's no point counting it as a
422239462Sdim  // use.
423239462Sdim  if (BO->isCompoundAssignmentOp())
424239462Sdim    classify(BO->getLHS(), Use);
425288943Sdim  else if (BO->getOpcode() == BO_Assign || BO->getOpcode() == BO_Comma)
426239462Sdim    classify(BO->getLHS(), Ignore);
427239462Sdim}
428239462Sdim
429239462Sdimvoid ClassifyRefs::VisitUnaryOperator(UnaryOperator *UO) {
430239462Sdim  // Increment and decrement are uses despite there being no lvalue-to-rvalue
431239462Sdim  // conversion.
432239462Sdim  if (UO->isIncrementDecrementOp())
433239462Sdim    classify(UO->getSubExpr(), Use);
434239462Sdim}
435239462Sdim
436288943Sdimstatic bool isPointerToConst(const QualType &QT) {
437288943Sdim  return QT->isAnyPointerType() && QT->getPointeeType().isConstQualified();
438288943Sdim}
439288943Sdim
440239462Sdimvoid ClassifyRefs::VisitCallExpr(CallExpr *CE) {
441280031Sdim  // Classify arguments to std::move as used.
442280031Sdim  if (CE->getNumArgs() == 1) {
443280031Sdim    if (FunctionDecl *FD = CE->getDirectCallee()) {
444280031Sdim      if (FD->isInStdNamespace() && FD->getIdentifier() &&
445280031Sdim          FD->getIdentifier()->isStr("move")) {
446288943Sdim        // RecordTypes are handled in SemaDeclCXX.cpp.
447288943Sdim        if (!CE->getArg(0)->getType()->isRecordType())
448288943Sdim          classify(CE->getArg(0), Use);
449280031Sdim        return;
450280031Sdim      }
451280031Sdim    }
452280031Sdim  }
453280031Sdim
454288943Sdim  // If a value is passed by const pointer or by const reference to a function,
455288943Sdim  // we should not assume that it is initialized by the call, and we
456288943Sdim  // conservatively do not assume that it is used.
457239462Sdim  for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end();
458288943Sdim       I != E; ++I) {
459288943Sdim    if ((*I)->isGLValue()) {
460288943Sdim      if ((*I)->getType().isConstQualified())
461288943Sdim        classify((*I), Ignore);
462288943Sdim    } else if (isPointerToConst((*I)->getType())) {
463288943Sdim      const Expr *Ex = stripCasts(DC->getParentASTContext(), *I);
464288943Sdim      const UnaryOperator *UO = dyn_cast<UnaryOperator>(Ex);
465288943Sdim      if (UO && UO->getOpcode() == UO_AddrOf)
466288943Sdim        Ex = UO->getSubExpr();
467288943Sdim      classify(Ex, Ignore);
468288943Sdim    }
469288943Sdim  }
470239462Sdim}
471239462Sdim
472239462Sdimvoid ClassifyRefs::VisitCastExpr(CastExpr *CE) {
473239462Sdim  if (CE->getCastKind() == CK_LValueToRValue)
474239462Sdim    classify(CE->getSubExpr(), Use);
475239462Sdim  else if (CStyleCastExpr *CSE = dyn_cast<CStyleCastExpr>(CE)) {
476239462Sdim    if (CSE->getType()->isVoidType()) {
477239462Sdim      // Squelch any detected load of an uninitialized value if
478239462Sdim      // we cast it to void.
479239462Sdim      // e.g. (void) x;
480239462Sdim      classify(CSE->getSubExpr(), Ignore);
481239462Sdim    }
482239462Sdim  }
483239462Sdim}
484239462Sdim
485239462Sdim//------------------------------------------------------------------------====//
486239462Sdim// Transfer function for uninitialized values analysis.
487239462Sdim//====------------------------------------------------------------------------//
488239462Sdim
489239462Sdimnamespace {
490226633Sdimclass TransferFunctions : public StmtVisitor<TransferFunctions> {
491221345Sdim  CFGBlockValues &vals;
492221345Sdim  const CFG &cfg;
493239462Sdim  const CFGBlock *block;
494234353Sdim  AnalysisDeclContext &ac;
495239462Sdim  const ClassifyRefs &classification;
496243830Sdim  ObjCNoReturn objCNoRet;
497249423Sdim  UninitVariablesHandler &handler;
498239462Sdim
499221345Sdimpublic:
500221345Sdim  TransferFunctions(CFGBlockValues &vals, const CFG &cfg,
501239462Sdim                    const CFGBlock *block, AnalysisDeclContext &ac,
502239462Sdim                    const ClassifyRefs &classification,
503249423Sdim                    UninitVariablesHandler &handler)
504239462Sdim    : vals(vals), cfg(cfg), block(block), ac(ac),
505243830Sdim      classification(classification), objCNoRet(ac.getASTContext()),
506243830Sdim      handler(handler) {}
507221345Sdim
508239462Sdim  void reportUse(const Expr *ex, const VarDecl *vd);
509239462Sdim
510243830Sdim  void VisitBinaryOperator(BinaryOperator *bo);
511221345Sdim  void VisitBlockExpr(BlockExpr *be);
512239462Sdim  void VisitCallExpr(CallExpr *ce);
513243830Sdim  void VisitDeclRefExpr(DeclRefExpr *dr);
514221345Sdim  void VisitDeclStmt(DeclStmt *ds);
515243830Sdim  void VisitObjCForCollectionStmt(ObjCForCollectionStmt *FS);
516243830Sdim  void VisitObjCMessageExpr(ObjCMessageExpr *ME);
517239462Sdim
518221345Sdim  bool isTrackedVar(const VarDecl *vd) {
519221345Sdim    return ::isTrackedVar(vd, cast<DeclContext>(ac.getDecl()));
520193326Sed  }
521193326Sed
522239462Sdim  FindVarResult findVar(const Expr *ex) {
523239462Sdim    return ::findVar(ex, cast<DeclContext>(ac.getDecl()));
524239462Sdim  }
525239462Sdim
526239462Sdim  UninitUse getUninitUse(const Expr *ex, const VarDecl *vd, Value v) {
527239462Sdim    UninitUse Use(ex, isAlwaysUninit(v));
528239462Sdim
529239462Sdim    assert(isUninitialized(v));
530239462Sdim    if (Use.getKind() == UninitUse::Always)
531239462Sdim      return Use;
532239462Sdim
533239462Sdim    // If an edge which leads unconditionally to this use did not initialize
534239462Sdim    // the variable, we can say something stronger than 'may be uninitialized':
535239462Sdim    // we can say 'either it's used uninitialized or you have dead code'.
536239462Sdim    //
537239462Sdim    // We track the number of successors of a node which have been visited, and
538239462Sdim    // visit a node once we have visited all of its successors. Only edges where
539239462Sdim    // the variable might still be uninitialized are followed. Since a variable
540239462Sdim    // can't transfer from being initialized to being uninitialized, this will
541239462Sdim    // trace out the subgraph which inevitably leads to the use and does not
542239462Sdim    // initialize the variable. We do not want to skip past loops, since their
543239462Sdim    // non-termination might be correlated with the initialization condition.
544239462Sdim    //
545239462Sdim    // For example:
546239462Sdim    //
547239462Sdim    //         void f(bool a, bool b) {
548239462Sdim    // block1:   int n;
549239462Sdim    //           if (a) {
550239462Sdim    // block2:     if (b)
551239462Sdim    // block3:       n = 1;
552239462Sdim    // block4:   } else if (b) {
553239462Sdim    // block5:     while (!a) {
554239462Sdim    // block6:       do_work(&a);
555239462Sdim    //               n = 2;
556239462Sdim    //             }
557239462Sdim    //           }
558239462Sdim    // block7:   if (a)
559239462Sdim    // block8:     g();
560239462Sdim    // block9:   return n;
561239462Sdim    //         }
562239462Sdim    //
563239462Sdim    // Starting from the maybe-uninitialized use in block 9:
564239462Sdim    //  * Block 7 is not visited because we have only visited one of its two
565239462Sdim    //    successors.
566239462Sdim    //  * Block 8 is visited because we've visited its only successor.
567239462Sdim    // From block 8:
568239462Sdim    //  * Block 7 is visited because we've now visited both of its successors.
569239462Sdim    // From block 7:
570239462Sdim    //  * Blocks 1, 2, 4, 5, and 6 are not visited because we didn't visit all
571239462Sdim    //    of their successors (we didn't visit 4, 3, 5, 6, and 5, respectively).
572239462Sdim    //  * Block 3 is not visited because it initializes 'n'.
573239462Sdim    // Now the algorithm terminates, having visited blocks 7 and 8, and having
574239462Sdim    // found the frontier is blocks 2, 4, and 5.
575239462Sdim    //
576239462Sdim    // 'n' is definitely uninitialized for two edges into block 7 (from blocks 2
577239462Sdim    // and 4), so we report that any time either of those edges is taken (in
578239462Sdim    // each case when 'b == false'), 'n' is used uninitialized.
579249423Sdim    SmallVector<const CFGBlock*, 32> Queue;
580249423Sdim    SmallVector<unsigned, 32> SuccsVisited(cfg.getNumBlockIDs(), 0);
581239462Sdim    Queue.push_back(block);
582239462Sdim    // Specify that we've already visited all successors of the starting block.
583239462Sdim    // This has the dual purpose of ensuring we never add it to the queue, and
584239462Sdim    // of marking it as not being a candidate element of the frontier.
585239462Sdim    SuccsVisited[block->getBlockID()] = block->succ_size();
586239462Sdim    while (!Queue.empty()) {
587261991Sdim      const CFGBlock *B = Queue.pop_back_val();
588261991Sdim
589261991Sdim      // If the use is always reached from the entry block, make a note of that.
590261991Sdim      if (B == &cfg.getEntry())
591261991Sdim        Use.setUninitAfterCall();
592261991Sdim
593239462Sdim      for (CFGBlock::const_pred_iterator I = B->pred_begin(), E = B->pred_end();
594239462Sdim           I != E; ++I) {
595239462Sdim        const CFGBlock *Pred = *I;
596276479Sdim        if (!Pred)
597276479Sdim          continue;
598276479Sdim
599261991Sdim        Value AtPredExit = vals.getValue(Pred, B, vd);
600261991Sdim        if (AtPredExit == Initialized)
601239462Sdim          // This block initializes the variable.
602239462Sdim          continue;
603261991Sdim        if (AtPredExit == MayUninitialized &&
604276479Sdim            vals.getValue(B, nullptr, vd) == Uninitialized) {
605261991Sdim          // This block declares the variable (uninitialized), and is reachable
606261991Sdim          // from a block that initializes the variable. We can't guarantee to
607261991Sdim          // give an earlier location for the diagnostic (and it appears that
608261991Sdim          // this code is intended to be reachable) so give a diagnostic here
609261991Sdim          // and go no further down this path.
610261991Sdim          Use.setUninitAfterDecl();
611261991Sdim          continue;
612261991Sdim        }
613239462Sdim
614239462Sdim        unsigned &SV = SuccsVisited[Pred->getBlockID()];
615239462Sdim        if (!SV) {
616239462Sdim          // When visiting the first successor of a block, mark all NULL
617239462Sdim          // successors as having been visited.
618239462Sdim          for (CFGBlock::const_succ_iterator SI = Pred->succ_begin(),
619239462Sdim                                             SE = Pred->succ_end();
620239462Sdim               SI != SE; ++SI)
621239462Sdim            if (!*SI)
622239462Sdim              ++SV;
623239462Sdim        }
624239462Sdim
625239462Sdim        if (++SV == Pred->succ_size())
626239462Sdim          // All paths from this block lead to the use and don't initialize the
627239462Sdim          // variable.
628239462Sdim          Queue.push_back(Pred);
629226633Sdim      }
630226633Sdim    }
631239462Sdim
632239462Sdim    // Scan the frontier, looking for blocks where the variable was
633239462Sdim    // uninitialized.
634239462Sdim    for (CFG::const_iterator BI = cfg.begin(), BE = cfg.end(); BI != BE; ++BI) {
635239462Sdim      const CFGBlock *Block = *BI;
636239462Sdim      unsigned BlockID = Block->getBlockID();
637239462Sdim      const Stmt *Term = Block->getTerminator();
638239462Sdim      if (SuccsVisited[BlockID] && SuccsVisited[BlockID] < Block->succ_size() &&
639239462Sdim          Term) {
640239462Sdim        // This block inevitably leads to the use. If we have an edge from here
641239462Sdim        // to a post-dominator block, and the variable is uninitialized on that
642239462Sdim        // edge, we have found a bug.
643239462Sdim        for (CFGBlock::const_succ_iterator I = Block->succ_begin(),
644239462Sdim             E = Block->succ_end(); I != E; ++I) {
645239462Sdim          const CFGBlock *Succ = *I;
646239462Sdim          if (Succ && SuccsVisited[Succ->getBlockID()] >= Succ->succ_size() &&
647239462Sdim              vals.getValue(Block, Succ, vd) == Uninitialized) {
648239462Sdim            // Switch cases are a special case: report the label to the caller
649239462Sdim            // as the 'terminator', not the switch statement itself. Suppress
650239462Sdim            // situations where no label matched: we can't be sure that's
651239462Sdim            // possible.
652239462Sdim            if (isa<SwitchStmt>(Term)) {
653239462Sdim              const Stmt *Label = Succ->getLabel();
654239462Sdim              if (!Label || !isa<SwitchCase>(Label))
655239462Sdim                // Might not be possible.
656239462Sdim                continue;
657239462Sdim              UninitUse::Branch Branch;
658239462Sdim              Branch.Terminator = Label;
659239462Sdim              Branch.Output = 0; // Ignored.
660239462Sdim              Use.addUninitBranch(Branch);
661239462Sdim            } else {
662239462Sdim              UninitUse::Branch Branch;
663239462Sdim              Branch.Terminator = Term;
664239462Sdim              Branch.Output = I - Block->succ_begin();
665239462Sdim              Use.addUninitBranch(Branch);
666239462Sdim            }
667239462Sdim          }
668239462Sdim        }
669239462Sdim      }
670239462Sdim    }
671239462Sdim
672239462Sdim    return Use;
673226633Sdim  }
674239462Sdim};
675226633Sdim}
676226633Sdim
677239462Sdimvoid TransferFunctions::reportUse(const Expr *ex, const VarDecl *vd) {
678239462Sdim  Value v = vals[vd];
679239462Sdim  if (isUninitialized(v))
680249423Sdim    handler.handleUseOfUninitVariable(vd, getUninitUse(ex, vd, v));
681193326Sed}
682198092Srdivacky
683239462Sdimvoid TransferFunctions::VisitObjCForCollectionStmt(ObjCForCollectionStmt *FS) {
684193326Sed  // This represents an initialization of the 'element' value.
685239462Sdim  if (DeclStmt *DS = dyn_cast<DeclStmt>(FS->getElement())) {
686239462Sdim    const VarDecl *VD = cast<VarDecl>(DS->getSingleDecl());
687239462Sdim    if (isTrackedVar(VD))
688239462Sdim      vals[VD] = Initialized;
689193326Sed  }
690221345Sdim}
691198092Srdivacky
692221345Sdimvoid TransferFunctions::VisitBlockExpr(BlockExpr *be) {
693221345Sdim  const BlockDecl *bd = be->getBlockDecl();
694276479Sdim  for (const auto &I : bd->captures()) {
695276479Sdim    const VarDecl *vd = I.getVariable();
696221345Sdim    if (!isTrackedVar(vd))
697221345Sdim      continue;
698276479Sdim    if (I.isByRef()) {
699221345Sdim      vals[vd] = Initialized;
700221345Sdim      continue;
701221345Sdim    }
702239462Sdim    reportUse(be, vd);
703221345Sdim  }
704193326Sed}
705198092Srdivacky
706239462Sdimvoid TransferFunctions::VisitCallExpr(CallExpr *ce) {
707243830Sdim  if (Decl *Callee = ce->getCalleeDecl()) {
708243830Sdim    if (Callee->hasAttr<ReturnsTwiceAttr>()) {
709243830Sdim      // After a call to a function like setjmp or vfork, any variable which is
710243830Sdim      // initialized anywhere within this function may now be initialized. For
711243830Sdim      // now, just assume such a call initializes all variables.  FIXME: Only
712243830Sdim      // mark variables as initialized if they have an initializer which is
713243830Sdim      // reachable from here.
714243830Sdim      vals.setAllScratchValues(Initialized);
715243830Sdim    }
716243830Sdim    else if (Callee->hasAttr<AnalyzerNoReturnAttr>()) {
717243830Sdim      // Functions labeled like "analyzer_noreturn" are often used to denote
718243830Sdim      // "panic" functions that in special debug situations can still return,
719243830Sdim      // but for the most part should not be treated as returning.  This is a
720243830Sdim      // useful annotation borrowed from the static analyzer that is useful for
721243830Sdim      // suppressing branch-specific false positives when we call one of these
722243830Sdim      // functions but keep pretending the path continues (when in reality the
723243830Sdim      // user doesn't care).
724243830Sdim      vals.setAllScratchValues(Unknown);
725243830Sdim    }
726243830Sdim  }
727226633Sdim}
728226633Sdim
729239462Sdimvoid TransferFunctions::VisitDeclRefExpr(DeclRefExpr *dr) {
730239462Sdim  switch (classification.get(dr)) {
731239462Sdim  case ClassifyRefs::Ignore:
732239462Sdim    break;
733239462Sdim  case ClassifyRefs::Use:
734239462Sdim    reportUse(dr, cast<VarDecl>(dr->getDecl()));
735239462Sdim    break;
736239462Sdim  case ClassifyRefs::Init:
737239462Sdim    vals[cast<VarDecl>(dr->getDecl())] = Initialized;
738239462Sdim    break;
739239462Sdim  case ClassifyRefs::SelfInit:
740249423Sdim      handler.handleSelfInit(cast<VarDecl>(dr->getDecl()));
741239462Sdim    break;
742221345Sdim  }
743221345Sdim}
744193326Sed
745239462Sdimvoid TransferFunctions::VisitBinaryOperator(BinaryOperator *BO) {
746239462Sdim  if (BO->getOpcode() == BO_Assign) {
747239462Sdim    FindVarResult Var = findVar(BO->getLHS());
748239462Sdim    if (const VarDecl *VD = Var.getDecl())
749239462Sdim      vals[VD] = Initialized;
750221345Sdim  }
751221345Sdim}
752198092Srdivacky
753239462Sdimvoid TransferFunctions::VisitDeclStmt(DeclStmt *DS) {
754276479Sdim  for (auto *DI : DS->decls()) {
755276479Sdim    VarDecl *VD = dyn_cast<VarDecl>(DI);
756239462Sdim    if (VD && isTrackedVar(VD)) {
757239462Sdim      if (getSelfInitExpr(VD)) {
758239462Sdim        // If the initializer consists solely of a reference to itself, we
759239462Sdim        // explicitly mark the variable as uninitialized. This allows code
760239462Sdim        // like the following:
761239462Sdim        //
762239462Sdim        //   int x = x;
763239462Sdim        //
764239462Sdim        // to deliberately leave a variable uninitialized. Different analysis
765239462Sdim        // clients can detect this pattern and adjust their reporting
766239462Sdim        // appropriately, but we need to continue to analyze subsequent uses
767239462Sdim        // of the variable.
768239462Sdim        vals[VD] = Uninitialized;
769239462Sdim      } else if (VD->getInit()) {
770239462Sdim        // Treat the new variable as initialized.
771239462Sdim        vals[VD] = Initialized;
772239462Sdim      } else {
773239462Sdim        // No initializer: the variable is now uninitialized. This matters
774239462Sdim        // for cases like:
775239462Sdim        //   while (...) {
776239462Sdim        //     int n;
777239462Sdim        //     use(n);
778239462Sdim        //     n = 0;
779239462Sdim        //   }
780239462Sdim        // FIXME: Mark the variable as uninitialized whenever its scope is
781239462Sdim        // left, since its scope could be re-entered by a jump over the
782239462Sdim        // declaration.
783239462Sdim        vals[VD] = Uninitialized;
784221345Sdim      }
785221345Sdim    }
786221345Sdim  }
787193326Sed}
788198092Srdivacky
789243830Sdimvoid TransferFunctions::VisitObjCMessageExpr(ObjCMessageExpr *ME) {
790243830Sdim  // If the Objective-C message expression is an implicit no-return that
791243830Sdim  // is not modeled in the CFG, set the tracked dataflow values to Unknown.
792243830Sdim  if (objCNoRet.isImplicitNoReturn(ME)) {
793243830Sdim    vals.setAllScratchValues(Unknown);
794243830Sdim  }
795243830Sdim}
796243830Sdim
797221345Sdim//------------------------------------------------------------------------====//
798221345Sdim// High-level "driver" logic for uninitialized values analysis.
799221345Sdim//====------------------------------------------------------------------------//
800193326Sed
801221345Sdimstatic bool runOnBlock(const CFGBlock *block, const CFG &cfg,
802234353Sdim                       AnalysisDeclContext &ac, CFGBlockValues &vals,
803239462Sdim                       const ClassifyRefs &classification,
804221345Sdim                       llvm::BitVector &wasAnalyzed,
805249423Sdim                       UninitVariablesHandler &handler) {
806221345Sdim  wasAnalyzed[block->getBlockID()] = true;
807221345Sdim  vals.resetScratch();
808239462Sdim  // Merge in values of predecessor blocks.
809221345Sdim  bool isFirst = true;
810221345Sdim  for (CFGBlock::const_pred_iterator I = block->pred_begin(),
811221345Sdim       E = block->pred_end(); I != E; ++I) {
812226633Sdim    const CFGBlock *pred = *I;
813276479Sdim    if (!pred)
814276479Sdim      continue;
815226633Sdim    if (wasAnalyzed[pred->getBlockID()]) {
816239462Sdim      vals.mergeIntoScratch(vals.getValueVector(pred), isFirst);
817226633Sdim      isFirst = false;
818226633Sdim    }
819221345Sdim  }
820221345Sdim  // Apply the transfer function.
821239462Sdim  TransferFunctions tf(vals, cfg, block, ac, classification, handler);
822221345Sdim  for (CFGBlock::const_iterator I = block->begin(), E = block->end();
823221345Sdim       I != E; ++I) {
824249423Sdim    if (Optional<CFGStmt> cs = I->getAs<CFGStmt>())
825226633Sdim      tf.Visit(const_cast<Stmt*>(cs->getStmt()));
826221345Sdim  }
827221345Sdim  return vals.updateValueVectorWithScratch(block);
828221345Sdim}
829198092Srdivacky
830249423Sdim/// PruneBlocksHandler is a special UninitVariablesHandler that is used
831249423Sdim/// to detect when a CFGBlock has any *potential* use of an uninitialized
832249423Sdim/// variable.  It is mainly used to prune out work during the final
833249423Sdim/// reporting pass.
834249423Sdimnamespace {
835249423Sdimstruct PruneBlocksHandler : public UninitVariablesHandler {
836249423Sdim  PruneBlocksHandler(unsigned numBlocks)
837249423Sdim    : hadUse(numBlocks, false), hadAnyUse(false),
838249423Sdim      currentBlock(0) {}
839249423Sdim
840288943Sdim  ~PruneBlocksHandler() override {}
841249423Sdim
842249423Sdim  /// Records if a CFGBlock had a potential use of an uninitialized variable.
843249423Sdim  llvm::BitVector hadUse;
844249423Sdim
845249423Sdim  /// Records if any CFGBlock had a potential use of an uninitialized variable.
846249423Sdim  bool hadAnyUse;
847249423Sdim
848249423Sdim  /// The current block to scribble use information.
849249423Sdim  unsigned currentBlock;
850249423Sdim
851276479Sdim  void handleUseOfUninitVariable(const VarDecl *vd,
852276479Sdim                                 const UninitUse &use) override {
853249423Sdim    hadUse[currentBlock] = true;
854249423Sdim    hadAnyUse = true;
855249423Sdim  }
856249423Sdim
857249423Sdim  /// Called when the uninitialized variable analysis detects the
858249423Sdim  /// idiom 'int x = x'.  All other uses of 'x' within the initializer
859249423Sdim  /// are handled by handleUseOfUninitVariable.
860276479Sdim  void handleSelfInit(const VarDecl *vd) override {
861249423Sdim    hadUse[currentBlock] = true;
862249423Sdim    hadAnyUse = true;
863249423Sdim  }
864249423Sdim};
865249423Sdim}
866249423Sdim
867224145Sdimvoid clang::runUninitializedVariablesAnalysis(
868224145Sdim    const DeclContext &dc,
869224145Sdim    const CFG &cfg,
870234353Sdim    AnalysisDeclContext &ac,
871224145Sdim    UninitVariablesHandler &handler,
872224145Sdim    UninitVariablesAnalysisStats &stats) {
873221345Sdim  CFGBlockValues vals(cfg);
874221345Sdim  vals.computeSetOfDeclarations(dc);
875221345Sdim  if (vals.hasNoDeclarations())
876221345Sdim    return;
877198092Srdivacky
878224145Sdim  stats.NumVariablesAnalyzed = vals.getNumEntries();
879224145Sdim
880239462Sdim  // Precompute which expressions are uses and which are initializations.
881239462Sdim  ClassifyRefs classification(ac);
882239462Sdim  cfg.VisitBlockStmts(classification);
883239462Sdim
884221345Sdim  // Mark all variables uninitialized at the entry.
885221345Sdim  const CFGBlock &entry = cfg.getEntry();
886239462Sdim  ValueVector &vec = vals.getValueVector(&entry);
887239462Sdim  const unsigned n = vals.getNumEntries();
888239462Sdim  for (unsigned j = 0; j < n ; ++j) {
889239462Sdim    vec[j] = Uninitialized;
890221345Sdim  }
891193326Sed
892221345Sdim  // Proceed with the workist.
893249423Sdim  DataflowWorklist worklist(cfg, *ac.getAnalysis<PostOrderCFGView>());
894221345Sdim  llvm::BitVector previouslyVisited(cfg.getNumBlockIDs());
895221345Sdim  worklist.enqueueSuccessors(&cfg.getEntry());
896221345Sdim  llvm::BitVector wasAnalyzed(cfg.getNumBlockIDs(), false);
897226633Sdim  wasAnalyzed[cfg.getEntry().getBlockID()] = true;
898249423Sdim  PruneBlocksHandler PBH(cfg.getNumBlockIDs());
899198092Srdivacky
900221345Sdim  while (const CFGBlock *block = worklist.dequeue()) {
901249423Sdim    PBH.currentBlock = block->getBlockID();
902249423Sdim
903221345Sdim    // Did the block change?
904239462Sdim    bool changed = runOnBlock(block, cfg, ac, vals,
905249423Sdim                              classification, wasAnalyzed, PBH);
906224145Sdim    ++stats.NumBlockVisits;
907221345Sdim    if (changed || !previouslyVisited[block->getBlockID()])
908221345Sdim      worklist.enqueueSuccessors(block);
909221345Sdim    previouslyVisited[block->getBlockID()] = true;
910193326Sed  }
911249423Sdim
912249423Sdim  if (!PBH.hadAnyUse)
913249423Sdim    return;
914249423Sdim
915249423Sdim  // Run through the blocks one more time, and report uninitialized variables.
916221345Sdim  for (CFG::const_iterator BI = cfg.begin(), BE = cfg.end(); BI != BE; ++BI) {
917226633Sdim    const CFGBlock *block = *BI;
918249423Sdim    if (PBH.hadUse[block->getBlockID()]) {
919249423Sdim      runOnBlock(block, cfg, ac, vals, classification, wasAnalyzed, handler);
920224145Sdim      ++stats.NumBlockVisits;
921224145Sdim    }
922221345Sdim  }
923221345Sdim}
924193326Sed
925221345SdimUninitVariablesHandler::~UninitVariablesHandler() {}
926