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