From: Ted Kremenek Date: Mon, 17 Sep 2007 19:59:27 +0000 (+0000) Subject: More progress on UnitializedValues checker. We now have preliminary support X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=cd5860ce7a793cdad1e55552bb23937263ea2921;p=clang More progress on UnitializedValues checker. We now have preliminary support for reporting errors and running the checker. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@42046 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/Analysis/UnintializedValues.cpp b/Analysis/UnintializedValues.cpp index c9c02d0afd..2640493095 100644 --- a/Analysis/UnintializedValues.cpp +++ b/Analysis/UnintializedValues.cpp @@ -14,13 +14,18 @@ #include "clang/Analysis/UninitializedValues.h" #include "clang/Analysis/CFGVarDeclVisitor.h" #include "clang/Analysis/CFGStmtVisitor.h" +#include "clang/Analysis/LocalCheckers.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/AST/ASTContext.h" #include "DataflowSolver.h" +#include "llvm/ADT/SmallPtrSet.h" + using namespace clang; -//===--------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// // Dataflow initialization logic. -//===--------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// namespace { @@ -52,9 +57,9 @@ void UninitializedValues::InitializeValues(const CFG& cfg) { V.ExprBV.resize(getAnalysisData().NumBlockExprs); } -//===--------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// // Transfer functions. -//===--------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// namespace { @@ -75,15 +80,19 @@ public: bool VisitStmt(Stmt* S); bool VisitCallExpr(CallExpr* C); bool BlockStmt_VisitExpr(Expr* E); + bool VisitDeclStmt(DeclStmt* D); static inline bool Initialized() { return true; } - static inline bool Unintialized() { return false; } + static inline bool Uninitialized() { return false; } }; bool TransferFuncs::VisitDeclRefExpr(DeclRefExpr* DR) { if (VarDecl* VD = dyn_cast(DR->getDecl())) { assert ( AD.VMap.find(VD) != AD.VMap.end() && "Unknown VarDecl."); + if (AD.Observer) + AD.Observer->ObserveDeclRefExpr(V,AD,DR,VD); + return V.DeclBV[ AD.VMap[VD] ]; } else @@ -95,10 +104,38 @@ bool TransferFuncs::VisitBinaryOperator(BinaryOperator* B) { assert ( AD.EMap.find(B) != AD.EMap.end() && "Unknown block-level expr."); return V.ExprBV[ AD.EMap[B] ]; } - + + if (B->isAssignmentOp()) { + // Get the Decl for the LHS, if any + for (Stmt* S = B->getLHS() ;; ) { + 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."); + return V.DeclBV[ AD.VMap[VD] ] = Visit(B->getRHS()); + } + + break; + } + } + return VisitStmt(B); } +bool TransferFuncs::VisitDeclStmt(DeclStmt* S) { + bool x = Initialized(); + + for (ScopedDecl* D = S->getDecl(); D != NULL; D = D->getNextDeclarator()) + if (VarDecl* VD = dyn_cast(D)) + if (Stmt* I = VD->getInit()) { + assert ( AD.VMap.find(VD) != AD.VMap.end() && "Unknown VarDecl."); + x = V.DeclBV[ AD.VMap[VD] ] = Visit(I); + } + + return x; +} + bool TransferFuncs::VisitCallExpr(CallExpr* C) { VisitStmt(C); return Initialized(); @@ -140,8 +177,8 @@ bool TransferFuncs::VisitStmt(Stmt* S) { // 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(); + if (Visit(*I) == Uninitialized()) + x = Uninitialized(); return x; } @@ -153,7 +190,7 @@ bool TransferFuncs::BlockStmt_VisitExpr(Expr* E) { } // end anonymous namespace -//===--------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// // Merge operator. // // In our transfer functions we take the approach that any @@ -171,7 +208,7 @@ bool TransferFuncs::BlockStmt_VisitExpr(Expr* E) { // 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 { @@ -190,24 +227,50 @@ struct Merge { }; } // end anonymous namespace -//===--------------------------------------------------------------------===// -// External interface (driver logic). -//===--------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// +// Unitialized values checker. Scan an AST and flag variable uses +//===----------------------------------------------------------------------===// -void UninitializedValues::CheckUninitializedValues(const CFG& cfg) { +UninitializedValues_ValueTypes::ObserverTy::~ObserverTy() {} - typedef DataflowSolver Solver; +namespace { - UninitializedValues U; +class UninitializedValuesChecker : public UninitializedValues::ObserverTy { + ASTContext &Ctx; + Diagnostic &Diags; + llvm::SmallPtrSet AlreadyWarned; - { // Compute the unitialized values information. - Solver S(U); - S.runOnCFG(cfg); +public: + UninitializedValuesChecker(ASTContext &ctx, Diagnostic &diags) + : Ctx(ctx), Diags(diags) {} + + virtual void ObserveDeclRefExpr(UninitializedValues::ValTy& V, + UninitializedValues::AnalysisDataTy& AD, + DeclRefExpr* DR, VarDecl* VD) { + + assert ( AD.VMap.find(VD) != AD.VMap.end() && "Unknown VarDecl."); + if (V.DeclBV[ AD.VMap[VD] ] == TransferFuncs::Uninitialized()) + if (AlreadyWarned.insert(VD)) + Diags.Report(DR->getSourceRange().Begin(), diag::warn_uninit_val); } +}; + +} // end anonymous namespace -// WarnObserver O; + +void CheckUninitializedValues(CFG& cfg, ASTContext &Ctx, Diagnostic &Diags) { + + typedef DataflowSolver Solver; + + // Compute the unitialized values information. + UninitializedValues U; Solver S(U); - - for (CFG::const_iterator I=cfg.begin(), E=cfg.end(); I!=E; ++I) + S.runOnCFG(cfg); + + // Scan for DeclRefExprs that use uninitialized values. + UninitializedValuesChecker Observer(Ctx,Diags); + U.getAnalysisData().Observer = &Observer; + + for (CFG::iterator I=cfg.begin(), E=cfg.end(); I!=E; ++I) S.runOnBlock(&*I); } diff --git a/include/clang/Analysis/LocalCheckers.h b/include/clang/Analysis/LocalCheckers.h index 19825fe228..c64bcb7d39 100644 --- a/include/clang/Analysis/LocalCheckers.h +++ b/include/clang/Analysis/LocalCheckers.h @@ -25,6 +25,10 @@ void CheckDeadStores(CFG& cfg, LiveVariables& L, ASTContext &Ctx, Diagnostic &Diags); void CheckDeadStores(CFG& cfg, ASTContext &Ctx, Diagnostic &Diags); + +void CheckUninitializedValues(CFG& cfg, ASTContext& Ctx, Diagnostic& Diags); + + } // end namespace clang #endif diff --git a/include/clang/Analysis/UninitializedValues.h b/include/clang/Analysis/UninitializedValues.h index 9358495da6..3fe1e17250 100644 --- a/include/clang/Analysis/UninitializedValues.h +++ b/include/clang/Analysis/UninitializedValues.h @@ -22,12 +22,18 @@ namespace clang { class VarDecl; class Expr; + class DeclRefExpr; /// UninitializedValues_ValueTypes - Utility class to wrap type declarations /// for dataflow values and dataflow analysis state for the /// Unitialized Values analysis. class UninitializedValues_ValueTypes { public: + + //===--------------------------------------------------------------------===// + // ValTy - Dataflow value. + //===--------------------------------------------------------------------===// + struct ValTy { llvm::BitVector DeclBV; llvm::BitVector ExprBV; @@ -48,36 +54,45 @@ public: } }; + //===--------------------------------------------------------------------===// + // AnalysisDataTy - Whole-function meta data used by the transfer function + // logic. + //===--------------------------------------------------------------------===// + + struct ObserverTy; + struct AnalysisDataTy { llvm::DenseMap VMap; llvm::DenseMap EMap; unsigned NumDecls; unsigned NumBlockExprs; + ObserverTy* Observer; - AnalysisDataTy() : NumDecls(0), NumBlockExprs(0) {} + AnalysisDataTy() : NumDecls(0), NumBlockExprs(0), Observer(NULL) {} }; + + //===--------------------------------------------------------------------===// + // ObserverTy - Observer for querying DeclRefExprs that use an uninitalized + // value. + //===--------------------------------------------------------------------===// + + struct ObserverTy { + virtual ~ObserverTy(); + virtual void ObserveDeclRefExpr(ValTy& Val, AnalysisDataTy& AD, + DeclRefExpr* DR, VarDecl* VD) = 0; + }; }; /// UninitializedValues - Objects of this class encapsulate dataflow analysis /// information regarding what variable declarations in a function are /// potentially unintialized. class UninitializedValues : - public DataflowValues { - - //===--------------------------------------------------------------------===// - // Public interface. - //===--------------------------------------------------------------------===// - - static void CheckUninitializedValues(const CFG& cfg); + public DataflowValues { +public: + typedef UninitializedValues_ValueTypes::ObserverTy ObserverTy; - //===--------------------------------------------------------------------===// - // Internal logic. - //===--------------------------------------------------------------------===// - -private: UninitializedValues() {} -public: /// IntializeValues - Create initial dataflow values and meta data for /// a given CFG. This is intended to be called by the dataflow solver. void InitializeValues(const CFG& cfg); diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index 4b7399ddbe..bf2947e8bb 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -753,6 +753,9 @@ DIAG(warn_floatingpoint_eq, WARNING, // CHECK: stores to variables that are no longer live (dead stores) 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") + // CFString checking DIAG(err_cfstring_literal_not_string_constant, ERROR, "CFString literal is not a string constant")