Created new "ExprDeclBitVector" type bundle for dataflow analyses that need boolean

values associated with ScopedDecls and CFGBlock-level Exprs.  This is the common
boilerplate needed by UninitializedValues and LiveVariables.

Refactored UninitializedValues to use ExprDeclBitVector.

Shortened the string diagnostic for UninitializedValues.

llvm-svn: 42408
This commit is contained in:
Ted Kremenek 2007-09-27 18:20:22 +00:00
parent 0d675ee06e
commit b9ce295b0a
4 changed files with 185 additions and 105 deletions

View File

@ -33,13 +33,8 @@ class RegisterDeclsExprs : public CFGRecStmtDeclVisitor<RegisterDeclsExprs> {
public:
RegisterDeclsExprs(UninitializedValues::AnalysisDataTy& ad) : AD(ad) {}
void VisitBlockVarDecl(BlockVarDecl* VD) {
if (!AD.isTracked(VD)) AD[VD] = AD.NumDecls++;
}
void BlockStmt_VisitExpr(Expr* E) {
if (!AD.isTracked(E)) AD[E] = AD.NumBlockExprs++;
}
void VisitBlockVarDecl(BlockVarDecl* VD) { AD.Register(VD); }
void BlockStmt_VisitExpr(Expr* E) { AD.Register(E); }
};
} // end anonymous namespace
@ -77,19 +72,19 @@ public:
bool VisitDeclStmt(DeclStmt* D);
BlockVarDecl* FindBlockVarDecl(Stmt* S);
static inline bool Initialized() { return true; }
static inline bool Uninitialized() { return false; }
};
static const bool Initialized = true;
static const bool Uninitialized = false;
bool TransferFuncs::VisitDeclRefExpr(DeclRefExpr* DR) {
if (BlockVarDecl* VD = dyn_cast<BlockVarDecl>(DR->getDecl())) {
if (AD.Observer) AD.Observer->ObserveDeclRefExpr(V,AD,DR,VD);
return V.getBitRef(VD,AD);
return V(VD,AD);
}
else return Initialized();
else return Initialized;
}
BlockVarDecl* TransferFuncs::FindBlockVarDecl(Stmt *S) {
@ -109,7 +104,7 @@ BlockVarDecl* TransferFuncs::FindBlockVarDecl(Stmt *S) {
bool TransferFuncs::VisitBinaryOperator(BinaryOperator* B) {
if (CFG::hasImplicitControlFlow(B))
return V.getBitRef(B,AD);
return V(B,AD);
if (B->isAssignmentOp())
// Get the Decl for the LHS (if any).
@ -122,22 +117,25 @@ bool TransferFuncs::VisitBinaryOperator(BinaryOperator* B) {
// just adding extra messages that don't
// contribute to diagnosing the bug. In InitWithAssigns mode
// we unconditionally set the assigned variable to Initialized to
// prevent Uninitialized propogation.
return V.getBitRef(VD,AD) = Initialized();
// prevent Uninitialized propagation.
return V(VD,AD) = Initialized;
}
else return V.getBitRef(VD,AD) = Visit(B->getRHS());
else return V(VD,AD) = Visit(B->getRHS());
return VisitStmt(B);
}
bool TransferFuncs::VisitDeclStmt(DeclStmt* S) {
bool x = Initialized();
bool x = Initialized;
for (ScopedDecl* D = S->getDecl(); D != NULL; D = D->getNextDeclarator())
if (BlockVarDecl* VD = dyn_cast<BlockVarDecl>(D))
if (Stmt* I = VD->getInit()) {
x = V.getBitRef(cast<Expr>(I),AD);
V.getBitRef(VD,AD) = x;
if (BlockVarDecl* VD = dyn_cast<BlockVarDecl>(D)) {
if (Stmt* I = VD->getInit())
x = InitWithAssigns ? Initialized : V(cast<Expr>(I),AD);
else
x = Uninitialized;
V(VD,AD) = x;
}
return x;
@ -145,7 +143,7 @@ bool TransferFuncs::VisitDeclStmt(DeclStmt* S) {
bool TransferFuncs::VisitCallExpr(CallExpr* C) {
VisitChildren(C);
return Initialized();
return Initialized;
}
bool TransferFuncs::VisitUnaryOperator(UnaryOperator* U) {
@ -153,7 +151,7 @@ bool TransferFuncs::VisitUnaryOperator(UnaryOperator* U) {
case UnaryOperator::AddrOf:
// For "&x", treat "x" as now being initialized.
if (BlockVarDecl* VD = FindBlockVarDecl(U->getSubExpr()))
V.getBitRef(VD,AD) = Initialized();
V(VD,AD) = Initialized;
else
return Visit(U->getSubExpr());
@ -163,20 +161,20 @@ bool TransferFuncs::VisitUnaryOperator(UnaryOperator* U) {
}
bool TransferFuncs::VisitStmt(Stmt* S) {
bool x = Initialized();
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) == Uninitialized()) x = Uninitialized();
if (Visit(*I) == Uninitialized) x = Uninitialized;
return x;
}
bool TransferFuncs::BlockStmt_VisitExpr(Expr* E) {
assert (AD.isTracked(E));
return V.getBitRef(E,AD) = Visit(E);
return V(E,AD) = Visit(E);
}
} // end anonymous namespace
@ -196,15 +194,9 @@ bool TransferFuncs::BlockStmt_VisitExpr(Expr* E) {
//===----------------------------------------------------------------------===//
namespace {
struct Merge {
void operator()(UninitializedValues::ValTy& Dst,
UninitializedValues::ValTy& Src) {
assert (Src.sizesEqual(Dst) && "BV sizes do not match.");
Dst.DeclBV |= Src.DeclBV;
Dst.ExprBV |= Src.ExprBV;
typedef ExprDeclBitVector_Types::Union Merge;
typedef DataflowSolver<UninitializedValues,TransferFuncs,Merge> Solver;
}
};
} // end anonymous namespace
//===----------------------------------------------------------------------===//
// Unitialized values checker. Scan an AST and flag variable uses
@ -228,7 +220,7 @@ public:
assert ( AD.isTracked(VD) && "Unknown VarDecl.");
if (V.getBitRef(VD,AD) == TransferFuncs::Uninitialized())
if (V(VD,AD) == Uninitialized)
if (AlreadyWarned.insert(VD))
Diags.Report(DR->getSourceRange().Begin(), diag::warn_uninit_val);
}
@ -238,8 +230,6 @@ public:
namespace clang {
void CheckUninitializedValues(CFG& cfg, ASTContext &Ctx, Diagnostic &Diags) {
typedef DataflowSolver<UninitializedValues,TransferFuncs,Merge> Solver;
// Compute the unitialized values information.
UninitializedValues U;
Solver S(U);

View File

@ -0,0 +1,149 @@
//=- ExprDeclBitVector.h - Dataflow types for Bitvector Analysis --*- C++ --*-//
//
// The LLVM Compiler Infrastructure
//
// This file was developed by Ted Kremenek and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file provides definition of dataflow types used by analyses such
// as LiveVariables and UninitializedValues. The underlying dataflow values
// are implemented as bitvectors, but the definitions in this file include
// the necessary boilerplate to use with our dataflow framework.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_EXPRDECLBVDVAL_H
#define LLVM_CLANG_EXPRDECLBVDVAL_H
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/DenseMap.h"
namespace clang {
class Expr;
class ScopedDecl;
struct ExprDeclBitVector_Types {
//===--------------------------------------------------------------------===//
// AnalysisDataTy - Whole-function meta data.
//===--------------------------------------------------------------------===//
class AnalysisDataTy {
typedef llvm::DenseMap<const ScopedDecl*, unsigned > DMapTy;
typedef llvm::DenseMap<const Expr*, unsigned > EMapTy;
EMapTy EMap;
DMapTy DMap;
unsigned NDecls;
unsigned NExprs;
public:
AnalysisDataTy() : NDecls(0), NExprs(0) {}
virtual ~AnalysisDataTy() {}
bool isTracked(const ScopedDecl* SD) { return DMap.find(SD) != DMap.end(); }
bool isTracked(const Expr* E) { return EMap.find(E) != EMap.end(); }
unsigned operator[](const ScopedDecl* SD) const {
DMapTy::const_iterator I = DMap.find(SD);
assert (I != DMap.end());
return I->second;
}
unsigned operator[](const Expr* E) const {
EMapTy::const_iterator I = EMap.find(E);
assert (I != EMap.end());
return I->second;
}
unsigned getNumDecls() const { return NDecls; }
unsigned getNumExprs() const { return NExprs; }
void Register(const ScopedDecl* SD) {
if (!isTracked(SD)) DMap[SD] = NDecls++;
}
void Register(const Expr* E) {
if (!isTracked(E)) EMap[E] = NExprs++;
}
};
//===--------------------------------------------------------------------===//
// ValTy - Dataflow value.
//===--------------------------------------------------------------------===//
class ValTy {
llvm::BitVector DeclBV;
llvm::BitVector ExprBV;
public:
void resetValues(AnalysisDataTy& AD) {
DeclBV.resize(AD.getNumDecls());
DeclBV.reset();
ExprBV.resize(AD.getNumExprs());
ExprBV.reset();
}
bool operator==(const ValTy& RHS) const {
assert (sizesEqual(RHS));
return DeclBV == RHS.DeclBV && ExprBV == RHS.ExprBV;
}
void copyValues(const ValTy& RHS) {
DeclBV = RHS.DeclBV;
ExprBV = RHS.ExprBV;
}
llvm::BitVector::reference
operator()(const ScopedDecl* SD, const AnalysisDataTy& AD) {
return DeclBV[AD[SD]];
}
const llvm::BitVector::reference
operator()(const ScopedDecl* SD, const AnalysisDataTy& AD) const {
return const_cast<ValTy&>(*this)(SD,AD);
}
llvm::BitVector::reference
operator()(const Expr* E, const AnalysisDataTy& AD) {
return ExprBV[AD[E]];
}
const llvm::BitVector::reference
operator()(const Expr* E, const AnalysisDataTy& AD) const {
return const_cast<ValTy&>(*this)(E,AD);
}
ValTy& operator|=(const ValTy& RHS) {
assert (sizesEqual(RHS));
DeclBV |= RHS.DeclBV;
ExprBV |= RHS.ExprBV;
return *this;
}
ValTy& operator&=(const ValTy& RHS) {
assert (sizesEqual(RHS));
DeclBV &= RHS.DeclBV;
ExprBV &= RHS.ExprBV;
return *this;
}
bool sizesEqual(const ValTy& RHS) const {
return DeclBV.size() == RHS.DeclBV.size()
&& ExprBV.size() == RHS.ExprBV.size();
}
};
//===--------------------------------------------------------------------===//
// Some useful merge operations.
//===--------------------------------------------------------------------===//
struct Union { void operator()(ValTy& Dst, ValTy& Src) { Dst |= Src; } };
struct Intersect { void operator()(ValTy& Dst, ValTy& Src) { Dst &= Src; } };
};
} // end namespace clang
#endif

View File

@ -15,7 +15,7 @@
#ifndef LLVM_CLANG_UNITVALS_H
#define LLVM_CLANG_UNITVALS_H
#include "llvm/ADT/BitVector.h"
#include "clang/Analysis/ExprDeclBitVector.h"
#include "clang/Analysis/FlowSensitive/DataflowValues.h"
namespace clang {
@ -31,75 +31,16 @@ namespace clang {
class UninitializedValues_ValueTypes {
public:
//===--------------------------------------------------------------------===//
// AnalysisDataTy - Whole-function meta data used by the transfer function
// logic.
//===--------------------------------------------------------------------===//
struct ObserverTy;
struct AnalysisDataTy {
llvm::DenseMap<const BlockVarDecl*, unsigned > VMap;
llvm::DenseMap<const Expr*, unsigned > EMap;
unsigned NumDecls;
unsigned NumBlockExprs;
struct AnalysisDataTy : public ExprDeclBitVector_Types::AnalysisDataTy {
AnalysisDataTy() : Observer(NULL) {}
virtual ~AnalysisDataTy() {};
ObserverTy* Observer;
AnalysisDataTy() : NumDecls(0), NumBlockExprs(0), Observer(NULL) {}
bool isTracked(const BlockVarDecl* VD) {
return VMap.find(VD) != VMap.end();
}
bool isTracked(const Expr* E) {
return EMap.find(E) != EMap.end();
}
unsigned& operator[](const BlockVarDecl *VD) { return VMap[VD]; }
unsigned& operator[](const Expr* E) { return EMap[E]; }
};
//===--------------------------------------------------------------------===//
// ValTy - Dataflow value.
//===--------------------------------------------------------------------===//
struct ValTy {
llvm::BitVector DeclBV;
llvm::BitVector ExprBV;
void resetValues(AnalysisDataTy& AD) {
DeclBV.resize(AD.NumDecls);
DeclBV.reset();
ExprBV.resize(AD.NumBlockExprs);
ExprBV.reset();
}
bool operator==(const ValTy& RHS) const {
return DeclBV == RHS.DeclBV && ExprBV == RHS.ExprBV;
}
void copyValues(const ValTy& RHS) {
DeclBV = RHS.DeclBV;
ExprBV = RHS.ExprBV;
}
llvm::BitVector::reference getBitRef(const BlockVarDecl* VD,
AnalysisDataTy& AD) {
assert (AD.isTracked(VD) && "BlockVarDecl not tracked.");
return DeclBV[AD.VMap[VD]];
}
llvm::BitVector::reference getBitRef(const Expr* E,
AnalysisDataTy& AD) {
assert (AD.isTracked(E) && "Expr not tracked.");
return ExprBV[AD.EMap[E]];
}
bool sizesEqual(ValTy& RHS) {
return DeclBV.size() == RHS.DeclBV.size() &&
ExprBV.size() == RHS.ExprBV.size();
}
};
typedef ExprDeclBitVector_Types::ValTy ValTy;
//===--------------------------------------------------------------------===//
// ObserverTy - Observer for querying DeclRefExprs that use an uninitalized

View File

@ -785,7 +785,7 @@ DIAG(warn_floatingpoint_eq, WARNING,
DIAG(warn_dead_store, WARNING, "value stored to variable is never used")
// CHECK: use of uninitialized values
DIAG(warn_uninit_val, WARNING, "use of potentially uninitialized variable")
DIAG(warn_uninit_val, WARNING, "use of uninitialized variable")
// CFString checking
DIAG(err_cfstring_literal_not_string_constant, ERROR,