xref: /minix3/external/bsd/llvm/dist/clang/lib/Analysis/UninitializedValues.cpp (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1f4a2713aSLionel Sambuc //==- UninitializedValues.cpp - Find Uninitialized Values -------*- C++ --*-==//
2f4a2713aSLionel Sambuc //
3f4a2713aSLionel Sambuc //                     The LLVM Compiler Infrastructure
4f4a2713aSLionel Sambuc //
5f4a2713aSLionel Sambuc // This file is distributed under the University of Illinois Open Source
6f4a2713aSLionel Sambuc // License. See LICENSE.TXT for details.
7f4a2713aSLionel Sambuc //
8f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
9f4a2713aSLionel Sambuc //
10f4a2713aSLionel Sambuc // This file implements uninitialized values analysis for source-level CFGs.
11f4a2713aSLionel Sambuc //
12f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
13f4a2713aSLionel Sambuc 
14f4a2713aSLionel Sambuc #include "clang/AST/ASTContext.h"
15f4a2713aSLionel Sambuc #include "clang/AST/Attr.h"
16f4a2713aSLionel Sambuc #include "clang/AST/Decl.h"
17f4a2713aSLionel Sambuc #include "clang/AST/StmtVisitor.h"
18f4a2713aSLionel Sambuc #include "clang/Analysis/Analyses/PostOrderCFGView.h"
19f4a2713aSLionel Sambuc #include "clang/Analysis/Analyses/UninitializedValues.h"
20f4a2713aSLionel Sambuc #include "clang/Analysis/AnalysisContext.h"
21f4a2713aSLionel Sambuc #include "clang/Analysis/CFG.h"
22f4a2713aSLionel Sambuc #include "clang/Analysis/DomainSpecific/ObjCNoReturn.h"
23f4a2713aSLionel Sambuc #include "llvm/ADT/DenseMap.h"
24f4a2713aSLionel Sambuc #include "llvm/ADT/Optional.h"
25f4a2713aSLionel Sambuc #include "llvm/ADT/PackedVector.h"
26f4a2713aSLionel Sambuc #include "llvm/ADT/SmallBitVector.h"
27f4a2713aSLionel Sambuc #include "llvm/ADT/SmallVector.h"
28f4a2713aSLionel Sambuc #include "llvm/Support/SaveAndRestore.h"
29f4a2713aSLionel Sambuc #include <utility>
30f4a2713aSLionel Sambuc 
31f4a2713aSLionel Sambuc using namespace clang;
32f4a2713aSLionel Sambuc 
33f4a2713aSLionel Sambuc #define DEBUG_LOGGING 0
34f4a2713aSLionel Sambuc 
isTrackedVar(const VarDecl * vd,const DeclContext * dc)35f4a2713aSLionel Sambuc static bool isTrackedVar(const VarDecl *vd, const DeclContext *dc) {
36f4a2713aSLionel Sambuc   if (vd->isLocalVarDecl() && !vd->hasGlobalStorage() &&
37*0a6a1f1dSLionel Sambuc       !vd->isExceptionVariable() && !vd->isInitCapture() &&
38f4a2713aSLionel Sambuc       vd->getDeclContext() == dc) {
39f4a2713aSLionel Sambuc     QualType ty = vd->getType();
40f4a2713aSLionel Sambuc     return ty->isScalarType() || ty->isVectorType();
41f4a2713aSLionel Sambuc   }
42f4a2713aSLionel Sambuc   return false;
43f4a2713aSLionel Sambuc }
44f4a2713aSLionel Sambuc 
45f4a2713aSLionel Sambuc //------------------------------------------------------------------------====//
46f4a2713aSLionel Sambuc // DeclToIndex: a mapping from Decls we track to value indices.
47f4a2713aSLionel Sambuc //====------------------------------------------------------------------------//
48f4a2713aSLionel Sambuc 
49f4a2713aSLionel Sambuc namespace {
50f4a2713aSLionel Sambuc class DeclToIndex {
51f4a2713aSLionel Sambuc   llvm::DenseMap<const VarDecl *, unsigned> map;
52f4a2713aSLionel Sambuc public:
DeclToIndex()53f4a2713aSLionel Sambuc   DeclToIndex() {}
54f4a2713aSLionel Sambuc 
55f4a2713aSLionel Sambuc   /// Compute the actual mapping from declarations to bits.
56f4a2713aSLionel Sambuc   void computeMap(const DeclContext &dc);
57f4a2713aSLionel Sambuc 
58f4a2713aSLionel Sambuc   /// Return the number of declarations in the map.
size() const59f4a2713aSLionel Sambuc   unsigned size() const { return map.size(); }
60f4a2713aSLionel Sambuc 
61f4a2713aSLionel Sambuc   /// Returns the bit vector index for a given declaration.
62f4a2713aSLionel Sambuc   Optional<unsigned> getValueIndex(const VarDecl *d) const;
63f4a2713aSLionel Sambuc };
64f4a2713aSLionel Sambuc }
65f4a2713aSLionel Sambuc 
computeMap(const DeclContext & dc)66f4a2713aSLionel Sambuc void DeclToIndex::computeMap(const DeclContext &dc) {
67f4a2713aSLionel Sambuc   unsigned count = 0;
68f4a2713aSLionel Sambuc   DeclContext::specific_decl_iterator<VarDecl> I(dc.decls_begin()),
69f4a2713aSLionel Sambuc                                                E(dc.decls_end());
70f4a2713aSLionel Sambuc   for ( ; I != E; ++I) {
71f4a2713aSLionel Sambuc     const VarDecl *vd = *I;
72f4a2713aSLionel Sambuc     if (isTrackedVar(vd, &dc))
73f4a2713aSLionel Sambuc       map[vd] = count++;
74f4a2713aSLionel Sambuc   }
75f4a2713aSLionel Sambuc }
76f4a2713aSLionel Sambuc 
getValueIndex(const VarDecl * d) const77f4a2713aSLionel Sambuc Optional<unsigned> DeclToIndex::getValueIndex(const VarDecl *d) const {
78f4a2713aSLionel Sambuc   llvm::DenseMap<const VarDecl *, unsigned>::const_iterator I = map.find(d);
79f4a2713aSLionel Sambuc   if (I == map.end())
80f4a2713aSLionel Sambuc     return None;
81f4a2713aSLionel Sambuc   return I->second;
82f4a2713aSLionel Sambuc }
83f4a2713aSLionel Sambuc 
84f4a2713aSLionel Sambuc //------------------------------------------------------------------------====//
85f4a2713aSLionel Sambuc // CFGBlockValues: dataflow values for CFG blocks.
86f4a2713aSLionel Sambuc //====------------------------------------------------------------------------//
87f4a2713aSLionel Sambuc 
88f4a2713aSLionel Sambuc // These values are defined in such a way that a merge can be done using
89f4a2713aSLionel Sambuc // a bitwise OR.
90f4a2713aSLionel Sambuc enum Value { Unknown = 0x0,         /* 00 */
91f4a2713aSLionel Sambuc              Initialized = 0x1,     /* 01 */
92f4a2713aSLionel Sambuc              Uninitialized = 0x2,   /* 10 */
93f4a2713aSLionel Sambuc              MayUninitialized = 0x3 /* 11 */ };
94f4a2713aSLionel Sambuc 
isUninitialized(const Value v)95f4a2713aSLionel Sambuc static bool isUninitialized(const Value v) {
96f4a2713aSLionel Sambuc   return v >= Uninitialized;
97f4a2713aSLionel Sambuc }
isAlwaysUninit(const Value v)98f4a2713aSLionel Sambuc static bool isAlwaysUninit(const Value v) {
99f4a2713aSLionel Sambuc   return v == Uninitialized;
100f4a2713aSLionel Sambuc }
101f4a2713aSLionel Sambuc 
102f4a2713aSLionel Sambuc namespace {
103f4a2713aSLionel Sambuc 
104f4a2713aSLionel Sambuc typedef llvm::PackedVector<Value, 2, llvm::SmallBitVector> ValueVector;
105f4a2713aSLionel Sambuc 
106f4a2713aSLionel Sambuc class CFGBlockValues {
107f4a2713aSLionel Sambuc   const CFG &cfg;
108f4a2713aSLionel Sambuc   SmallVector<ValueVector, 8> vals;
109f4a2713aSLionel Sambuc   ValueVector scratch;
110f4a2713aSLionel Sambuc   DeclToIndex declToIndex;
111f4a2713aSLionel Sambuc public:
112f4a2713aSLionel Sambuc   CFGBlockValues(const CFG &cfg);
113f4a2713aSLionel Sambuc 
getNumEntries() const114f4a2713aSLionel Sambuc   unsigned getNumEntries() const { return declToIndex.size(); }
115f4a2713aSLionel Sambuc 
116f4a2713aSLionel Sambuc   void computeSetOfDeclarations(const DeclContext &dc);
getValueVector(const CFGBlock * block)117f4a2713aSLionel Sambuc   ValueVector &getValueVector(const CFGBlock *block) {
118f4a2713aSLionel Sambuc     return vals[block->getBlockID()];
119f4a2713aSLionel Sambuc   }
120f4a2713aSLionel Sambuc 
121f4a2713aSLionel Sambuc   void setAllScratchValues(Value V);
122f4a2713aSLionel Sambuc   void mergeIntoScratch(ValueVector const &source, bool isFirst);
123f4a2713aSLionel Sambuc   bool updateValueVectorWithScratch(const CFGBlock *block);
124f4a2713aSLionel Sambuc 
hasNoDeclarations() const125f4a2713aSLionel Sambuc   bool hasNoDeclarations() const {
126f4a2713aSLionel Sambuc     return declToIndex.size() == 0;
127f4a2713aSLionel Sambuc   }
128f4a2713aSLionel Sambuc 
129f4a2713aSLionel Sambuc   void resetScratch();
130f4a2713aSLionel Sambuc 
131f4a2713aSLionel Sambuc   ValueVector::reference operator[](const VarDecl *vd);
132f4a2713aSLionel Sambuc 
getValue(const CFGBlock * block,const CFGBlock * dstBlock,const VarDecl * vd)133f4a2713aSLionel Sambuc   Value getValue(const CFGBlock *block, const CFGBlock *dstBlock,
134f4a2713aSLionel Sambuc                  const VarDecl *vd) {
135f4a2713aSLionel Sambuc     const Optional<unsigned> &idx = declToIndex.getValueIndex(vd);
136f4a2713aSLionel Sambuc     assert(idx.hasValue());
137f4a2713aSLionel Sambuc     return getValueVector(block)[idx.getValue()];
138f4a2713aSLionel Sambuc   }
139f4a2713aSLionel Sambuc };
140f4a2713aSLionel Sambuc } // end anonymous namespace
141f4a2713aSLionel Sambuc 
CFGBlockValues(const CFG & c)142f4a2713aSLionel Sambuc CFGBlockValues::CFGBlockValues(const CFG &c) : cfg(c), vals(0) {}
143f4a2713aSLionel Sambuc 
computeSetOfDeclarations(const DeclContext & dc)144f4a2713aSLionel Sambuc void CFGBlockValues::computeSetOfDeclarations(const DeclContext &dc) {
145f4a2713aSLionel Sambuc   declToIndex.computeMap(dc);
146f4a2713aSLionel Sambuc   unsigned decls = declToIndex.size();
147f4a2713aSLionel Sambuc   scratch.resize(decls);
148f4a2713aSLionel Sambuc   unsigned n = cfg.getNumBlockIDs();
149f4a2713aSLionel Sambuc   if (!n)
150f4a2713aSLionel Sambuc     return;
151f4a2713aSLionel Sambuc   vals.resize(n);
152f4a2713aSLionel Sambuc   for (unsigned i = 0; i < n; ++i)
153f4a2713aSLionel Sambuc     vals[i].resize(decls);
154f4a2713aSLionel Sambuc }
155f4a2713aSLionel Sambuc 
156f4a2713aSLionel Sambuc #if DEBUG_LOGGING
printVector(const CFGBlock * block,ValueVector & bv,unsigned num)157f4a2713aSLionel Sambuc static void printVector(const CFGBlock *block, ValueVector &bv,
158f4a2713aSLionel Sambuc                         unsigned num) {
159f4a2713aSLionel Sambuc   llvm::errs() << block->getBlockID() << " :";
160f4a2713aSLionel Sambuc   for (unsigned i = 0; i < bv.size(); ++i) {
161f4a2713aSLionel Sambuc     llvm::errs() << ' ' << bv[i];
162f4a2713aSLionel Sambuc   }
163f4a2713aSLionel Sambuc   llvm::errs() << " : " << num << '\n';
164f4a2713aSLionel Sambuc }
165f4a2713aSLionel Sambuc #endif
166f4a2713aSLionel Sambuc 
setAllScratchValues(Value V)167f4a2713aSLionel Sambuc void CFGBlockValues::setAllScratchValues(Value V) {
168f4a2713aSLionel Sambuc   for (unsigned I = 0, E = scratch.size(); I != E; ++I)
169f4a2713aSLionel Sambuc     scratch[I] = V;
170f4a2713aSLionel Sambuc }
171f4a2713aSLionel Sambuc 
mergeIntoScratch(ValueVector const & source,bool isFirst)172f4a2713aSLionel Sambuc void CFGBlockValues::mergeIntoScratch(ValueVector const &source,
173f4a2713aSLionel Sambuc                                       bool isFirst) {
174f4a2713aSLionel Sambuc   if (isFirst)
175f4a2713aSLionel Sambuc     scratch = source;
176f4a2713aSLionel Sambuc   else
177f4a2713aSLionel Sambuc     scratch |= source;
178f4a2713aSLionel Sambuc }
179f4a2713aSLionel Sambuc 
updateValueVectorWithScratch(const CFGBlock * block)180f4a2713aSLionel Sambuc bool CFGBlockValues::updateValueVectorWithScratch(const CFGBlock *block) {
181f4a2713aSLionel Sambuc   ValueVector &dst = getValueVector(block);
182f4a2713aSLionel Sambuc   bool changed = (dst != scratch);
183f4a2713aSLionel Sambuc   if (changed)
184f4a2713aSLionel Sambuc     dst = scratch;
185f4a2713aSLionel Sambuc #if DEBUG_LOGGING
186f4a2713aSLionel Sambuc   printVector(block, scratch, 0);
187f4a2713aSLionel Sambuc #endif
188f4a2713aSLionel Sambuc   return changed;
189f4a2713aSLionel Sambuc }
190f4a2713aSLionel Sambuc 
resetScratch()191f4a2713aSLionel Sambuc void CFGBlockValues::resetScratch() {
192f4a2713aSLionel Sambuc   scratch.reset();
193f4a2713aSLionel Sambuc }
194f4a2713aSLionel Sambuc 
operator [](const VarDecl * vd)195f4a2713aSLionel Sambuc ValueVector::reference CFGBlockValues::operator[](const VarDecl *vd) {
196f4a2713aSLionel Sambuc   const Optional<unsigned> &idx = declToIndex.getValueIndex(vd);
197f4a2713aSLionel Sambuc   assert(idx.hasValue());
198f4a2713aSLionel Sambuc   return scratch[idx.getValue()];
199f4a2713aSLionel Sambuc }
200f4a2713aSLionel Sambuc 
201f4a2713aSLionel Sambuc //------------------------------------------------------------------------====//
202f4a2713aSLionel Sambuc // Worklist: worklist for dataflow analysis.
203f4a2713aSLionel Sambuc //====------------------------------------------------------------------------//
204f4a2713aSLionel Sambuc 
205f4a2713aSLionel Sambuc namespace {
206f4a2713aSLionel Sambuc class DataflowWorklist {
207f4a2713aSLionel Sambuc   PostOrderCFGView::iterator PO_I, PO_E;
208f4a2713aSLionel Sambuc   SmallVector<const CFGBlock *, 20> worklist;
209f4a2713aSLionel Sambuc   llvm::BitVector enqueuedBlocks;
210f4a2713aSLionel Sambuc public:
DataflowWorklist(const CFG & cfg,PostOrderCFGView & view)211f4a2713aSLionel Sambuc   DataflowWorklist(const CFG &cfg, PostOrderCFGView &view)
212f4a2713aSLionel Sambuc     : PO_I(view.begin()), PO_E(view.end()),
213f4a2713aSLionel Sambuc       enqueuedBlocks(cfg.getNumBlockIDs(), true) {
214f4a2713aSLionel Sambuc         // Treat the first block as already analyzed.
215f4a2713aSLionel Sambuc         if (PO_I != PO_E) {
216f4a2713aSLionel Sambuc           assert(*PO_I == &cfg.getEntry());
217f4a2713aSLionel Sambuc           enqueuedBlocks[(*PO_I)->getBlockID()] = false;
218f4a2713aSLionel Sambuc           ++PO_I;
219f4a2713aSLionel Sambuc         }
220f4a2713aSLionel Sambuc       }
221f4a2713aSLionel Sambuc 
222f4a2713aSLionel Sambuc   void enqueueSuccessors(const CFGBlock *block);
223f4a2713aSLionel Sambuc   const CFGBlock *dequeue();
224f4a2713aSLionel Sambuc };
225f4a2713aSLionel Sambuc }
226f4a2713aSLionel Sambuc 
enqueueSuccessors(const clang::CFGBlock * block)227f4a2713aSLionel Sambuc void DataflowWorklist::enqueueSuccessors(const clang::CFGBlock *block) {
228f4a2713aSLionel Sambuc   for (CFGBlock::const_succ_iterator I = block->succ_begin(),
229f4a2713aSLionel Sambuc        E = block->succ_end(); I != E; ++I) {
230f4a2713aSLionel Sambuc     const CFGBlock *Successor = *I;
231f4a2713aSLionel Sambuc     if (!Successor || enqueuedBlocks[Successor->getBlockID()])
232f4a2713aSLionel Sambuc       continue;
233f4a2713aSLionel Sambuc     worklist.push_back(Successor);
234f4a2713aSLionel Sambuc     enqueuedBlocks[Successor->getBlockID()] = true;
235f4a2713aSLionel Sambuc   }
236f4a2713aSLionel Sambuc }
237f4a2713aSLionel Sambuc 
dequeue()238f4a2713aSLionel Sambuc const CFGBlock *DataflowWorklist::dequeue() {
239*0a6a1f1dSLionel Sambuc   const CFGBlock *B = nullptr;
240f4a2713aSLionel Sambuc 
241f4a2713aSLionel Sambuc   // First dequeue from the worklist.  This can represent
242f4a2713aSLionel Sambuc   // updates along backedges that we want propagated as quickly as possible.
243f4a2713aSLionel Sambuc   if (!worklist.empty())
244f4a2713aSLionel Sambuc     B = worklist.pop_back_val();
245f4a2713aSLionel Sambuc 
246f4a2713aSLionel Sambuc   // Next dequeue from the initial reverse post order.  This is the
247f4a2713aSLionel Sambuc   // theoretical ideal in the presence of no back edges.
248f4a2713aSLionel Sambuc   else if (PO_I != PO_E) {
249f4a2713aSLionel Sambuc     B = *PO_I;
250f4a2713aSLionel Sambuc     ++PO_I;
251f4a2713aSLionel Sambuc   }
252f4a2713aSLionel Sambuc   else {
253*0a6a1f1dSLionel Sambuc     return nullptr;
254f4a2713aSLionel Sambuc   }
255f4a2713aSLionel Sambuc 
256f4a2713aSLionel Sambuc   assert(enqueuedBlocks[B->getBlockID()] == true);
257f4a2713aSLionel Sambuc   enqueuedBlocks[B->getBlockID()] = false;
258f4a2713aSLionel Sambuc   return B;
259f4a2713aSLionel Sambuc }
260f4a2713aSLionel Sambuc 
261f4a2713aSLionel Sambuc //------------------------------------------------------------------------====//
262f4a2713aSLionel Sambuc // Classification of DeclRefExprs as use or initialization.
263f4a2713aSLionel Sambuc //====------------------------------------------------------------------------//
264f4a2713aSLionel Sambuc 
265f4a2713aSLionel Sambuc namespace {
266f4a2713aSLionel Sambuc class FindVarResult {
267f4a2713aSLionel Sambuc   const VarDecl *vd;
268f4a2713aSLionel Sambuc   const DeclRefExpr *dr;
269f4a2713aSLionel Sambuc public:
FindVarResult(const VarDecl * vd,const DeclRefExpr * dr)270f4a2713aSLionel Sambuc   FindVarResult(const VarDecl *vd, const DeclRefExpr *dr) : vd(vd), dr(dr) {}
271f4a2713aSLionel Sambuc 
getDeclRefExpr() const272f4a2713aSLionel Sambuc   const DeclRefExpr *getDeclRefExpr() const { return dr; }
getDecl() const273f4a2713aSLionel Sambuc   const VarDecl *getDecl() const { return vd; }
274f4a2713aSLionel Sambuc };
275f4a2713aSLionel Sambuc 
stripCasts(ASTContext & C,const Expr * Ex)276f4a2713aSLionel Sambuc static const Expr *stripCasts(ASTContext &C, const Expr *Ex) {
277f4a2713aSLionel Sambuc   while (Ex) {
278f4a2713aSLionel Sambuc     Ex = Ex->IgnoreParenNoopCasts(C);
279f4a2713aSLionel Sambuc     if (const CastExpr *CE = dyn_cast<CastExpr>(Ex)) {
280f4a2713aSLionel Sambuc       if (CE->getCastKind() == CK_LValueBitCast) {
281f4a2713aSLionel Sambuc         Ex = CE->getSubExpr();
282f4a2713aSLionel Sambuc         continue;
283f4a2713aSLionel Sambuc       }
284f4a2713aSLionel Sambuc     }
285f4a2713aSLionel Sambuc     break;
286f4a2713aSLionel Sambuc   }
287f4a2713aSLionel Sambuc   return Ex;
288f4a2713aSLionel Sambuc }
289f4a2713aSLionel Sambuc 
290f4a2713aSLionel Sambuc /// If E is an expression comprising a reference to a single variable, find that
291f4a2713aSLionel Sambuc /// variable.
findVar(const Expr * E,const DeclContext * DC)292f4a2713aSLionel Sambuc static FindVarResult findVar(const Expr *E, const DeclContext *DC) {
293f4a2713aSLionel Sambuc   if (const DeclRefExpr *DRE =
294f4a2713aSLionel Sambuc         dyn_cast<DeclRefExpr>(stripCasts(DC->getParentASTContext(), E)))
295f4a2713aSLionel Sambuc     if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl()))
296f4a2713aSLionel Sambuc       if (isTrackedVar(VD, DC))
297f4a2713aSLionel Sambuc         return FindVarResult(VD, DRE);
298*0a6a1f1dSLionel Sambuc   return FindVarResult(nullptr, nullptr);
299f4a2713aSLionel Sambuc }
300f4a2713aSLionel Sambuc 
301f4a2713aSLionel Sambuc /// \brief Classify each DeclRefExpr as an initialization or a use. Any
302f4a2713aSLionel Sambuc /// DeclRefExpr which isn't explicitly classified will be assumed to have
303f4a2713aSLionel Sambuc /// escaped the analysis and will be treated as an initialization.
304f4a2713aSLionel Sambuc class ClassifyRefs : public StmtVisitor<ClassifyRefs> {
305f4a2713aSLionel Sambuc public:
306f4a2713aSLionel Sambuc   enum Class {
307f4a2713aSLionel Sambuc     Init,
308f4a2713aSLionel Sambuc     Use,
309f4a2713aSLionel Sambuc     SelfInit,
310f4a2713aSLionel Sambuc     Ignore
311f4a2713aSLionel Sambuc   };
312f4a2713aSLionel Sambuc 
313f4a2713aSLionel Sambuc private:
314f4a2713aSLionel Sambuc   const DeclContext *DC;
315f4a2713aSLionel Sambuc   llvm::DenseMap<const DeclRefExpr*, Class> Classification;
316f4a2713aSLionel Sambuc 
isTrackedVar(const VarDecl * VD) const317f4a2713aSLionel Sambuc   bool isTrackedVar(const VarDecl *VD) const {
318f4a2713aSLionel Sambuc     return ::isTrackedVar(VD, DC);
319f4a2713aSLionel Sambuc   }
320f4a2713aSLionel Sambuc 
321f4a2713aSLionel Sambuc   void classify(const Expr *E, Class C);
322f4a2713aSLionel Sambuc 
323f4a2713aSLionel Sambuc public:
ClassifyRefs(AnalysisDeclContext & AC)324f4a2713aSLionel Sambuc   ClassifyRefs(AnalysisDeclContext &AC) : DC(cast<DeclContext>(AC.getDecl())) {}
325f4a2713aSLionel Sambuc 
326f4a2713aSLionel Sambuc   void VisitDeclStmt(DeclStmt *DS);
327f4a2713aSLionel Sambuc   void VisitUnaryOperator(UnaryOperator *UO);
328f4a2713aSLionel Sambuc   void VisitBinaryOperator(BinaryOperator *BO);
329f4a2713aSLionel Sambuc   void VisitCallExpr(CallExpr *CE);
330f4a2713aSLionel Sambuc   void VisitCastExpr(CastExpr *CE);
331f4a2713aSLionel Sambuc 
operator ()(Stmt * S)332f4a2713aSLionel Sambuc   void operator()(Stmt *S) { Visit(S); }
333f4a2713aSLionel Sambuc 
get(const DeclRefExpr * DRE) const334f4a2713aSLionel Sambuc   Class get(const DeclRefExpr *DRE) const {
335f4a2713aSLionel Sambuc     llvm::DenseMap<const DeclRefExpr*, Class>::const_iterator I
336f4a2713aSLionel Sambuc         = Classification.find(DRE);
337f4a2713aSLionel Sambuc     if (I != Classification.end())
338f4a2713aSLionel Sambuc       return I->second;
339f4a2713aSLionel Sambuc 
340f4a2713aSLionel Sambuc     const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl());
341f4a2713aSLionel Sambuc     if (!VD || !isTrackedVar(VD))
342f4a2713aSLionel Sambuc       return Ignore;
343f4a2713aSLionel Sambuc 
344f4a2713aSLionel Sambuc     return Init;
345f4a2713aSLionel Sambuc   }
346f4a2713aSLionel Sambuc };
347f4a2713aSLionel Sambuc }
348f4a2713aSLionel Sambuc 
getSelfInitExpr(VarDecl * VD)349f4a2713aSLionel Sambuc static const DeclRefExpr *getSelfInitExpr(VarDecl *VD) {
350f4a2713aSLionel Sambuc   if (Expr *Init = VD->getInit()) {
351f4a2713aSLionel Sambuc     const DeclRefExpr *DRE
352f4a2713aSLionel Sambuc       = dyn_cast<DeclRefExpr>(stripCasts(VD->getASTContext(), Init));
353f4a2713aSLionel Sambuc     if (DRE && DRE->getDecl() == VD)
354f4a2713aSLionel Sambuc       return DRE;
355f4a2713aSLionel Sambuc   }
356*0a6a1f1dSLionel Sambuc   return nullptr;
357f4a2713aSLionel Sambuc }
358f4a2713aSLionel Sambuc 
classify(const Expr * E,Class C)359f4a2713aSLionel Sambuc void ClassifyRefs::classify(const Expr *E, Class C) {
360f4a2713aSLionel Sambuc   // The result of a ?: could also be an lvalue.
361f4a2713aSLionel Sambuc   E = E->IgnoreParens();
362f4a2713aSLionel Sambuc   if (const ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) {
363*0a6a1f1dSLionel Sambuc     classify(CO->getTrueExpr(), C);
364f4a2713aSLionel Sambuc     classify(CO->getFalseExpr(), C);
365f4a2713aSLionel Sambuc     return;
366f4a2713aSLionel Sambuc   }
367f4a2713aSLionel Sambuc 
368*0a6a1f1dSLionel Sambuc   if (const BinaryConditionalOperator *BCO =
369*0a6a1f1dSLionel Sambuc           dyn_cast<BinaryConditionalOperator>(E)) {
370*0a6a1f1dSLionel Sambuc     classify(BCO->getFalseExpr(), C);
371*0a6a1f1dSLionel Sambuc     return;
372*0a6a1f1dSLionel Sambuc   }
373*0a6a1f1dSLionel Sambuc 
374*0a6a1f1dSLionel Sambuc   if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(E)) {
375*0a6a1f1dSLionel Sambuc     classify(OVE->getSourceExpr(), C);
376*0a6a1f1dSLionel Sambuc     return;
377*0a6a1f1dSLionel Sambuc   }
378*0a6a1f1dSLionel Sambuc 
379*0a6a1f1dSLionel Sambuc   if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
380*0a6a1f1dSLionel Sambuc     if (BO->getOpcode() == BO_Comma)
381*0a6a1f1dSLionel Sambuc       classify(BO->getRHS(), C);
382*0a6a1f1dSLionel Sambuc     return;
383*0a6a1f1dSLionel Sambuc   }
384*0a6a1f1dSLionel Sambuc 
385f4a2713aSLionel Sambuc   FindVarResult Var = findVar(E, DC);
386f4a2713aSLionel Sambuc   if (const DeclRefExpr *DRE = Var.getDeclRefExpr())
387f4a2713aSLionel Sambuc     Classification[DRE] = std::max(Classification[DRE], C);
388f4a2713aSLionel Sambuc }
389f4a2713aSLionel Sambuc 
VisitDeclStmt(DeclStmt * DS)390f4a2713aSLionel Sambuc void ClassifyRefs::VisitDeclStmt(DeclStmt *DS) {
391*0a6a1f1dSLionel Sambuc   for (auto *DI : DS->decls()) {
392*0a6a1f1dSLionel Sambuc     VarDecl *VD = dyn_cast<VarDecl>(DI);
393f4a2713aSLionel Sambuc     if (VD && isTrackedVar(VD))
394f4a2713aSLionel Sambuc       if (const DeclRefExpr *DRE = getSelfInitExpr(VD))
395f4a2713aSLionel Sambuc         Classification[DRE] = SelfInit;
396f4a2713aSLionel Sambuc   }
397f4a2713aSLionel Sambuc }
398f4a2713aSLionel Sambuc 
VisitBinaryOperator(BinaryOperator * BO)399f4a2713aSLionel Sambuc void ClassifyRefs::VisitBinaryOperator(BinaryOperator *BO) {
400f4a2713aSLionel Sambuc   // Ignore the evaluation of a DeclRefExpr on the LHS of an assignment. If this
401f4a2713aSLionel Sambuc   // is not a compound-assignment, we will treat it as initializing the variable
402f4a2713aSLionel Sambuc   // when TransferFunctions visits it. A compound-assignment does not affect
403f4a2713aSLionel Sambuc   // whether a variable is uninitialized, and there's no point counting it as a
404f4a2713aSLionel Sambuc   // use.
405f4a2713aSLionel Sambuc   if (BO->isCompoundAssignmentOp())
406f4a2713aSLionel Sambuc     classify(BO->getLHS(), Use);
407f4a2713aSLionel Sambuc   else if (BO->getOpcode() == BO_Assign)
408f4a2713aSLionel Sambuc     classify(BO->getLHS(), Ignore);
409f4a2713aSLionel Sambuc }
410f4a2713aSLionel Sambuc 
VisitUnaryOperator(UnaryOperator * UO)411f4a2713aSLionel Sambuc void ClassifyRefs::VisitUnaryOperator(UnaryOperator *UO) {
412f4a2713aSLionel Sambuc   // Increment and decrement are uses despite there being no lvalue-to-rvalue
413f4a2713aSLionel Sambuc   // conversion.
414f4a2713aSLionel Sambuc   if (UO->isIncrementDecrementOp())
415f4a2713aSLionel Sambuc     classify(UO->getSubExpr(), Use);
416f4a2713aSLionel Sambuc }
417f4a2713aSLionel Sambuc 
VisitCallExpr(CallExpr * CE)418f4a2713aSLionel Sambuc void ClassifyRefs::VisitCallExpr(CallExpr *CE) {
419*0a6a1f1dSLionel Sambuc   // Classify arguments to std::move as used.
420*0a6a1f1dSLionel Sambuc   if (CE->getNumArgs() == 1) {
421*0a6a1f1dSLionel Sambuc     if (FunctionDecl *FD = CE->getDirectCallee()) {
422*0a6a1f1dSLionel Sambuc       if (FD->isInStdNamespace() && FD->getIdentifier() &&
423*0a6a1f1dSLionel Sambuc           FD->getIdentifier()->isStr("move")) {
424*0a6a1f1dSLionel Sambuc         classify(CE->getArg(0), Use);
425*0a6a1f1dSLionel Sambuc         return;
426*0a6a1f1dSLionel Sambuc       }
427*0a6a1f1dSLionel Sambuc     }
428*0a6a1f1dSLionel Sambuc   }
429*0a6a1f1dSLionel Sambuc 
430f4a2713aSLionel Sambuc   // If a value is passed by const reference to a function, we should not assume
431f4a2713aSLionel Sambuc   // that it is initialized by the call, and we conservatively do not assume
432f4a2713aSLionel Sambuc   // that it is used.
433f4a2713aSLionel Sambuc   for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end();
434f4a2713aSLionel Sambuc        I != E; ++I)
435f4a2713aSLionel Sambuc     if ((*I)->getType().isConstQualified() && (*I)->isGLValue())
436f4a2713aSLionel Sambuc       classify(*I, Ignore);
437f4a2713aSLionel Sambuc }
438f4a2713aSLionel Sambuc 
VisitCastExpr(CastExpr * CE)439f4a2713aSLionel Sambuc void ClassifyRefs::VisitCastExpr(CastExpr *CE) {
440f4a2713aSLionel Sambuc   if (CE->getCastKind() == CK_LValueToRValue)
441f4a2713aSLionel Sambuc     classify(CE->getSubExpr(), Use);
442f4a2713aSLionel Sambuc   else if (CStyleCastExpr *CSE = dyn_cast<CStyleCastExpr>(CE)) {
443f4a2713aSLionel Sambuc     if (CSE->getType()->isVoidType()) {
444f4a2713aSLionel Sambuc       // Squelch any detected load of an uninitialized value if
445f4a2713aSLionel Sambuc       // we cast it to void.
446f4a2713aSLionel Sambuc       // e.g. (void) x;
447f4a2713aSLionel Sambuc       classify(CSE->getSubExpr(), Ignore);
448f4a2713aSLionel Sambuc     }
449f4a2713aSLionel Sambuc   }
450f4a2713aSLionel Sambuc }
451f4a2713aSLionel Sambuc 
452f4a2713aSLionel Sambuc //------------------------------------------------------------------------====//
453f4a2713aSLionel Sambuc // Transfer function for uninitialized values analysis.
454f4a2713aSLionel Sambuc //====------------------------------------------------------------------------//
455f4a2713aSLionel Sambuc 
456f4a2713aSLionel Sambuc namespace {
457f4a2713aSLionel Sambuc class TransferFunctions : public StmtVisitor<TransferFunctions> {
458f4a2713aSLionel Sambuc   CFGBlockValues &vals;
459f4a2713aSLionel Sambuc   const CFG &cfg;
460f4a2713aSLionel Sambuc   const CFGBlock *block;
461f4a2713aSLionel Sambuc   AnalysisDeclContext &ac;
462f4a2713aSLionel Sambuc   const ClassifyRefs &classification;
463f4a2713aSLionel Sambuc   ObjCNoReturn objCNoRet;
464f4a2713aSLionel Sambuc   UninitVariablesHandler &handler;
465f4a2713aSLionel Sambuc 
466f4a2713aSLionel Sambuc public:
TransferFunctions(CFGBlockValues & vals,const CFG & cfg,const CFGBlock * block,AnalysisDeclContext & ac,const ClassifyRefs & classification,UninitVariablesHandler & handler)467f4a2713aSLionel Sambuc   TransferFunctions(CFGBlockValues &vals, const CFG &cfg,
468f4a2713aSLionel Sambuc                     const CFGBlock *block, AnalysisDeclContext &ac,
469f4a2713aSLionel Sambuc                     const ClassifyRefs &classification,
470f4a2713aSLionel Sambuc                     UninitVariablesHandler &handler)
471f4a2713aSLionel Sambuc     : vals(vals), cfg(cfg), block(block), ac(ac),
472f4a2713aSLionel Sambuc       classification(classification), objCNoRet(ac.getASTContext()),
473f4a2713aSLionel Sambuc       handler(handler) {}
474f4a2713aSLionel Sambuc 
475f4a2713aSLionel Sambuc   void reportUse(const Expr *ex, const VarDecl *vd);
476f4a2713aSLionel Sambuc 
477f4a2713aSLionel Sambuc   void VisitBinaryOperator(BinaryOperator *bo);
478f4a2713aSLionel Sambuc   void VisitBlockExpr(BlockExpr *be);
479f4a2713aSLionel Sambuc   void VisitCallExpr(CallExpr *ce);
480f4a2713aSLionel Sambuc   void VisitDeclRefExpr(DeclRefExpr *dr);
481f4a2713aSLionel Sambuc   void VisitDeclStmt(DeclStmt *ds);
482f4a2713aSLionel Sambuc   void VisitObjCForCollectionStmt(ObjCForCollectionStmt *FS);
483f4a2713aSLionel Sambuc   void VisitObjCMessageExpr(ObjCMessageExpr *ME);
484f4a2713aSLionel Sambuc 
isTrackedVar(const VarDecl * vd)485f4a2713aSLionel Sambuc   bool isTrackedVar(const VarDecl *vd) {
486f4a2713aSLionel Sambuc     return ::isTrackedVar(vd, cast<DeclContext>(ac.getDecl()));
487f4a2713aSLionel Sambuc   }
488f4a2713aSLionel Sambuc 
findVar(const Expr * ex)489f4a2713aSLionel Sambuc   FindVarResult findVar(const Expr *ex) {
490f4a2713aSLionel Sambuc     return ::findVar(ex, cast<DeclContext>(ac.getDecl()));
491f4a2713aSLionel Sambuc   }
492f4a2713aSLionel Sambuc 
getUninitUse(const Expr * ex,const VarDecl * vd,Value v)493f4a2713aSLionel Sambuc   UninitUse getUninitUse(const Expr *ex, const VarDecl *vd, Value v) {
494f4a2713aSLionel Sambuc     UninitUse Use(ex, isAlwaysUninit(v));
495f4a2713aSLionel Sambuc 
496f4a2713aSLionel Sambuc     assert(isUninitialized(v));
497f4a2713aSLionel Sambuc     if (Use.getKind() == UninitUse::Always)
498f4a2713aSLionel Sambuc       return Use;
499f4a2713aSLionel Sambuc 
500f4a2713aSLionel Sambuc     // If an edge which leads unconditionally to this use did not initialize
501f4a2713aSLionel Sambuc     // the variable, we can say something stronger than 'may be uninitialized':
502f4a2713aSLionel Sambuc     // we can say 'either it's used uninitialized or you have dead code'.
503f4a2713aSLionel Sambuc     //
504f4a2713aSLionel Sambuc     // We track the number of successors of a node which have been visited, and
505f4a2713aSLionel Sambuc     // visit a node once we have visited all of its successors. Only edges where
506f4a2713aSLionel Sambuc     // the variable might still be uninitialized are followed. Since a variable
507f4a2713aSLionel Sambuc     // can't transfer from being initialized to being uninitialized, this will
508f4a2713aSLionel Sambuc     // trace out the subgraph which inevitably leads to the use and does not
509f4a2713aSLionel Sambuc     // initialize the variable. We do not want to skip past loops, since their
510f4a2713aSLionel Sambuc     // non-termination might be correlated with the initialization condition.
511f4a2713aSLionel Sambuc     //
512f4a2713aSLionel Sambuc     // For example:
513f4a2713aSLionel Sambuc     //
514f4a2713aSLionel Sambuc     //         void f(bool a, bool b) {
515f4a2713aSLionel Sambuc     // block1:   int n;
516f4a2713aSLionel Sambuc     //           if (a) {
517f4a2713aSLionel Sambuc     // block2:     if (b)
518f4a2713aSLionel Sambuc     // block3:       n = 1;
519f4a2713aSLionel Sambuc     // block4:   } else if (b) {
520f4a2713aSLionel Sambuc     // block5:     while (!a) {
521f4a2713aSLionel Sambuc     // block6:       do_work(&a);
522f4a2713aSLionel Sambuc     //               n = 2;
523f4a2713aSLionel Sambuc     //             }
524f4a2713aSLionel Sambuc     //           }
525f4a2713aSLionel Sambuc     // block7:   if (a)
526f4a2713aSLionel Sambuc     // block8:     g();
527f4a2713aSLionel Sambuc     // block9:   return n;
528f4a2713aSLionel Sambuc     //         }
529f4a2713aSLionel Sambuc     //
530f4a2713aSLionel Sambuc     // Starting from the maybe-uninitialized use in block 9:
531f4a2713aSLionel Sambuc     //  * Block 7 is not visited because we have only visited one of its two
532f4a2713aSLionel Sambuc     //    successors.
533f4a2713aSLionel Sambuc     //  * Block 8 is visited because we've visited its only successor.
534f4a2713aSLionel Sambuc     // From block 8:
535f4a2713aSLionel Sambuc     //  * Block 7 is visited because we've now visited both of its successors.
536f4a2713aSLionel Sambuc     // From block 7:
537f4a2713aSLionel Sambuc     //  * Blocks 1, 2, 4, 5, and 6 are not visited because we didn't visit all
538f4a2713aSLionel Sambuc     //    of their successors (we didn't visit 4, 3, 5, 6, and 5, respectively).
539f4a2713aSLionel Sambuc     //  * Block 3 is not visited because it initializes 'n'.
540f4a2713aSLionel Sambuc     // Now the algorithm terminates, having visited blocks 7 and 8, and having
541f4a2713aSLionel Sambuc     // found the frontier is blocks 2, 4, and 5.
542f4a2713aSLionel Sambuc     //
543f4a2713aSLionel Sambuc     // 'n' is definitely uninitialized for two edges into block 7 (from blocks 2
544f4a2713aSLionel Sambuc     // and 4), so we report that any time either of those edges is taken (in
545f4a2713aSLionel Sambuc     // each case when 'b == false'), 'n' is used uninitialized.
546f4a2713aSLionel Sambuc     SmallVector<const CFGBlock*, 32> Queue;
547f4a2713aSLionel Sambuc     SmallVector<unsigned, 32> SuccsVisited(cfg.getNumBlockIDs(), 0);
548f4a2713aSLionel Sambuc     Queue.push_back(block);
549f4a2713aSLionel Sambuc     // Specify that we've already visited all successors of the starting block.
550f4a2713aSLionel Sambuc     // This has the dual purpose of ensuring we never add it to the queue, and
551f4a2713aSLionel Sambuc     // of marking it as not being a candidate element of the frontier.
552f4a2713aSLionel Sambuc     SuccsVisited[block->getBlockID()] = block->succ_size();
553f4a2713aSLionel Sambuc     while (!Queue.empty()) {
554f4a2713aSLionel Sambuc       const CFGBlock *B = Queue.pop_back_val();
555f4a2713aSLionel Sambuc 
556f4a2713aSLionel Sambuc       // If the use is always reached from the entry block, make a note of that.
557f4a2713aSLionel Sambuc       if (B == &cfg.getEntry())
558f4a2713aSLionel Sambuc         Use.setUninitAfterCall();
559f4a2713aSLionel Sambuc 
560f4a2713aSLionel Sambuc       for (CFGBlock::const_pred_iterator I = B->pred_begin(), E = B->pred_end();
561f4a2713aSLionel Sambuc            I != E; ++I) {
562f4a2713aSLionel Sambuc         const CFGBlock *Pred = *I;
563*0a6a1f1dSLionel Sambuc         if (!Pred)
564*0a6a1f1dSLionel Sambuc           continue;
565*0a6a1f1dSLionel Sambuc 
566f4a2713aSLionel Sambuc         Value AtPredExit = vals.getValue(Pred, B, vd);
567f4a2713aSLionel Sambuc         if (AtPredExit == Initialized)
568f4a2713aSLionel Sambuc           // This block initializes the variable.
569f4a2713aSLionel Sambuc           continue;
570f4a2713aSLionel Sambuc         if (AtPredExit == MayUninitialized &&
571*0a6a1f1dSLionel Sambuc             vals.getValue(B, nullptr, vd) == Uninitialized) {
572f4a2713aSLionel Sambuc           // This block declares the variable (uninitialized), and is reachable
573f4a2713aSLionel Sambuc           // from a block that initializes the variable. We can't guarantee to
574f4a2713aSLionel Sambuc           // give an earlier location for the diagnostic (and it appears that
575f4a2713aSLionel Sambuc           // this code is intended to be reachable) so give a diagnostic here
576f4a2713aSLionel Sambuc           // and go no further down this path.
577f4a2713aSLionel Sambuc           Use.setUninitAfterDecl();
578f4a2713aSLionel Sambuc           continue;
579f4a2713aSLionel Sambuc         }
580f4a2713aSLionel Sambuc 
581f4a2713aSLionel Sambuc         unsigned &SV = SuccsVisited[Pred->getBlockID()];
582f4a2713aSLionel Sambuc         if (!SV) {
583f4a2713aSLionel Sambuc           // When visiting the first successor of a block, mark all NULL
584f4a2713aSLionel Sambuc           // successors as having been visited.
585f4a2713aSLionel Sambuc           for (CFGBlock::const_succ_iterator SI = Pred->succ_begin(),
586f4a2713aSLionel Sambuc                                              SE = Pred->succ_end();
587f4a2713aSLionel Sambuc                SI != SE; ++SI)
588f4a2713aSLionel Sambuc             if (!*SI)
589f4a2713aSLionel Sambuc               ++SV;
590f4a2713aSLionel Sambuc         }
591f4a2713aSLionel Sambuc 
592f4a2713aSLionel Sambuc         if (++SV == Pred->succ_size())
593f4a2713aSLionel Sambuc           // All paths from this block lead to the use and don't initialize the
594f4a2713aSLionel Sambuc           // variable.
595f4a2713aSLionel Sambuc           Queue.push_back(Pred);
596f4a2713aSLionel Sambuc       }
597f4a2713aSLionel Sambuc     }
598f4a2713aSLionel Sambuc 
599f4a2713aSLionel Sambuc     // Scan the frontier, looking for blocks where the variable was
600f4a2713aSLionel Sambuc     // uninitialized.
601f4a2713aSLionel Sambuc     for (CFG::const_iterator BI = cfg.begin(), BE = cfg.end(); BI != BE; ++BI) {
602f4a2713aSLionel Sambuc       const CFGBlock *Block = *BI;
603f4a2713aSLionel Sambuc       unsigned BlockID = Block->getBlockID();
604f4a2713aSLionel Sambuc       const Stmt *Term = Block->getTerminator();
605f4a2713aSLionel Sambuc       if (SuccsVisited[BlockID] && SuccsVisited[BlockID] < Block->succ_size() &&
606f4a2713aSLionel Sambuc           Term) {
607f4a2713aSLionel Sambuc         // This block inevitably leads to the use. If we have an edge from here
608f4a2713aSLionel Sambuc         // to a post-dominator block, and the variable is uninitialized on that
609f4a2713aSLionel Sambuc         // edge, we have found a bug.
610f4a2713aSLionel Sambuc         for (CFGBlock::const_succ_iterator I = Block->succ_begin(),
611f4a2713aSLionel Sambuc              E = Block->succ_end(); I != E; ++I) {
612f4a2713aSLionel Sambuc           const CFGBlock *Succ = *I;
613f4a2713aSLionel Sambuc           if (Succ && SuccsVisited[Succ->getBlockID()] >= Succ->succ_size() &&
614f4a2713aSLionel Sambuc               vals.getValue(Block, Succ, vd) == Uninitialized) {
615f4a2713aSLionel Sambuc             // Switch cases are a special case: report the label to the caller
616f4a2713aSLionel Sambuc             // as the 'terminator', not the switch statement itself. Suppress
617f4a2713aSLionel Sambuc             // situations where no label matched: we can't be sure that's
618f4a2713aSLionel Sambuc             // possible.
619f4a2713aSLionel Sambuc             if (isa<SwitchStmt>(Term)) {
620f4a2713aSLionel Sambuc               const Stmt *Label = Succ->getLabel();
621f4a2713aSLionel Sambuc               if (!Label || !isa<SwitchCase>(Label))
622f4a2713aSLionel Sambuc                 // Might not be possible.
623f4a2713aSLionel Sambuc                 continue;
624f4a2713aSLionel Sambuc               UninitUse::Branch Branch;
625f4a2713aSLionel Sambuc               Branch.Terminator = Label;
626f4a2713aSLionel Sambuc               Branch.Output = 0; // Ignored.
627f4a2713aSLionel Sambuc               Use.addUninitBranch(Branch);
628f4a2713aSLionel Sambuc             } else {
629f4a2713aSLionel Sambuc               UninitUse::Branch Branch;
630f4a2713aSLionel Sambuc               Branch.Terminator = Term;
631f4a2713aSLionel Sambuc               Branch.Output = I - Block->succ_begin();
632f4a2713aSLionel Sambuc               Use.addUninitBranch(Branch);
633f4a2713aSLionel Sambuc             }
634f4a2713aSLionel Sambuc           }
635f4a2713aSLionel Sambuc         }
636f4a2713aSLionel Sambuc       }
637f4a2713aSLionel Sambuc     }
638f4a2713aSLionel Sambuc 
639f4a2713aSLionel Sambuc     return Use;
640f4a2713aSLionel Sambuc   }
641f4a2713aSLionel Sambuc };
642f4a2713aSLionel Sambuc }
643f4a2713aSLionel Sambuc 
reportUse(const Expr * ex,const VarDecl * vd)644f4a2713aSLionel Sambuc void TransferFunctions::reportUse(const Expr *ex, const VarDecl *vd) {
645f4a2713aSLionel Sambuc   Value v = vals[vd];
646f4a2713aSLionel Sambuc   if (isUninitialized(v))
647f4a2713aSLionel Sambuc     handler.handleUseOfUninitVariable(vd, getUninitUse(ex, vd, v));
648f4a2713aSLionel Sambuc }
649f4a2713aSLionel Sambuc 
VisitObjCForCollectionStmt(ObjCForCollectionStmt * FS)650f4a2713aSLionel Sambuc void TransferFunctions::VisitObjCForCollectionStmt(ObjCForCollectionStmt *FS) {
651f4a2713aSLionel Sambuc   // This represents an initialization of the 'element' value.
652f4a2713aSLionel Sambuc   if (DeclStmt *DS = dyn_cast<DeclStmt>(FS->getElement())) {
653f4a2713aSLionel Sambuc     const VarDecl *VD = cast<VarDecl>(DS->getSingleDecl());
654f4a2713aSLionel Sambuc     if (isTrackedVar(VD))
655f4a2713aSLionel Sambuc       vals[VD] = Initialized;
656f4a2713aSLionel Sambuc   }
657f4a2713aSLionel Sambuc }
658f4a2713aSLionel Sambuc 
VisitBlockExpr(BlockExpr * be)659f4a2713aSLionel Sambuc void TransferFunctions::VisitBlockExpr(BlockExpr *be) {
660f4a2713aSLionel Sambuc   const BlockDecl *bd = be->getBlockDecl();
661*0a6a1f1dSLionel Sambuc   for (const auto &I : bd->captures()) {
662*0a6a1f1dSLionel Sambuc     const VarDecl *vd = I.getVariable();
663f4a2713aSLionel Sambuc     if (!isTrackedVar(vd))
664f4a2713aSLionel Sambuc       continue;
665*0a6a1f1dSLionel Sambuc     if (I.isByRef()) {
666f4a2713aSLionel Sambuc       vals[vd] = Initialized;
667f4a2713aSLionel Sambuc       continue;
668f4a2713aSLionel Sambuc     }
669f4a2713aSLionel Sambuc     reportUse(be, vd);
670f4a2713aSLionel Sambuc   }
671f4a2713aSLionel Sambuc }
672f4a2713aSLionel Sambuc 
VisitCallExpr(CallExpr * ce)673f4a2713aSLionel Sambuc void TransferFunctions::VisitCallExpr(CallExpr *ce) {
674f4a2713aSLionel Sambuc   if (Decl *Callee = ce->getCalleeDecl()) {
675f4a2713aSLionel Sambuc     if (Callee->hasAttr<ReturnsTwiceAttr>()) {
676f4a2713aSLionel Sambuc       // After a call to a function like setjmp or vfork, any variable which is
677f4a2713aSLionel Sambuc       // initialized anywhere within this function may now be initialized. For
678f4a2713aSLionel Sambuc       // now, just assume such a call initializes all variables.  FIXME: Only
679f4a2713aSLionel Sambuc       // mark variables as initialized if they have an initializer which is
680f4a2713aSLionel Sambuc       // reachable from here.
681f4a2713aSLionel Sambuc       vals.setAllScratchValues(Initialized);
682f4a2713aSLionel Sambuc     }
683f4a2713aSLionel Sambuc     else if (Callee->hasAttr<AnalyzerNoReturnAttr>()) {
684f4a2713aSLionel Sambuc       // Functions labeled like "analyzer_noreturn" are often used to denote
685f4a2713aSLionel Sambuc       // "panic" functions that in special debug situations can still return,
686f4a2713aSLionel Sambuc       // but for the most part should not be treated as returning.  This is a
687f4a2713aSLionel Sambuc       // useful annotation borrowed from the static analyzer that is useful for
688f4a2713aSLionel Sambuc       // suppressing branch-specific false positives when we call one of these
689f4a2713aSLionel Sambuc       // functions but keep pretending the path continues (when in reality the
690f4a2713aSLionel Sambuc       // user doesn't care).
691f4a2713aSLionel Sambuc       vals.setAllScratchValues(Unknown);
692f4a2713aSLionel Sambuc     }
693f4a2713aSLionel Sambuc   }
694f4a2713aSLionel Sambuc }
695f4a2713aSLionel Sambuc 
VisitDeclRefExpr(DeclRefExpr * dr)696f4a2713aSLionel Sambuc void TransferFunctions::VisitDeclRefExpr(DeclRefExpr *dr) {
697f4a2713aSLionel Sambuc   switch (classification.get(dr)) {
698f4a2713aSLionel Sambuc   case ClassifyRefs::Ignore:
699f4a2713aSLionel Sambuc     break;
700f4a2713aSLionel Sambuc   case ClassifyRefs::Use:
701f4a2713aSLionel Sambuc     reportUse(dr, cast<VarDecl>(dr->getDecl()));
702f4a2713aSLionel Sambuc     break;
703f4a2713aSLionel Sambuc   case ClassifyRefs::Init:
704f4a2713aSLionel Sambuc     vals[cast<VarDecl>(dr->getDecl())] = Initialized;
705f4a2713aSLionel Sambuc     break;
706f4a2713aSLionel Sambuc   case ClassifyRefs::SelfInit:
707f4a2713aSLionel Sambuc       handler.handleSelfInit(cast<VarDecl>(dr->getDecl()));
708f4a2713aSLionel Sambuc     break;
709f4a2713aSLionel Sambuc   }
710f4a2713aSLionel Sambuc }
711f4a2713aSLionel Sambuc 
VisitBinaryOperator(BinaryOperator * BO)712f4a2713aSLionel Sambuc void TransferFunctions::VisitBinaryOperator(BinaryOperator *BO) {
713f4a2713aSLionel Sambuc   if (BO->getOpcode() == BO_Assign) {
714f4a2713aSLionel Sambuc     FindVarResult Var = findVar(BO->getLHS());
715f4a2713aSLionel Sambuc     if (const VarDecl *VD = Var.getDecl())
716f4a2713aSLionel Sambuc       vals[VD] = Initialized;
717f4a2713aSLionel Sambuc   }
718f4a2713aSLionel Sambuc }
719f4a2713aSLionel Sambuc 
VisitDeclStmt(DeclStmt * DS)720f4a2713aSLionel Sambuc void TransferFunctions::VisitDeclStmt(DeclStmt *DS) {
721*0a6a1f1dSLionel Sambuc   for (auto *DI : DS->decls()) {
722*0a6a1f1dSLionel Sambuc     VarDecl *VD = dyn_cast<VarDecl>(DI);
723f4a2713aSLionel Sambuc     if (VD && isTrackedVar(VD)) {
724f4a2713aSLionel Sambuc       if (getSelfInitExpr(VD)) {
725f4a2713aSLionel Sambuc         // If the initializer consists solely of a reference to itself, we
726f4a2713aSLionel Sambuc         // explicitly mark the variable as uninitialized. This allows code
727f4a2713aSLionel Sambuc         // like the following:
728f4a2713aSLionel Sambuc         //
729f4a2713aSLionel Sambuc         //   int x = x;
730f4a2713aSLionel Sambuc         //
731f4a2713aSLionel Sambuc         // to deliberately leave a variable uninitialized. Different analysis
732f4a2713aSLionel Sambuc         // clients can detect this pattern and adjust their reporting
733f4a2713aSLionel Sambuc         // appropriately, but we need to continue to analyze subsequent uses
734f4a2713aSLionel Sambuc         // of the variable.
735f4a2713aSLionel Sambuc         vals[VD] = Uninitialized;
736f4a2713aSLionel Sambuc       } else if (VD->getInit()) {
737f4a2713aSLionel Sambuc         // Treat the new variable as initialized.
738f4a2713aSLionel Sambuc         vals[VD] = Initialized;
739f4a2713aSLionel Sambuc       } else {
740f4a2713aSLionel Sambuc         // No initializer: the variable is now uninitialized. This matters
741f4a2713aSLionel Sambuc         // for cases like:
742f4a2713aSLionel Sambuc         //   while (...) {
743f4a2713aSLionel Sambuc         //     int n;
744f4a2713aSLionel Sambuc         //     use(n);
745f4a2713aSLionel Sambuc         //     n = 0;
746f4a2713aSLionel Sambuc         //   }
747f4a2713aSLionel Sambuc         // FIXME: Mark the variable as uninitialized whenever its scope is
748f4a2713aSLionel Sambuc         // left, since its scope could be re-entered by a jump over the
749f4a2713aSLionel Sambuc         // declaration.
750f4a2713aSLionel Sambuc         vals[VD] = Uninitialized;
751f4a2713aSLionel Sambuc       }
752f4a2713aSLionel Sambuc     }
753f4a2713aSLionel Sambuc   }
754f4a2713aSLionel Sambuc }
755f4a2713aSLionel Sambuc 
VisitObjCMessageExpr(ObjCMessageExpr * ME)756f4a2713aSLionel Sambuc void TransferFunctions::VisitObjCMessageExpr(ObjCMessageExpr *ME) {
757f4a2713aSLionel Sambuc   // If the Objective-C message expression is an implicit no-return that
758f4a2713aSLionel Sambuc   // is not modeled in the CFG, set the tracked dataflow values to Unknown.
759f4a2713aSLionel Sambuc   if (objCNoRet.isImplicitNoReturn(ME)) {
760f4a2713aSLionel Sambuc     vals.setAllScratchValues(Unknown);
761f4a2713aSLionel Sambuc   }
762f4a2713aSLionel Sambuc }
763f4a2713aSLionel Sambuc 
764f4a2713aSLionel Sambuc //------------------------------------------------------------------------====//
765f4a2713aSLionel Sambuc // High-level "driver" logic for uninitialized values analysis.
766f4a2713aSLionel Sambuc //====------------------------------------------------------------------------//
767f4a2713aSLionel Sambuc 
runOnBlock(const CFGBlock * block,const CFG & cfg,AnalysisDeclContext & ac,CFGBlockValues & vals,const ClassifyRefs & classification,llvm::BitVector & wasAnalyzed,UninitVariablesHandler & handler)768f4a2713aSLionel Sambuc static bool runOnBlock(const CFGBlock *block, const CFG &cfg,
769f4a2713aSLionel Sambuc                        AnalysisDeclContext &ac, CFGBlockValues &vals,
770f4a2713aSLionel Sambuc                        const ClassifyRefs &classification,
771f4a2713aSLionel Sambuc                        llvm::BitVector &wasAnalyzed,
772f4a2713aSLionel Sambuc                        UninitVariablesHandler &handler) {
773f4a2713aSLionel Sambuc   wasAnalyzed[block->getBlockID()] = true;
774f4a2713aSLionel Sambuc   vals.resetScratch();
775f4a2713aSLionel Sambuc   // Merge in values of predecessor blocks.
776f4a2713aSLionel Sambuc   bool isFirst = true;
777f4a2713aSLionel Sambuc   for (CFGBlock::const_pred_iterator I = block->pred_begin(),
778f4a2713aSLionel Sambuc        E = block->pred_end(); I != E; ++I) {
779f4a2713aSLionel Sambuc     const CFGBlock *pred = *I;
780*0a6a1f1dSLionel Sambuc     if (!pred)
781*0a6a1f1dSLionel Sambuc       continue;
782f4a2713aSLionel Sambuc     if (wasAnalyzed[pred->getBlockID()]) {
783f4a2713aSLionel Sambuc       vals.mergeIntoScratch(vals.getValueVector(pred), isFirst);
784f4a2713aSLionel Sambuc       isFirst = false;
785f4a2713aSLionel Sambuc     }
786f4a2713aSLionel Sambuc   }
787f4a2713aSLionel Sambuc   // Apply the transfer function.
788f4a2713aSLionel Sambuc   TransferFunctions tf(vals, cfg, block, ac, classification, handler);
789f4a2713aSLionel Sambuc   for (CFGBlock::const_iterator I = block->begin(), E = block->end();
790f4a2713aSLionel Sambuc        I != E; ++I) {
791f4a2713aSLionel Sambuc     if (Optional<CFGStmt> cs = I->getAs<CFGStmt>())
792f4a2713aSLionel Sambuc       tf.Visit(const_cast<Stmt*>(cs->getStmt()));
793f4a2713aSLionel Sambuc   }
794f4a2713aSLionel Sambuc   return vals.updateValueVectorWithScratch(block);
795f4a2713aSLionel Sambuc }
796f4a2713aSLionel Sambuc 
797f4a2713aSLionel Sambuc /// PruneBlocksHandler is a special UninitVariablesHandler that is used
798f4a2713aSLionel Sambuc /// to detect when a CFGBlock has any *potential* use of an uninitialized
799f4a2713aSLionel Sambuc /// variable.  It is mainly used to prune out work during the final
800f4a2713aSLionel Sambuc /// reporting pass.
801f4a2713aSLionel Sambuc namespace {
802f4a2713aSLionel Sambuc struct PruneBlocksHandler : public UninitVariablesHandler {
PruneBlocksHandler__anonee8ffdc90611::PruneBlocksHandler803f4a2713aSLionel Sambuc   PruneBlocksHandler(unsigned numBlocks)
804f4a2713aSLionel Sambuc     : hadUse(numBlocks, false), hadAnyUse(false),
805f4a2713aSLionel Sambuc       currentBlock(0) {}
806f4a2713aSLionel Sambuc 
~PruneBlocksHandler__anonee8ffdc90611::PruneBlocksHandler807f4a2713aSLionel Sambuc   virtual ~PruneBlocksHandler() {}
808f4a2713aSLionel Sambuc 
809f4a2713aSLionel Sambuc   /// Records if a CFGBlock had a potential use of an uninitialized variable.
810f4a2713aSLionel Sambuc   llvm::BitVector hadUse;
811f4a2713aSLionel Sambuc 
812f4a2713aSLionel Sambuc   /// Records if any CFGBlock had a potential use of an uninitialized variable.
813f4a2713aSLionel Sambuc   bool hadAnyUse;
814f4a2713aSLionel Sambuc 
815f4a2713aSLionel Sambuc   /// The current block to scribble use information.
816f4a2713aSLionel Sambuc   unsigned currentBlock;
817f4a2713aSLionel Sambuc 
handleUseOfUninitVariable__anonee8ffdc90611::PruneBlocksHandler818*0a6a1f1dSLionel Sambuc   void handleUseOfUninitVariable(const VarDecl *vd,
819*0a6a1f1dSLionel Sambuc                                  const UninitUse &use) override {
820f4a2713aSLionel Sambuc     hadUse[currentBlock] = true;
821f4a2713aSLionel Sambuc     hadAnyUse = true;
822f4a2713aSLionel Sambuc   }
823f4a2713aSLionel Sambuc 
824f4a2713aSLionel Sambuc   /// Called when the uninitialized variable analysis detects the
825f4a2713aSLionel Sambuc   /// idiom 'int x = x'.  All other uses of 'x' within the initializer
826f4a2713aSLionel Sambuc   /// are handled by handleUseOfUninitVariable.
handleSelfInit__anonee8ffdc90611::PruneBlocksHandler827*0a6a1f1dSLionel Sambuc   void handleSelfInit(const VarDecl *vd) override {
828f4a2713aSLionel Sambuc     hadUse[currentBlock] = true;
829f4a2713aSLionel Sambuc     hadAnyUse = true;
830f4a2713aSLionel Sambuc   }
831f4a2713aSLionel Sambuc };
832f4a2713aSLionel Sambuc }
833f4a2713aSLionel Sambuc 
runUninitializedVariablesAnalysis(const DeclContext & dc,const CFG & cfg,AnalysisDeclContext & ac,UninitVariablesHandler & handler,UninitVariablesAnalysisStats & stats)834f4a2713aSLionel Sambuc void clang::runUninitializedVariablesAnalysis(
835f4a2713aSLionel Sambuc     const DeclContext &dc,
836f4a2713aSLionel Sambuc     const CFG &cfg,
837f4a2713aSLionel Sambuc     AnalysisDeclContext &ac,
838f4a2713aSLionel Sambuc     UninitVariablesHandler &handler,
839f4a2713aSLionel Sambuc     UninitVariablesAnalysisStats &stats) {
840f4a2713aSLionel Sambuc   CFGBlockValues vals(cfg);
841f4a2713aSLionel Sambuc   vals.computeSetOfDeclarations(dc);
842f4a2713aSLionel Sambuc   if (vals.hasNoDeclarations())
843f4a2713aSLionel Sambuc     return;
844f4a2713aSLionel Sambuc 
845f4a2713aSLionel Sambuc   stats.NumVariablesAnalyzed = vals.getNumEntries();
846f4a2713aSLionel Sambuc 
847f4a2713aSLionel Sambuc   // Precompute which expressions are uses and which are initializations.
848f4a2713aSLionel Sambuc   ClassifyRefs classification(ac);
849f4a2713aSLionel Sambuc   cfg.VisitBlockStmts(classification);
850f4a2713aSLionel Sambuc 
851f4a2713aSLionel Sambuc   // Mark all variables uninitialized at the entry.
852f4a2713aSLionel Sambuc   const CFGBlock &entry = cfg.getEntry();
853f4a2713aSLionel Sambuc   ValueVector &vec = vals.getValueVector(&entry);
854f4a2713aSLionel Sambuc   const unsigned n = vals.getNumEntries();
855f4a2713aSLionel Sambuc   for (unsigned j = 0; j < n ; ++j) {
856f4a2713aSLionel Sambuc     vec[j] = Uninitialized;
857f4a2713aSLionel Sambuc   }
858f4a2713aSLionel Sambuc 
859f4a2713aSLionel Sambuc   // Proceed with the workist.
860f4a2713aSLionel Sambuc   DataflowWorklist worklist(cfg, *ac.getAnalysis<PostOrderCFGView>());
861f4a2713aSLionel Sambuc   llvm::BitVector previouslyVisited(cfg.getNumBlockIDs());
862f4a2713aSLionel Sambuc   worklist.enqueueSuccessors(&cfg.getEntry());
863f4a2713aSLionel Sambuc   llvm::BitVector wasAnalyzed(cfg.getNumBlockIDs(), false);
864f4a2713aSLionel Sambuc   wasAnalyzed[cfg.getEntry().getBlockID()] = true;
865f4a2713aSLionel Sambuc   PruneBlocksHandler PBH(cfg.getNumBlockIDs());
866f4a2713aSLionel Sambuc 
867f4a2713aSLionel Sambuc   while (const CFGBlock *block = worklist.dequeue()) {
868f4a2713aSLionel Sambuc     PBH.currentBlock = block->getBlockID();
869f4a2713aSLionel Sambuc 
870f4a2713aSLionel Sambuc     // Did the block change?
871f4a2713aSLionel Sambuc     bool changed = runOnBlock(block, cfg, ac, vals,
872f4a2713aSLionel Sambuc                               classification, wasAnalyzed, PBH);
873f4a2713aSLionel Sambuc     ++stats.NumBlockVisits;
874f4a2713aSLionel Sambuc     if (changed || !previouslyVisited[block->getBlockID()])
875f4a2713aSLionel Sambuc       worklist.enqueueSuccessors(block);
876f4a2713aSLionel Sambuc     previouslyVisited[block->getBlockID()] = true;
877f4a2713aSLionel Sambuc   }
878f4a2713aSLionel Sambuc 
879f4a2713aSLionel Sambuc   if (!PBH.hadAnyUse)
880f4a2713aSLionel Sambuc     return;
881f4a2713aSLionel Sambuc 
882f4a2713aSLionel Sambuc   // Run through the blocks one more time, and report uninitialized variables.
883f4a2713aSLionel Sambuc   for (CFG::const_iterator BI = cfg.begin(), BE = cfg.end(); BI != BE; ++BI) {
884f4a2713aSLionel Sambuc     const CFGBlock *block = *BI;
885f4a2713aSLionel Sambuc     if (PBH.hadUse[block->getBlockID()]) {
886f4a2713aSLionel Sambuc       runOnBlock(block, cfg, ac, vals, classification, wasAnalyzed, handler);
887f4a2713aSLionel Sambuc       ++stats.NumBlockVisits;
888f4a2713aSLionel Sambuc     }
889f4a2713aSLionel Sambuc   }
890f4a2713aSLionel Sambuc }
891f4a2713aSLionel Sambuc 
~UninitVariablesHandler()892f4a2713aSLionel Sambuc UninitVariablesHandler::~UninitVariablesHandler() {}
893