From: Ted Kremenek Date: Tue, 15 Mar 2011 03:17:01 +0000 (+0000) Subject: Remove old UninitializedValues analysis. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f3f5379f6da7f8f141a53e2945871a5aa5431e02;p=clang Remove old UninitializedValues analysis. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@127656 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Analysis/Analyses/UninitializedValues.h b/include/clang/Analysis/Analyses/UninitializedValues.h deleted file mode 100644 index cd771acb06..0000000000 --- a/include/clang/Analysis/Analyses/UninitializedValues.h +++ /dev/null @@ -1,77 +0,0 @@ -//===- UninitializedValues.h - unintialized values analysis ----*- C++ --*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file provides the interface for the Unintialized Values analysis, -// a flow-sensitive analysis that detects when variable values are unintialized. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_UNITVALS_H -#define LLVM_CLANG_UNITVALS_H - -#include "clang/Analysis/Support/BlkExprDeclBitVector.h" -#include "clang/Analysis/FlowSensitive/DataflowValues.h" - -namespace clang { - - class BlockVarDecl; - class Expr; - class DeclRefExpr; - class VarDecl; - -/// UninitializedValues_ValueTypes - Utility class to wrap type declarations -/// for dataflow values and dataflow analysis state for the -/// Unitialized Values analysis. -class UninitializedValues_ValueTypes { -public: - - struct ObserverTy; - - struct AnalysisDataTy : public StmtDeclBitVector_Types::AnalysisDataTy { - AnalysisDataTy() : Observer(NULL), FullUninitTaint(true) {} - virtual ~AnalysisDataTy() {} - - ObserverTy* Observer; - bool FullUninitTaint; - }; - - typedef StmtDeclBitVector_Types::ValTy ValTy; - - //===--------------------------------------------------------------------===// - // 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: - typedef UninitializedValues_ValueTypes::ObserverTy ObserverTy; - - UninitializedValues(CFG &cfg) { getAnalysisData().setCFG(cfg); } - - /// 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); -}; - - -void CheckUninitializedValues(CFG& cfg, ASTContext& Ctx, Diagnostic& Diags, - bool FullUninitTaint=false); -} // end namespace clang -#endif diff --git a/lib/Analysis/CMakeLists.txt b/lib/Analysis/CMakeLists.txt index 84b211f2cf..ab1dd75730 100644 --- a/lib/Analysis/CMakeLists.txt +++ b/lib/Analysis/CMakeLists.txt @@ -12,7 +12,6 @@ add_clang_library(clangAnalysis PseudoConstantAnalysis.cpp ReachableCode.cpp ScanfFormatString.cpp - UninitializedValues.cpp UninitializedValuesV2.cpp ) diff --git a/lib/Analysis/UninitializedValues.cpp b/lib/Analysis/UninitializedValues.cpp deleted file mode 100644 index c08cbedf4b..0000000000 --- a/lib/Analysis/UninitializedValues.cpp +++ /dev/null @@ -1,317 +0,0 @@ -//==- UninitializedValues.cpp - Find Uninitialized Values -------*- C++ --*-==// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements Uninitialized Values analysis for source-level CFGs. -// -//===----------------------------------------------------------------------===// - -#include "clang/Analysis/Analyses/UninitializedValues.h" -#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h" -#include "clang/Analysis/AnalysisDiagnostic.h" -#include "clang/AST/ASTContext.h" -#include "clang/Analysis/FlowSensitive/DataflowSolver.h" - -#include "llvm/ADT/SmallPtrSet.h" - -using namespace clang; - -//===----------------------------------------------------------------------===// -// Dataflow initialization logic. -//===----------------------------------------------------------------------===// - -namespace { - -class RegisterDecls - : public CFGRecStmtDeclVisitor { - - UninitializedValues::AnalysisDataTy& AD; -public: - RegisterDecls(UninitializedValues::AnalysisDataTy& ad) : AD(ad) {} - - void VisitVarDecl(VarDecl* VD) { AD.Register(VD); } - CFG& getCFG() { return AD.getCFG(); } -}; - -} // end anonymous namespace - -void UninitializedValues::InitializeValues(const CFG& cfg) { - RegisterDecls R(getAnalysisData()); - cfg.VisitBlockStmts(R); -} - -//===----------------------------------------------------------------------===// -// Transfer functions. -//===----------------------------------------------------------------------===// - -namespace { -class TransferFuncs - : public CFGStmtVisitor { - - UninitializedValues::ValTy V; - UninitializedValues::AnalysisDataTy& AD; -public: - TransferFuncs(UninitializedValues::AnalysisDataTy& ad) : AD(ad) {} - - UninitializedValues::ValTy& getVal() { return V; } - CFG& getCFG() { return AD.getCFG(); } - - void SetTopValue(UninitializedValues::ValTy& X) { - X.setDeclValues(AD); - X.resetBlkExprValues(AD); - } - - bool VisitDeclRefExpr(DeclRefExpr* DR); - bool VisitBinaryOperator(BinaryOperator* B); - bool VisitUnaryOperator(UnaryOperator* U); - bool VisitStmt(Stmt* S); - bool VisitCallExpr(CallExpr* C); - bool VisitDeclStmt(DeclStmt* D); - bool VisitAbstractConditionalOperator(AbstractConditionalOperator* C); - bool BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt* S); - - bool Visit(Stmt *S); - bool BlockStmt_VisitExpr(Expr* E); - - void VisitTerminator(CFGBlock* B) { } - - void setCurrentBlock(const CFGBlock *block) {} -}; - -static const bool Initialized = false; -static const bool Uninitialized = true; - -bool TransferFuncs::VisitDeclRefExpr(DeclRefExpr* DR) { - - if (VarDecl* VD = dyn_cast(DR->getDecl())) - if (VD->isLocalVarDecl()) { - - if (AD.Observer) - AD.Observer->ObserveDeclRefExpr(V, AD, DR, VD); - - // Pseudo-hack to prevent cascade of warnings. If an accessed variable - // is uninitialized, then we are already going to flag a warning for - // this variable, which a "source" of uninitialized values. - // We can otherwise do a full "taint" of uninitialized values. The - // client has both options by toggling AD.FullUninitTaint. - - if (AD.FullUninitTaint) - return V(VD,AD); - } - - return Initialized; -} - -static VarDecl* FindBlockVarDecl(Expr* E) { - - // Blast through casts and parentheses to find any DeclRefExprs that - // refer to a block VarDecl. - - if (DeclRefExpr* DR = dyn_cast(E->IgnoreParenCasts())) - if (VarDecl* VD = dyn_cast(DR->getDecl())) - if (VD->isLocalVarDecl()) return VD; - - return NULL; -} - -bool TransferFuncs::VisitBinaryOperator(BinaryOperator* B) { - - if (VarDecl* VD = FindBlockVarDecl(B->getLHS())) - if (B->isAssignmentOp()) { - if (B->getOpcode() == BO_Assign) - return V(VD,AD) = Visit(B->getRHS()); - else // Handle +=, -=, *=, etc. We do want '&', not '&&'. - return V(VD,AD) = Visit(B->getLHS()) & Visit(B->getRHS()); - } - - return VisitStmt(B); -} - -bool TransferFuncs::VisitDeclStmt(DeclStmt* S) { - for (DeclStmt::decl_iterator I=S->decl_begin(), E=S->decl_end(); I!=E; ++I) { - VarDecl *VD = dyn_cast(*I); - if (VD && VD->isLocalVarDecl()) { - if (Stmt* I = VD->getInit()) { - // Visit the subexpression to check for uses of uninitialized values, - // even if we don't propagate that value. - bool isSubExprUninit = Visit(I); - V(VD,AD) = AD.FullUninitTaint ? isSubExprUninit : Initialized; - } - else { - // Special case for declarations of array types. For things like: - // - // char x[10]; - // - // we should treat "x" as being initialized, because the variable - // "x" really refers to the memory block. Clearly x[1] is - // uninitialized, but expressions like "(char *) x" really do refer to - // an initialized value. This simple dataflow analysis does not reason - // about the contents of arrays, although it could be potentially - // extended to do so if the array were of constant size. - if (VD->getType()->isArrayType()) - V(VD,AD) = Initialized; - else - V(VD,AD) = Uninitialized; - } - } - } - return Uninitialized; // Value is never consumed. -} - -bool TransferFuncs::VisitCallExpr(CallExpr* C) { - VisitChildren(C); - return Initialized; -} - -bool TransferFuncs::VisitUnaryOperator(UnaryOperator* U) { - switch (U->getOpcode()) { - case UO_AddrOf: { - VarDecl* VD = FindBlockVarDecl(U->getSubExpr()); - if (VD && VD->isLocalVarDecl()) - return V(VD,AD) = Initialized; - break; - } - - default: - break; - } - - return Visit(U->getSubExpr()); -} - -bool -TransferFuncs::BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) { - // This represents a use of the 'collection' - bool x = Visit(S->getCollection()); - - if (x == Uninitialized) - return Uninitialized; - - // This represents an initialization of the 'element' value. - Stmt* Element = S->getElement(); - VarDecl* VD = 0; - - if (DeclStmt* DS = dyn_cast(Element)) - VD = cast(DS->getSingleDecl()); - else { - Expr* ElemExpr = cast(Element)->IgnoreParens(); - - // Initialize the value of the reference variable. - if (DeclRefExpr* DR = dyn_cast(ElemExpr)) - VD = cast(DR->getDecl()); - else - return Visit(ElemExpr); - } - - V(VD,AD) = Initialized; - return Initialized; -} - - -bool TransferFuncs:: -VisitAbstractConditionalOperator(AbstractConditionalOperator* C) { - Visit(C->getCond()); - - bool rhsResult = Visit(C->getFalseExpr()); - // Handle the GNU extension for missing LHS. - if (isa(C)) - return Visit(C->getTrueExpr()) & rhsResult; // Yes: we want &, not &&. - else - return rhsResult; -} - -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_range I = S->children(); I; ++I) - if (*I && Visit(*I) == Uninitialized) x = Uninitialized; - - return x; -} - -bool TransferFuncs::Visit(Stmt *S) { - if (AD.isTracked(static_cast(S))) return V(static_cast(S),AD); - else return static_cast*>(this)->Visit(S); -} - -bool TransferFuncs::BlockStmt_VisitExpr(Expr* E) { - bool x = static_cast*>(this)->Visit(E); - if (AD.isTracked(E)) V(E,AD) = x; - return x; -} - -} // end anonymous namespace - -//===----------------------------------------------------------------------===// -// Merge operator. -// -// In our transfer functions we take the approach that any -// combination of uninitialized values, e.g. -// Uninitialized + ___ = Uninitialized. -// -// Merges take the same approach, preferring soundness. At a confluence point, -// if any predecessor has a variable marked uninitialized, the value is -// uninitialized at the confluence point. -//===----------------------------------------------------------------------===// - -namespace { - typedef StmtDeclBitVector_Types::Union Merge; - typedef DataflowSolver Solver; -} - -//===----------------------------------------------------------------------===// -// Uninitialized values checker. Scan an AST and flag variable uses -//===----------------------------------------------------------------------===// - -UninitializedValues_ValueTypes::ObserverTy::~ObserverTy() {} - -namespace { -class UninitializedValuesChecker - : public UninitializedValues::ObserverTy { - - ASTContext &Ctx; - Diagnostic &Diags; - llvm::SmallPtrSet AlreadyWarned; - -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.isTracked(VD) && "Unknown VarDecl."); - - if (V(VD,AD) == Uninitialized) - if (AlreadyWarned.insert(VD)) - Diags.Report(Ctx.getFullLoc(DR->getSourceRange().getBegin()), - diag::warn_uninit_val); - } -}; -} // end anonymous namespace - -namespace clang { -void CheckUninitializedValues(CFG& cfg, ASTContext &Ctx, Diagnostic &Diags, - bool FullUninitTaint) { - - // Compute the uninitialized values information. - UninitializedValues U(cfg); - U.getAnalysisData().FullUninitTaint = FullUninitTaint; - Solver S(U); - S.runOnCFG(cfg); - - // Scan for DeclRefExprs that use uninitialized values. - UninitializedValuesChecker Observer(Ctx,Diags); - U.getAnalysisData().Observer = &Observer; - S.runOnAllBlocks(cfg); -} -} // end namespace clang diff --git a/test/Analysis/conditional-op-missing-lhs.c b/test/Analysis/conditional-op-missing-lhs.c deleted file mode 100644 index 5f7068bd5f..0000000000 --- a/test/Analysis/conditional-op-missing-lhs.c +++ /dev/null @@ -1,28 +0,0 @@ -// RUN: %clang_cc1 -analyze -analyzer-checker=deadcode.DeadStores -warn-uninit-values -verify %s -// FIXME: The current UninitializedValuesChecker will go away; replace it and re-enable test. -// XFAIL: * - -void f1() -{ - int i; - - int j = i ? : 1; // expected-warning{{use of uninitialized variable}} //expected-warning{{Value stored to 'j' during its initialization is never read}} -} - -void *f2(int *i) -{ - return i ? : 0; -} - -void *f3(int *i) -{ - int a; - - return &a ? : i; -} - -void f4() -{ - char c[1 ? : 2]; -} - diff --git a/test/Analysis/uninit-vals.c b/test/Analysis/uninit-vals.c deleted file mode 100644 index 85088734ab..0000000000 --- a/test/Analysis/uninit-vals.c +++ /dev/null @@ -1,55 +0,0 @@ -// RUN: %clang_cc1 -analyze -warn-uninit-values -verify %s -// FIXME: The current UninitializedValuesChecker will go away; replace it and re-enable test. -// XFAIL: * - -int f1() { - int x; - return x; // expected-warning {{use of uninitialized variable}} -} - -int f2(int x) { - int y; - int z = x + y; // expected-warning {{use of uninitialized variable}} - return z; -} - - -int f3(int x) { - int y; - return x ? 1 : y; // expected-warning {{use of uninitialized variable}} -} - -int f4(int x) { - int y; - if (x) y = 1; - return y; // expected-warning {{use of uninitialized variable}} -} - -void f5() { - int a; - a = 30; // no-warning -} - -void f6(int i) { - int x; - for (i = 0 ; i < 10; i++) - printf("%d",x++); // expected-warning {{use of uninitialized variable}} \ - // expected-warning{{implicitly declaring C library function 'printf' with type 'int (const char *, ...)'}} \ - // expected-note{{please include the header or explicitly provide a declaration for 'printf'}} -} - -void f7(int i) { - int x = i; - int y; - for (i = 0; i < 10; i++ ) { - printf("%d",x++); // no-warning - x += y; // expected-warning {{use of uninitialized variable}} - } -} - -int f8(int j) { - int x = 1, y = x + 1; - if (y) // no-warning - return x; - return y; -} diff --git a/test/Sema/uninit-variables.c b/test/Sema/uninit-variables.c index 973e504f63..bb29552901 100644 --- a/test/Sema/uninit-variables.c +++ b/test/Sema/uninit-variables.c @@ -260,3 +260,71 @@ int test38(int r, int x, int y) return ((r < 0) || ((r == 0) && (x < y))); } +int test39(int x) { + int y; // expected-note {{variable 'y' is declared here}} expected-note{{add initialization to silence this warning}} + int z = x + y; // expected-warning {{variable 'y' is possibly uninitialized when used here}} + return z; +} + + +int test40(int x) { + int y; // expected-note {{variable 'y' is declared here}} expected-note{{add initialization to silence this warning}} + return x ? 1 : y; // expected-warning {{variable 'y' is possibly uninitialized when used here}} +} + +int test41(int x) { + int y; // expected-note {{variable 'y' is declared here}} expected-note{{add initialization to silence this warning}} + if (x) y = 1; // no-warning + return y; // expected-warning {{variable 'y' is possibly uninitialized when used here}} +} + +void test42() { + int a; + a = 30; // no-warning +} + +void test43_aux(int x); +void test43(int i) { + int x; // expected-note {{variable 'x' is declared here}} expected-note{{add initialization to silence this warning}} + for (i = 0 ; i < 10; i++) + test43_aux(x++); // expected-warning {{variable 'x' is possibly uninitialized when used here}} +} + +void test44(int i) { + int x = i; + int y; // expected-note {{variable 'y' is declared here}} expected-note{{add initialization to silence this warning}} + for (i = 0; i < 10; i++ ) { + test43_aux(x++); // no-warning + x += y; // expected-warning {{variable 'y' is possibly uninitialized when used here}} + } +} + +int test45(int j) { + int x = 1, y = x + 1; + if (y) // no-warning + return x; + return y; +} + +void test46() +{ + int i; // expected-note {{variable 'i' is declared here}} expected-note{{add initialization to silence this warning}} + int j = i ? : 1; // expected-warning {{variable 'i' is possibly uninitialized when used here}} +} + +void *test47(int *i) +{ + return i ? : 0; // no-warning +} + +void *test49(int *i) +{ + int a; + return &a ? : i; // no-warning +} + +void test50() +{ + char c[1 ? : 2]; // no-warning +} +