From: Ted Kremenek Date: Mon, 17 Sep 2007 18:31:23 +0000 (+0000) Subject: Split tracking of unitialized values for Decls and CFGBlock-level expressions. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=20ee4fbee7db6b551de7d509801bbe25367aacf2;p=clang Split tracking of unitialized values for Decls and CFGBlock-level expressions. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@42041 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/Analysis/UnintializedValues.cpp b/Analysis/UnintializedValues.cpp index dd741c1af3..c9c02d0afd 100644 --- a/Analysis/UnintializedValues.cpp +++ b/Analysis/UnintializedValues.cpp @@ -33,12 +33,12 @@ public: void VisitVarDecl(VarDecl* D) { if (AD.VMap.find(D) == AD.VMap.end()) - AD.VMap[D] = AD.Counter++; + AD.VMap[D] = AD.NumDecls++; } void BlockStmt_VisitExpr(Expr* E) { if (AD.EMap.find(E) == AD.EMap.end()) - AD.EMap[E] = AD.Counter++; + AD.EMap[E] = AD.NumBlockExprs++; } }; @@ -47,7 +47,9 @@ public: void UninitializedValues::InitializeValues(const CFG& cfg) { RegisterDeclsAndExprs R(cfg,this->getAnalysisData()); R.VisitAllDecls(); - getBlockDataMap()[ &cfg.getEntry() ].resize( getAnalysisData().Counter ); + UninitializedValues::ValTy& V = getBlockDataMap()[&cfg.getEntry()]; + V.DeclBV.resize(getAnalysisData().NumDecls); + V.ExprBV.resize(getAnalysisData().NumBlockExprs); } //===--------------------------------------------------------------------===// @@ -55,43 +57,139 @@ void UninitializedValues::InitializeValues(const CFG& cfg) { //===--------------------------------------------------------------------===// namespace { + class TransferFuncs : public CFGStmtVisitor { UninitializedValues::ValTy V; UninitializedValues::AnalysisDataTy& AD; public: TransferFuncs(UninitializedValues::AnalysisDataTy& ad) : AD(ad) { - V.resize(AD.Counter); + V.DeclBV.resize(AD.NumDecls); + V.ExprBV.resize(AD.NumBlockExprs); } UninitializedValues::ValTy& getVal() { return V; } -// bool VisitDeclRefExpr(DeclRefExpr* DR); -// bool VisitBinaryOperator(BinaryOperator* B); -// bool VisitUnaryOperator(UnaryOperator* U); + bool VisitDeclRefExpr(DeclRefExpr* DR); + bool VisitBinaryOperator(BinaryOperator* B); + bool VisitUnaryOperator(UnaryOperator* U); + bool VisitStmt(Stmt* S); + bool VisitCallExpr(CallExpr* C); + bool BlockStmt_VisitExpr(Expr* E); + + static inline bool Initialized() { return true; } + static inline bool Unintialized() { return false; } }; + + +bool TransferFuncs::VisitDeclRefExpr(DeclRefExpr* DR) { + if (VarDecl* VD = dyn_cast(DR->getDecl())) { + assert ( AD.VMap.find(VD) != AD.VMap.end() && "Unknown VarDecl."); + return V.DeclBV[ AD.VMap[VD] ]; + } + else + return Initialized(); +} + +bool TransferFuncs::VisitBinaryOperator(BinaryOperator* B) { + if (CFG::hasImplicitControlFlow(B)) { + assert ( AD.EMap.find(B) != AD.EMap.end() && "Unknown block-level expr."); + return V.ExprBV[ AD.EMap[B] ]; + } + + return VisitStmt(B); +} + +bool TransferFuncs::VisitCallExpr(CallExpr* C) { + VisitStmt(C); + return Initialized(); +} + +bool TransferFuncs::VisitUnaryOperator(UnaryOperator* U) { + switch (U->getOpcode()) { + case UnaryOperator::AddrOf: { + // Blast through parentheses and find the decl (if any). Treat it + // as initialized from this point forward. + for (Stmt* S = U->getSubExpr() ;; ) + if (ParenExpr* P = dyn_cast(S)) + S = P->getSubExpr(); + else if (DeclRefExpr* DR = dyn_cast(S)) { + if (VarDecl* VD = dyn_cast(DR->getDecl())) { + assert ( AD.VMap.find(VD) != AD.VMap.end() && "Unknown VarDecl."); + V.DeclBV[ AD.VMap[VD] ] = Initialized(); + } + break; + } + else { + // Evaluate the transfer function for subexpressions, even + // if we cannot reason more deeply about the &-expression. + return Visit(U->getSubExpr()); + } + + return Initialized(); + } + + default: + return Visit(U->getSubExpr()); + } +} + +bool TransferFuncs::VisitStmt(Stmt* S) { + bool x = Initialized(); + + // We don't stop at the first subexpression that is Uninitialized because + // evaluating some subexpressions may result in propogating "Uninitialized" + // or "Initialized" to variables referenced in the other subexpressions. + for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I!=E; ++I) + if (Visit(*I) == Unintialized()) + x = Unintialized(); + + return x; +} + +bool TransferFuncs::BlockStmt_VisitExpr(Expr* E) { + assert ( AD.EMap.find(E) != AD.EMap.end() ); + return V.ExprBV[ AD.EMap[E] ] = Visit(E); +} + } // end anonymous namespace //===--------------------------------------------------------------------===// // Merge operator. +// +// In our transfer functions we take the approach that any +// combination of unintialized values, e.g. Unitialized + ___ = Unitialized. +// +// Merges take the opposite approach. +// +// In the merge of dataflow values (for Decls) we prefer unsoundness, and +// prefer false negatives to false positives. At merges, if a value for a +// tracked Decl is EVER initialized in any of the predecessors we treat it as +// initialized at the confluence point. +// +// For tracked CFGBlock-level expressions (such as the result of +// short-circuit), we do the opposite merge: if a value is EVER uninitialized +// in a predecessor we treat it as uninitalized at the confluence point. +// The reason we do this is because dataflow values for tracked Exprs are +// not as control-dependent as dataflow values for tracked Decls. //===--------------------------------------------------------------------===// namespace { struct Merge { void operator()(UninitializedValues::ValTy& Dst, UninitializedValues::ValTy& Src) { - assert (Dst.size() == Src.size() && "Bitvector sizes do not match."); - Src |= Dst; + assert (Dst.DeclBV.size() == Src.DeclBV.size() + && "Bitvector sizes do not match."); + + Dst.DeclBV |= Src.DeclBV; + + assert (Dst.ExprBV.size() == Src.ExprBV.size() + && "Bitvector sizes do not match."); + + Dst.ExprBV &= Src.ExprBV; } }; } // end anonymous namespace -//===--------------------------------------------------------------------===// -// Observer to flag warnings for uses of uninitialized variables. -//===--------------------------------------------------------------------===// - - - - //===--------------------------------------------------------------------===// // External interface (driver logic). //===--------------------------------------------------------------------===// diff --git a/include/clang/Analysis/UninitializedValues.h b/include/clang/Analysis/UninitializedValues.h index ba01cb58f0..9358495da6 100644 --- a/include/clang/Analysis/UninitializedValues.h +++ b/include/clang/Analysis/UninitializedValues.h @@ -28,27 +28,33 @@ namespace clang { /// Unitialized Values analysis. class UninitializedValues_ValueTypes { public: - class ValTy { - llvm::BitVector BV; - public: - // Accessors to internal bitvector. - unsigned size() const { return BV.size(); } - void resize(unsigned i) { BV.resize(i); } - llvm::BitVector::reference operator[](unsigned i) { return BV[i]; } - void operator|=(const ValTy& RHS) { BV |= RHS.BV; } - + struct ValTy { + llvm::BitVector DeclBV; + llvm::BitVector ExprBV; + // Used by the solver. - void resetValues() { BV.reset(); } - bool equal(ValTy& RHS) const { return BV == RHS.BV; } - void copyValues(ValTy& RHS) { BV = RHS.BV; } + void resetValues() { + DeclBV.reset(); + ExprBV.reset(); + } + + bool equal(ValTy& RHS) const { + return DeclBV == RHS.DeclBV && ExprBV == RHS.ExprBV; + } + + void copyValues(ValTy& RHS) { + DeclBV = RHS.DeclBV; + ExprBV = RHS.ExprBV; + } }; struct AnalysisDataTy { llvm::DenseMap VMap; llvm::DenseMap EMap; - unsigned Counter; + unsigned NumDecls; + unsigned NumBlockExprs; - AnalysisDataTy() : Counter(0) {} + AnalysisDataTy() : NumDecls(0), NumBlockExprs(0) {} }; };