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 ∾
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