diff options
Diffstat (limited to 'include/clang/Analysis')
33 files changed, 8208 insertions, 0 deletions
diff --git a/include/clang/Analysis/Analyses/LiveVariables.h b/include/clang/Analysis/Analyses/LiveVariables.h new file mode 100644 index 000000000000..b41cd684e951 --- /dev/null +++ b/include/clang/Analysis/Analyses/LiveVariables.h @@ -0,0 +1,119 @@ +//===- LiveVariables.h - Live Variable Analysis for Source CFGs -*- 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 Live Variables analysis for source-level CFGs. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIVEVARIABLES_H +#define LLVM_CLANG_LIVEVARIABLES_H + +#include "clang/AST/Decl.h" +#include "clang/Analysis/Support/BlkExprDeclBitVector.h" +#include "clang/Analysis/FlowSensitive/DataflowValues.h" + +namespace clang { + +class Stmt; +class DeclRefExpr; +class SourceManager; + +struct LiveVariables_ValueTypes { + + struct ObserverTy; + + // We keep dataflow state for declarations and block-level expressions; + typedef StmtDeclBitVector_Types::ValTy ValTy; + + // We need to keep track of both declarations and CFGBlock-level expressions, + // (so that we don't explore such expressions twice). We also want + // to compute liveness information for block-level expressions, since these + // act as "temporary" values. + + struct AnalysisDataTy : public StmtDeclBitVector_Types::AnalysisDataTy { + ObserverTy* Observer; + ValTy AlwaysLive; + + AnalysisDataTy() : Observer(NULL) {} + }; + + //===-----------------------------------------------------===// + // ObserverTy - Observer for uninitialized values queries. + //===-----------------------------------------------------===// + + struct ObserverTy { + virtual ~ObserverTy() {} + + /// ObserveStmt - A callback invoked right before invoking the + /// liveness transfer function on the given statement. + virtual void ObserveStmt(Stmt* S, const AnalysisDataTy& AD, + const ValTy& V) {} + + virtual void ObserverKill(DeclRefExpr* DR) {} + }; +}; + +class LiveVariables : public DataflowValues<LiveVariables_ValueTypes, + dataflow::backward_analysis_tag> { + + +public: + typedef LiveVariables_ValueTypes::ObserverTy ObserverTy; + + LiveVariables(ASTContext& Ctx, CFG& cfg); + + /// IsLive - Return true if a variable is live at beginning of a + /// specified block. + bool isLive(const CFGBlock* B, const VarDecl* D) const; + + /// IsLive - Returns true if a variable is live at the beginning of the + /// the statement. This query only works if liveness information + /// has been recorded at the statement level (see runOnAllBlocks), and + /// only returns liveness information for block-level expressions. + bool isLive(const Stmt* S, const VarDecl* D) const; + + /// IsLive - Returns true the block-level expression "value" is live + /// before the given block-level expression (see runOnAllBlocks). + bool isLive(const Stmt* Loc, const Stmt* StmtVal) const; + + /// IsLive - Return true if a variable is live according to the + /// provided livness bitvector. + bool isLive(const ValTy& V, const VarDecl* D) const; + + /// dumpLiveness - Print to stderr the liveness information encoded + /// by a specified bitvector. + void dumpLiveness(const ValTy& V, SourceManager& M) const; + + /// dumpBlockLiveness - Print to stderr the liveness information + /// associated with each basic block. + void dumpBlockLiveness(SourceManager& M) const; + + /// getNumDecls - Return the number of variables (declarations) that + /// whose liveness status is being tracked by the dataflow + /// analysis. + unsigned getNumDecls() const { return getAnalysisData().getNumDecls(); } + + /// IntializeValues - This routine can perform extra initialization, but + /// for LiveVariables this does nothing since all that logic is in + /// the constructor. + void InitializeValues(const CFG& cfg) {} + + void runOnCFG(CFG& cfg); + + /// runOnAllBlocks - Propagate the dataflow values once for each block, + /// starting from the current dataflow values. 'recordStmtValues' indicates + /// whether the method should store dataflow values per each individual + /// block-level expression. + void runOnAllBlocks(const CFG& cfg, ObserverTy* Obs, + bool recordStmtValues=false); +}; + +} // end namespace clang + +#endif diff --git a/include/clang/Analysis/Analyses/UninitializedValues.h b/include/clang/Analysis/Analyses/UninitializedValues.h new file mode 100644 index 000000000000..7a9da03e4bd2 --- /dev/null +++ b/include/clang/Analysis/Analyses/UninitializedValues.h @@ -0,0 +1,74 @@ +//===- 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<UninitializedValues_ValueTypes> { +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); +}; + +} // end namespace clang +#endif diff --git a/include/clang/Analysis/AnalysisDiagnostic.h b/include/clang/Analysis/AnalysisDiagnostic.h new file mode 100644 index 000000000000..e82dc9ed9f3f --- /dev/null +++ b/include/clang/Analysis/AnalysisDiagnostic.h @@ -0,0 +1,27 @@ +//===--- DiagnosticAnalysis.h - Diagnostics for libanalysis -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_DIAGNOSTICANALYSIS_H +#define LLVM_CLANG_DIAGNOSTICANALYSIS_H + +#include "clang/Basic/Diagnostic.h" + +namespace clang { + namespace diag { + enum { +#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP) ENUM, +#define ANALYSISSTART +#include "clang/Basic/DiagnosticAnalysisKinds.inc" +#undef DIAG + NUM_BUILTIN_ANALYSIS_DIAGNOSTICS + }; + } // end namespace diag +} // end namespace clang + +#endif diff --git a/include/clang/Analysis/FlowSensitive/DataflowSolver.h b/include/clang/Analysis/FlowSensitive/DataflowSolver.h new file mode 100644 index 000000000000..38612593368b --- /dev/null +++ b/include/clang/Analysis/FlowSensitive/DataflowSolver.h @@ -0,0 +1,291 @@ +//===--- DataflowSolver.h - Skeleton Dataflow Analysis Code -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines skeleton code for implementing dataflow analyses. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSES_DATAFLOW_SOLVER +#define LLVM_CLANG_ANALYSES_DATAFLOW_SOLVER + +#include "clang/AST/CFG.h" +#include "clang/Analysis/ProgramPoint.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "functional" // STL + +namespace clang { + +//===----------------------------------------------------------------------===// +/// DataflowWorkListTy - Data structure representing the worklist used for +/// dataflow algorithms. +//===----------------------------------------------------------------------===// + +class DataflowWorkListTy { + typedef llvm::SmallPtrSet<const CFGBlock*,20> BlockSet; + BlockSet wlist; +public: + /// enqueue - Add a block to the worklist. Blocks already on the + /// worklist are not added a second time. + void enqueue(const CFGBlock* B) { wlist.insert(B); } + + /// dequeue - Remove a block from the worklist. + const CFGBlock* dequeue() { + assert (!wlist.empty()); + const CFGBlock* B = *wlist.begin(); + wlist.erase(B); + return B; + } + + /// isEmpty - Return true if the worklist is empty. + bool isEmpty() const { return wlist.empty(); } +}; + +//===----------------------------------------------------------------------===// +// BlockItrTraits - Traits classes that allow transparent iteration +// over successors/predecessors of a block depending on the direction +// of our dataflow analysis. +//===----------------------------------------------------------------------===// + +namespace dataflow { +template<typename Tag> struct ItrTraits {}; + +template <> struct ItrTraits<forward_analysis_tag> { + typedef CFGBlock::const_pred_iterator PrevBItr; + typedef CFGBlock::const_succ_iterator NextBItr; + typedef CFGBlock::const_iterator StmtItr; + + static PrevBItr PrevBegin(const CFGBlock* B) { return B->pred_begin(); } + static PrevBItr PrevEnd(const CFGBlock* B) { return B->pred_end(); } + + static NextBItr NextBegin(const CFGBlock* B) { return B->succ_begin(); } + static NextBItr NextEnd(const CFGBlock* B) { return B->succ_end(); } + + static StmtItr StmtBegin(const CFGBlock* B) { return B->begin(); } + static StmtItr StmtEnd(const CFGBlock* B) { return B->end(); } + + static BlockEdge PrevEdge(const CFGBlock* B, const CFGBlock* Prev) { + return BlockEdge(Prev, B); + } + + static BlockEdge NextEdge(const CFGBlock* B, const CFGBlock* Next) { + return BlockEdge(B, Next); + } +}; + +template <> struct ItrTraits<backward_analysis_tag> { + typedef CFGBlock::const_succ_iterator PrevBItr; + typedef CFGBlock::const_pred_iterator NextBItr; + typedef CFGBlock::const_reverse_iterator StmtItr; + + static PrevBItr PrevBegin(const CFGBlock* B) { return B->succ_begin(); } + static PrevBItr PrevEnd(const CFGBlock* B) { return B->succ_end(); } + + static NextBItr NextBegin(const CFGBlock* B) { return B->pred_begin(); } + static NextBItr NextEnd(const CFGBlock* B) { return B->pred_end(); } + + static StmtItr StmtBegin(const CFGBlock* B) { return B->rbegin(); } + static StmtItr StmtEnd(const CFGBlock* B) { return B->rend(); } + + static BlockEdge PrevEdge(const CFGBlock* B, const CFGBlock* Prev) { + return BlockEdge(B, Prev); + } + + static BlockEdge NextEdge(const CFGBlock* B, const CFGBlock* Next) { + return BlockEdge(Next, B); + } +}; +} // end namespace dataflow + +//===----------------------------------------------------------------------===// +/// DataflowSolverTy - Generic dataflow solver. +//===----------------------------------------------------------------------===// + +template <typename _DFValuesTy, // Usually a subclass of DataflowValues + typename _TransferFuncsTy, + typename _MergeOperatorTy, + typename _Equal = std::equal_to<typename _DFValuesTy::ValTy> > +class DataflowSolver { + + //===----------------------------------------------------===// + // Type declarations. + //===----------------------------------------------------===// + +public: + typedef _DFValuesTy DFValuesTy; + typedef _TransferFuncsTy TransferFuncsTy; + typedef _MergeOperatorTy MergeOperatorTy; + + typedef typename _DFValuesTy::AnalysisDirTag AnalysisDirTag; + typedef typename _DFValuesTy::ValTy ValTy; + typedef typename _DFValuesTy::EdgeDataMapTy EdgeDataMapTy; + typedef typename _DFValuesTy::BlockDataMapTy BlockDataMapTy; + + typedef dataflow::ItrTraits<AnalysisDirTag> ItrTraits; + typedef typename ItrTraits::NextBItr NextBItr; + typedef typename ItrTraits::PrevBItr PrevBItr; + typedef typename ItrTraits::StmtItr StmtItr; + + //===----------------------------------------------------===// + // External interface: constructing and running the solver. + //===----------------------------------------------------===// + +public: + DataflowSolver(DFValuesTy& d) : D(d), TF(d.getAnalysisData()) {} + ~DataflowSolver() {} + + /// runOnCFG - Computes dataflow values for all blocks in a CFG. + void runOnCFG(CFG& cfg, bool recordStmtValues = false) { + // Set initial dataflow values and boundary conditions. + D.InitializeValues(cfg); + // Solve the dataflow equations. This will populate D.EdgeDataMap + // with dataflow values. + SolveDataflowEquations(cfg, recordStmtValues); + } + + /// runOnBlock - Computes dataflow values for a given block. This + /// should usually be invoked only after previously computing + /// dataflow values using runOnCFG, as runOnBlock is intended to + /// only be used for querying the dataflow values within a block + /// with and Observer object. + void runOnBlock(const CFGBlock* B, bool recordStmtValues) { + BlockDataMapTy& M = D.getBlockDataMap(); + typename BlockDataMapTy::iterator I = M.find(B); + + if (I != M.end()) { + TF.getVal().copyValues(I->second); + ProcessBlock(B, recordStmtValues, AnalysisDirTag()); + } + } + + void runOnBlock(const CFGBlock& B, bool recordStmtValues) { + runOnBlock(&B, recordStmtValues); + } + void runOnBlock(CFG::iterator& I, bool recordStmtValues) { + runOnBlock(*I, recordStmtValues); + } + void runOnBlock(CFG::const_iterator& I, bool recordStmtValues) { + runOnBlock(*I, recordStmtValues); + } + + void runOnAllBlocks(const CFG& cfg, bool recordStmtValues = false) { + for (CFG::const_iterator I=cfg.begin(), E=cfg.end(); I!=E; ++I) + runOnBlock(I, recordStmtValues); + } + + //===----------------------------------------------------===// + // Internal solver logic. + //===----------------------------------------------------===// + +private: + + /// SolveDataflowEquations - Perform the actual worklist algorithm + /// to compute dataflow values. + void SolveDataflowEquations(CFG& cfg, bool recordStmtValues) { + // Enqueue all blocks to ensure the dataflow values are computed + // for every block. Not all blocks are guaranteed to reach the exit block. + for (CFG::iterator I=cfg.begin(), E=cfg.end(); I!=E; ++I) + WorkList.enqueue(&*I); + + while (!WorkList.isEmpty()) { + const CFGBlock* B = WorkList.dequeue(); + ProcessMerge(cfg,B); + ProcessBlock(B, recordStmtValues, AnalysisDirTag()); + UpdateEdges(cfg,B,TF.getVal()); + } + } + + void ProcessMerge(CFG& cfg, const CFGBlock* B) { + ValTy& V = TF.getVal(); + TF.SetTopValue(V); + + // Merge dataflow values from all predecessors of this block. + MergeOperatorTy Merge; + + EdgeDataMapTy& M = D.getEdgeDataMap(); + bool firstMerge = true; + + for (PrevBItr I=ItrTraits::PrevBegin(B),E=ItrTraits::PrevEnd(B); I!=E; ++I){ + + typename EdgeDataMapTy::iterator EI = + M.find(ItrTraits::PrevEdge(B, *I)); + + if (EI != M.end()) { + if (firstMerge) { + firstMerge = false; + V.copyValues(EI->second); + } + else Merge(V,EI->second); + } + } + + // Set the data for the block. + D.getBlockDataMap()[B].copyValues(V); + } + + /// ProcessBlock - Process the transfer functions for a given block. + void ProcessBlock(const CFGBlock* B, bool recordStmtValues, + dataflow::forward_analysis_tag) { + + for (StmtItr I=ItrTraits::StmtBegin(B), E=ItrTraits::StmtEnd(B); I!=E;++I) + ProcessStmt(*I, recordStmtValues, AnalysisDirTag()); + + TF.VisitTerminator(const_cast<CFGBlock*>(B)); + } + + void ProcessBlock(const CFGBlock* B, bool recordStmtValues, + dataflow::backward_analysis_tag) { + + TF.VisitTerminator(const_cast<CFGBlock*>(B)); + + for (StmtItr I=ItrTraits::StmtBegin(B), E=ItrTraits::StmtEnd(B); I!=E;++I) + ProcessStmt(*I, recordStmtValues, AnalysisDirTag()); + } + + void ProcessStmt(const Stmt* S, bool record, dataflow::forward_analysis_tag) { + if (record) D.getStmtDataMap()[S] = TF.getVal(); + TF.BlockStmt_Visit(const_cast<Stmt*>(S)); + } + + void ProcessStmt(const Stmt* S, bool record, dataflow::backward_analysis_tag){ + TF.BlockStmt_Visit(const_cast<Stmt*>(S)); + if (record) D.getStmtDataMap()[S] = TF.getVal(); + } + + /// UpdateEdges - After processing the transfer functions for a + /// block, update the dataflow value associated with the block's + /// outgoing/incoming edges (depending on whether we do a + // forward/backward analysis respectively) + void UpdateEdges(CFG& cfg, const CFGBlock* B, ValTy& V) { + for (NextBItr I=ItrTraits::NextBegin(B), E=ItrTraits::NextEnd(B); I!=E; ++I) + UpdateEdgeValue(ItrTraits::NextEdge(B, *I),V,*I); + } + + /// UpdateEdgeValue - Update the value associated with a given edge. + void UpdateEdgeValue(BlockEdge E, ValTy& V, const CFGBlock* TargetBlock) { + EdgeDataMapTy& M = D.getEdgeDataMap(); + typename EdgeDataMapTy::iterator I = M.find(E); + + if (I == M.end()) { // First computed value for this edge? + M[E].copyValues(V); + WorkList.enqueue(TargetBlock); + } + else if (!_Equal()(V,I->second)) { + I->second.copyValues(V); + WorkList.enqueue(TargetBlock); + } + } + +private: + DFValuesTy& D; + DataflowWorkListTy WorkList; + TransferFuncsTy TF; +}; + +} // end namespace clang +#endif diff --git a/include/clang/Analysis/FlowSensitive/DataflowValues.h b/include/clang/Analysis/FlowSensitive/DataflowValues.h new file mode 100644 index 000000000000..d6427a5cab47 --- /dev/null +++ b/include/clang/Analysis/FlowSensitive/DataflowValues.h @@ -0,0 +1,172 @@ +//===--- DataflowValues.h - Data structure for dataflow 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 defines a skeleton data structure for encapsulating the dataflow +// values for a CFG. Typically this is subclassed to provide methods for +// computing these values from a CFG. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSES_DATAFLOW_VALUES +#define LLVM_CLANG_ANALYSES_DATAFLOW_VALUES + +#include "clang/AST/CFG.h" +#include "clang/Analysis/ProgramPoint.h" +#include "llvm/ADT/DenseMap.h" + +//===----------------------------------------------------------------------===// +/// Dataflow Directional Tag Classes. These are used for tag dispatching +/// within the dataflow solver/transfer functions to determine what direction +/// a dataflow analysis flows. +//===----------------------------------------------------------------------===// + +namespace clang { +namespace dataflow { + struct forward_analysis_tag {}; + struct backward_analysis_tag {}; +} // end namespace dataflow + +//===----------------------------------------------------------------------===// +/// DataflowValues. Container class to store dataflow values for a CFG. +//===----------------------------------------------------------------------===// + +template <typename ValueTypes, + typename _AnalysisDirTag = dataflow::forward_analysis_tag > +class DataflowValues { + + //===--------------------------------------------------------------------===// + // Type declarations. + //===--------------------------------------------------------------------===// + +public: + typedef typename ValueTypes::ValTy ValTy; + typedef typename ValueTypes::AnalysisDataTy AnalysisDataTy; + typedef _AnalysisDirTag AnalysisDirTag; + typedef llvm::DenseMap<ProgramPoint, ValTy> EdgeDataMapTy; + typedef llvm::DenseMap<const CFGBlock*, ValTy> BlockDataMapTy; + typedef llvm::DenseMap<const Stmt*, ValTy> StmtDataMapTy; + + //===--------------------------------------------------------------------===// + // Predicates. + //===--------------------------------------------------------------------===// + +public: + /// isForwardAnalysis - Returns true if the dataflow values are computed + /// from a forward analysis. + bool isForwardAnalysis() { return isForwardAnalysis(AnalysisDirTag()); } + + /// isBackwardAnalysis - Returns true if the dataflow values are computed + /// from a backward analysis. + bool isBackwardAnalysis() { return !isForwardAnalysis(); } + +private: + bool isForwardAnalysis(dataflow::forward_analysis_tag) { return true; } + bool isForwardAnalysis(dataflow::backward_analysis_tag) { return false; } + + //===--------------------------------------------------------------------===// + // Initialization and accessors methods. + //===--------------------------------------------------------------------===// + +public: + DataflowValues() : StmtDataMap(NULL) {} + ~DataflowValues() { delete StmtDataMap; } + + /// InitializeValues - Invoked by the solver to initialize state needed for + /// dataflow analysis. This method is usually specialized by subclasses. + void InitializeValues(const CFG& cfg) {}; + + + /// getEdgeData - Retrieves the dataflow values associated with a + /// CFG edge. + ValTy& getEdgeData(const BlockEdge& E) { + typename EdgeDataMapTy::iterator I = EdgeDataMap.find(E); + assert (I != EdgeDataMap.end() && "No data associated with Edge."); + return I->second; + } + + const ValTy& getEdgeData(const BlockEdge& E) const { + return reinterpret_cast<DataflowValues*>(this)->getEdgeData(E); + } + + /// getBlockData - Retrieves the dataflow values associated with a + /// specified CFGBlock. If the dataflow analysis is a forward analysis, + /// this data is associated with the END of the block. If the analysis + /// is a backwards analysis, it is associated with the ENTRY of the block. + ValTy& getBlockData(const CFGBlock* B) { + typename BlockDataMapTy::iterator I = BlockDataMap.find(B); + assert (I != BlockDataMap.end() && "No data associated with block."); + return I->second; + } + + const ValTy& getBlockData(const CFGBlock* B) const { + return const_cast<DataflowValues*>(this)->getBlockData(B); + } + + /// getStmtData - Retrieves the dataflow values associated with a + /// specified Stmt. If the dataflow analysis is a forward analysis, + /// this data corresponds to the point immediately before a Stmt. + /// If the analysis is a backwards analysis, it is associated with + /// the point after a Stmt. This data is only computed for block-level + /// expressions, and only when requested when the analysis is executed. + ValTy& getStmtData(const Stmt* S) { + assert (StmtDataMap && "Dataflow values were not computed for statements."); + typename StmtDataMapTy::iterator I = StmtDataMap->find(S); + assert (I != StmtDataMap->end() && "No data associated with statement."); + return I->second; + } + + const ValTy& getStmtData(const Stmt* S) const { + return const_cast<DataflowValues*>(this)->getStmtData(S); + } + + /// getEdgeDataMap - Retrieves the internal map between CFG edges and + /// dataflow values. Usually used by a dataflow solver to compute + /// values for blocks. + EdgeDataMapTy& getEdgeDataMap() { return EdgeDataMap; } + const EdgeDataMapTy& getEdgeDataMap() const { return EdgeDataMap; } + + /// getBlockDataMap - Retrieves the internal map between CFGBlocks and + /// dataflow values. If the dataflow analysis operates in the forward + /// direction, the values correspond to the dataflow values at the start + /// of the block. Otherwise, for a backward analysis, the values correpsond + /// to the dataflow values at the end of the block. + BlockDataMapTy& getBlockDataMap() { return BlockDataMap; } + const BlockDataMapTy& getBlockDataMap() const { return BlockDataMap; } + + /// getStmtDataMap - Retrieves the internal map between Stmts and + /// dataflow values. + StmtDataMapTy& getStmtDataMap() { + if (!StmtDataMap) StmtDataMap = new StmtDataMapTy(); + return *StmtDataMap; + } + + const StmtDataMapTy& getStmtDataMap() const { + return const_cast<DataflowValues*>(this)->getStmtDataMap(); + } + + /// getAnalysisData - Retrieves the meta data associated with a + /// dataflow analysis for analyzing a particular CFG. + /// This is typically consumed by transfer function code (via the solver). + /// This can also be used by subclasses to interpret the dataflow values. + AnalysisDataTy& getAnalysisData() { return AnalysisData; } + const AnalysisDataTy& getAnalysisData() const { return AnalysisData; } + + //===--------------------------------------------------------------------===// + // Internal data. + //===--------------------------------------------------------------------===// + +protected: + EdgeDataMapTy EdgeDataMap; + BlockDataMapTy BlockDataMap; + StmtDataMapTy* StmtDataMap; + AnalysisDataTy AnalysisData; +}; + +} // end namespace clang +#endif diff --git a/include/clang/Analysis/LocalCheckers.h b/include/clang/Analysis/LocalCheckers.h new file mode 100644 index 000000000000..23610f9a2d97 --- /dev/null +++ b/include/clang/Analysis/LocalCheckers.h @@ -0,0 +1,54 @@ +//==- LocalCheckers.h - Intra-Procedural+Flow-Sensitive Checkers -*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the interface to call a set of intra-procedural (local) +// checkers that use flow/path-sensitive analyses to find bugs. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_LOCALCHECKERS_H +#define LLVM_CLANG_ANALYSIS_LOCALCHECKERS_H + +namespace clang { + +class CFG; +class Decl; +class Diagnostic; +class ASTContext; +class PathDiagnosticClient; +class GRTransferFuncs; +class BugType; +class LangOptions; +class ParentMap; +class LiveVariables; +class BugReporter; +class ObjCImplementationDecl; +class LangOptions; +class GRExprEngine; + +void CheckDeadStores(LiveVariables& L, BugReporter& BR); + +void CheckUninitializedValues(CFG& cfg, ASTContext& Ctx, Diagnostic& Diags, + bool FullUninitTaint=false); + +GRTransferFuncs* MakeGRSimpleValsTF(); +GRTransferFuncs* MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled, + const LangOptions& lopts); + +void CheckObjCDealloc(ObjCImplementationDecl* D, const LangOptions& L, + BugReporter& BR); + +void CheckObjCInstMethSignature(ObjCImplementationDecl* ID, BugReporter& BR); +void CheckObjCUnusedIvar(ObjCImplementationDecl* D, BugReporter& BR); + +void RegisterAppleChecks(GRExprEngine& Eng); + +} // end namespace clang + +#endif diff --git a/include/clang/Analysis/PathDiagnostic.h b/include/clang/Analysis/PathDiagnostic.h new file mode 100644 index 000000000000..994b35e5efda --- /dev/null +++ b/include/clang/Analysis/PathDiagnostic.h @@ -0,0 +1,487 @@ +//===--- PathDiagnostic.h - Path-Specific Diagnostic Handling ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the PathDiagnostic-related interfaces. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_PATH_DIAGNOSTIC_H +#define LLVM_CLANG_PATH_DIAGNOSTIC_H + +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/Diagnostic.h" +#include "llvm/ADT/OwningPtr.h" + +#include <vector> +#include <deque> +#include <string> +#include <algorithm> + +namespace clang { + +//===----------------------------------------------------------------------===// +// High-level interface for handlers of path-sensitive diagnostics. +//===----------------------------------------------------------------------===// + +class PathDiagnostic; +class Stmt; +class Decl; +class Preprocessor; + +class PathDiagnosticClient : public DiagnosticClient { +public: + PathDiagnosticClient() {} + virtual ~PathDiagnosticClient() {} + + virtual void SetPreprocessor(Preprocessor *PP) {} + + virtual void HandleDiagnostic(Diagnostic::Level DiagLevel, + const DiagnosticInfo &Info); + + virtual void HandlePathDiagnostic(const PathDiagnostic* D) = 0; + + enum PathGenerationScheme { Minimal, Extensive }; + virtual PathGenerationScheme getGenerationScheme() const { return Minimal; } + virtual bool supportsLogicalOpControlFlow() const { return false; } + virtual bool supportsAllBlockEdges() const { return false; } + virtual bool useVerboseDescription() const { return true; } +}; + +//===----------------------------------------------------------------------===// +// Path-sensitive diagnostics. +//===----------------------------------------------------------------------===// + +class PathDiagnosticRange : public SourceRange { +public: + const bool isPoint; + + PathDiagnosticRange(const SourceRange &R, bool isP = false) + : SourceRange(R), isPoint(isP) {} +}; + +class PathDiagnosticLocation { +private: + enum Kind { RangeK, SingleLocK, StmtK, DeclK } K; + SourceRange R; + const Stmt *S; + const Decl *D; + const SourceManager *SM; +public: + PathDiagnosticLocation() + : K(SingleLocK), S(0), D(0), SM(0) {} + + PathDiagnosticLocation(FullSourceLoc L) + : K(SingleLocK), R(L, L), S(0), D(0), SM(&L.getManager()) {} + + PathDiagnosticLocation(const Stmt *s, const SourceManager &sm) + : K(StmtK), S(s), D(0), SM(&sm) {} + + PathDiagnosticLocation(SourceRange r, const SourceManager &sm) + : K(RangeK), R(r), S(0), D(0), SM(&sm) {} + + PathDiagnosticLocation(const Decl *d, const SourceManager &sm) + : K(DeclK), S(0), D(d), SM(&sm) {} + + bool operator==(const PathDiagnosticLocation &X) const { + return K == X.K && R == X.R && S == X.S && D == X.D; + } + + bool operator!=(const PathDiagnosticLocation &X) const { + return K != X.K || R != X.R || S != X.S || D != X.D;; + } + + PathDiagnosticLocation& operator=(const PathDiagnosticLocation &X) { + K = X.K; + R = X.R; + S = X.S; + D = X.D; + SM = X.SM; + return *this; + } + + bool isValid() const { + return SM != 0; + } + + const SourceManager& getSourceManager() const { assert(isValid());return *SM;} + + FullSourceLoc asLocation() const; + PathDiagnosticRange asRange() const; + const Stmt *asStmt() const { assert(isValid()); return S; } + const Decl *asDecl() const { assert(isValid()); return D; } + + bool hasRange() const { return K == StmtK || K == RangeK || K == DeclK; } + + void invalidate() { + *this = PathDiagnosticLocation(); + } + + void flatten(); + + const SourceManager& getManager() const { assert(isValid()); return *SM; } +}; + +class PathDiagnosticLocationPair { +private: + PathDiagnosticLocation Start, End; +public: + PathDiagnosticLocationPair(const PathDiagnosticLocation &start, + const PathDiagnosticLocation &end) + : Start(start), End(end) {} + + const PathDiagnosticLocation &getStart() const { return Start; } + const PathDiagnosticLocation &getEnd() const { return End; } + + void flatten() { + Start.flatten(); + End.flatten(); + } +}; + +//===----------------------------------------------------------------------===// +// Path "pieces" for path-sensitive diagnostics. +//===----------------------------------------------------------------------===// + +class PathDiagnosticPiece { +public: + enum Kind { ControlFlow, Event, Macro }; + enum DisplayHint { Above, Below }; + +private: + const std::string str; + std::vector<CodeModificationHint> CodeModificationHints; + const Kind kind; + const DisplayHint Hint; + std::vector<SourceRange> ranges; + + // Do not implement: + PathDiagnosticPiece(); + PathDiagnosticPiece(const PathDiagnosticPiece &P); + PathDiagnosticPiece& operator=(const PathDiagnosticPiece &P); + +protected: + PathDiagnosticPiece(const std::string& s, Kind k, DisplayHint hint = Below); + + PathDiagnosticPiece(const char* s, Kind k, DisplayHint hint = Below); + + PathDiagnosticPiece(Kind k, DisplayHint hint = Below); + +public: + virtual ~PathDiagnosticPiece(); + + const std::string& getString() const { return str; } + + /// getDisplayHint - Return a hint indicating where the diagnostic should + /// be displayed by the PathDiagnosticClient. + DisplayHint getDisplayHint() const { return Hint; } + + virtual PathDiagnosticLocation getLocation() const = 0; + virtual void flattenLocations() = 0; + + Kind getKind() const { return kind; } + + void addRange(SourceRange R) { ranges.push_back(R); } + + void addRange(SourceLocation B, SourceLocation E) { + ranges.push_back(SourceRange(B,E)); + } + + void addCodeModificationHint(const CodeModificationHint& Hint) { + CodeModificationHints.push_back(Hint); + } + + typedef const SourceRange* range_iterator; + + range_iterator ranges_begin() const { + return ranges.empty() ? NULL : &ranges[0]; + } + + range_iterator ranges_end() const { + return ranges_begin() + ranges.size(); + } + + typedef const CodeModificationHint *code_modifications_iterator; + + code_modifications_iterator code_modifications_begin() const { + return CodeModificationHints.empty()? 0 : &CodeModificationHints[0]; + } + + code_modifications_iterator code_modifications_end() const { + return CodeModificationHints.empty()? 0 + : &CodeModificationHints[0] + CodeModificationHints.size(); + } + + static inline bool classof(const PathDiagnosticPiece* P) { + return true; + } +}; + +class PathDiagnosticSpotPiece : public PathDiagnosticPiece { +private: + PathDiagnosticLocation Pos; +public: + PathDiagnosticSpotPiece(const PathDiagnosticLocation &pos, + const std::string& s, + PathDiagnosticPiece::Kind k, + bool addPosRange = true) + : PathDiagnosticPiece(s, k), Pos(pos) { + assert(Pos.asLocation().isValid() && + "PathDiagnosticSpotPiece's must have a valid location."); + if (addPosRange && Pos.hasRange()) addRange(Pos.asRange()); + } + + PathDiagnosticLocation getLocation() const { return Pos; } + virtual void flattenLocations() { Pos.flatten(); } +}; + +class PathDiagnosticEventPiece : public PathDiagnosticSpotPiece { + +public: + PathDiagnosticEventPiece(const PathDiagnosticLocation &pos, + const std::string& s, bool addPosRange = true) + : PathDiagnosticSpotPiece(pos, s, Event, addPosRange) {} + + PathDiagnosticEventPiece(const PathDiagnosticLocation &pos, const char* s, + bool addPosRange = true) + : PathDiagnosticSpotPiece(pos, s, Event, addPosRange) {} + + ~PathDiagnosticEventPiece(); + + static inline bool classof(const PathDiagnosticPiece* P) { + return P->getKind() == Event; + } +}; + +class PathDiagnosticControlFlowPiece : public PathDiagnosticPiece { + std::vector<PathDiagnosticLocationPair> LPairs; +public: + PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos, + const PathDiagnosticLocation &endPos, + const std::string& s) + : PathDiagnosticPiece(s, ControlFlow) { + LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos)); + } + + PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos, + const PathDiagnosticLocation &endPos, + const char* s) + : PathDiagnosticPiece(s, ControlFlow) { + LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos)); + } + + PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos, + const PathDiagnosticLocation &endPos) + : PathDiagnosticPiece(ControlFlow) { + LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos)); + } + + ~PathDiagnosticControlFlowPiece(); + + PathDiagnosticLocation getStartLocation() const { + assert(!LPairs.empty() && + "PathDiagnosticControlFlowPiece needs at least one location."); + return LPairs[0].getStart(); + } + + PathDiagnosticLocation getEndLocation() const { + assert(!LPairs.empty() && + "PathDiagnosticControlFlowPiece needs at least one location."); + return LPairs[0].getEnd(); + } + + void push_back(const PathDiagnosticLocationPair &X) { LPairs.push_back(X); } + + virtual PathDiagnosticLocation getLocation() const { + return getStartLocation(); + } + + typedef std::vector<PathDiagnosticLocationPair>::iterator iterator; + iterator begin() { return LPairs.begin(); } + iterator end() { return LPairs.end(); } + + virtual void flattenLocations() { + for (iterator I=begin(), E=end(); I!=E; ++I) I->flatten(); + } + + typedef std::vector<PathDiagnosticLocationPair>::const_iterator + const_iterator; + const_iterator begin() const { return LPairs.begin(); } + const_iterator end() const { return LPairs.end(); } + + static inline bool classof(const PathDiagnosticPiece* P) { + return P->getKind() == ControlFlow; + } +}; + +class PathDiagnosticMacroPiece : public PathDiagnosticSpotPiece { + std::vector<PathDiagnosticPiece*> SubPieces; +public: + PathDiagnosticMacroPiece(const PathDiagnosticLocation &pos) + : PathDiagnosticSpotPiece(pos, "", Macro) {} + + ~PathDiagnosticMacroPiece(); + + bool containsEvent() const; + + void push_back(PathDiagnosticPiece* P) { SubPieces.push_back(P); } + + typedef std::vector<PathDiagnosticPiece*>::iterator iterator; + iterator begin() { return SubPieces.begin(); } + iterator end() { return SubPieces.end(); } + + virtual void flattenLocations() { + PathDiagnosticSpotPiece::flattenLocations(); + for (iterator I=begin(), E=end(); I!=E; ++I) (*I)->flattenLocations(); + } + + typedef std::vector<PathDiagnosticPiece*>::const_iterator const_iterator; + const_iterator begin() const { return SubPieces.begin(); } + const_iterator end() const { return SubPieces.end(); } + + static inline bool classof(const PathDiagnosticPiece* P) { + return P->getKind() == Macro; + } +}; + +/// PathDiagnostic - PathDiagnostic objects represent a single path-sensitive +/// diagnostic. It represents an ordered-collection of PathDiagnosticPieces, +/// each which represent the pieces of the path. +class PathDiagnostic { + std::deque<PathDiagnosticPiece*> path; + unsigned Size; + std::string BugType; + std::string Desc; + std::string Category; + std::deque<std::string> OtherDesc; + +public: + PathDiagnostic(); + + PathDiagnostic(const char* bugtype, const char* desc, const char* category); + + PathDiagnostic(const std::string& bugtype, const std::string& desc, + const std::string& category); + + ~PathDiagnostic(); + + const std::string& getDescription() const { return Desc; } + const std::string& getBugType() const { return BugType; } + const std::string& getCategory() const { return Category; } + + typedef std::deque<std::string>::const_iterator meta_iterator; + meta_iterator meta_begin() const { return OtherDesc.begin(); } + meta_iterator meta_end() const { return OtherDesc.end(); } + void addMeta(const std::string& s) { OtherDesc.push_back(s); } + void addMeta(const char* s) { OtherDesc.push_back(s); } + + PathDiagnosticLocation getLocation() const { + assert(Size > 0 && "getLocation() requires a non-empty PathDiagnostic."); + return rbegin()->getLocation(); + } + + void push_front(PathDiagnosticPiece* piece) { + path.push_front(piece); + ++Size; + } + + void push_back(PathDiagnosticPiece* piece) { + path.push_back(piece); + ++Size; + } + + PathDiagnosticPiece* back() { + return path.back(); + } + + const PathDiagnosticPiece* back() const { + return path.back(); + } + + unsigned size() const { return Size; } + bool empty() const { return Size == 0; } + + void resetPath(bool deletePieces = true); + + class iterator { + public: + typedef std::deque<PathDiagnosticPiece*>::iterator ImplTy; + + typedef PathDiagnosticPiece value_type; + typedef value_type& reference; + typedef value_type* pointer; + typedef ptrdiff_t difference_type; + typedef std::bidirectional_iterator_tag iterator_category; + + private: + ImplTy I; + + public: + iterator(const ImplTy& i) : I(i) {} + + bool operator==(const iterator& X) const { return I == X.I; } + bool operator!=(const iterator& X) const { return I != X.I; } + + PathDiagnosticPiece& operator*() const { return **I; } + PathDiagnosticPiece* operator->() const { return *I; } + + iterator& operator++() { ++I; return *this; } + iterator& operator--() { --I; return *this; } + }; + + class const_iterator { + public: + typedef std::deque<PathDiagnosticPiece*>::const_iterator ImplTy; + + typedef const PathDiagnosticPiece value_type; + typedef value_type& reference; + typedef value_type* pointer; + typedef ptrdiff_t difference_type; + typedef std::bidirectional_iterator_tag iterator_category; + + private: + ImplTy I; + + public: + const_iterator(const ImplTy& i) : I(i) {} + + bool operator==(const const_iterator& X) const { return I == X.I; } + bool operator!=(const const_iterator& X) const { return I != X.I; } + + reference operator*() const { return **I; } + pointer operator->() const { return *I; } + + const_iterator& operator++() { ++I; return *this; } + const_iterator& operator--() { --I; return *this; } + }; + + typedef std::reverse_iterator<iterator> reverse_iterator; + typedef std::reverse_iterator<const_iterator> const_reverse_iterator; + + // forward iterator creation methods. + + iterator begin() { return path.begin(); } + iterator end() { return path.end(); } + + const_iterator begin() const { return path.begin(); } + const_iterator end() const { return path.end(); } + + // reverse iterator creation methods. + reverse_iterator rbegin() { return reverse_iterator(end()); } + const_reverse_iterator rbegin() const{ return const_reverse_iterator(end()); } + reverse_iterator rend() { return reverse_iterator(begin()); } + const_reverse_iterator rend() const { return const_reverse_iterator(begin());} + + void flattenLocations() { + for (iterator I = begin(), E = end(); I != E; ++I) I->flattenLocations(); + } +}; + + +} //end clang namespace +#endif diff --git a/include/clang/Analysis/PathSensitive/BasicValueFactory.h b/include/clang/Analysis/PathSensitive/BasicValueFactory.h new file mode 100644 index 000000000000..b694e9b29940 --- /dev/null +++ b/include/clang/Analysis/PathSensitive/BasicValueFactory.h @@ -0,0 +1,163 @@ +//=== BasicValueFactory.h - Basic values for Path Sens 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 defines BasicValueFactory, a class that manages the lifetime +// of APSInt objects and symbolic constraints used by GRExprEngine +// and related classes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_BASICVALUEFACTORY_H +#define LLVM_CLANG_ANALYSIS_BASICVALUEFACTORY_H + +#include "clang/Analysis/PathSensitive/SymbolManager.h" +#include "clang/Analysis/PathSensitive/SVals.h" +#include "clang/AST/ASTContext.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/APSInt.h" +#include "llvm/ADT/ImmutableList.h" + +namespace clang { + +class CompoundValData : public llvm::FoldingSetNode { + QualType T; + llvm::ImmutableList<SVal> L; + +public: + CompoundValData(QualType t, llvm::ImmutableList<SVal> l) + : T(t), L(l) {} + + typedef llvm::ImmutableList<SVal>::iterator iterator; + iterator begin() const { return L.begin(); } + iterator end() const { return L.end(); } + + static void Profile(llvm::FoldingSetNodeID& ID, QualType T, + llvm::ImmutableList<SVal> L); + + void Profile(llvm::FoldingSetNodeID& ID) { Profile(ID, T, L); } +}; + +class BasicValueFactory { + typedef llvm::FoldingSet<llvm::FoldingSetNodeWrapper<llvm::APSInt> > + APSIntSetTy; + + ASTContext& Ctx; + llvm::BumpPtrAllocator& BPAlloc; + + APSIntSetTy APSIntSet; + void* PersistentSVals; + void* PersistentSValPairs; + + llvm::ImmutableList<SVal>::Factory SValListFactory; + llvm::FoldingSet<CompoundValData> CompoundValDataSet; + +public: + BasicValueFactory(ASTContext& ctx, llvm::BumpPtrAllocator& Alloc) + : Ctx(ctx), BPAlloc(Alloc), PersistentSVals(0), PersistentSValPairs(0), + SValListFactory(Alloc) {} + + ~BasicValueFactory(); + + ASTContext& getContext() const { return Ctx; } + + const llvm::APSInt& getValue(const llvm::APSInt& X); + const llvm::APSInt& getValue(const llvm::APInt& X, bool isUnsigned); + const llvm::APSInt& getValue(uint64_t X, unsigned BitWidth, bool isUnsigned); + const llvm::APSInt& getValue(uint64_t X, QualType T); + + /// Convert - Create a new persistent APSInt with the same value as 'From' + /// but with the bitwidth and signedness of 'To'. + const llvm::APSInt& Convert(const llvm::APSInt& To, + const llvm::APSInt& From) { + + if (To.isUnsigned() == From.isUnsigned() && + To.getBitWidth() == From.getBitWidth()) + return From; + + return getValue(From.getSExtValue(), + To.getBitWidth(), + To.isUnsigned()); + } + + const llvm::APSInt& getIntValue(uint64_t X, bool isUnsigned) { + QualType T = isUnsigned ? Ctx.UnsignedIntTy : Ctx.IntTy; + return getValue(X, T); + } + + inline const llvm::APSInt& getMaxValue(const llvm::APSInt &v) { + return getValue(llvm::APSInt::getMaxValue(v.getBitWidth(), v.isUnsigned())); + } + + inline const llvm::APSInt& getMinValue(const llvm::APSInt &v) { + return getValue(llvm::APSInt::getMinValue(v.getBitWidth(), v.isUnsigned())); + } + + inline const llvm::APSInt& getMaxValue(QualType T) { + assert(T->isIntegerType() || Loc::IsLocType(T)); + bool isUnsigned = T->isUnsignedIntegerType() || Loc::IsLocType(T); + return getValue(llvm::APSInt::getMaxValue(Ctx.getTypeSize(T), isUnsigned)); + } + + inline const llvm::APSInt& getMinValue(QualType T) { + assert(T->isIntegerType() || Loc::IsLocType(T)); + bool isUnsigned = T->isUnsignedIntegerType() || Loc::IsLocType(T); + return getValue(llvm::APSInt::getMinValue(Ctx.getTypeSize(T), isUnsigned)); + } + + inline const llvm::APSInt& Add1(const llvm::APSInt& V) { + llvm::APSInt X = V; + ++X; + return getValue(X); + } + + inline const llvm::APSInt& Sub1(const llvm::APSInt& V) { + llvm::APSInt X = V; + --X; + return getValue(X); + } + + inline const llvm::APSInt& getZeroWithPtrWidth(bool isUnsigned = true) { + return getValue(0, Ctx.getTypeSize(Ctx.VoidPtrTy), isUnsigned); + } + + inline const llvm::APSInt& getTruthValue(bool b, QualType T) { + return getValue(b ? 1 : 0, Ctx.getTypeSize(T), false); + } + + inline const llvm::APSInt& getTruthValue(bool b) { + return getTruthValue(b, Ctx.IntTy); + } + + const CompoundValData* getCompoundValData(QualType T, + llvm::ImmutableList<SVal> Vals); + + llvm::ImmutableList<SVal> getEmptySValList() { + return SValListFactory.GetEmptyList(); + } + + llvm::ImmutableList<SVal> consVals(SVal X, llvm::ImmutableList<SVal> L) { + return SValListFactory.Add(X, L); + } + + const llvm::APSInt* EvaluateAPSInt(BinaryOperator::Opcode Op, + const llvm::APSInt& V1, + const llvm::APSInt& V2); + + const std::pair<SVal, uintptr_t>& + getPersistentSValWithData(const SVal& V, uintptr_t Data); + + const std::pair<SVal, SVal>& + getPersistentSValPair(const SVal& V1, const SVal& V2); + + const SVal* getPersistentSVal(SVal X); +}; + +} // end clang namespace + +#endif diff --git a/include/clang/Analysis/PathSensitive/BugReporter.h b/include/clang/Analysis/PathSensitive/BugReporter.h new file mode 100644 index 000000000000..90fd9d8ebf45 --- /dev/null +++ b/include/clang/Analysis/PathSensitive/BugReporter.h @@ -0,0 +1,466 @@ +//===--- BugReporter.h - Generate PathDiagnostics --------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines BugReporter, a utility class for generating +// PathDiagnostics for analyses based on GRState. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_BUGREPORTER +#define LLVM_CLANG_ANALYSIS_BUGREPORTER + +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Analysis/PathSensitive/GRState.h" +#include "clang/Analysis/PathSensitive/ExplodedGraph.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/ImmutableSet.h" +#include <list> + +namespace clang { + +class PathDiagnostic; +class PathDiagnosticPiece; +class PathDiagnosticClient; +class ASTContext; +class Diagnostic; +class BugReporter; +class BugReporterContext; +class GRExprEngine; +class GRState; +class Stmt; +class BugType; +class ParentMap; + +//===----------------------------------------------------------------------===// +// Interface for individual bug reports. +//===----------------------------------------------------------------------===// + +class BugReporterVisitor { +public: + virtual ~BugReporterVisitor(); + virtual PathDiagnosticPiece* VisitNode(const ExplodedNode<GRState>* N, + const ExplodedNode<GRState>* PrevN, + BugReporterContext& BRC) = 0; + + virtual bool isOwnedByReporterContext() { return true; } +}; + +// FIXME: Combine this with RangedBugReport and remove RangedBugReport. +class BugReport : public BugReporterVisitor { +protected: + BugType& BT; + std::string ShortDescription; + std::string Description; + const ExplodedNode<GRState> *EndNode; + SourceRange R; + +protected: + friend class BugReporter; + friend class BugReportEquivClass; + + virtual void Profile(llvm::FoldingSetNodeID& hash) const { + hash.AddInteger(getLocation().getRawEncoding()); + } + +public: + class NodeResolver { + public: + virtual ~NodeResolver() {} + virtual const ExplodedNode<GRState>* + getOriginalNode(const ExplodedNode<GRState>* N) = 0; + }; + + BugReport(BugType& bt, const char* desc, const ExplodedNode<GRState> *n) + : BT(bt), Description(desc), EndNode(n) {} + + BugReport(BugType& bt, const char* shortDesc, const char* desc, + const ExplodedNode<GRState> *n) + : BT(bt), ShortDescription(shortDesc), Description(desc), EndNode(n) {} + + virtual ~BugReport(); + + virtual bool isOwnedByReporterContext() { return false; } + + const BugType& getBugType() const { return BT; } + BugType& getBugType() { return BT; } + + // FIXME: Perhaps this should be moved into a subclass? + const ExplodedNode<GRState>* getEndNode() const { return EndNode; } + + // FIXME: Do we need this? Maybe getLocation() should return a ProgramPoint + // object. + // FIXME: If we do need it, we can probably just make it private to + // BugReporter. + Stmt* getStmt(BugReporter& BR) const; + + const std::string& getDescription() const { return Description; } + + const std::string& getShortDescription() const { + return ShortDescription.empty() ? Description : ShortDescription; + } + + // FIXME: Is this needed? + virtual std::pair<const char**,const char**> getExtraDescriptiveText() { + return std::make_pair((const char**)0,(const char**)0); + } + + // FIXME: Perhaps move this into a subclass. + virtual PathDiagnosticPiece* getEndPath(BugReporterContext& BRC, + const ExplodedNode<GRState>* N); + + /// getLocation - Return the "definitive" location of the reported bug. + /// While a bug can span an entire path, usually there is a specific + /// location that can be used to identify where the key issue occured. + /// This location is used by clients rendering diagnostics. + virtual SourceLocation getLocation() const; + + /// getRanges - Returns the source ranges associated with this bug. + virtual void getRanges(BugReporter& BR,const SourceRange*& beg, + const SourceRange*& end); + + virtual PathDiagnosticPiece* VisitNode(const ExplodedNode<GRState>* N, + const ExplodedNode<GRState>* PrevN, + BugReporterContext& BR); + + virtual void registerInitialVisitors(BugReporterContext& BRC, + const ExplodedNode<GRState>* N) {} +}; + +//===----------------------------------------------------------------------===// +// BugTypes (collections of related reports). +//===----------------------------------------------------------------------===// + +class BugReportEquivClass : public llvm::FoldingSetNode { + // List of *owned* BugReport objects. + std::list<BugReport*> Reports; + + friend class BugReporter; + void AddReport(BugReport* R) { Reports.push_back(R); } +public: + BugReportEquivClass(BugReport* R) { Reports.push_back(R); } + ~BugReportEquivClass(); + + void Profile(llvm::FoldingSetNodeID& ID) const { + assert(!Reports.empty()); + (*Reports.begin())->Profile(ID); + } + + class iterator { + std::list<BugReport*>::iterator impl; + public: + iterator(std::list<BugReport*>::iterator i) : impl(i) {} + iterator& operator++() { ++impl; return *this; } + bool operator==(const iterator& I) const { return I.impl == impl; } + bool operator!=(const iterator& I) const { return I.impl != impl; } + BugReport* operator*() const { return *impl; } + BugReport* operator->() const { return *impl; } + }; + + class const_iterator { + std::list<BugReport*>::const_iterator impl; + public: + const_iterator(std::list<BugReport*>::const_iterator i) : impl(i) {} + const_iterator& operator++() { ++impl; return *this; } + bool operator==(const const_iterator& I) const { return I.impl == impl; } + bool operator!=(const const_iterator& I) const { return I.impl != impl; } + const BugReport* operator*() const { return *impl; } + const BugReport* operator->() const { return *impl; } + }; + + iterator begin() { return iterator(Reports.begin()); } + iterator end() { return iterator(Reports.end()); } + + const_iterator begin() const { return const_iterator(Reports.begin()); } + const_iterator end() const { return const_iterator(Reports.end()); } +}; + +class BugType { +private: + const std::string Name; + const std::string Category; + llvm::FoldingSet<BugReportEquivClass> EQClasses; + friend class BugReporter; +public: + BugType(const char *name, const char* cat) : Name(name), Category(cat) {} + virtual ~BugType(); + + // FIXME: Should these be made strings as well? + const std::string& getName() const { return Name; } + const std::string& getCategory() const { return Category; } + + virtual void FlushReports(BugReporter& BR); + void AddReport(BugReport* BR); + + typedef llvm::FoldingSet<BugReportEquivClass>::iterator iterator; + iterator begin() { return EQClasses.begin(); } + iterator end() { return EQClasses.end(); } + + typedef llvm::FoldingSet<BugReportEquivClass>::const_iterator const_iterator; + const_iterator begin() const { return EQClasses.begin(); } + const_iterator end() const { return EQClasses.end(); } +}; + +//===----------------------------------------------------------------------===// +// Specialized subclasses of BugReport. +//===----------------------------------------------------------------------===// + +// FIXME: Collapse this with the default BugReport class. +class RangedBugReport : public BugReport { + std::vector<SourceRange> Ranges; +public: + RangedBugReport(BugType& D, const char* description, ExplodedNode<GRState> *n) + : BugReport(D, description, n) {} + + RangedBugReport(BugType& D, const char *shortDescription, + const char *description, ExplodedNode<GRState> *n) + : BugReport(D, shortDescription, description, n) {} + + ~RangedBugReport(); + + // FIXME: Move this out of line. + void addRange(SourceRange R) { Ranges.push_back(R); } + + // FIXME: Move this out of line. + void getRanges(BugReporter& BR,const SourceRange*& beg, + const SourceRange*& end) { + + if (Ranges.empty()) { + beg = NULL; + end = NULL; + } + else { + beg = &Ranges[0]; + end = beg + Ranges.size(); + } + } +}; + +//===----------------------------------------------------------------------===// +// BugReporter and friends. +//===----------------------------------------------------------------------===// + +class BugReporterData { +public: + virtual ~BugReporterData(); + virtual Diagnostic& getDiagnostic() = 0; + virtual PathDiagnosticClient* getPathDiagnosticClient() = 0; + virtual ASTContext& getContext() = 0; + virtual SourceManager& getSourceManager() = 0; + virtual CFG* getCFG() = 0; + virtual ParentMap& getParentMap() = 0; + virtual LiveVariables* getLiveVariables() = 0; +}; + +class BugReporter { +public: + enum Kind { BaseBRKind, GRBugReporterKind }; + +private: + typedef llvm::ImmutableSet<BugType*> BugTypesTy; + BugTypesTy::Factory F; + BugTypesTy BugTypes; + + const Kind kind; + BugReporterData& D; + + void FlushReport(BugReportEquivClass& EQ); + +protected: + BugReporter(BugReporterData& d, Kind k) : BugTypes(F.GetEmptySet()), kind(k), D(d) {} + +public: + BugReporter(BugReporterData& d) : BugTypes(F.GetEmptySet()), kind(BaseBRKind), D(d) {} + virtual ~BugReporter(); + + void FlushReports(); + + Kind getKind() const { return kind; } + + Diagnostic& getDiagnostic() { + return D.getDiagnostic(); + } + + PathDiagnosticClient* getPathDiagnosticClient() { + return D.getPathDiagnosticClient(); + } + + typedef BugTypesTy::iterator iterator; + iterator begin() { return BugTypes.begin(); } + iterator end() { return BugTypes.end(); } + + ASTContext& getContext() { return D.getContext(); } + + SourceManager& getSourceManager() { return D.getSourceManager(); } + + CFG* getCFG() { return D.getCFG(); } + + ParentMap& getParentMap() { return D.getParentMap(); } + + LiveVariables* getLiveVariables() { return D.getLiveVariables(); } + + virtual void GeneratePathDiagnostic(PathDiagnostic& PD, + BugReportEquivClass& EQ) {} + + void Register(BugType *BT); + + void EmitReport(BugReport *R); + + void EmitBasicReport(const char* BugName, const char* BugStr, + SourceLocation Loc, + SourceRange* RangeBeg, unsigned NumRanges); + + void EmitBasicReport(const char* BugName, const char* BugCategory, + const char* BugStr, SourceLocation Loc, + SourceRange* RangeBeg, unsigned NumRanges); + + + void EmitBasicReport(const char* BugName, const char* BugStr, + SourceLocation Loc) { + EmitBasicReport(BugName, BugStr, Loc, 0, 0); + } + + void EmitBasicReport(const char* BugName, const char* BugCategory, + const char* BugStr, SourceLocation Loc) { + EmitBasicReport(BugName, BugCategory, BugStr, Loc, 0, 0); + } + + void EmitBasicReport(const char* BugName, const char* BugStr, + SourceLocation Loc, SourceRange R) { + EmitBasicReport(BugName, BugStr, Loc, &R, 1); + } + + void EmitBasicReport(const char* BugName, const char* Category, + const char* BugStr, SourceLocation Loc, SourceRange R) { + EmitBasicReport(BugName, Category, BugStr, Loc, &R, 1); + } + + static bool classof(const BugReporter* R) { return true; } +}; + +// FIXME: Get rid of GRBugReporter. It's the wrong abstraction. +class GRBugReporter : public BugReporter { + GRExprEngine& Eng; + llvm::SmallSet<SymbolRef, 10> NotableSymbols; +public: + GRBugReporter(BugReporterData& d, GRExprEngine& eng) + : BugReporter(d, GRBugReporterKind), Eng(eng) {} + + virtual ~GRBugReporter(); + + /// getEngine - Return the analysis engine used to analyze a given + /// function or method. + GRExprEngine& getEngine() { return Eng; } + + /// getGraph - Get the exploded graph created by the analysis engine + /// for the analyzed method or function. + ExplodedGraph<GRState>& getGraph(); + + /// getStateManager - Return the state manager used by the analysis + /// engine. + GRStateManager& getStateManager(); + + virtual void GeneratePathDiagnostic(PathDiagnostic& PD, + BugReportEquivClass& R); + + void addNotableSymbol(SymbolRef Sym) { + NotableSymbols.insert(Sym); + } + + bool isNotable(SymbolRef Sym) const { + return (bool) NotableSymbols.count(Sym); + } + + /// classof - Used by isa<>, cast<>, and dyn_cast<>. + static bool classof(const BugReporter* R) { + return R->getKind() == GRBugReporterKind; + } +}; + +class BugReporterContext { + GRBugReporter &BR; + std::vector<BugReporterVisitor*> Callbacks; +public: + BugReporterContext(GRBugReporter& br) : BR(br) {} + virtual ~BugReporterContext(); + + void addVisitor(BugReporterVisitor* visitor) { + if (visitor) Callbacks.push_back(visitor); + } + + typedef std::vector<BugReporterVisitor*>::iterator visitor_iterator; + visitor_iterator visitor_begin() { return Callbacks.begin(); } + visitor_iterator visitor_end() { return Callbacks.end(); } + + GRBugReporter& getBugReporter() { return BR; } + + ExplodedGraph<GRState>& getGraph() { return BR.getGraph(); } + + void addNotableSymbol(SymbolRef Sym) { + // FIXME: For now forward to GRBugReporter. + BR.addNotableSymbol(Sym); + } + + bool isNotable(SymbolRef Sym) const { + // FIXME: For now forward to GRBugReporter. + return BR.isNotable(Sym); + } + + GRStateManager& getStateManager() { + return BR.getStateManager(); + } + + ValueManager& getValueManager() { + return getStateManager().getValueManager(); + } + + ASTContext& getASTContext() { + return BR.getContext(); + } + + SourceManager& getSourceManager() { + return BR.getSourceManager(); + } + + const Decl& getCodeDecl() { + return getStateManager().getCodeDecl(); + } + + const CFG& getCFG() { + return *BR.getCFG(); + } + + virtual BugReport::NodeResolver& getNodeResolver() = 0; +}; + +class DiagBugReport : public RangedBugReport { + std::list<std::string> Strs; + FullSourceLoc L; +public: + DiagBugReport(BugType& D, const char* desc, FullSourceLoc l) : + RangedBugReport(D, desc, 0), L(l) {} + + virtual ~DiagBugReport() {} + + // FIXME: Move out-of-line (virtual function). + SourceLocation getLocation() const { return L; } + + void addString(const std::string& s) { Strs.push_back(s); } + + typedef std::list<std::string>::const_iterator str_iterator; + str_iterator str_begin() const { return Strs.begin(); } + str_iterator str_end() const { return Strs.end(); } +}; + +} // end clang namespace + +#endif diff --git a/include/clang/Analysis/PathSensitive/ConstraintManager.h b/include/clang/Analysis/PathSensitive/ConstraintManager.h new file mode 100644 index 000000000000..c8e5e85c8a1a --- /dev/null +++ b/include/clang/Analysis/PathSensitive/ConstraintManager.h @@ -0,0 +1,67 @@ +//== ConstraintManager.h - Constraints on symbolic 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 defined the interface to manage constraints on symbolic values. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_CONSTRAINT_MANAGER_H +#define LLVM_CLANG_ANALYSIS_CONSTRAINT_MANAGER_H + +// FIXME: Typedef LiveSymbolsTy/DeadSymbolsTy at a more appropriate place. +#include "clang/Analysis/PathSensitive/Store.h" + +namespace llvm { +class APSInt; +} + +namespace clang { + +class GRState; +class GRStateManager; +class SVal; + +class ConstraintManager { +public: + virtual ~ConstraintManager(); + virtual const GRState* Assume(const GRState* St, SVal Cond, + bool Assumption, bool& isFeasible) = 0; + + virtual const GRState* AssumeInBound(const GRState* St, SVal Idx, + SVal UpperBound, bool Assumption, + bool& isFeasible) = 0; + + virtual const llvm::APSInt* getSymVal(const GRState* St, SymbolRef sym) + const = 0; + + virtual bool isEqual(const GRState* St, SymbolRef sym, + const llvm::APSInt& V) const = 0; + + virtual const GRState* RemoveDeadBindings(const GRState* St, + SymbolReaper& SymReaper) = 0; + + virtual void print(const GRState* St, std::ostream& Out, + const char* nl, const char *sep) = 0; + + virtual void EndPath(const GRState* St) {} + + /// canReasonAbout - Not all ConstraintManagers can accurately reason about + /// all SVal values. This method returns true if the ConstraintManager can + /// reasonably handle a given SVal value. This is typically queried by + /// GRExprEngine to determine if the value should be replaced with a + /// conjured symbolic value in order to recover some precision. + virtual bool canReasonAbout(SVal X) const = 0; +}; + +ConstraintManager* CreateBasicConstraintManager(GRStateManager& statemgr); +ConstraintManager* CreateRangeConstraintManager(GRStateManager& statemgr); + +} // end clang namespace + +#endif diff --git a/include/clang/Analysis/PathSensitive/Environment.h b/include/clang/Analysis/PathSensitive/Environment.h new file mode 100644 index 000000000000..fde8b167f3c7 --- /dev/null +++ b/include/clang/Analysis/PathSensitive/Environment.h @@ -0,0 +1,151 @@ +//== Environment.h - Map from Stmt* to Locations/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 defined the Environment and EnvironmentManager classes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_ENVIRONMENT_H +#define LLVM_CLANG_ANALYSIS_ENVIRONMENT_H + +// For using typedefs in StoreManager. Should find a better place for these +// typedefs. +#include "clang/Analysis/PathSensitive/Store.h" + +#include "llvm/ADT/ImmutableMap.h" +#include "llvm/ADT/SmallVector.h" +#include "clang/Analysis/PathSensitive/SVals.h" +#include "llvm/Support/Allocator.h" +#include "llvm/ADT/FoldingSet.h" + +namespace clang { + +class EnvironmentManager; +class BasicValueFactory; +class LiveVariables; + +class Environment : public llvm::FoldingSetNode { +private: + + friend class EnvironmentManager; + + // Type definitions. + typedef llvm::ImmutableMap<Stmt*,SVal> BindingsTy; + + // Data. + BindingsTy SubExprBindings; + BindingsTy BlkExprBindings; + + Environment(BindingsTy seb, BindingsTy beb) + : SubExprBindings(seb), BlkExprBindings(beb) {} + +public: + + typedef BindingsTy::iterator seb_iterator; + seb_iterator seb_begin() const { return SubExprBindings.begin(); } + seb_iterator seb_end() const { return SubExprBindings.end(); } + + typedef BindingsTy::iterator beb_iterator; + beb_iterator beb_begin() const { return BlkExprBindings.begin(); } + beb_iterator beb_end() const { return BlkExprBindings.end(); } + + SVal LookupSubExpr(Stmt* E) const { + const SVal* X = SubExprBindings.lookup(cast<Expr>(E)); + return X ? *X : UnknownVal(); + } + + SVal LookupBlkExpr(Stmt* E) const { + const SVal* X = BlkExprBindings.lookup(E); + return X ? *X : UnknownVal(); + } + + SVal LookupExpr(Stmt* E) const { + const SVal* X = SubExprBindings.lookup(E); + if (X) return *X; + X = BlkExprBindings.lookup(E); + return X ? *X : UnknownVal(); + } + + SVal GetSVal(Stmt* Ex, BasicValueFactory& BasicVals) const; + SVal GetBlkExprSVal(Stmt* Ex, BasicValueFactory& BasicVals) const; + + /// Profile - Profile the contents of an Environment object for use + /// in a FoldingSet. + static void Profile(llvm::FoldingSetNodeID& ID, const Environment* E) { + E->SubExprBindings.Profile(ID); + E->BlkExprBindings.Profile(ID); + } + + /// Profile - Used to profile the contents of this object for inclusion + /// in a FoldingSet. + void Profile(llvm::FoldingSetNodeID& ID) const { + Profile(ID, this); + } + + bool operator==(const Environment& RHS) const { + return SubExprBindings == RHS.SubExprBindings && + BlkExprBindings == RHS.BlkExprBindings; + } +}; + +class EnvironmentManager { +private: + typedef Environment::BindingsTy::Factory FactoryTy; + FactoryTy F; + +public: + + EnvironmentManager(llvm::BumpPtrAllocator& Allocator) : F(Allocator) {} + ~EnvironmentManager() {} + + /// RemoveBlkExpr - Return a new environment object with the same bindings as + /// the provided environment except with any bindings for the provided Stmt* + /// removed. This method only removes bindings for block-level expressions. + /// Using this method on a non-block level expression will return the + /// same environment object. + Environment RemoveBlkExpr(const Environment& Env, Stmt* E) { + return Environment(Env.SubExprBindings, F.Remove(Env.BlkExprBindings, E)); + } + + Environment RemoveSubExpr(const Environment& Env, Stmt* E) { + return Environment(F.Remove(Env.SubExprBindings, E), Env.BlkExprBindings); + } + + Environment AddBlkExpr(const Environment& Env, Stmt* E, SVal V) { + return Environment(Env.SubExprBindings, F.Add(Env.BlkExprBindings, E, V)); + } + + Environment AddSubExpr(const Environment& Env, Stmt* E, SVal V) { + return Environment(F.Add(Env.SubExprBindings, E, V), Env.BlkExprBindings); + } + + /// RemoveSubExprBindings - Return a new environment object with + /// the same bindings as the provided environment except with all the + /// subexpression bindings removed. + Environment RemoveSubExprBindings(const Environment& Env) { + return Environment(F.GetEmptyMap(), Env.BlkExprBindings); + } + + Environment getInitialEnvironment() { + return Environment(F.GetEmptyMap(), F.GetEmptyMap()); + } + + Environment BindExpr(const Environment& Env, Stmt* E, SVal V, + bool isBlkExpr, bool Invalidate); + + Environment + RemoveDeadBindings(Environment Env, Stmt* Loc, SymbolReaper& SymReaper, + GRStateManager& StateMgr, const GRState *state, + llvm::SmallVectorImpl<const MemRegion*>& DRoots); + +}; + +} // end clang namespace + +#endif diff --git a/include/clang/Analysis/PathSensitive/ExplodedGraph.h b/include/clang/Analysis/PathSensitive/ExplodedGraph.h new file mode 100644 index 000000000000..8494d935650d --- /dev/null +++ b/include/clang/Analysis/PathSensitive/ExplodedGraph.h @@ -0,0 +1,582 @@ +//=-- ExplodedGraph.h - Local, Path-Sens. "Exploded Graph" -*- C++ -*-------==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the template classes ExplodedNode and ExplodedGraph, +// which represent a path-sensitive, intra-procedural "exploded graph." +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_EXPLODEDGRAPH +#define LLVM_CLANG_ANALYSIS_EXPLODEDGRAPH + +#include "clang/Analysis/ProgramPoint.h" +#include "clang/AST/Decl.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/Support/Allocator.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/GraphTraits.h" +#include "llvm/ADT/DepthFirstIterator.h" +#include "llvm/Support/Casting.h" + +namespace clang { + +class GRCoreEngineImpl; +class ExplodedNodeImpl; +class CFG; +class ASTContext; + +class GRStmtNodeBuilderImpl; +class GRBranchNodeBuilderImpl; +class GRIndirectGotoNodeBuilderImpl; +class GRSwitchNodeBuilderImpl; +class GREndPathNodebuilderImpl; + +//===----------------------------------------------------------------------===// +// ExplodedGraph "implementation" classes. These classes are not typed to +// contain a specific kind of state. Typed-specialized versions are defined +// on top of these classes. +//===----------------------------------------------------------------------===// + +class ExplodedNodeImpl : public llvm::FoldingSetNode { +protected: + friend class ExplodedGraphImpl; + friend class GRCoreEngineImpl; + friend class GRStmtNodeBuilderImpl; + friend class GRBranchNodeBuilderImpl; + friend class GRIndirectGotoNodeBuilderImpl; + friend class GRSwitchNodeBuilderImpl; + friend class GREndPathNodeBuilderImpl; + + class NodeGroup { + enum { Size1 = 0x0, SizeOther = 0x1, AuxFlag = 0x2, Mask = 0x3 }; + uintptr_t P; + + unsigned getKind() const { + return P & 0x1; + } + + void* getPtr() const { + assert (!getFlag()); + return reinterpret_cast<void*>(P & ~Mask); + } + + ExplodedNodeImpl* getNode() const { + return reinterpret_cast<ExplodedNodeImpl*>(getPtr()); + } + + public: + NodeGroup() : P(0) {} + + ~NodeGroup(); + + ExplodedNodeImpl** begin() const; + + ExplodedNodeImpl** end() const; + + unsigned size() const; + + bool empty() const { return size() == 0; } + + void addNode(ExplodedNodeImpl* N); + + void setFlag() { + assert (P == 0); + P = AuxFlag; + } + + bool getFlag() const { + return P & AuxFlag ? true : false; + } + }; + + /// Location - The program location (within a function body) associated + /// with this node. + const ProgramPoint Location; + + /// State - The state associated with this node. + const void* State; + + /// Preds - The predecessors of this node. + NodeGroup Preds; + + /// Succs - The successors of this node. + NodeGroup Succs; + + /// Construct a ExplodedNodeImpl with the provided location and state. + explicit ExplodedNodeImpl(const ProgramPoint& loc, const void* state) + : Location(loc), State(state) {} + + /// addPredeccessor - Adds a predecessor to the current node, and + /// in tandem add this node as a successor of the other node. + void addPredecessor(ExplodedNodeImpl* V); + +public: + + /// getLocation - Returns the edge associated with the given node. + ProgramPoint getLocation() const { return Location; } + + template <typename T> + const T* getLocationAs() const { return llvm::dyn_cast<T>(&Location); } + + unsigned succ_size() const { return Succs.size(); } + unsigned pred_size() const { return Preds.size(); } + bool succ_empty() const { return Succs.empty(); } + bool pred_empty() const { return Preds.empty(); } + + bool isSink() const { return Succs.getFlag(); } + void markAsSink() { Succs.setFlag(); } + + // For debugging. + +public: + + class Auditor { + public: + virtual ~Auditor(); + virtual void AddEdge(ExplodedNodeImpl* Src, ExplodedNodeImpl* Dst) = 0; + }; + + static void SetAuditor(Auditor* A); +}; + + +template <typename StateTy> +struct GRTrait { + static inline void Profile(llvm::FoldingSetNodeID& ID, const StateTy* St) { + St->Profile(ID); + } +}; + + +template <typename StateTy> +class ExplodedNode : public ExplodedNodeImpl { +public: + /// Construct a ExplodedNodeImpl with the given node ID, program edge, + /// and state. + explicit ExplodedNode(const ProgramPoint& loc, const StateTy* St) + : ExplodedNodeImpl(loc, St) {} + + /// getState - Returns the state associated with the node. + inline const StateTy* getState() const { + return static_cast<const StateTy*>(State); + } + + // Profiling (for FoldingSet). + + static inline void Profile(llvm::FoldingSetNodeID& ID, + const ProgramPoint& Loc, + const StateTy* state) { + ID.Add(Loc); + GRTrait<StateTy>::Profile(ID, state); + } + + inline void Profile(llvm::FoldingSetNodeID& ID) const { + Profile(ID, getLocation(), getState()); + } + + void addPredecessor(ExplodedNode* V) { + ExplodedNodeImpl::addPredecessor(V); + } + + ExplodedNode* getFirstPred() { + return pred_empty() ? NULL : *(pred_begin()); + } + + const ExplodedNode* getFirstPred() const { + return const_cast<ExplodedNode*>(this)->getFirstPred(); + } + + // Iterators over successor and predecessor vertices. + typedef ExplodedNode** succ_iterator; + typedef const ExplodedNode* const * const_succ_iterator; + typedef ExplodedNode** pred_iterator; + typedef const ExplodedNode* const * const_pred_iterator; + + pred_iterator pred_begin() { return (ExplodedNode**) Preds.begin(); } + pred_iterator pred_end() { return (ExplodedNode**) Preds.end(); } + + const_pred_iterator pred_begin() const { + return const_cast<ExplodedNode*>(this)->pred_begin(); + } + const_pred_iterator pred_end() const { + return const_cast<ExplodedNode*>(this)->pred_end(); + } + + succ_iterator succ_begin() { return (ExplodedNode**) Succs.begin(); } + succ_iterator succ_end() { return (ExplodedNode**) Succs.end(); } + + const_succ_iterator succ_begin() const { + return const_cast<ExplodedNode*>(this)->succ_begin(); + } + const_succ_iterator succ_end() const { + return const_cast<ExplodedNode*>(this)->succ_end(); + } +}; + +class InterExplodedGraphMapImpl; + +class ExplodedGraphImpl { +protected: + friend class GRCoreEngineImpl; + friend class GRStmtNodeBuilderImpl; + friend class GRBranchNodeBuilderImpl; + friend class GRIndirectGotoNodeBuilderImpl; + friend class GRSwitchNodeBuilderImpl; + friend class GREndPathNodeBuilderImpl; + + // Type definitions. + typedef llvm::SmallVector<ExplodedNodeImpl*,2> RootsTy; + typedef llvm::SmallVector<ExplodedNodeImpl*,10> EndNodesTy; + + /// Roots - The roots of the simulation graph. Usually there will be only + /// one, but clients are free to establish multiple subgraphs within a single + /// SimulGraph. Moreover, these subgraphs can often merge when paths from + /// different roots reach the same state at the same program location. + RootsTy Roots; + + /// EndNodes - The nodes in the simulation graph which have been + /// specially marked as the endpoint of an abstract simulation path. + EndNodesTy EndNodes; + + /// Allocator - BumpPtrAllocator to create nodes. + llvm::BumpPtrAllocator Allocator; + + /// cfg - The CFG associated with this analysis graph. + CFG& cfg; + + /// CodeDecl - The declaration containing the code being analyzed. This + /// can be a FunctionDecl or and ObjCMethodDecl. + Decl& CodeDecl; + + /// Ctx - The ASTContext used to "interpret" CodeDecl. + ASTContext& Ctx; + + /// NumNodes - The number of nodes in the graph. + unsigned NumNodes; + + /// getNodeImpl - Retrieve the node associated with a (Location,State) + /// pair, where 'State' is represented as an opaque void*. This method + /// is intended to be used only by GRCoreEngineImpl. + virtual ExplodedNodeImpl* getNodeImpl(const ProgramPoint& L, + const void* State, + bool* IsNew) = 0; + + virtual ExplodedGraphImpl* MakeEmptyGraph() const = 0; + + /// addRoot - Add an untyped node to the set of roots. + ExplodedNodeImpl* addRoot(ExplodedNodeImpl* V) { + Roots.push_back(V); + return V; + } + + /// addEndOfPath - Add an untyped node to the set of EOP nodes. + ExplodedNodeImpl* addEndOfPath(ExplodedNodeImpl* V) { + EndNodes.push_back(V); + return V; + } + + // ctor. + ExplodedGraphImpl(CFG& c, Decl& cd, ASTContext& ctx) + : cfg(c), CodeDecl(cd), Ctx(ctx), NumNodes(0) {} + +public: + virtual ~ExplodedGraphImpl() {} + + unsigned num_roots() const { return Roots.size(); } + unsigned num_eops() const { return EndNodes.size(); } + + bool empty() const { return NumNodes == 0; } + unsigned size() const { return NumNodes; } + + llvm::BumpPtrAllocator& getAllocator() { return Allocator; } + CFG& getCFG() { return cfg; } + ASTContext& getContext() { return Ctx; } + + Decl& getCodeDecl() { return CodeDecl; } + const Decl& getCodeDecl() const { return CodeDecl; } + + const FunctionDecl* getFunctionDecl() const { + return llvm::dyn_cast<FunctionDecl>(&CodeDecl); + } + + typedef llvm::DenseMap<const ExplodedNodeImpl*, ExplodedNodeImpl*> NodeMap; + + ExplodedGraphImpl* Trim(const ExplodedNodeImpl* const * NBeg, + const ExplodedNodeImpl* const * NEnd, + InterExplodedGraphMapImpl *M, + llvm::DenseMap<const void*, const void*> *InverseMap) + const; +}; + +class InterExplodedGraphMapImpl { + llvm::DenseMap<const ExplodedNodeImpl*, ExplodedNodeImpl*> M; + friend class ExplodedGraphImpl; + void add(const ExplodedNodeImpl* From, ExplodedNodeImpl* To); + +protected: + ExplodedNodeImpl* getMappedImplNode(const ExplodedNodeImpl* N) const; + + InterExplodedGraphMapImpl(); +public: + virtual ~InterExplodedGraphMapImpl() {} +}; + +//===----------------------------------------------------------------------===// +// Type-specialized ExplodedGraph classes. +//===----------------------------------------------------------------------===// + +template <typename STATE> +class InterExplodedGraphMap : public InterExplodedGraphMapImpl { +public: + InterExplodedGraphMap() {}; + ~InterExplodedGraphMap() {}; + + ExplodedNode<STATE>* getMappedNode(const ExplodedNode<STATE>* N) const { + return static_cast<ExplodedNode<STATE>*>(getMappedImplNode(N)); + } +}; + +template <typename STATE> +class ExplodedGraph : public ExplodedGraphImpl { +public: + typedef STATE StateTy; + typedef ExplodedNode<StateTy> NodeTy; + typedef llvm::FoldingSet<NodeTy> AllNodesTy; + +protected: + /// Nodes - The nodes in the graph. + AllNodesTy Nodes; + +protected: + virtual ExplodedNodeImpl* getNodeImpl(const ProgramPoint& L, + const void* State, + bool* IsNew) { + + return getNode(L, static_cast<const StateTy*>(State), IsNew); + } + + virtual ExplodedGraphImpl* MakeEmptyGraph() const { + return new ExplodedGraph(cfg, CodeDecl, Ctx); + } + +public: + ExplodedGraph(CFG& c, Decl& cd, ASTContext& ctx) + : ExplodedGraphImpl(c, cd, ctx) {} + + /// getNode - Retrieve the node associated with a (Location,State) pair, + /// where the 'Location' is a ProgramPoint in the CFG. If no node for + /// this pair exists, it is created. IsNew is set to true if + /// the node was freshly created. + NodeTy* getNode(const ProgramPoint& L, const StateTy* State, + bool* IsNew = NULL) { + + // Profile 'State' to determine if we already have an existing node. + llvm::FoldingSetNodeID profile; + void* InsertPos = 0; + + NodeTy::Profile(profile, L, State); + NodeTy* V = Nodes.FindNodeOrInsertPos(profile, InsertPos); + + if (!V) { + // Allocate a new node. + V = (NodeTy*) Allocator.Allocate<NodeTy>(); + new (V) NodeTy(L, State); + + // Insert the node into the node set and return it. + Nodes.InsertNode(V, InsertPos); + + ++NumNodes; + + if (IsNew) *IsNew = true; + } + else + if (IsNew) *IsNew = false; + + return V; + } + + // Iterators. + typedef NodeTy** roots_iterator; + typedef const NodeTy** const_roots_iterator; + typedef NodeTy** eop_iterator; + typedef const NodeTy** const_eop_iterator; + typedef typename AllNodesTy::iterator node_iterator; + typedef typename AllNodesTy::const_iterator const_node_iterator; + + node_iterator nodes_begin() { + return Nodes.begin(); + } + + node_iterator nodes_end() { + return Nodes.end(); + } + + const_node_iterator nodes_begin() const { + return Nodes.begin(); + } + + const_node_iterator nodes_end() const { + return Nodes.end(); + } + + roots_iterator roots_begin() { + return reinterpret_cast<roots_iterator>(Roots.begin()); + } + + roots_iterator roots_end() { + return reinterpret_cast<roots_iterator>(Roots.end()); + } + + const_roots_iterator roots_begin() const { + return const_cast<ExplodedGraph>(this)->roots_begin(); + } + + const_roots_iterator roots_end() const { + return const_cast<ExplodedGraph>(this)->roots_end(); + } + + eop_iterator eop_begin() { + return reinterpret_cast<eop_iterator>(EndNodes.begin()); + } + + eop_iterator eop_end() { + return reinterpret_cast<eop_iterator>(EndNodes.end()); + } + + const_eop_iterator eop_begin() const { + return const_cast<ExplodedGraph>(this)->eop_begin(); + } + + const_eop_iterator eop_end() const { + return const_cast<ExplodedGraph>(this)->eop_end(); + } + + std::pair<ExplodedGraph*, InterExplodedGraphMap<STATE>*> + Trim(const NodeTy* const* NBeg, const NodeTy* const* NEnd, + llvm::DenseMap<const void*, const void*> *InverseMap = 0) const { + + if (NBeg == NEnd) + return std::make_pair((ExplodedGraph*) 0, + (InterExplodedGraphMap<STATE>*) 0); + + assert (NBeg < NEnd); + + const ExplodedNodeImpl* const* NBegImpl = + (const ExplodedNodeImpl* const*) NBeg; + const ExplodedNodeImpl* const* NEndImpl = + (const ExplodedNodeImpl* const*) NEnd; + + llvm::OwningPtr<InterExplodedGraphMap<STATE> > + M(new InterExplodedGraphMap<STATE>()); + + ExplodedGraphImpl* G = ExplodedGraphImpl::Trim(NBegImpl, NEndImpl, M.get(), + InverseMap); + + return std::make_pair(static_cast<ExplodedGraph*>(G), M.take()); + } +}; + +template <typename StateTy> +class ExplodedNodeSet { + + typedef ExplodedNode<StateTy> NodeTy; + typedef llvm::SmallPtrSet<NodeTy*,5> ImplTy; + ImplTy Impl; + +public: + ExplodedNodeSet(NodeTy* N) { + assert (N && !static_cast<ExplodedNodeImpl*>(N)->isSink()); + Impl.insert(N); + } + + ExplodedNodeSet() {} + + inline void Add(NodeTy* N) { + if (N && !static_cast<ExplodedNodeImpl*>(N)->isSink()) Impl.insert(N); + } + + typedef typename ImplTy::iterator iterator; + typedef typename ImplTy::const_iterator const_iterator; + + inline unsigned size() const { return Impl.size(); } + inline bool empty() const { return Impl.empty(); } + + inline void clear() { Impl.clear(); } + + inline iterator begin() { return Impl.begin(); } + inline iterator end() { return Impl.end(); } + + inline const_iterator begin() const { return Impl.begin(); } + inline const_iterator end() const { return Impl.end(); } +}; + +} // end clang namespace + +// GraphTraits + +namespace llvm { + template<typename StateTy> + struct GraphTraits<clang::ExplodedNode<StateTy>*> { + typedef clang::ExplodedNode<StateTy> NodeType; + typedef typename NodeType::succ_iterator ChildIteratorType; + typedef llvm::df_iterator<NodeType*> nodes_iterator; + + static inline NodeType* getEntryNode(NodeType* N) { + return N; + } + + static inline ChildIteratorType child_begin(NodeType* N) { + return N->succ_begin(); + } + + static inline ChildIteratorType child_end(NodeType* N) { + return N->succ_end(); + } + + static inline nodes_iterator nodes_begin(NodeType* N) { + return df_begin(N); + } + + static inline nodes_iterator nodes_end(NodeType* N) { + return df_end(N); + } + }; + + template<typename StateTy> + struct GraphTraits<const clang::ExplodedNode<StateTy>*> { + typedef const clang::ExplodedNode<StateTy> NodeType; + typedef typename NodeType::succ_iterator ChildIteratorType; + typedef llvm::df_iterator<NodeType*> nodes_iterator; + + static inline NodeType* getEntryNode(NodeType* N) { + return N; + } + + static inline ChildIteratorType child_begin(NodeType* N) { + return N->succ_begin(); + } + + static inline ChildIteratorType child_end(NodeType* N) { + return N->succ_end(); + } + + static inline nodes_iterator nodes_begin(NodeType* N) { + return df_begin(N); + } + + static inline nodes_iterator nodes_end(NodeType* N) { + return df_end(N); + } + }; + +} // end llvm namespace + +#endif diff --git a/include/clang/Analysis/PathSensitive/GRAuditor.h b/include/clang/Analysis/PathSensitive/GRAuditor.h new file mode 100644 index 000000000000..eca591d4af0e --- /dev/null +++ b/include/clang/Analysis/PathSensitive/GRAuditor.h @@ -0,0 +1,39 @@ +//==- GRAuditor.h - Observers of the creation of ExplodedNodes------*- C++ -*-// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines GRAuditor and its primary subclasses, an interface +// to audit the creation of ExplodedNodes. This interface can be used +// to implement simple checkers that do not mutate analysis state but +// instead operate by perfoming simple logical checks at key monitoring +// locations (e.g., function calls). +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_GRAUDITOR +#define LLVM_CLANG_ANALYSIS_GRAUDITOR + +#include "clang/AST/Expr.h" +#include "clang/Analysis/PathSensitive/ExplodedGraph.h" + +namespace clang { + +template <typename STATE> +class GRAuditor { +public: + typedef ExplodedNode<STATE> NodeTy; + typedef typename STATE::ManagerTy ManagerTy; + + virtual ~GRAuditor() {} + virtual bool Audit(NodeTy* N, ManagerTy& M) = 0; +}; + + +} // end clang namespace + +#endif diff --git a/include/clang/Analysis/PathSensitive/GRBlockCounter.h b/include/clang/Analysis/PathSensitive/GRBlockCounter.h new file mode 100644 index 000000000000..b4fd2704b81a --- /dev/null +++ b/include/clang/Analysis/PathSensitive/GRBlockCounter.h @@ -0,0 +1,50 @@ +//==- GRBlockCounter.h - ADT for counting block visits -------------*- C++ -*-// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines GRBlockCounter, an abstract data type used to count +// the number of times a given block has been visited along a path +// analyzed by GRCoreEngine. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_GRBLOCKCOUNTER +#define LLVM_CLANG_ANALYSIS_GRBLOCKCOUNTER + +namespace llvm { + class BumpPtrAllocator; +} + +namespace clang { + +class GRBlockCounter { + void* Data; + + GRBlockCounter(void* D) : Data(D) {} + +public: + GRBlockCounter() : Data(0) {} + + unsigned getNumVisited(unsigned BlockID) const; + + class Factory { + void* F; + public: + Factory(llvm::BumpPtrAllocator& Alloc); + ~Factory(); + + GRBlockCounter GetEmptyCounter(); + GRBlockCounter IncrementCount(GRBlockCounter BC, unsigned BlockID); + }; + + friend class Factory; +}; + +} // end clang namespace + +#endif diff --git a/include/clang/Analysis/PathSensitive/GRCoreEngine.h b/include/clang/Analysis/PathSensitive/GRCoreEngine.h new file mode 100644 index 000000000000..0fbdbde55bd5 --- /dev/null +++ b/include/clang/Analysis/PathSensitive/GRCoreEngine.h @@ -0,0 +1,668 @@ +//==- GRCoreEngine.h - Path-Sensitive Dataflow Engine ------------------*- C++ -*-// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines a generic engine for intraprocedural, path-sensitive, +// dataflow analysis via graph reachability. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_GRENGINE +#define LLVM_CLANG_ANALYSIS_GRENGINE + +#include "clang/AST/Expr.h" +#include "clang/Analysis/PathSensitive/ExplodedGraph.h" +#include "clang/Analysis/PathSensitive/GRWorkList.h" +#include "clang/Analysis/PathSensitive/GRBlockCounter.h" +#include "clang/Analysis/PathSensitive/GRAuditor.h" +#include "llvm/ADT/OwningPtr.h" + +namespace clang { + +class GRStmtNodeBuilderImpl; +class GRBranchNodeBuilderImpl; +class GRIndirectGotoNodeBuilderImpl; +class GRSwitchNodeBuilderImpl; +class GREndPathNodeBuilderImpl; +class GRWorkList; + +//===----------------------------------------------------------------------===// +/// GRCoreEngineImpl - Implements the core logic of the graph-reachability +/// analysis. It traverses the CFG and generates the ExplodedGraph. +/// Program "states" are treated as opaque void pointers. +/// The template class GRCoreEngine (which subclasses GRCoreEngineImpl) +/// provides the matching component to the engine that knows the actual types +/// for states. Note that this engine only dispatches to transfer functions +/// at the statement and block-level. The analyses themselves must implement +/// any transfer function logic and the sub-expression level (if any). +class GRCoreEngineImpl { +protected: + friend class GRStmtNodeBuilderImpl; + friend class GRBranchNodeBuilderImpl; + friend class GRIndirectGotoNodeBuilderImpl; + friend class GRSwitchNodeBuilderImpl; + friend class GREndPathNodeBuilderImpl; + + /// G - The simulation graph. Each node is a (location,state) pair. + llvm::OwningPtr<ExplodedGraphImpl> G; + + /// WList - A set of queued nodes that need to be processed by the + /// worklist algorithm. It is up to the implementation of WList to decide + /// the order that nodes are processed. + GRWorkList* WList; + + /// BCounterFactory - A factory object for created GRBlockCounter objects. + /// These are used to record for key nodes in the ExplodedGraph the + /// number of times different CFGBlocks have been visited along a path. + GRBlockCounter::Factory BCounterFactory; + + void GenerateNode(const ProgramPoint& Loc, const void* State, + ExplodedNodeImpl* Pred); + + /// getInitialState - Gets the void* representing the initial 'state' + /// of the analysis. This is simply a wrapper (implemented + /// in GRCoreEngine) that performs type erasure on the initial + /// state returned by the checker object. + virtual const void* getInitialState() = 0; + + void HandleBlockEdge(const BlockEdge& E, ExplodedNodeImpl* Pred); + void HandleBlockEntrance(const BlockEntrance& E, ExplodedNodeImpl* Pred); + void HandleBlockExit(CFGBlock* B, ExplodedNodeImpl* Pred); + void HandlePostStmt(const PostStmt& S, CFGBlock* B, + unsigned StmtIdx, ExplodedNodeImpl *Pred); + + void HandleBranch(Stmt* Cond, Stmt* Term, CFGBlock* B, + ExplodedNodeImpl* Pred); + + virtual void ProcessEndPath(GREndPathNodeBuilderImpl& Builder) = 0; + + virtual bool ProcessBlockEntrance(CFGBlock* Blk, const void* State, + GRBlockCounter BC) = 0; + + virtual void ProcessStmt(Stmt* S, GRStmtNodeBuilderImpl& Builder) = 0; + + virtual void ProcessBranch(Stmt* Condition, Stmt* Terminator, + GRBranchNodeBuilderImpl& Builder) = 0; + + virtual void ProcessIndirectGoto(GRIndirectGotoNodeBuilderImpl& Builder) = 0; + + virtual void ProcessSwitch(GRSwitchNodeBuilderImpl& Builder) = 0; + +private: + GRCoreEngineImpl(const GRCoreEngineImpl&); // Do not implement. + GRCoreEngineImpl& operator=(const GRCoreEngineImpl&); + +protected: + GRCoreEngineImpl(ExplodedGraphImpl* g, GRWorkList* wl) + : G(g), WList(wl), BCounterFactory(g->getAllocator()) {} + +public: + /// ExecuteWorkList - Run the worklist algorithm for a maximum number of + /// steps. Returns true if there is still simulation state on the worklist. + bool ExecuteWorkList(unsigned Steps); + + virtual ~GRCoreEngineImpl(); + + CFG& getCFG() { return G->getCFG(); } +}; + +class GRStmtNodeBuilderImpl { + GRCoreEngineImpl& Eng; + CFGBlock& B; + const unsigned Idx; + ExplodedNodeImpl* Pred; + ExplodedNodeImpl* LastNode; + + typedef llvm::SmallPtrSet<ExplodedNodeImpl*,5> DeferredTy; + DeferredTy Deferred; + + void GenerateAutoTransition(ExplodedNodeImpl* N); + +public: + GRStmtNodeBuilderImpl(CFGBlock* b, unsigned idx, + ExplodedNodeImpl* N, GRCoreEngineImpl* e); + + ~GRStmtNodeBuilderImpl(); + + ExplodedNodeImpl* getBasePredecessor() const { return Pred; } + + ExplodedNodeImpl* getLastNode() const { + return LastNode ? (LastNode->isSink() ? NULL : LastNode) : NULL; + } + + GRBlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();} + + unsigned getCurrentBlockCount() const { + return getBlockCounter().getNumVisited(B.getBlockID()); + } + + ExplodedNodeImpl* + generateNodeImpl(PostStmt PP, const void* State, ExplodedNodeImpl* Pred); + + ExplodedNodeImpl* + generateNodeImpl(Stmt* S, const void* State, ExplodedNodeImpl* Pred, + ProgramPoint::Kind K = ProgramPoint::PostStmtKind, + const void *tag = 0); + + ExplodedNodeImpl* + generateNodeImpl(Stmt* S, const void* State, + ProgramPoint::Kind K = ProgramPoint::PostStmtKind, + const void *tag = 0) { + ExplodedNodeImpl* N = getLastNode(); + assert (N && "Predecessor of new node is infeasible."); + return generateNodeImpl(S, State, N, K, tag); + } + + ExplodedNodeImpl* + generateNodeImpl(Stmt* S, const void* State, const void *tag = 0) { + ExplodedNodeImpl* N = getLastNode(); + assert (N && "Predecessor of new node is infeasible."); + return generateNodeImpl(S, State, N, ProgramPoint::PostStmtKind, tag); + } + + /// getStmt - Return the current block-level expression associated with + /// this builder. + Stmt* getStmt() const { return B[Idx]; } + + /// getBlock - Return the CFGBlock associated with the block-level expression + /// of this builder. + CFGBlock* getBlock() const { return &B; } +}; + + +template<typename STATE> +class GRStmtNodeBuilder { +public: + typedef STATE StateTy; + typedef typename StateTy::ManagerTy StateManagerTy; + typedef ExplodedNode<StateTy> NodeTy; + +private: + GRStmtNodeBuilderImpl& NB; + StateManagerTy& Mgr; + const StateTy* CleanedState; + GRAuditor<StateTy>* Auditor; + +public: + GRStmtNodeBuilder(GRStmtNodeBuilderImpl& nb, StateManagerTy& mgr) : + NB(nb), Mgr(mgr), Auditor(0), PurgingDeadSymbols(false), + BuildSinks(false), HasGeneratedNode(false), + PointKind(ProgramPoint::PostStmtKind), Tag(0) { + + CleanedState = getLastNode()->getState(); + } + + void setAuditor(GRAuditor<StateTy>* A) { + Auditor = A; + } + + NodeTy* getLastNode() const { + return static_cast<NodeTy*>(NB.getLastNode()); + } + + NodeTy* generateNode(PostStmt PP, const StateTy* St, NodeTy* Pred) { + HasGeneratedNode = true; + return static_cast<NodeTy*>(NB.generateNodeImpl(PP, St, Pred)); + } + + NodeTy* generateNode(Stmt* S, const StateTy* St, NodeTy* Pred, + ProgramPoint::Kind K) { + HasGeneratedNode = true; + if (PurgingDeadSymbols) K = ProgramPoint::PostPurgeDeadSymbolsKind; + return static_cast<NodeTy*>(NB.generateNodeImpl(S, St, Pred, K, Tag)); + } + + NodeTy* generateNode(Stmt* S, const StateTy* St, NodeTy* Pred) { + return generateNode(S, St, Pred, PointKind); + } + + NodeTy* generateNode(Stmt* S, const StateTy* St, ProgramPoint::Kind K) { + HasGeneratedNode = true; + if (PurgingDeadSymbols) K = ProgramPoint::PostPurgeDeadSymbolsKind; + return static_cast<NodeTy*>(NB.generateNodeImpl(S, St, K, Tag)); + } + + NodeTy* generateNode(Stmt* S, const StateTy* St) { + return generateNode(S, St, PointKind); + } + + + GRBlockCounter getBlockCounter() const { + return NB.getBlockCounter(); + } + + unsigned getCurrentBlockCount() const { + return NB.getCurrentBlockCount(); + } + + const StateTy* GetState(NodeTy* Pred) const { + if ((ExplodedNodeImpl*) Pred == NB.getBasePredecessor()) + return CleanedState; + else + return Pred->getState(); + } + + void SetCleanedState(const StateTy* St) { + CleanedState = St; + } + + NodeTy* MakeNode(ExplodedNodeSet<StateTy>& Dst, Stmt* S, + NodeTy* Pred, const StateTy* St) { + return MakeNode(Dst, S, Pred, St, PointKind); + } + + NodeTy* MakeNode(ExplodedNodeSet<StateTy>& Dst, Stmt* S, + NodeTy* Pred, const StateTy* St, ProgramPoint::Kind K) { + + const StateTy* PredState = GetState(Pred); + + // If the state hasn't changed, don't generate a new node. + if (!BuildSinks && St == PredState && Auditor == 0) { + Dst.Add(Pred); + return NULL; + } + + NodeTy* N = generateNode(S, St, Pred, K); + + if (N) { + if (BuildSinks) + N->markAsSink(); + else { + if (Auditor && Auditor->Audit(N, Mgr)) + N->markAsSink(); + + Dst.Add(N); + } + } + + return N; + } + + NodeTy* MakeSinkNode(ExplodedNodeSet<StateTy>& Dst, Stmt* S, + NodeTy* Pred, const StateTy* St) { + bool Tmp = BuildSinks; + BuildSinks = true; + NodeTy* N = MakeNode(Dst, S, Pred, St); + BuildSinks = Tmp; + return N; + } + + bool PurgingDeadSymbols; + bool BuildSinks; + bool HasGeneratedNode; + ProgramPoint::Kind PointKind; + const void *Tag; +}; + +class GRBranchNodeBuilderImpl { + GRCoreEngineImpl& Eng; + CFGBlock* Src; + CFGBlock* DstT; + CFGBlock* DstF; + ExplodedNodeImpl* Pred; + + typedef llvm::SmallVector<ExplodedNodeImpl*,3> DeferredTy; + DeferredTy Deferred; + + bool GeneratedTrue; + bool GeneratedFalse; + +public: + GRBranchNodeBuilderImpl(CFGBlock* src, CFGBlock* dstT, CFGBlock* dstF, + ExplodedNodeImpl* pred, GRCoreEngineImpl* e) + : Eng(*e), Src(src), DstT(dstT), DstF(dstF), Pred(pred), + GeneratedTrue(false), GeneratedFalse(false) {} + + ~GRBranchNodeBuilderImpl(); + + ExplodedNodeImpl* getPredecessor() const { return Pred; } + const ExplodedGraphImpl& getGraph() const { return *Eng.G; } + GRBlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();} + + ExplodedNodeImpl* generateNodeImpl(const void* State, bool branch); + + CFGBlock* getTargetBlock(bool branch) const { + return branch ? DstT : DstF; + } + + void markInfeasible(bool branch) { + if (branch) GeneratedTrue = true; + else GeneratedFalse = true; + } +}; + +template<typename STATE> +class GRBranchNodeBuilder { + typedef STATE StateTy; + typedef ExplodedGraph<StateTy> GraphTy; + typedef typename GraphTy::NodeTy NodeTy; + + GRBranchNodeBuilderImpl& NB; + +public: + GRBranchNodeBuilder(GRBranchNodeBuilderImpl& nb) : NB(nb) {} + + const GraphTy& getGraph() const { + return static_cast<const GraphTy&>(NB.getGraph()); + } + + NodeTy* getPredecessor() const { + return static_cast<NodeTy*>(NB.getPredecessor()); + } + + const StateTy* getState() const { + return getPredecessor()->getState(); + } + + NodeTy* generateNode(const StateTy* St, bool branch) { + return static_cast<NodeTy*>(NB.generateNodeImpl(St, branch)); + } + + GRBlockCounter getBlockCounter() const { + return NB.getBlockCounter(); + } + + CFGBlock* getTargetBlock(bool branch) const { + return NB.getTargetBlock(branch); + } + + void markInfeasible(bool branch) { + NB.markInfeasible(branch); + } +}; + +class GRIndirectGotoNodeBuilderImpl { + GRCoreEngineImpl& Eng; + CFGBlock* Src; + CFGBlock& DispatchBlock; + Expr* E; + ExplodedNodeImpl* Pred; +public: + GRIndirectGotoNodeBuilderImpl(ExplodedNodeImpl* pred, CFGBlock* src, + Expr* e, CFGBlock* dispatch, + GRCoreEngineImpl* eng) + : Eng(*eng), Src(src), DispatchBlock(*dispatch), E(e), Pred(pred) {} + + + class Iterator { + CFGBlock::succ_iterator I; + + friend class GRIndirectGotoNodeBuilderImpl; + Iterator(CFGBlock::succ_iterator i) : I(i) {} + public: + + Iterator& operator++() { ++I; return *this; } + bool operator!=(const Iterator& X) const { return I != X.I; } + + LabelStmt* getLabel() const { + return llvm::cast<LabelStmt>((*I)->getLabel()); + } + + CFGBlock* getBlock() const { + return *I; + } + }; + + Iterator begin() { return Iterator(DispatchBlock.succ_begin()); } + Iterator end() { return Iterator(DispatchBlock.succ_end()); } + + ExplodedNodeImpl* generateNodeImpl(const Iterator& I, const void* State, + bool isSink); + + Expr* getTarget() const { return E; } + const void* getState() const { return Pred->State; } +}; + +template<typename STATE> +class GRIndirectGotoNodeBuilder { + typedef STATE StateTy; + typedef ExplodedGraph<StateTy> GraphTy; + typedef typename GraphTy::NodeTy NodeTy; + + GRIndirectGotoNodeBuilderImpl& NB; + +public: + GRIndirectGotoNodeBuilder(GRIndirectGotoNodeBuilderImpl& nb) : NB(nb) {} + + typedef GRIndirectGotoNodeBuilderImpl::Iterator iterator; + + iterator begin() { return NB.begin(); } + iterator end() { return NB.end(); } + + Expr* getTarget() const { return NB.getTarget(); } + + NodeTy* generateNode(const iterator& I, const StateTy* St, bool isSink=false){ + return static_cast<NodeTy*>(NB.generateNodeImpl(I, St, isSink)); + } + + const StateTy* getState() const { + return static_cast<const StateTy*>(NB.getState()); + } +}; + +class GRSwitchNodeBuilderImpl { + GRCoreEngineImpl& Eng; + CFGBlock* Src; + Expr* Condition; + ExplodedNodeImpl* Pred; +public: + GRSwitchNodeBuilderImpl(ExplodedNodeImpl* pred, CFGBlock* src, + Expr* condition, GRCoreEngineImpl* eng) + : Eng(*eng), Src(src), Condition(condition), Pred(pred) {} + + class Iterator { + CFGBlock::succ_reverse_iterator I; + + friend class GRSwitchNodeBuilderImpl; + Iterator(CFGBlock::succ_reverse_iterator i) : I(i) {} + public: + + Iterator& operator++() { ++I; return *this; } + bool operator!=(const Iterator& X) const { return I != X.I; } + + CaseStmt* getCase() const { + return llvm::cast<CaseStmt>((*I)->getLabel()); + } + + CFGBlock* getBlock() const { + return *I; + } + }; + + Iterator begin() { return Iterator(Src->succ_rbegin()+1); } + Iterator end() { return Iterator(Src->succ_rend()); } + + ExplodedNodeImpl* generateCaseStmtNodeImpl(const Iterator& I, + const void* State); + + ExplodedNodeImpl* generateDefaultCaseNodeImpl(const void* State, + bool isSink); + + Expr* getCondition() const { return Condition; } + const void* getState() const { return Pred->State; } +}; + +template<typename STATE> +class GRSwitchNodeBuilder { + typedef STATE StateTy; + typedef ExplodedGraph<StateTy> GraphTy; + typedef typename GraphTy::NodeTy NodeTy; + + GRSwitchNodeBuilderImpl& NB; + +public: + GRSwitchNodeBuilder(GRSwitchNodeBuilderImpl& nb) : NB(nb) {} + + typedef GRSwitchNodeBuilderImpl::Iterator iterator; + + iterator begin() { return NB.begin(); } + iterator end() { return NB.end(); } + + Expr* getCondition() const { return NB.getCondition(); } + + NodeTy* generateCaseStmtNode(const iterator& I, const StateTy* St) { + return static_cast<NodeTy*>(NB.generateCaseStmtNodeImpl(I, St)); + } + + NodeTy* generateDefaultCaseNode(const StateTy* St, bool isSink = false) { + return static_cast<NodeTy*>(NB.generateDefaultCaseNodeImpl(St, isSink)); + } + + const StateTy* getState() const { + return static_cast<const StateTy*>(NB.getState()); + } +}; + + +class GREndPathNodeBuilderImpl { + GRCoreEngineImpl& Eng; + CFGBlock& B; + ExplodedNodeImpl* Pred; + bool HasGeneratedNode; + +public: + GREndPathNodeBuilderImpl(CFGBlock* b, ExplodedNodeImpl* N, + GRCoreEngineImpl* e) + : Eng(*e), B(*b), Pred(N), HasGeneratedNode(false) {} + + ~GREndPathNodeBuilderImpl(); + + ExplodedNodeImpl* getPredecessor() const { return Pred; } + + GRBlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();} + + unsigned getCurrentBlockCount() const { + return getBlockCounter().getNumVisited(B.getBlockID()); + } + + ExplodedNodeImpl* generateNodeImpl(const void* State, + const void *tag = 0, + ExplodedNodeImpl *P = 0); + + CFGBlock* getBlock() const { return &B; } +}; + + +template<typename STATE> +class GREndPathNodeBuilder { + typedef STATE StateTy; + typedef ExplodedNode<StateTy> NodeTy; + + GREndPathNodeBuilderImpl& NB; + +public: + GREndPathNodeBuilder(GREndPathNodeBuilderImpl& nb) : NB(nb) {} + + NodeTy* getPredecessor() const { + return static_cast<NodeTy*>(NB.getPredecessor()); + } + + GRBlockCounter getBlockCounter() const { + return NB.getBlockCounter(); + } + + unsigned getCurrentBlockCount() const { + return NB.getCurrentBlockCount(); + } + + const StateTy* getState() const { + return getPredecessor()->getState(); + } + + NodeTy* MakeNode(const StateTy* St, const void *tag = 0) { + return static_cast<NodeTy*>(NB.generateNodeImpl(St, tag)); + } + + NodeTy *generateNode(const StateTy *St, NodeTy *Pred, const void *tag = 0) { + return static_cast<NodeTy*>(NB.generateNodeImpl(St, tag, Pred)); + } +}; + + +template<typename SUBENGINE> +class GRCoreEngine : public GRCoreEngineImpl { +public: + typedef SUBENGINE SubEngineTy; + typedef typename SubEngineTy::StateTy StateTy; + typedef typename StateTy::ManagerTy StateManagerTy; + typedef ExplodedGraph<StateTy> GraphTy; + typedef typename GraphTy::NodeTy NodeTy; + +protected: + SubEngineTy& SubEngine; + + virtual const void* getInitialState() { + return SubEngine.getInitialState(); + } + + virtual void ProcessEndPath(GREndPathNodeBuilderImpl& BuilderImpl) { + GREndPathNodeBuilder<StateTy> Builder(BuilderImpl); + SubEngine.ProcessEndPath(Builder); + } + + virtual void ProcessStmt(Stmt* S, GRStmtNodeBuilderImpl& BuilderImpl) { + GRStmtNodeBuilder<StateTy> Builder(BuilderImpl,SubEngine.getStateManager()); + SubEngine.ProcessStmt(S, Builder); + } + + virtual bool ProcessBlockEntrance(CFGBlock* Blk, const void* State, + GRBlockCounter BC) { + return SubEngine.ProcessBlockEntrance(Blk, + static_cast<const StateTy*>(State), + BC); + } + + virtual void ProcessBranch(Stmt* Condition, Stmt* Terminator, + GRBranchNodeBuilderImpl& BuilderImpl) { + GRBranchNodeBuilder<StateTy> Builder(BuilderImpl); + SubEngine.ProcessBranch(Condition, Terminator, Builder); + } + + virtual void ProcessIndirectGoto(GRIndirectGotoNodeBuilderImpl& BuilderImpl) { + GRIndirectGotoNodeBuilder<StateTy> Builder(BuilderImpl); + SubEngine.ProcessIndirectGoto(Builder); + } + + virtual void ProcessSwitch(GRSwitchNodeBuilderImpl& BuilderImpl) { + GRSwitchNodeBuilder<StateTy> Builder(BuilderImpl); + SubEngine.ProcessSwitch(Builder); + } + +public: + /// Construct a GRCoreEngine object to analyze the provided CFG using + /// a DFS exploration of the exploded graph. + GRCoreEngine(CFG& cfg, Decl& cd, ASTContext& ctx, SubEngineTy& subengine) + : GRCoreEngineImpl(new GraphTy(cfg, cd, ctx), + GRWorkList::MakeBFS()), + SubEngine(subengine) {} + + /// Construct a GRCoreEngine object to analyze the provided CFG and to + /// use the provided worklist object to execute the worklist algorithm. + /// The GRCoreEngine object assumes ownership of 'wlist'. + GRCoreEngine(CFG& cfg, Decl& cd, ASTContext& ctx, GRWorkList* wlist, + SubEngineTy& subengine) + : GRCoreEngineImpl(new GraphTy(cfg, cd, ctx), wlist), + SubEngine(subengine) {} + + virtual ~GRCoreEngine() {} + + /// getGraph - Returns the exploded graph. + GraphTy& getGraph() { + return *static_cast<GraphTy*>(G.get()); + } + + /// takeGraph - Returns the exploded graph. Ownership of the graph is + /// transfered to the caller. + GraphTy* takeGraph() { + return static_cast<GraphTy*>(G.take()); + } +}; + +} // end clang namespace + +#endif diff --git a/include/clang/Analysis/PathSensitive/GRExprEngine.h b/include/clang/Analysis/PathSensitive/GRExprEngine.h new file mode 100644 index 000000000000..2068b1beaa13 --- /dev/null +++ b/include/clang/Analysis/PathSensitive/GRExprEngine.h @@ -0,0 +1,738 @@ +//===-- GRExprEngine.h - Path-Sensitive Expression-Level Dataflow ---*- C++ -*-= +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines a meta-engine for path-sensitive dataflow analysis that +// is built on GRCoreEngine, but provides the boilerplate to execute transfer +// functions and build the ExplodedGraph at the expression level. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_GREXPRENGINE +#define LLVM_CLANG_ANALYSIS_GREXPRENGINE + +#include "clang/Analysis/PathSensitive/GRCoreEngine.h" +#include "clang/Analysis/PathSensitive/GRState.h" +#include "clang/Analysis/PathSensitive/GRSimpleAPICheck.h" +#include "clang/Analysis/PathSensitive/GRTransferFuncs.h" +#include "clang/Analysis/PathSensitive/BugReporter.h" +#include "clang/AST/Type.h" +#include "clang/AST/ExprObjC.h" + +namespace clang { + + class PathDiagnosticClient; + class Diagnostic; + class ObjCForCollectionStmt; + +class GRExprEngine { +public: + typedef GRState StateTy; + typedef ExplodedGraph<StateTy> GraphTy; + typedef GraphTy::NodeTy NodeTy; + + // Builders. + typedef GRStmtNodeBuilder<StateTy> StmtNodeBuilder; + typedef GRBranchNodeBuilder<StateTy> BranchNodeBuilder; + typedef GRIndirectGotoNodeBuilder<StateTy> IndirectGotoNodeBuilder; + typedef GRSwitchNodeBuilder<StateTy> SwitchNodeBuilder; + typedef GREndPathNodeBuilder<StateTy> EndPathNodeBuilder; + typedef ExplodedNodeSet<StateTy> NodeSet; + +protected: + GRCoreEngine<GRExprEngine> CoreEngine; + + /// G - the simulation graph. + GraphTy& G; + + /// Liveness - live-variables information the ValueDecl* and block-level + /// Expr* in the CFG. Used to prune out dead state. + LiveVariables& Liveness; + + /// Builder - The current GRStmtNodeBuilder which is used when building the + /// nodes for a given statement. + StmtNodeBuilder* Builder; + + /// StateMgr - Object that manages the data for all created states. + GRStateManager StateMgr; + + /// SymMgr - Object that manages the symbol information. + SymbolManager& SymMgr; + + /// ValMgr - Object that manages/creates SVals. + ValueManager &ValMgr; + + /// EntryNode - The immediate predecessor node. + NodeTy* EntryNode; + + /// CleanedState - The state for EntryNode "cleaned" of all dead + /// variables and symbols (as determined by a liveness analysis). + const GRState* CleanedState; + + /// CurrentStmt - The current block-level statement. + Stmt* CurrentStmt; + + // Obj-C Class Identifiers. + IdentifierInfo* NSExceptionII; + + // Obj-C Selectors. + Selector* NSExceptionInstanceRaiseSelectors; + Selector RaiseSel; + + llvm::OwningPtr<GRSimpleAPICheck> BatchAuditor; + + /// PurgeDead - Remove dead bindings before processing a statement. + bool PurgeDead; + + /// BR - The BugReporter associated with this engine. It is important that + // this object be placed at the very end of member variables so that its + // destructor is called before the rest of the GRExprEngine is destroyed. + GRBugReporter BR; + + /// EargerlyAssume - A flag indicating how the engine should handle + // expressions such as: 'x = (y != 0)'. When this flag is true then + // the subexpression 'y != 0' will be eagerly assumed to be true or false, + // thus evaluating it to the integers 0 or 1 respectively. The upside + // is that this can increase analysis precision until we have a better way + // to lazily evaluate such logic. The downside is that it eagerly + // bifurcates paths. + const bool EagerlyAssume; + +public: + typedef llvm::SmallPtrSet<NodeTy*,2> ErrorNodes; + typedef llvm::DenseMap<NodeTy*, Expr*> UndefArgsTy; + + /// NilReceiverStructRetExplicit - Nodes in the ExplodedGraph that resulted + /// from [x ...] with 'x' definitely being nil and the result was a 'struct' + // (an undefined value). + ErrorNodes NilReceiverStructRetExplicit; + + /// NilReceiverStructRetImplicit - Nodes in the ExplodedGraph that resulted + /// from [x ...] with 'x' possibly being nil and the result was a 'struct' + // (an undefined value). + ErrorNodes NilReceiverStructRetImplicit; + + /// NilReceiverLargerThanVoidPtrRetExplicit - Nodes in the ExplodedGraph that + /// resulted from [x ...] with 'x' definitely being nil and the result's size + // was larger than sizeof(void *) (an undefined value). + ErrorNodes NilReceiverLargerThanVoidPtrRetExplicit; + + /// NilReceiverLargerThanVoidPtrRetImplicit - Nodes in the ExplodedGraph that + /// resulted from [x ...] with 'x' possibly being nil and the result's size + // was larger than sizeof(void *) (an undefined value). + ErrorNodes NilReceiverLargerThanVoidPtrRetImplicit; + + /// RetsStackAddr - Nodes in the ExplodedGraph that result from returning + /// the address of a stack variable. + ErrorNodes RetsStackAddr; + + /// RetsUndef - Nodes in the ExplodedGraph that result from returning + /// an undefined value. + ErrorNodes RetsUndef; + + /// UndefBranches - Nodes in the ExplodedGraph that result from + /// taking a branch based on an undefined value. + ErrorNodes UndefBranches; + + /// UndefStores - Sinks in the ExplodedGraph that result from + /// making a store to an undefined lvalue. + ErrorNodes UndefStores; + + /// NoReturnCalls - Sinks in the ExplodedGraph that result from + // calling a function with the attribute "noreturn". + ErrorNodes NoReturnCalls; + + /// ImplicitNullDeref - Nodes in the ExplodedGraph that result from + /// taking a dereference on a symbolic pointer that MAY be NULL. + ErrorNodes ImplicitNullDeref; + + /// ExplicitNullDeref - Nodes in the ExplodedGraph that result from + /// taking a dereference on a symbolic pointer that MUST be NULL. + ErrorNodes ExplicitNullDeref; + + /// UnitDeref - Nodes in the ExplodedGraph that result from + /// taking a dereference on an undefined value. + ErrorNodes UndefDeref; + + /// ImplicitBadDivides - Nodes in the ExplodedGraph that result from + /// evaluating a divide or modulo operation where the denominator + /// MAY be zero. + ErrorNodes ImplicitBadDivides; + + /// ExplicitBadDivides - Nodes in the ExplodedGraph that result from + /// evaluating a divide or modulo operation where the denominator + /// MUST be zero or undefined. + ErrorNodes ExplicitBadDivides; + + /// ImplicitBadSizedVLA - Nodes in the ExplodedGraph that result from + /// constructing a zero-sized VLA where the size may be zero. + ErrorNodes ImplicitBadSizedVLA; + + /// ExplicitBadSizedVLA - Nodes in the ExplodedGraph that result from + /// constructing a zero-sized VLA where the size must be zero. + ErrorNodes ExplicitBadSizedVLA; + + /// UndefResults - Nodes in the ExplodedGraph where the operands are defined + /// by the result is not. Excludes divide-by-zero errors. + ErrorNodes UndefResults; + + /// BadCalls - Nodes in the ExplodedGraph resulting from calls to function + /// pointers that are NULL (or other constants) or Undefined. + ErrorNodes BadCalls; + + /// UndefReceiver - Nodes in the ExplodedGraph resulting from message + /// ObjC message expressions where the receiver is undefined (uninitialized). + ErrorNodes UndefReceivers; + + /// UndefArg - Nodes in the ExplodedGraph resulting from calls to functions + /// where a pass-by-value argument has an undefined value. + UndefArgsTy UndefArgs; + + /// MsgExprUndefArgs - Nodes in the ExplodedGraph resulting from + /// message expressions where a pass-by-value argument has an undefined + /// value. + UndefArgsTy MsgExprUndefArgs; + + /// OutOfBoundMemAccesses - Nodes in the ExplodedGraph resulting from + /// out-of-bound memory accesses where the index MAY be out-of-bound. + ErrorNodes ImplicitOOBMemAccesses; + + /// OutOfBoundMemAccesses - Nodes in the ExplodedGraph resulting from + /// out-of-bound memory accesses where the index MUST be out-of-bound. + ErrorNodes ExplicitOOBMemAccesses; + +public: + GRExprEngine(CFG& cfg, Decl& CD, ASTContext& Ctx, LiveVariables& L, + BugReporterData& BRD, + bool purgeDead, bool eagerlyAssume = true, + StoreManagerCreator SMC = CreateBasicStoreManager, + ConstraintManagerCreator CMC = CreateBasicConstraintManager); + + ~GRExprEngine(); + + void ExecuteWorkList(unsigned Steps = 150000) { + CoreEngine.ExecuteWorkList(Steps); + } + + /// getContext - Return the ASTContext associated with this analysis. + ASTContext& getContext() const { return G.getContext(); } + + /// getCFG - Returns the CFG associated with this analysis. + CFG& getCFG() { return G.getCFG(); } + + GRTransferFuncs& getTF() { return *StateMgr.TF; } + + BugReporter& getBugReporter() { return BR; } + + /// setTransferFunctions + void setTransferFunctions(GRTransferFuncs* tf); + + void setTransferFunctions(GRTransferFuncs& tf) { + setTransferFunctions(&tf); + } + + /// ViewGraph - Visualize the ExplodedGraph created by executing the + /// simulation. + void ViewGraph(bool trim = false); + + void ViewGraph(NodeTy** Beg, NodeTy** End); + + /// getLiveness - Returned computed live-variables information for the + /// analyzed function. + const LiveVariables& getLiveness() const { return Liveness; } + LiveVariables& getLiveness() { return Liveness; } + + /// getInitialState - Return the initial state used for the root vertex + /// in the ExplodedGraph. + const GRState* getInitialState(); + + GraphTy& getGraph() { return G; } + const GraphTy& getGraph() const { return G; } + + void RegisterInternalChecks(); + + bool isRetStackAddr(const NodeTy* N) const { + return N->isSink() && RetsStackAddr.count(const_cast<NodeTy*>(N)) != 0; + } + + bool isUndefControlFlow(const NodeTy* N) const { + return N->isSink() && UndefBranches.count(const_cast<NodeTy*>(N)) != 0; + } + + bool isUndefStore(const NodeTy* N) const { + return N->isSink() && UndefStores.count(const_cast<NodeTy*>(N)) != 0; + } + + bool isImplicitNullDeref(const NodeTy* N) const { + return N->isSink() && ImplicitNullDeref.count(const_cast<NodeTy*>(N)) != 0; + } + + bool isExplicitNullDeref(const NodeTy* N) const { + return N->isSink() && ExplicitNullDeref.count(const_cast<NodeTy*>(N)) != 0; + } + + bool isUndefDeref(const NodeTy* N) const { + return N->isSink() && UndefDeref.count(const_cast<NodeTy*>(N)) != 0; + } + + bool isImplicitBadDivide(const NodeTy* N) const { + return N->isSink() && ImplicitBadDivides.count(const_cast<NodeTy*>(N)) != 0; + } + + bool isExplicitBadDivide(const NodeTy* N) const { + return N->isSink() && ExplicitBadDivides.count(const_cast<NodeTy*>(N)) != 0; + } + + bool isNoReturnCall(const NodeTy* N) const { + return N->isSink() && NoReturnCalls.count(const_cast<NodeTy*>(N)) != 0; + } + + bool isUndefResult(const NodeTy* N) const { + return N->isSink() && UndefResults.count(const_cast<NodeTy*>(N)) != 0; + } + + bool isBadCall(const NodeTy* N) const { + return N->isSink() && BadCalls.count(const_cast<NodeTy*>(N)) != 0; + } + + bool isUndefArg(const NodeTy* N) const { + return N->isSink() && + (UndefArgs.find(const_cast<NodeTy*>(N)) != UndefArgs.end() || + MsgExprUndefArgs.find(const_cast<NodeTy*>(N)) != MsgExprUndefArgs.end()); + } + + bool isUndefReceiver(const NodeTy* N) const { + return N->isSink() && UndefReceivers.count(const_cast<NodeTy*>(N)) != 0; + } + + typedef ErrorNodes::iterator ret_stackaddr_iterator; + ret_stackaddr_iterator ret_stackaddr_begin() { return RetsStackAddr.begin(); } + ret_stackaddr_iterator ret_stackaddr_end() { return RetsStackAddr.end(); } + + typedef ErrorNodes::iterator ret_undef_iterator; + ret_undef_iterator ret_undef_begin() { return RetsUndef.begin(); } + ret_undef_iterator ret_undef_end() { return RetsUndef.end(); } + + typedef ErrorNodes::iterator undef_branch_iterator; + undef_branch_iterator undef_branches_begin() { return UndefBranches.begin(); } + undef_branch_iterator undef_branches_end() { return UndefBranches.end(); } + + typedef ErrorNodes::iterator null_deref_iterator; + null_deref_iterator null_derefs_begin() { return ExplicitNullDeref.begin(); } + null_deref_iterator null_derefs_end() { return ExplicitNullDeref.end(); } + + null_deref_iterator implicit_null_derefs_begin() { + return ImplicitNullDeref.begin(); + } + null_deref_iterator implicit_null_derefs_end() { + return ImplicitNullDeref.end(); + } + + typedef ErrorNodes::iterator nil_receiver_struct_ret_iterator; + + nil_receiver_struct_ret_iterator nil_receiver_struct_ret_begin() { + return NilReceiverStructRetExplicit.begin(); + } + + nil_receiver_struct_ret_iterator nil_receiver_struct_ret_end() { + return NilReceiverStructRetExplicit.end(); + } + + typedef ErrorNodes::iterator nil_receiver_larger_than_voidptr_ret_iterator; + + nil_receiver_larger_than_voidptr_ret_iterator + nil_receiver_larger_than_voidptr_ret_begin() { + return NilReceiverLargerThanVoidPtrRetExplicit.begin(); + } + + nil_receiver_larger_than_voidptr_ret_iterator + nil_receiver_larger_than_voidptr_ret_end() { + return NilReceiverLargerThanVoidPtrRetExplicit.end(); + } + + typedef ErrorNodes::iterator undef_deref_iterator; + undef_deref_iterator undef_derefs_begin() { return UndefDeref.begin(); } + undef_deref_iterator undef_derefs_end() { return UndefDeref.end(); } + + typedef ErrorNodes::iterator bad_divide_iterator; + + bad_divide_iterator explicit_bad_divides_begin() { + return ExplicitBadDivides.begin(); + } + + bad_divide_iterator explicit_bad_divides_end() { + return ExplicitBadDivides.end(); + } + + bad_divide_iterator implicit_bad_divides_begin() { + return ImplicitBadDivides.begin(); + } + + bad_divide_iterator implicit_bad_divides_end() { + return ImplicitBadDivides.end(); + } + + typedef ErrorNodes::iterator undef_result_iterator; + undef_result_iterator undef_results_begin() { return UndefResults.begin(); } + undef_result_iterator undef_results_end() { return UndefResults.end(); } + + typedef ErrorNodes::iterator bad_calls_iterator; + bad_calls_iterator bad_calls_begin() { return BadCalls.begin(); } + bad_calls_iterator bad_calls_end() { return BadCalls.end(); } + + typedef UndefArgsTy::iterator undef_arg_iterator; + undef_arg_iterator undef_arg_begin() { return UndefArgs.begin(); } + undef_arg_iterator undef_arg_end() { return UndefArgs.end(); } + + undef_arg_iterator msg_expr_undef_arg_begin() { + return MsgExprUndefArgs.begin(); + } + undef_arg_iterator msg_expr_undef_arg_end() { + return MsgExprUndefArgs.end(); + } + + typedef ErrorNodes::iterator undef_receivers_iterator; + + undef_receivers_iterator undef_receivers_begin() { + return UndefReceivers.begin(); + } + + undef_receivers_iterator undef_receivers_end() { + return UndefReceivers.end(); + } + + typedef ErrorNodes::iterator oob_memacc_iterator; + oob_memacc_iterator implicit_oob_memacc_begin() { + return ImplicitOOBMemAccesses.begin(); + } + oob_memacc_iterator implicit_oob_memacc_end() { + return ImplicitOOBMemAccesses.end(); + } + oob_memacc_iterator explicit_oob_memacc_begin() { + return ExplicitOOBMemAccesses.begin(); + } + oob_memacc_iterator explicit_oob_memacc_end() { + return ExplicitOOBMemAccesses.end(); + } + + void AddCheck(GRSimpleAPICheck* A, Stmt::StmtClass C); + void AddCheck(GRSimpleAPICheck* A); + + /// ProcessStmt - Called by GRCoreEngine. Used to generate new successor + /// nodes by processing the 'effects' of a block-level statement. + void ProcessStmt(Stmt* S, StmtNodeBuilder& builder); + + /// ProcessBlockEntrance - Called by GRCoreEngine when start processing + /// a CFGBlock. This method returns true if the analysis should continue + /// exploring the given path, and false otherwise. + bool ProcessBlockEntrance(CFGBlock* B, const GRState* St, + GRBlockCounter BC); + + /// ProcessBranch - Called by GRCoreEngine. Used to generate successor + /// nodes by processing the 'effects' of a branch condition. + void ProcessBranch(Stmt* Condition, Stmt* Term, BranchNodeBuilder& builder); + + /// ProcessIndirectGoto - Called by GRCoreEngine. Used to generate successor + /// nodes by processing the 'effects' of a computed goto jump. + void ProcessIndirectGoto(IndirectGotoNodeBuilder& builder); + + /// ProcessSwitch - Called by GRCoreEngine. Used to generate successor + /// nodes by processing the 'effects' of a switch statement. + void ProcessSwitch(SwitchNodeBuilder& builder); + + /// ProcessEndPath - Called by GRCoreEngine. Used to generate end-of-path + /// nodes when the control reaches the end of a function. + void ProcessEndPath(EndPathNodeBuilder& builder) { + getTF().EvalEndPath(*this, builder); + StateMgr.EndPath(builder.getState()); + } + + GRStateManager& getStateManager() { return StateMgr; } + const GRStateManager& getStateManager() const { return StateMgr; } + + StoreManager& getStoreManager() { return StateMgr.getStoreManager(); } + + ConstraintManager& getConstraintManager() { + return StateMgr.getConstraintManager(); + } + + // FIXME: Remove when we migrate over to just using ValueManager. + BasicValueFactory& getBasicVals() { + return StateMgr.getBasicVals(); + } + const BasicValueFactory& getBasicVals() const { + return StateMgr.getBasicVals(); + } + + ValueManager &getValueManager() { return ValMgr; } + const ValueManager &getValueManager() const { return ValMgr; } + + // FIXME: Remove when we migrate over to just using ValueManager. + SymbolManager& getSymbolManager() { return SymMgr; } + const SymbolManager& getSymbolManager() const { return SymMgr; } + +protected: + + const GRState* GetState(NodeTy* N) { + return N == EntryNode ? CleanedState : N->getState(); + } + +public: + + const GRState* BindExpr(const GRState* St, Expr* Ex, SVal V) { + return StateMgr.BindExpr(St, Ex, V); + } + + const GRState* BindExpr(const GRState* St, const Expr* Ex, SVal V) { + return BindExpr(St, const_cast<Expr*>(Ex), V); + } + +protected: + + const GRState* BindBlkExpr(const GRState* St, Expr* Ex, SVal V) { + return StateMgr.BindExpr(St, Ex, V, true, false); + } + + const GRState* BindLoc(const GRState* St, Loc LV, SVal V) { + return StateMgr.BindLoc(St, LV, V); + } + + SVal GetSVal(const GRState* St, Stmt* Ex) { + return StateMgr.GetSVal(St, Ex); + } + + SVal GetSVal(const GRState* St, const Stmt* Ex) { + return GetSVal(St, const_cast<Stmt*>(Ex)); + } + + SVal GetBlkExprSVal(const GRState* St, Stmt* Ex) { + return StateMgr.GetBlkExprSVal(St, Ex); + } + + SVal GetSVal(const GRState* St, Loc LV, QualType T = QualType()) { + return StateMgr.GetSVal(St, LV, T); + } + + inline NonLoc MakeConstantVal(uint64_t X, Expr* Ex) { + return NonLoc::MakeVal(getBasicVals(), X, Ex->getType()); + } + + /// Assume - Create new state by assuming that a given expression + /// is true or false. + const GRState* Assume(const GRState* St, SVal Cond, bool Assumption, + bool& isFeasible) { + return StateMgr.Assume(St, Cond, Assumption, isFeasible); + } + + const GRState* Assume(const GRState* St, Loc Cond, bool Assumption, + bool& isFeasible) { + return StateMgr.Assume(St, Cond, Assumption, isFeasible); + } + + const GRState* AssumeInBound(const GRState* St, SVal Idx, SVal UpperBound, + bool Assumption, bool& isFeasible) { + return StateMgr.AssumeInBound(St, Idx, UpperBound, Assumption, isFeasible); + } + +public: + NodeTy* MakeNode(NodeSet& Dst, Stmt* S, NodeTy* Pred, const GRState* St, + ProgramPoint::Kind K = ProgramPoint::PostStmtKind, + const void *tag = 0); +protected: + + /// Visit - Transfer function logic for all statements. Dispatches to + /// other functions that handle specific kinds of statements. + void Visit(Stmt* S, NodeTy* Pred, NodeSet& Dst); + + /// VisitLValue - Evaluate the lvalue of the expression. For example, if Ex is + /// a DeclRefExpr, it evaluates to the MemRegionVal which represents its + /// storage location. Note that not all kinds of expressions has lvalue. + void VisitLValue(Expr* Ex, NodeTy* Pred, NodeSet& Dst); + + /// VisitArraySubscriptExpr - Transfer function for array accesses. + void VisitArraySubscriptExpr(ArraySubscriptExpr* Ex, NodeTy* Pred, + NodeSet& Dst, bool asLValue); + + /// VisitAsmStmt - Transfer function logic for inline asm. + void VisitAsmStmt(AsmStmt* A, NodeTy* Pred, NodeSet& Dst); + + void VisitAsmStmtHelperOutputs(AsmStmt* A, + AsmStmt::outputs_iterator I, + AsmStmt::outputs_iterator E, + NodeTy* Pred, NodeSet& Dst); + + void VisitAsmStmtHelperInputs(AsmStmt* A, + AsmStmt::inputs_iterator I, + AsmStmt::inputs_iterator E, + NodeTy* Pred, NodeSet& Dst); + + /// VisitBinaryOperator - Transfer function logic for binary operators. + void VisitBinaryOperator(BinaryOperator* B, NodeTy* Pred, NodeSet& Dst); + + + /// VisitCall - Transfer function for function calls. + void VisitCall(CallExpr* CE, NodeTy* Pred, + CallExpr::arg_iterator AI, CallExpr::arg_iterator AE, + NodeSet& Dst); + void VisitCallRec(CallExpr* CE, NodeTy* Pred, + CallExpr::arg_iterator AI, CallExpr::arg_iterator AE, + NodeSet& Dst, const FunctionProtoType *, + unsigned ParamIdx = 0); + + /// VisitCast - Transfer function logic for all casts (implicit and explicit). + void VisitCast(Expr* CastE, Expr* Ex, NodeTy* Pred, NodeSet& Dst); + + /// VisitCastPointerToInteger - Transfer function (called by VisitCast) that + /// handles pointer to integer casts and array to integer casts. + void VisitCastPointerToInteger(SVal V, const GRState* state, QualType PtrTy, + Expr* CastE, NodeTy* Pred, NodeSet& Dst); + + /// VisitCompoundLiteralExpr - Transfer function logic for compound literals. + void VisitCompoundLiteralExpr(CompoundLiteralExpr* CL, NodeTy* Pred, + NodeSet& Dst, bool asLValue); + + /// VisitDeclRefExpr - Transfer function logic for DeclRefExprs. + void VisitDeclRefExpr(DeclRefExpr* DR, NodeTy* Pred, NodeSet& Dst, + bool asLValue); + + /// VisitDeclStmt - Transfer function logic for DeclStmts. + void VisitDeclStmt(DeclStmt* DS, NodeTy* Pred, NodeSet& Dst); + + /// VisitGuardedExpr - Transfer function logic for ?, __builtin_choose + void VisitGuardedExpr(Expr* Ex, Expr* L, Expr* R, NodeTy* Pred, NodeSet& Dst); + + void VisitInitListExpr(InitListExpr* E, NodeTy* Pred, NodeSet& Dst); + + /// VisitLogicalExpr - Transfer function logic for '&&', '||' + void VisitLogicalExpr(BinaryOperator* B, NodeTy* Pred, NodeSet& Dst); + + /// VisitMemberExpr - Transfer function for member expressions. + void VisitMemberExpr(MemberExpr* M, NodeTy* Pred, NodeSet& Dst,bool asLValue); + + /// VisitObjCIvarRefExpr - Transfer function logic for ObjCIvarRefExprs. + void VisitObjCIvarRefExpr(ObjCIvarRefExpr* DR, NodeTy* Pred, NodeSet& Dst, + bool asLValue); + + /// VisitObjCForCollectionStmt - Transfer function logic for + /// ObjCForCollectionStmt. + void VisitObjCForCollectionStmt(ObjCForCollectionStmt* S, NodeTy* Pred, + NodeSet& Dst); + + void VisitObjCForCollectionStmtAux(ObjCForCollectionStmt* S, NodeTy* Pred, + NodeSet& Dst, SVal ElementV); + + /// VisitObjCMessageExpr - Transfer function for ObjC message expressions. + void VisitObjCMessageExpr(ObjCMessageExpr* ME, NodeTy* Pred, NodeSet& Dst); + + void VisitObjCMessageExprArgHelper(ObjCMessageExpr* ME, + ObjCMessageExpr::arg_iterator I, + ObjCMessageExpr::arg_iterator E, + NodeTy* Pred, NodeSet& Dst); + + void VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME, NodeTy* Pred, + NodeSet& Dst); + + /// VisitReturnStmt - Transfer function logic for return statements. + void VisitReturnStmt(ReturnStmt* R, NodeTy* Pred, NodeSet& Dst); + + /// VisitSizeOfAlignOfExpr - Transfer function for sizeof. + void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr* Ex, NodeTy* Pred, + NodeSet& Dst); + + /// VisitUnaryOperator - Transfer function logic for unary operators. + void VisitUnaryOperator(UnaryOperator* B, NodeTy* Pred, NodeSet& Dst, + bool asLValue); + + const GRState* CheckDivideZero(Expr* Ex, const GRState* St, NodeTy* Pred, + SVal Denom); + + /// EvalEagerlyAssume - Given the nodes in 'Src', eagerly assume symbolic + /// expressions of the form 'x != 0' and generate new nodes (stored in Dst) + /// with those assumptions. + void EvalEagerlyAssume(NodeSet& Dst, NodeSet& Src, Expr *Ex); + + SVal EvalCast(SVal X, QualType CastT) { + if (X.isUnknownOrUndef()) + return X; + + if (isa<Loc>(X)) + return getTF().EvalCast(*this, cast<Loc>(X), CastT); + else + return getTF().EvalCast(*this, cast<NonLoc>(X), CastT); + } + + SVal EvalMinus(UnaryOperator* U, SVal X) { + return X.isValid() ? getTF().EvalMinus(*this, U, cast<NonLoc>(X)) : X; + } + + SVal EvalComplement(SVal X) { + return X.isValid() ? getTF().EvalComplement(*this, cast<NonLoc>(X)) : X; + } + +public: + + SVal EvalBinOp(BinaryOperator::Opcode Op, NonLoc L, NonLoc R, QualType T) { + return R.isValid() ? getTF().DetermEvalBinOpNN(*this, Op, L, R, T) + : R; + } + + SVal EvalBinOp(BinaryOperator::Opcode Op, NonLoc L, SVal R, QualType T) { + return R.isValid() ? getTF().DetermEvalBinOpNN(*this, Op, L, + cast<NonLoc>(R), T) : R; + } + + void EvalBinOp(ExplodedNodeSet<GRState>& Dst, Expr* Ex, + BinaryOperator::Opcode Op, NonLoc L, NonLoc R, + ExplodedNode<GRState>* Pred, QualType T); + + void EvalBinOp(GRStateSet& OStates, const GRState* St, Expr* Ex, + BinaryOperator::Opcode Op, NonLoc L, NonLoc R, QualType T); + + SVal EvalBinOp(const GRState *state, BinaryOperator::Opcode Op, SVal L,SVal R, + QualType T); + +protected: + + void EvalCall(NodeSet& Dst, CallExpr* CE, SVal L, NodeTy* Pred); + + void EvalObjCMessageExpr(NodeSet& Dst, ObjCMessageExpr* ME, NodeTy* Pred) { + assert (Builder && "GRStmtNodeBuilder must be defined."); + getTF().EvalObjCMessageExpr(Dst, *this, *Builder, ME, Pred); + } + + void EvalReturn(NodeSet& Dst, ReturnStmt* s, NodeTy* Pred); + + const GRState* MarkBranch(const GRState* St, Stmt* Terminator, + bool branchTaken); + + /// EvalBind - Handle the semantics of binding a value to a specific location. + /// This method is used by EvalStore, VisitDeclStmt, and others. + void EvalBind(NodeSet& Dst, Expr* Ex, NodeTy* Pred, + const GRState* St, SVal location, SVal Val); + +public: + void EvalLoad(NodeSet& Dst, Expr* Ex, NodeTy* Pred, + const GRState* St, SVal location, const void *tag = 0); + + NodeTy* EvalLocation(Stmt* Ex, NodeTy* Pred, + const GRState* St, SVal location, + const void *tag = 0); + + + void EvalStore(NodeSet& Dst, Expr* E, NodeTy* Pred, const GRState* St, + SVal TargetLV, SVal Val, const void *tag = 0); + + void EvalStore(NodeSet& Dst, Expr* E, Expr* StoreE, NodeTy* Pred, + const GRState* St, SVal TargetLV, SVal Val, + const void *tag = 0); + +}; + +} // end clang namespace + +#endif diff --git a/include/clang/Analysis/PathSensitive/GRExprEngineBuilders.h b/include/clang/Analysis/PathSensitive/GRExprEngineBuilders.h new file mode 100644 index 000000000000..6c23745de23a --- /dev/null +++ b/include/clang/Analysis/PathSensitive/GRExprEngineBuilders.h @@ -0,0 +1,101 @@ +//===-- GRExprEngineBuilders.h - "Builder" classes for GRExprEngine -*- C++ -*-= +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines smart builder "references" which are used to marshal +// builders between GRExprEngine objects and their related components. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_GREXPRENGINE_BUILDERS +#define LLVM_CLANG_ANALYSIS_GREXPRENGINE_BUILDERS +#include "clang/Analysis/PathSensitive/GRExprEngine.h" + +namespace clang { + + +// SaveAndRestore - A utility class that uses RAII to save and restore +// the value of a variable. +template<typename T> +struct SaveAndRestore { + SaveAndRestore(T& x) : X(x), old_value(x) {} + ~SaveAndRestore() { X = old_value; } + T get() { return old_value; } +private: + T& X; + T old_value; +}; + +// SaveOr - Similar to SaveAndRestore. Operates only on bools; the old +// value of a variable is saved, and during the dstor the old value is +// or'ed with the new value. +struct SaveOr { + SaveOr(bool& x) : X(x), old_value(x) { x = false; } + ~SaveOr() { X |= old_value; } +private: + bool& X; + const bool old_value; +}; + +class GRStmtNodeBuilderRef { + GRExprEngine::NodeSet &Dst; + GRExprEngine::StmtNodeBuilder &B; + GRExprEngine& Eng; + GRExprEngine::NodeTy* Pred; + const GRState* state; + const Stmt* stmt; + const unsigned OldSize; + const bool AutoCreateNode; + SaveAndRestore<bool> OldSink; + SaveAndRestore<const void*> OldTag; + SaveOr OldHasGen; + +private: + friend class GRExprEngine; + + GRStmtNodeBuilderRef(); // do not implement + void operator=(const GRStmtNodeBuilderRef&); // do not implement + + GRStmtNodeBuilderRef(GRExprEngine::NodeSet &dst, + GRExprEngine::StmtNodeBuilder &builder, + GRExprEngine& eng, + GRExprEngine::NodeTy* pred, + const GRState *st, + const Stmt* s, bool auto_create_node) + : Dst(dst), B(builder), Eng(eng), Pred(pred), + state(st), stmt(s), OldSize(Dst.size()), AutoCreateNode(auto_create_node), + OldSink(B.BuildSinks), OldTag(B.Tag), OldHasGen(B.HasGeneratedNode) {} + +public: + + ~GRStmtNodeBuilderRef() { + // Handle the case where no nodes where generated. Auto-generate that + // contains the updated state if we aren't generating sinks. + if (!B.BuildSinks && Dst.size() == OldSize && !B.HasGeneratedNode) { + if (AutoCreateNode) + B.MakeNode(Dst, const_cast<Stmt*>(stmt), Pred, state); + else + Dst.Add(Pred); + } + } + + GRStateRef getState() { + return GRStateRef(state, Eng.getStateManager()); + } + + GRStateManager& getStateManager() { + return Eng.getStateManager(); + } + + GRExprEngine::NodeTy* MakeNode(const GRState* state) { + return B.MakeNode(Dst, const_cast<Stmt*>(stmt), Pred, state); + } +}; + +} // end clang namespace +#endif diff --git a/include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h b/include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h new file mode 100644 index 000000000000..e54b31dfe883 --- /dev/null +++ b/include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h @@ -0,0 +1,40 @@ +// GRCheckAPI.h - Simple API checks based on GRAuditor ------------*- C++ -*--// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the interface for building simple, path-sensitive checks +// that are stateless and only emit warnings at errors that occur at +// CallExpr or ObjCMessageExpr. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_GRAPICHECKS +#define LLVM_CLANG_ANALYSIS_GRAPICHECKS + +#include "clang/Analysis/PathSensitive/GRAuditor.h" +#include "clang/Analysis/PathSensitive/GRState.h" + +namespace clang { + +class Diagnostic; +class BugReporter; +class ASTContext; +class GRExprEngine; +class PathDiagnosticClient; +template <typename T> class ExplodedGraph; + + +class GRSimpleAPICheck : public GRAuditor<GRState> { +public: + GRSimpleAPICheck() {} + virtual ~GRSimpleAPICheck() {} +}; + +} // end namespace clang + +#endif diff --git a/include/clang/Analysis/PathSensitive/GRState.h b/include/clang/Analysis/PathSensitive/GRState.h new file mode 100644 index 000000000000..d61feea4819e --- /dev/null +++ b/include/clang/Analysis/PathSensitive/GRState.h @@ -0,0 +1,820 @@ +//== GRState*h - Path-Sens. "State" for tracking valuues -----*- C++ -*--==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines SymbolRef, ExprBindKey, and GRState* +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_VALUESTATE_H +#define LLVM_CLANG_ANALYSIS_VALUESTATE_H + +// FIXME: Reduce the number of includes. + +#include "clang/Analysis/PathSensitive/Environment.h" +#include "clang/Analysis/PathSensitive/Store.h" +#include "clang/Analysis/PathSensitive/ConstraintManager.h" +#include "clang/Analysis/PathSensitive/ValueManager.h" +#include "clang/Analysis/PathSensitive/GRCoreEngine.h" +#include "clang/AST/Expr.h" +#include "clang/AST/Decl.h" +#include "clang/AST/ASTContext.h" +#include "clang/Analysis/Analyses/LiveVariables.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/ADT/APSInt.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/ImmutableMap.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/Streams.h" + +#include <functional> + +namespace clang { + +class GRStateManager; +class GRTransferFuncs; + +typedef ConstraintManager* (*ConstraintManagerCreator)(GRStateManager&); +typedef StoreManager* (*StoreManagerCreator)(GRStateManager&); + +//===----------------------------------------------------------------------===// +// GRStateTrait - Traits used by the Generic Data Map of a GRState. +//===----------------------------------------------------------------------===// + +template <typename T> struct GRStatePartialTrait; + +template <typename T> struct GRStateTrait { + typedef typename T::data_type data_type; + static inline void* GDMIndex() { return &T::TagInt; } + static inline void* MakeVoidPtr(data_type D) { return (void*) D; } + static inline data_type MakeData(void* const* P) { + return P ? (data_type) *P : (data_type) 0; + } +}; + +//===----------------------------------------------------------------------===// +// GRState- An ImmutableMap type Stmt*/Decl*/Symbols to SVals. +//===----------------------------------------------------------------------===// + +/// GRState - This class encapsulates the actual data values for +/// for a "state" in our symbolic value tracking. It is intended to be +/// used as a functional object; that is once it is created and made +/// "persistent" in a FoldingSet its values will never change. +class GRState : public llvm::FoldingSetNode { +public: + // Typedefs. + typedef llvm::ImmutableSet<llvm::APSInt*> IntSetTy; + typedef llvm::ImmutableMap<void*, void*> GenericDataMap; + + typedef GRStateManager ManagerTy; + +private: + void operator=(const GRState& R) const; + + friend class GRStateManager; + + Environment Env; + Store St; + + // FIXME: Make these private. +public: + GenericDataMap GDM; + +public: + + /// This ctor is used when creating the first GRState object. + GRState(const Environment& env, Store st, GenericDataMap gdm) + : Env(env), + St(st), + GDM(gdm) {} + + /// Copy ctor - We must explicitly define this or else the "Next" ptr + /// in FoldingSetNode will also get copied. + GRState(const GRState& RHS) + : llvm::FoldingSetNode(), + Env(RHS.Env), + St(RHS.St), + GDM(RHS.GDM) {} + + /// getEnvironment - Return the environment associated with this state. + /// The environment is the mapping from expressions to values. + const Environment& getEnvironment() const { return Env; } + + /// getStore - Return the store associated with this state. The store + /// is a mapping from locations to values. + Store getStore() const { return St; } + + /// getGDM - Return the generic data map associated with this state. + GenericDataMap getGDM() const { return GDM; } + + /// Profile - Profile the contents of a GRState object for use + /// in a FoldingSet. + static void Profile(llvm::FoldingSetNodeID& ID, const GRState* V) { + V->Env.Profile(ID); + ID.AddPointer(V->St); + V->GDM.Profile(ID); + } + + /// Profile - Used to profile the contents of this object for inclusion + /// in a FoldingSet. + void Profile(llvm::FoldingSetNodeID& ID) const { + Profile(ID, this); + } + + SVal LookupExpr(Expr* E) const { + return Env.LookupExpr(E); + } + + // Iterators. + typedef Environment::seb_iterator seb_iterator; + seb_iterator seb_begin() const { return Env.seb_begin(); } + seb_iterator seb_end() const { return Env.beb_end(); } + + typedef Environment::beb_iterator beb_iterator; + beb_iterator beb_begin() const { return Env.beb_begin(); } + beb_iterator beb_end() const { return Env.beb_end(); } + + // Trait based GDM dispatch. + void* const* FindGDM(void* K) const; + + template <typename T> + typename GRStateTrait<T>::data_type + get() const { + return GRStateTrait<T>::MakeData(FindGDM(GRStateTrait<T>::GDMIndex())); + } + + template<typename T> + typename GRStateTrait<T>::lookup_type + get(typename GRStateTrait<T>::key_type key) const { + void* const* d = FindGDM(GRStateTrait<T>::GDMIndex()); + return GRStateTrait<T>::Lookup(GRStateTrait<T>::MakeData(d), key); + } + + template<typename T> + bool contains(typename GRStateTrait<T>::key_type key) const { + void* const* d = FindGDM(GRStateTrait<T>::GDMIndex()); + return GRStateTrait<T>::Contains(GRStateTrait<T>::MakeData(d), key); + } + + // State pretty-printing. + class Printer { + public: + virtual ~Printer() {} + virtual void Print(std::ostream& Out, const GRState* state, + const char* nl, const char* sep) = 0; + }; + + void print(std::ostream& Out, StoreManager& StoreMgr, + ConstraintManager& ConstraintMgr, + Printer **Beg = 0, Printer **End = 0, + const char* nl = "\n", const char *sep = "") const; + + // Tags used for the Generic Data Map. + struct NullDerefTag { + static int TagInt; + typedef const SVal* data_type; + }; +}; + +template<> struct GRTrait<GRState*> { + static inline void* toPtr(GRState* St) { return (void*) St; } + static inline GRState* toState(void* P) { return (GRState*) P; } + static inline void Profile(llvm::FoldingSetNodeID& profile, GRState* St) { + // At this point states have already been uniqued. Just + // add the pointer. + profile.AddPointer(St); + } +}; + + +class GRStateSet { + typedef llvm::SmallPtrSet<const GRState*,5> ImplTy; + ImplTy Impl; +public: + GRStateSet() {} + + inline void Add(const GRState* St) { + Impl.insert(St); + } + + typedef ImplTy::const_iterator iterator; + + inline unsigned size() const { return Impl.size(); } + inline bool empty() const { return Impl.empty(); } + + inline iterator begin() const { return Impl.begin(); } + inline iterator end() const { return Impl.end(); } + + class AutoPopulate { + GRStateSet& S; + unsigned StartSize; + const GRState* St; + public: + AutoPopulate(GRStateSet& s, const GRState* st) + : S(s), StartSize(S.size()), St(st) {} + + ~AutoPopulate() { + if (StartSize == S.size()) + S.Add(St); + } + }; +}; + +//===----------------------------------------------------------------------===// +// GRStateManager - Factory object for GRStates. +//===----------------------------------------------------------------------===// + +class GRStateRef; + +class GRStateManager { + friend class GRExprEngine; + friend class GRStateRef; + +private: + EnvironmentManager EnvMgr; + llvm::OwningPtr<StoreManager> StoreMgr; + llvm::OwningPtr<ConstraintManager> ConstraintMgr; + GRState::IntSetTy::Factory ISetFactory; + + GRState::GenericDataMap::Factory GDMFactory; + + typedef llvm::DenseMap<void*,std::pair<void*,void (*)(void*)> > GDMContextsTy; + GDMContextsTy GDMContexts; + + /// Printers - A set of printer objects used for pretty-printing a GRState. + /// GRStateManager owns these objects. + std::vector<GRState::Printer*> Printers; + + /// StateSet - FoldingSet containing all the states created for analyzing + /// a particular function. This is used to unique states. + llvm::FoldingSet<GRState> StateSet; + + /// ValueMgr - Object that manages the data for all created SVals. + ValueManager ValueMgr; + + /// Alloc - A BumpPtrAllocator to allocate states. + llvm::BumpPtrAllocator& Alloc; + + /// CurrentStmt - The block-level statement currently being visited. This + /// is set by GRExprEngine. + Stmt* CurrentStmt; + + /// cfg - The CFG for the analyzed function/method. + CFG& cfg; + + /// codedecl - The Decl representing the function/method being analyzed. + const Decl& codedecl; + + /// TF - Object that represents a bundle of transfer functions + /// for manipulating and creating SVals. + GRTransferFuncs* TF; + + /// Liveness - live-variables information of the ValueDecl* and block-level + /// Expr* in the CFG. Used to get initial store and prune out dead state. + LiveVariables& Liveness; + +private: + + Environment RemoveBlkExpr(const Environment& Env, Expr* E) { + return EnvMgr.RemoveBlkExpr(Env, E); + } + + // FIXME: Remove when we do lazy initializaton of variable bindings. +// const GRState* BindVar(const GRState* St, VarDecl* D, SVal V) { +// return SetSVal(St, getLoc(D), V); +// } + +public: + + GRStateManager(ASTContext& Ctx, + StoreManagerCreator CreateStoreManager, + ConstraintManagerCreator CreateConstraintManager, + llvm::BumpPtrAllocator& alloc, CFG& c, + const Decl& cd, LiveVariables& L) + : EnvMgr(alloc), + ISetFactory(alloc), + GDMFactory(alloc), + ValueMgr(alloc, Ctx), + Alloc(alloc), + cfg(c), + codedecl(cd), + Liveness(L) { + StoreMgr.reset((*CreateStoreManager)(*this)); + ConstraintMgr.reset((*CreateConstraintManager)(*this)); + } + + ~GRStateManager(); + + const GRState* getInitialState(); + + ASTContext &getContext() { return ValueMgr.getContext(); } + const ASTContext &getContext() const { return ValueMgr.getContext(); } + + const Decl &getCodeDecl() { return codedecl; } + GRTransferFuncs& getTransferFuncs() { return *TF; } + + BasicValueFactory &getBasicVals() { + return ValueMgr.getBasicValueFactory(); + } + const BasicValueFactory& getBasicVals() const { + return ValueMgr.getBasicValueFactory(); + } + + SymbolManager &getSymbolManager() { + return ValueMgr.getSymbolManager(); + } + const SymbolManager &getSymbolManager() const { + return ValueMgr.getSymbolManager(); + } + + ValueManager &getValueManager() { return ValueMgr; } + const ValueManager &getValueManager() const { return ValueMgr; } + + LiveVariables& getLiveVariables() { return Liveness; } + llvm::BumpPtrAllocator& getAllocator() { return Alloc; } + + MemRegionManager& getRegionManager() { + return ValueMgr.getRegionManager(); + } + const MemRegionManager& getRegionManager() const { + return ValueMgr.getRegionManager(); + } + + StoreManager& getStoreManager() { return *StoreMgr; } + ConstraintManager& getConstraintManager() { return *ConstraintMgr; } + + const GRState* BindDecl(const GRState* St, const VarDecl* VD, SVal IVal) { + // Store manager should return a persistent state. + return StoreMgr->BindDecl(St, VD, IVal); + } + + const GRState* BindDeclWithNoInit(const GRState* St, const VarDecl* VD) { + // Store manager should return a persistent state. + return StoreMgr->BindDeclWithNoInit(St, VD); + } + + /// BindCompoundLiteral - Return the state that has the bindings currently + /// in 'state' plus the bindings for the CompoundLiteral. 'R' is the region + /// for the compound literal and 'BegInit' and 'EndInit' represent an + /// array of initializer values. + const GRState* BindCompoundLiteral(const GRState* St, + const CompoundLiteralExpr* CL, SVal V) { + return StoreMgr->BindCompoundLiteral(St, CL, V); + } + + const GRState* RemoveDeadBindings(const GRState* St, Stmt* Loc, + SymbolReaper& SymReaper); + + const GRState* RemoveSubExprBindings(const GRState* St) { + GRState NewSt = *St; + NewSt.Env = EnvMgr.RemoveSubExprBindings(NewSt.Env); + return getPersistentState(NewSt); + } + + + // Utility methods for getting regions. + + VarRegion* getRegion(const VarDecl* D) { + return getRegionManager().getVarRegion(D); + } + + const MemRegion* getSelfRegion(const GRState* state) { + return StoreMgr->getSelfRegion(state->getStore()); + } + + // Get the lvalue for a variable reference. + SVal GetLValue(const GRState* St, const VarDecl* D) { + return StoreMgr->getLValueVar(St, D); + } + + // Get the lvalue for a StringLiteral. + SVal GetLValue(const GRState* St, const StringLiteral* E) { + return StoreMgr->getLValueString(St, E); + } + + SVal GetLValue(const GRState* St, const CompoundLiteralExpr* CL) { + return StoreMgr->getLValueCompoundLiteral(St, CL); + } + + // Get the lvalue for an ivar reference. + SVal GetLValue(const GRState* St, const ObjCIvarDecl* D, SVal Base) { + return StoreMgr->getLValueIvar(St, D, Base); + } + + // Get the lvalue for a field reference. + SVal GetLValue(const GRState* St, SVal Base, const FieldDecl* D) { + return StoreMgr->getLValueField(St, Base, D); + } + + // Get the lvalue for an array index. + SVal GetLValue(const GRState* St, QualType ElementType, SVal Base, SVal Idx) { + return StoreMgr->getLValueElement(St, ElementType, Base, Idx); + } + + // Methods that query & manipulate the Environment. + + SVal GetSVal(const GRState* St, Stmt* Ex) { + return St->getEnvironment().GetSVal(Ex, getBasicVals()); + } + + SVal GetSValAsScalarOrLoc(const GRState* state, const Stmt *S) { + if (const Expr *Ex = dyn_cast<Expr>(S)) { + QualType T = Ex->getType(); + if (Loc::IsLocType(T) || T->isIntegerType()) + return GetSVal(state, S); + } + + return UnknownVal(); + } + + + SVal GetSVal(const GRState* St, const Stmt* Ex) { + return St->getEnvironment().GetSVal(const_cast<Stmt*>(Ex), getBasicVals()); + } + + SVal GetBlkExprSVal(const GRState* St, Stmt* Ex) { + return St->getEnvironment().GetBlkExprSVal(Ex, getBasicVals()); + } + + + + const GRState* BindExpr(const GRState* St, Stmt* Ex, SVal V, + bool isBlkExpr, bool Invalidate) { + + const Environment& OldEnv = St->getEnvironment(); + Environment NewEnv = EnvMgr.BindExpr(OldEnv, Ex, V, isBlkExpr, Invalidate); + + if (NewEnv == OldEnv) + return St; + + GRState NewSt = *St; + NewSt.Env = NewEnv; + return getPersistentState(NewSt); + } + + const GRState* BindExpr(const GRState* St, Stmt* Ex, SVal V, + bool Invalidate = true) { + + bool isBlkExpr = false; + + if (Ex == CurrentStmt) { + // FIXME: Should this just be an assertion? When would we want to set + // the value of a block-level expression if it wasn't CurrentStmt? + isBlkExpr = cfg.isBlkExpr(Ex); + + if (!isBlkExpr) + return St; + } + + return BindExpr(St, Ex, V, isBlkExpr, Invalidate); + } + + SVal ArrayToPointer(Loc Array) { + return StoreMgr->ArrayToPointer(Array); + } + + // Methods that manipulate the GDM. + const GRState* addGDM(const GRState* St, void* Key, void* Data); + + // Methods that query or create regions. + bool hasStackStorage(const MemRegion* R) { + return getRegionManager().hasStackStorage(R); + } + + // Methods that query & manipulate the Store. + + void iterBindings(const GRState* state, StoreManager::BindingsHandler& F) { + StoreMgr->iterBindings(state->getStore(), F); + } + + + SVal GetSVal(const GRState* state, Loc LV, QualType T = QualType()) { + return StoreMgr->Retrieve(state, LV, T); + } + + SVal GetSVal(const GRState* state, const MemRegion* R) { + return StoreMgr->Retrieve(state, loc::MemRegionVal(R)); + } + + SVal GetSValAsScalarOrLoc(const GRState* state, const MemRegion *R) { + // We only want to do fetches from regions that we can actually bind + // values. For example, SymbolicRegions of type 'id<...>' cannot + // have direct bindings (but their can be bindings on their subregions). + if (!R->isBoundable(getContext())) + return UnknownVal(); + + if (const TypedRegion *TR = dyn_cast<TypedRegion>(R)) { + QualType T = TR->getValueType(getContext()); + if (Loc::IsLocType(T) || T->isIntegerType()) + return GetSVal(state, R); + } + + return UnknownVal(); + } + + const GRState* BindLoc(const GRState* St, Loc LV, SVal V) { + return StoreMgr->Bind(St, LV, V); + } + + void Unbind(GRState& St, Loc LV) { + St.St = StoreMgr->Remove(St.St, LV); + } + + const GRState* Unbind(const GRState* St, Loc LV); + + const GRState* getPersistentState(GRState& Impl); + + // MakeStateWithStore - get a persistent state with the new store. + const GRState* MakeStateWithStore(const GRState* St, Store store); + + bool isEqual(const GRState* state, Expr* Ex, const llvm::APSInt& V); + bool isEqual(const GRState* state, Expr* Ex, uint64_t); + + + //==---------------------------------------------------------------------==// + // Generic Data Map methods. + //==---------------------------------------------------------------------==// + // + // GRStateManager and GRState support a "generic data map" that allows + // different clients of GRState objects to embed arbitrary data within a + // GRState object. The generic data map is essentially an immutable map + // from a "tag" (that acts as the "key" for a client) and opaque values. + // Tags/keys and values are simply void* values. The typical way that clients + // generate unique tags are by taking the address of a static variable. + // Clients are responsible for ensuring that data values referred to by a + // the data pointer are immutable (and thus are essentially purely functional + // data). + // + // The templated methods below use the GRStateTrait<T> class + // to resolve keys into the GDM and to return data values to clients. + // + + // Trait based GDM dispatch. + template <typename T> + const GRState* set(const GRState* st, typename GRStateTrait<T>::data_type D) { + return addGDM(st, GRStateTrait<T>::GDMIndex(), + GRStateTrait<T>::MakeVoidPtr(D)); + } + + template<typename T> + const GRState* set(const GRState* st, + typename GRStateTrait<T>::key_type K, + typename GRStateTrait<T>::value_type V, + typename GRStateTrait<T>::context_type C) { + + return addGDM(st, GRStateTrait<T>::GDMIndex(), + GRStateTrait<T>::MakeVoidPtr(GRStateTrait<T>::Set(st->get<T>(), K, V, C))); + } + + template <typename T> + const GRState* add(const GRState* st, + typename GRStateTrait<T>::key_type K, + typename GRStateTrait<T>::context_type C) { + return addGDM(st, GRStateTrait<T>::GDMIndex(), + GRStateTrait<T>::MakeVoidPtr(GRStateTrait<T>::Add(st->get<T>(), K, C))); + } + + template <typename T> + const GRState* remove(const GRState* st, + typename GRStateTrait<T>::key_type K, + typename GRStateTrait<T>::context_type C) { + + return addGDM(st, GRStateTrait<T>::GDMIndex(), + GRStateTrait<T>::MakeVoidPtr(GRStateTrait<T>::Remove(st->get<T>(), K, C))); + } + + + void* FindGDMContext(void* index, + void* (*CreateContext)(llvm::BumpPtrAllocator&), + void (*DeleteContext)(void*)); + + template <typename T> + typename GRStateTrait<T>::context_type get_context() { + void* p = FindGDMContext(GRStateTrait<T>::GDMIndex(), + GRStateTrait<T>::CreateContext, + GRStateTrait<T>::DeleteContext); + + return GRStateTrait<T>::MakeContext(p); + } + + //==---------------------------------------------------------------------==// + // Constraints on values. + //==---------------------------------------------------------------------==// + // + // Each GRState records constraints on symbolic values. These constraints + // are managed using the ConstraintManager associated with a GRStateManager. + // As constraints gradually accrue on symbolic values, added constraints + // may conflict and indicate that a state is infeasible (as no real values + // could satisfy all the constraints). This is the principal mechanism + // for modeling path-sensitivity in GRExprEngine/GRState. + // + // Various "Assume" methods form the interface for adding constraints to + // symbolic values. A call to "Assume" indicates an assumption being placed + // on one or symbolic values. Assume methods take the following inputs: + // + // (1) A GRState object representing the current state. + // + // (2) The assumed constraint (which is specific to a given "Assume" method). + // + // (3) A binary value "Assumption" that indicates whether the constraint is + // assumed to be true or false. + // + // The output of "Assume" are two values: + // + // (a) "isFeasible" is set to true or false to indicate whether or not + // the assumption is feasible. + // + // (b) A new GRState object with the added constraints. + // + // FIXME: (a) should probably disappear since it is redundant with (b). + // (i.e., (b) could just be set to NULL). + // + + const GRState* Assume(const GRState* St, SVal Cond, bool Assumption, + bool& isFeasible) { + const GRState *state = + ConstraintMgr->Assume(St, Cond, Assumption, isFeasible); + assert(!isFeasible || state); + return isFeasible ? state : NULL; + } + + const GRState* AssumeInBound(const GRState* St, SVal Idx, SVal UpperBound, + bool Assumption, bool& isFeasible) { + const GRState *state = + ConstraintMgr->AssumeInBound(St, Idx, UpperBound, Assumption, + isFeasible); + assert(!isFeasible || state); + return isFeasible ? state : NULL; + } + + const llvm::APSInt* getSymVal(const GRState* St, SymbolRef sym) { + return ConstraintMgr->getSymVal(St, sym); + } + + void EndPath(const GRState* St) { + ConstraintMgr->EndPath(St); + } + + bool scanReachableSymbols(SVal val, const GRState* state, + SymbolVisitor& visitor); +}; + +//===----------------------------------------------------------------------===// +// GRStateRef - A "fat" reference to GRState that also bundles GRStateManager. +//===----------------------------------------------------------------------===// + +class GRStateRef { + const GRState* St; + GRStateManager* Mgr; +public: + GRStateRef(const GRState* st, GRStateManager& mgr) : St(st), Mgr(&mgr) {} + + const GRState* getState() const { return St; } + operator const GRState*() const { return St; } + GRStateManager& getManager() const { return *Mgr; } + + SVal GetSVal(Expr* Ex) { + return Mgr->GetSVal(St, Ex); + } + + SVal GetBlkExprSVal(Expr* Ex) { + return Mgr->GetBlkExprSVal(St, Ex); + } + + SVal GetSValAsScalarOrLoc(const Expr *Ex) { + return Mgr->GetSValAsScalarOrLoc(St, Ex); + } + + SVal GetSVal(Loc LV, QualType T = QualType()) { + return Mgr->GetSVal(St, LV, T); + } + + SVal GetSVal(const MemRegion* R) { + return Mgr->GetSVal(St, R); + } + + SVal GetSValAsScalarOrLoc(const MemRegion *R) { + return Mgr->GetSValAsScalarOrLoc(St, R); + } + + GRStateRef BindExpr(Stmt* Ex, SVal V, bool isBlkExpr, bool Invalidate) { + return GRStateRef(Mgr->BindExpr(St, Ex, V, isBlkExpr, Invalidate), *Mgr); + } + + GRStateRef BindExpr(Stmt* Ex, SVal V, bool Invalidate = true) { + return GRStateRef(Mgr->BindExpr(St, Ex, V, Invalidate), *Mgr); + } + + GRStateRef BindDecl(const VarDecl* VD, SVal InitVal) { + return GRStateRef(Mgr->BindDecl(St, VD, InitVal), *Mgr); + } + + GRStateRef BindLoc(Loc LV, SVal V) { + return GRStateRef(Mgr->BindLoc(St, LV, V), *Mgr); + } + + GRStateRef BindLoc(SVal LV, SVal V) { + if (!isa<Loc>(LV)) return *this; + return BindLoc(cast<Loc>(LV), V); + } + + GRStateRef Unbind(Loc LV) { + return GRStateRef(Mgr->Unbind(St, LV), *Mgr); + } + + // Trait based GDM dispatch. + template<typename T> + typename GRStateTrait<T>::data_type get() const { + return St->get<T>(); + } + + template<typename T> + typename GRStateTrait<T>::lookup_type + get(typename GRStateTrait<T>::key_type key) const { + return St->get<T>(key); + } + + template<typename T> + GRStateRef set(typename GRStateTrait<T>::data_type D) { + return GRStateRef(Mgr->set<T>(St, D), *Mgr); + } + + template <typename T> + typename GRStateTrait<T>::context_type get_context() { + return Mgr->get_context<T>(); + } + + template<typename T> + GRStateRef set(typename GRStateTrait<T>::key_type K, + typename GRStateTrait<T>::value_type E, + typename GRStateTrait<T>::context_type C) { + return GRStateRef(Mgr->set<T>(St, K, E, C), *Mgr); + } + + template<typename T> + GRStateRef set(typename GRStateTrait<T>::key_type K, + typename GRStateTrait<T>::value_type E) { + return GRStateRef(Mgr->set<T>(St, K, E, get_context<T>()), *Mgr); + } + + template<typename T> + GRStateRef add(typename GRStateTrait<T>::key_type K) { + return GRStateRef(Mgr->add<T>(St, K, get_context<T>()), *Mgr); + } + + template<typename T> + GRStateRef remove(typename GRStateTrait<T>::key_type K, + typename GRStateTrait<T>::context_type C) { + return GRStateRef(Mgr->remove<T>(St, K, C), *Mgr); + } + + template<typename T> + GRStateRef remove(typename GRStateTrait<T>::key_type K) { + return GRStateRef(Mgr->remove<T>(St, K, get_context<T>()), *Mgr); + } + + template<typename T> + bool contains(typename GRStateTrait<T>::key_type key) const { + return St->contains<T>(key); + } + + // Lvalue methods. + SVal GetLValue(const VarDecl* VD) { + return Mgr->GetLValue(St, VD); + } + + GRStateRef Assume(SVal Cond, bool Assumption, bool& isFeasible) { + return GRStateRef(Mgr->Assume(St, Cond, Assumption, isFeasible), *Mgr); + } + + template <typename CB> + CB scanReachableSymbols(SVal val) { + CB cb(*this); + Mgr->scanReachableSymbols(val, St, cb); + return cb; + } + + SymbolManager& getSymbolManager() { return Mgr->getSymbolManager(); } + BasicValueFactory& getBasicVals() { return Mgr->getBasicVals(); } + + // Pretty-printing. + void print(std::ostream& Out, const char* nl = "\n", + const char *sep = "") const; + + void printStdErr() const; + + void printDOT(std::ostream& Out) const; +}; + +} // end clang namespace + +#endif diff --git a/include/clang/Analysis/PathSensitive/GRStateTrait.h b/include/clang/Analysis/PathSensitive/GRStateTrait.h new file mode 100644 index 000000000000..ce43cda31e9e --- /dev/null +++ b/include/clang/Analysis/PathSensitive/GRStateTrait.h @@ -0,0 +1,148 @@ +//==- GRStateTrait.h - Partial implementations of GRStateTrait -----*- C++ -*-// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines partial implementations of template specializations of +// the class GRStateTrait<>. GRStateTrait<> is used by GRState to implement +// set/get methods for mapulating a GRState's generic data map. +// +//===----------------------------------------------------------------------===// + + +#ifndef LLVM_CLANG_ANALYSIS_GRSTATETRAIT_H +#define LLVM_CLANG_ANALYSIS_GRSTATETRAIT_H + +namespace llvm { + class BumpPtrAllocator; + template <typename K, typename D, typename I> class ImmutableMap; + template <typename K, typename I> class ImmutableSet; + template <typename T> class ImmutableList; + template <typename T> class ImmutableListImpl; +} + +namespace clang { + template <typename T> struct GRStatePartialTrait; + + // Partial-specialization for ImmutableMap. + + template <typename Key, typename Data, typename Info> + struct GRStatePartialTrait< llvm::ImmutableMap<Key,Data,Info> > { + typedef llvm::ImmutableMap<Key,Data,Info> data_type; + typedef typename data_type::Factory& context_type; + typedef Key key_type; + typedef Data value_type; + typedef const value_type* lookup_type; + + static inline data_type MakeData(void* const* p) { + return p ? data_type((typename data_type::TreeTy*) *p) : data_type(0); + } + static inline void* MakeVoidPtr(data_type B) { + return B.getRoot(); + } + static lookup_type Lookup(data_type B, key_type K) { + return B.lookup(K); + } + static data_type Set(data_type B, key_type K, value_type E,context_type F){ + return F.Add(B, K, E); + } + + static data_type Remove(data_type B, key_type K, context_type F) { + return F.Remove(B, K); + } + + static inline context_type MakeContext(void* p) { + return *((typename data_type::Factory*) p); + } + + static void* CreateContext(llvm::BumpPtrAllocator& Alloc) { + return new typename data_type::Factory(Alloc); + } + + static void DeleteContext(void* Ctx) { + delete (typename data_type::Factory*) Ctx; + } + }; + + + // Partial-specialization for ImmutableSet. + + template <typename Key, typename Info> + struct GRStatePartialTrait< llvm::ImmutableSet<Key,Info> > { + typedef llvm::ImmutableSet<Key,Info> data_type; + typedef typename data_type::Factory& context_type; + typedef Key key_type; + + static inline data_type MakeData(void* const* p) { + return p ? data_type((typename data_type::TreeTy*) *p) : data_type(0); + } + + static inline void* MakeVoidPtr(data_type B) { + return B.getRoot(); + } + + static data_type Add(data_type B, key_type K, context_type F) { + return F.Add(B, K); + } + + static data_type Remove(data_type B, key_type K, context_type F) { + return F.Remove(B, K); + } + + static bool Contains(data_type B, key_type K) { + return B.contains(K); + } + + static inline context_type MakeContext(void* p) { + return *((typename data_type::Factory*) p); + } + + static void* CreateContext(llvm::BumpPtrAllocator& Alloc) { + return new typename data_type::Factory(Alloc); + } + + static void DeleteContext(void* Ctx) { + delete (typename data_type::Factory*) Ctx; + } + }; + + // Partial-specialization for ImmutableList. + + template <typename T> + struct GRStatePartialTrait< llvm::ImmutableList<T> > { + typedef llvm::ImmutableList<T> data_type; + typedef T key_type; + typedef typename data_type::Factory& context_type; + + static data_type Add(data_type L, key_type K, context_type F) { + return F.Add(K, L); + } + + static inline data_type MakeData(void* const* p) { + return p ? data_type((const llvm::ImmutableListImpl<T>*) *p) + : data_type(0); + } + + static inline void* MakeVoidPtr(data_type D) { + return (void*) D.getInternalPointer(); + } + + static inline context_type MakeContext(void* p) { + return *((typename data_type::Factory*) p); + } + + static void* CreateContext(llvm::BumpPtrAllocator& Alloc) { + return new typename data_type::Factory(Alloc); + } + + static void DeleteContext(void* Ctx) { + delete (typename data_type::Factory*) Ctx; + } + }; +} // end clang namespace + +#endif diff --git a/include/clang/Analysis/PathSensitive/GRTransferFuncs.h b/include/clang/Analysis/PathSensitive/GRTransferFuncs.h new file mode 100644 index 000000000000..0f353d07004f --- /dev/null +++ b/include/clang/Analysis/PathSensitive/GRTransferFuncs.h @@ -0,0 +1,123 @@ +//== GRTransferFuncs.h - Path-Sens. Transfer Functions Interface -*- C++ -*--=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines GRTransferFuncs, which provides a base-class that +// defines an interface for transfer functions used by GRExprEngine. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_GRTF +#define LLVM_CLANG_ANALYSIS_GRTF + +#include "clang/Analysis/PathSensitive/SVals.h" +#include "clang/Analysis/PathSensitive/GRCoreEngine.h" +#include "clang/Analysis/PathSensitive/GRState.h" +#include <vector> + +namespace clang { + + class GRExprEngine; + class BugReporter; + class ObjCMessageExpr; + class GRStmtNodeBuilderRef; + +class GRTransferFuncs { + friend class GRExprEngine; +protected: + virtual SVal DetermEvalBinOpNN(GRExprEngine& Eng, + BinaryOperator::Opcode Op, + NonLoc L, NonLoc R, QualType T) { + return UnknownVal(); + } + +public: + GRTransferFuncs() {} + virtual ~GRTransferFuncs() {} + + virtual void RegisterPrinters(std::vector<GRState::Printer*>& Printers) {} + virtual void RegisterChecks(BugReporter& BR) {} + + // Casts. + + virtual SVal EvalCast(GRExprEngine& Engine, NonLoc V, QualType CastT) =0; + virtual SVal EvalCast(GRExprEngine& Engine, Loc V, QualType CastT) = 0; + + // Unary Operators. + + virtual SVal EvalMinus(GRExprEngine& Engine, UnaryOperator* U, NonLoc X) = 0; + + virtual SVal EvalComplement(GRExprEngine& Engine, NonLoc X) = 0; + + // Binary Operators. + // FIXME: We're moving back towards using GREXprEngine directly. No need + // for OStates + virtual void EvalBinOpNN(GRStateSet& OStates, GRExprEngine& Eng, + const GRState* St, Expr* Ex, + BinaryOperator::Opcode Op, NonLoc L, NonLoc R, + QualType T); + + virtual SVal EvalBinOp(GRExprEngine& Engine, BinaryOperator::Opcode Op, + Loc L, Loc R) = 0; + + // Pointer arithmetic. + + virtual SVal EvalBinOp(GRExprEngine& Engine, const GRState *state, + BinaryOperator::Opcode Op, Loc L, NonLoc R) = 0; + + // Calls. + + virtual void EvalCall(ExplodedNodeSet<GRState>& Dst, + GRExprEngine& Engine, + GRStmtNodeBuilder<GRState>& Builder, + CallExpr* CE, SVal L, + ExplodedNode<GRState>* Pred) {} + + virtual void EvalObjCMessageExpr(ExplodedNodeSet<GRState>& Dst, + GRExprEngine& Engine, + GRStmtNodeBuilder<GRState>& Builder, + ObjCMessageExpr* ME, + ExplodedNode<GRState>* Pred) {} + + // Stores. + + virtual void EvalBind(GRStmtNodeBuilderRef& B, SVal location, SVal val) {} + + // End-of-path and dead symbol notification. + + virtual void EvalEndPath(GRExprEngine& Engine, + GREndPathNodeBuilder<GRState>& Builder) {} + + + virtual void EvalDeadSymbols(ExplodedNodeSet<GRState>& Dst, + GRExprEngine& Engine, + GRStmtNodeBuilder<GRState>& Builder, + ExplodedNode<GRState>* Pred, + Stmt* S, const GRState* state, + SymbolReaper& SymReaper) {} + + // Return statements. + virtual void EvalReturn(ExplodedNodeSet<GRState>& Dst, + GRExprEngine& Engine, + GRStmtNodeBuilder<GRState>& Builder, + ReturnStmt* S, + ExplodedNode<GRState>* Pred) {} + + // Assumptions. + + virtual const GRState* EvalAssume(GRStateManager& VMgr, + const GRState* St, + SVal Cond, bool Assumption, + bool& isFeasible) { + return St; + } +}; + +} // end clang namespace + +#endif diff --git a/include/clang/Analysis/PathSensitive/GRWorkList.h b/include/clang/Analysis/PathSensitive/GRWorkList.h new file mode 100644 index 000000000000..c76532294c1f --- /dev/null +++ b/include/clang/Analysis/PathSensitive/GRWorkList.h @@ -0,0 +1,76 @@ +//==- GRWorkList.h - Worklist class used by GRCoreEngine -----------*- C++ -*-// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines GRWorkList, a pure virtual class that represents an opaque +// worklist used by GRCoreEngine to explore the reachability state space. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_GRWORKLIST +#define LLVM_CLANG_ANALYSIS_GRWORKLIST + +#include "clang/Analysis/PathSensitive/GRBlockCounter.h" + +namespace clang { + +class ExplodedNodeImpl; + +class GRWorkListUnit { + ExplodedNodeImpl* Node; + GRBlockCounter Counter; + CFGBlock* Block; + unsigned BlockIdx; + +public: + GRWorkListUnit(ExplodedNodeImpl* N, GRBlockCounter C, + CFGBlock* B, unsigned idx) + : Node(N), + Counter(C), + Block(B), + BlockIdx(idx) {} + + explicit GRWorkListUnit(ExplodedNodeImpl* N, GRBlockCounter C) + : Node(N), + Counter(C), + Block(NULL), + BlockIdx(0) {} + + ExplodedNodeImpl* getNode() const { return Node; } + GRBlockCounter getBlockCounter() const { return Counter; } + CFGBlock* getBlock() const { return Block; } + unsigned getIndex() const { return BlockIdx; } +}; + +class GRWorkList { + GRBlockCounter CurrentCounter; +public: + virtual ~GRWorkList(); + virtual bool hasWork() const = 0; + + virtual void Enqueue(const GRWorkListUnit& U) = 0; + + void Enqueue(ExplodedNodeImpl* N, CFGBlock& B, unsigned idx) { + Enqueue(GRWorkListUnit(N, CurrentCounter, &B, idx)); + } + + void Enqueue(ExplodedNodeImpl* N) { + Enqueue(GRWorkListUnit(N, CurrentCounter)); + } + + virtual GRWorkListUnit Dequeue() = 0; + + void setBlockCounter(GRBlockCounter C) { CurrentCounter = C; } + GRBlockCounter getBlockCounter() const { return CurrentCounter; } + + static GRWorkList *MakeDFS(); + static GRWorkList *MakeBFS(); + static GRWorkList *MakeBFSBlockDFSContents(); +}; +} // end clang namespace +#endif diff --git a/include/clang/Analysis/PathSensitive/MemRegion.h b/include/clang/Analysis/PathSensitive/MemRegion.h new file mode 100644 index 000000000000..0e8da2aee318 --- /dev/null +++ b/include/clang/Analysis/PathSensitive/MemRegion.h @@ -0,0 +1,665 @@ +//== MemRegion.h - Abstract memory regions for static 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 defines MemRegion and its subclasses. MemRegion defines a +// partially-typed abstraction of memory useful for path-sensitive dataflow +// analyses. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_MEMREGION_H +#define LLVM_CLANG_ANALYSIS_MEMREGION_H + +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Analysis/PathSensitive/SymbolManager.h" +#include "clang/Analysis/PathSensitive/SVals.h" +#include "clang/AST/ASTContext.h" +#include "llvm/Support/Casting.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/ImmutableList.h" +#include "llvm/ADT/ImmutableMap.h" +#include "llvm/Support/Allocator.h" +#include <string> + +namespace llvm { class raw_ostream; } + +namespace clang { + +class MemRegionManager; + + +/// MemRegion - The root abstract class for all memory regions. +class MemRegion : public llvm::FoldingSetNode { +public: + enum Kind { MemSpaceRegionKind, + SymbolicRegionKind, + AllocaRegionKind, + // Typed regions. + BEG_TYPED_REGIONS, + CodeTextRegionKind, + CompoundLiteralRegionKind, + StringRegionKind, ElementRegionKind, + TypedViewRegionKind, + // Decl Regions. + BEG_DECL_REGIONS, + VarRegionKind, FieldRegionKind, + ObjCIvarRegionKind, ObjCObjectRegionKind, + END_DECL_REGIONS, + END_TYPED_REGIONS }; +private: + const Kind kind; + +protected: + MemRegion(Kind k) : kind(k) {} + virtual ~MemRegion(); + +public: + // virtual MemExtent getExtent(MemRegionManager& mrm) const = 0; + virtual void Profile(llvm::FoldingSetNodeID& ID) const = 0; + + std::string getString() const; + + virtual void print(llvm::raw_ostream& os) const; + + Kind getKind() const { return kind; } + + template<typename RegionTy> const RegionTy* getAs() const; + + virtual bool isBoundable(ASTContext&) const { return true; } + + static bool classof(const MemRegion*) { return true; } +}; + +/// MemSpaceRegion - A memory region that represents and "memory space"; +/// for example, the set of global variables, the stack frame, etc. +class MemSpaceRegion : public MemRegion { + friend class MemRegionManager; + MemSpaceRegion() : MemRegion(MemSpaceRegionKind) {} + +public: + //RegionExtent getExtent() const { return UndefinedExtent(); } + + void Profile(llvm::FoldingSetNodeID& ID) const; + + bool isBoundable(ASTContext &) const { return false; } + + static bool classof(const MemRegion* R) { + return R->getKind() == MemSpaceRegionKind; + } +}; + +/// SubRegion - A region that subsets another larger region. Most regions +/// are subclasses of SubRegion. +class SubRegion : public MemRegion { +protected: + const MemRegion* superRegion; + SubRegion(const MemRegion* sReg, Kind k) : MemRegion(k), superRegion(sReg) {} + +public: + const MemRegion* getSuperRegion() const { + return superRegion; + } + + bool isSubRegionOf(const MemRegion* R) const; + + static bool classof(const MemRegion* R) { + return R->getKind() > MemSpaceRegionKind; + } +}; + +/// AllocaRegion - A region that represents an untyped blob of bytes created +/// by a call to 'alloca'. +class AllocaRegion : public SubRegion { + friend class MemRegionManager; +protected: + unsigned Cnt; // Block counter. Used to distinguish different pieces of + // memory allocated by alloca at the same call site. + const Expr* Ex; + + AllocaRegion(const Expr* ex, unsigned cnt, const MemRegion* superRegion) + : SubRegion(superRegion, AllocaRegionKind), Cnt(cnt), Ex(ex) {} + +public: + + const Expr* getExpr() const { return Ex; } + + void Profile(llvm::FoldingSetNodeID& ID) const; + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Expr* Ex, + unsigned Cnt); + + void print(llvm::raw_ostream& os) const; + + static bool classof(const MemRegion* R) { + return R->getKind() == AllocaRegionKind; + } +}; + +/// TypedRegion - An abstract class representing regions that are typed. +class TypedRegion : public SubRegion { +protected: + TypedRegion(const MemRegion* sReg, Kind k) : SubRegion(sReg, k) {} + +public: + virtual QualType getValueType(ASTContext &C) const = 0; + + virtual QualType getLocationType(ASTContext& C) const { + // FIXME: We can possibly optimize this later to cache this value. + return C.getPointerType(getValueType(C)); + } + + QualType getDesugaredValueType(ASTContext& C) const { + QualType T = getValueType(C); + return T.getTypePtr() ? T->getDesugaredType() : T; + } + + QualType getDesugaredLocationType(ASTContext& C) const { + return getLocationType(C)->getDesugaredType(); + } + + bool isBoundable(ASTContext &C) const { + return !getValueType(C).isNull(); + } + + static bool classof(const MemRegion* R) { + unsigned k = R->getKind(); + return k > BEG_TYPED_REGIONS && k < END_TYPED_REGIONS; + } +}; + +/// CodeTextRegion - A region that represents code texts of a function. It wraps +/// two kinds of code texts: real function and symbolic function. Real function +/// is a function declared in the program. Symbolic function is a function +/// pointer that we don't know which function it points to. +class CodeTextRegion : public TypedRegion { +public: + enum CodeKind { Declared, Symbolic }; + +private: + // The function pointer kind that this CodeTextRegion represents. + CodeKind codekind; + + // Data may be a SymbolRef or FunctionDecl*. + const void* Data; + + // Cached function pointer type. + QualType LocationType; + +public: + + CodeTextRegion(const FunctionDecl* fd, QualType t, const MemRegion* sreg) + : TypedRegion(sreg, CodeTextRegionKind), + codekind(Declared), + Data(fd), + LocationType(t) {} + + CodeTextRegion(SymbolRef sym, QualType t, const MemRegion* sreg) + : TypedRegion(sreg, CodeTextRegionKind), + codekind(Symbolic), + Data(sym), + LocationType(t) {} + + QualType getValueType(ASTContext &C) const { + // Do not get the object type of a CodeTextRegion. + assert(0); + return QualType(); + } + + QualType getLocationType(ASTContext &C) const { + return LocationType; + } + + bool isDeclared() const { return codekind == Declared; } + bool isSymbolic() const { return codekind == Symbolic; } + + const FunctionDecl* getDecl() const { + assert(codekind == Declared); + return static_cast<const FunctionDecl*>(Data); + } + + SymbolRef getSymbol() const { + assert(codekind == Symbolic); + return const_cast<SymbolRef>(static_cast<const SymbolRef>(Data)); + } + + bool isBoundable(ASTContext&) const { return false; } + + virtual void print(llvm::raw_ostream& os) const; + + void Profile(llvm::FoldingSetNodeID& ID) const; + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, + const void* data, QualType t); + + static bool classof(const MemRegion* R) { + return R->getKind() == CodeTextRegionKind; + } +}; + +/// SymbolicRegion - A special, "non-concrete" region. Unlike other region +/// clases, SymbolicRegion represents a region that serves as an alias for +/// either a real region, a NULL pointer, etc. It essentially is used to +/// map the concept of symbolic values into the domain of regions. Symbolic +/// regions do not need to be typed. +class SymbolicRegion : public SubRegion { +protected: + const SymbolRef sym; + +public: + SymbolicRegion(const SymbolRef s, const MemRegion* sreg) + : SubRegion(sreg, SymbolicRegionKind), sym(s) {} + + SymbolRef getSymbol() const { + return sym; + } + + void Profile(llvm::FoldingSetNodeID& ID) const; + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, SymbolRef sym); + + void print(llvm::raw_ostream& os) const; + + static bool classof(const MemRegion* R) { + return R->getKind() == SymbolicRegionKind; + } +}; + +/// StringRegion - Region associated with a StringLiteral. +class StringRegion : public TypedRegion { + friend class MemRegionManager; + const StringLiteral* Str; +protected: + + StringRegion(const StringLiteral* str, MemRegion* sreg) + : TypedRegion(sreg, StringRegionKind), Str(str) {} + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, + const StringLiteral* Str, + const MemRegion* superRegion); + +public: + + const StringLiteral* getStringLiteral() const { return Str; } + + QualType getValueType(ASTContext& C) const { + return Str->getType(); + } + + void Profile(llvm::FoldingSetNodeID& ID) const { + ProfileRegion(ID, Str, superRegion); + } + + void print(llvm::raw_ostream& os) const; + + static bool classof(const MemRegion* R) { + return R->getKind() == StringRegionKind; + } +}; + +class TypedViewRegion : public TypedRegion { + friend class MemRegionManager; + QualType LValueType; + + TypedViewRegion(QualType lvalueType, const MemRegion* sreg) + : TypedRegion(sreg, TypedViewRegionKind), LValueType(lvalueType) {} + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, QualType T, + const MemRegion* superRegion); + +public: + + void print(llvm::raw_ostream& os) const; + + QualType getLocationType(ASTContext&) const { + return LValueType; + } + + QualType getValueType(ASTContext&) const { + const PointerType* PTy = LValueType->getAsPointerType(); + assert(PTy); + return PTy->getPointeeType(); + } + + bool isBoundable(ASTContext &C) const { + return isa<PointerType>(LValueType); + } + + void Profile(llvm::FoldingSetNodeID& ID) const { + ProfileRegion(ID, LValueType, superRegion); + } + + static bool classof(const MemRegion* R) { + return R->getKind() == TypedViewRegionKind; + } + + const MemRegion *removeViews() const; +}; + + +/// CompoundLiteralRegion - A memory region representing a compound literal. +/// Compound literals are essentially temporaries that are stack allocated +/// or in the global constant pool. +class CompoundLiteralRegion : public TypedRegion { +private: + friend class MemRegionManager; + const CompoundLiteralExpr* CL; + + CompoundLiteralRegion(const CompoundLiteralExpr* cl, const MemRegion* sReg) + : TypedRegion(sReg, CompoundLiteralRegionKind), CL(cl) {} + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, + const CompoundLiteralExpr* CL, + const MemRegion* superRegion); +public: + QualType getValueType(ASTContext& C) const { + return C.getCanonicalType(CL->getType()); + } + + void Profile(llvm::FoldingSetNodeID& ID) const; + + void print(llvm::raw_ostream& os) const; + + const CompoundLiteralExpr* getLiteralExpr() const { return CL; } + + static bool classof(const MemRegion* R) { + return R->getKind() == CompoundLiteralRegionKind; + } +}; + +class DeclRegion : public TypedRegion { +protected: + const Decl* D; + + DeclRegion(const Decl* d, const MemRegion* sReg, Kind k) + : TypedRegion(sReg, k), D(d) {} + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Decl* D, + const MemRegion* superRegion, Kind k); + +public: + const Decl* getDecl() const { return D; } + void Profile(llvm::FoldingSetNodeID& ID) const; + + static bool classof(const MemRegion* R) { + unsigned k = R->getKind(); + return k > BEG_DECL_REGIONS && k < END_DECL_REGIONS; + } +}; + +class VarRegion : public DeclRegion { + friend class MemRegionManager; + + VarRegion(const VarDecl* vd, const MemRegion* sReg) + : DeclRegion(vd, sReg, VarRegionKind) {} + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, VarDecl* VD, + const MemRegion* superRegion) { + DeclRegion::ProfileRegion(ID, VD, superRegion, VarRegionKind); + } + +public: + const VarDecl* getDecl() const { return cast<VarDecl>(D); } + + QualType getValueType(ASTContext& C) const { + // FIXME: We can cache this if needed. + return C.getCanonicalType(getDecl()->getType()); + } + + void print(llvm::raw_ostream& os) const; + + static bool classof(const MemRegion* R) { + return R->getKind() == VarRegionKind; + } +}; + +class FieldRegion : public DeclRegion { + friend class MemRegionManager; + + FieldRegion(const FieldDecl* fd, const MemRegion* sReg) + : DeclRegion(fd, sReg, FieldRegionKind) {} + +public: + + void print(llvm::raw_ostream& os) const; + + const FieldDecl* getDecl() const { return cast<FieldDecl>(D); } + + QualType getValueType(ASTContext& C) const { + // FIXME: We can cache this if needed. + return C.getCanonicalType(getDecl()->getType()); + } + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, FieldDecl* FD, + const MemRegion* superRegion) { + DeclRegion::ProfileRegion(ID, FD, superRegion, FieldRegionKind); + } + + static bool classof(const MemRegion* R) { + return R->getKind() == FieldRegionKind; + } +}; + +class ObjCObjectRegion : public DeclRegion { + + friend class MemRegionManager; + + ObjCObjectRegion(const ObjCInterfaceDecl* ivd, const MemRegion* sReg) + : DeclRegion(ivd, sReg, ObjCObjectRegionKind) {} + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, ObjCInterfaceDecl* ivd, + const MemRegion* superRegion) { + DeclRegion::ProfileRegion(ID, ivd, superRegion, ObjCObjectRegionKind); + } + +public: + const ObjCInterfaceDecl* getInterface() const { + return cast<ObjCInterfaceDecl>(D); + } + + QualType getValueType(ASTContext& C) const { + return C.getObjCInterfaceType(getInterface()); + } + + static bool classof(const MemRegion* R) { + return R->getKind() == ObjCObjectRegionKind; + } +}; + +class ObjCIvarRegion : public DeclRegion { + + friend class MemRegionManager; + + ObjCIvarRegion(const ObjCIvarDecl* ivd, const MemRegion* sReg) + : DeclRegion(ivd, sReg, ObjCIvarRegionKind) {} + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, ObjCIvarDecl* ivd, + const MemRegion* superRegion) { + DeclRegion::ProfileRegion(ID, ivd, superRegion, ObjCIvarRegionKind); + } + +public: + const ObjCIvarDecl* getDecl() const { return cast<ObjCIvarDecl>(D); } + QualType getValueType(ASTContext&) const { return getDecl()->getType(); } + + static bool classof(const MemRegion* R) { + return R->getKind() == ObjCIvarRegionKind; + } +}; + +class ElementRegion : public TypedRegion { + friend class MemRegionManager; + + QualType ElementType; + SVal Index; + + ElementRegion(QualType elementType, SVal Idx, const MemRegion* sReg) + : TypedRegion(sReg, ElementRegionKind), + ElementType(elementType), Index(Idx) { + assert((!isa<nonloc::ConcreteInt>(&Idx) || + cast<nonloc::ConcreteInt>(&Idx)->getValue().isSigned()) && + "The index must be signed"); + } + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, QualType elementType, + SVal Idx, const MemRegion* superRegion); + +public: + + SVal getIndex() const { return Index; } + + QualType getValueType(ASTContext&) const { + return ElementType; + } + + QualType getElementType() const { + return ElementType; + } + + void print(llvm::raw_ostream& os) const; + + void Profile(llvm::FoldingSetNodeID& ID) const; + + static bool classof(const MemRegion* R) { + return R->getKind() == ElementRegionKind; + } +}; + +template<typename RegionTy> +const RegionTy* MemRegion::getAs() const { + const MemRegion *R = this; + + do { + if (const RegionTy* RT = dyn_cast<RegionTy>(R)) + return RT; + + if (const TypedViewRegion *TR = dyn_cast<TypedViewRegion>(R)) { + R = TR->getSuperRegion(); + continue; + } + + break; + } + while (R); + + return 0; +} + +//===----------------------------------------------------------------------===// +// MemRegionManager - Factory object for creating regions. +//===----------------------------------------------------------------------===// + +class MemRegionManager { + llvm::BumpPtrAllocator& A; + llvm::FoldingSet<MemRegion> Regions; + + MemSpaceRegion* globals; + MemSpaceRegion* stack; + MemSpaceRegion* heap; + MemSpaceRegion* unknown; + MemSpaceRegion* code; + +public: + MemRegionManager(llvm::BumpPtrAllocator& a) + : A(a), globals(0), stack(0), heap(0), unknown(0), code(0) {} + + ~MemRegionManager() {} + + /// getStackRegion - Retrieve the memory region associated with the + /// current stack frame. + MemSpaceRegion* getStackRegion(); + + /// getGlobalsRegion - Retrieve the memory region associated with + /// all global variables. + MemSpaceRegion* getGlobalsRegion(); + + /// getHeapRegion - Retrieve the memory region associated with the + /// generic "heap". + MemSpaceRegion* getHeapRegion(); + + /// getUnknownRegion - Retrieve the memory region associated with unknown + /// memory space. + MemSpaceRegion* getUnknownRegion(); + + MemSpaceRegion* getCodeRegion(); + + bool isGlobalsRegion(const MemRegion* R) { + assert(R); + return R == globals; + } + + /// onStack - check if the region is allocated on the stack. + bool onStack(const MemRegion* R); + + /// onHeap - check if the region is allocated on the heap, usually by malloc. + bool onHeap(const MemRegion* R); + + /// getAllocaRegion - Retrieve a region associated with a call to alloca(). + AllocaRegion* getAllocaRegion(const Expr* Ex, unsigned Cnt); + + /// getCompoundLiteralRegion - Retrieve the region associated with a + /// given CompoundLiteral. + CompoundLiteralRegion* + getCompoundLiteralRegion(const CompoundLiteralExpr* CL); + + /// getSymbolicRegion - Retrieve or create a "symbolic" memory region. + SymbolicRegion* getSymbolicRegion(SymbolRef sym); + + StringRegion* getStringRegion(const StringLiteral* Str); + + /// getVarRegion - Retrieve or create the memory region associated with + /// a specified VarDecl. + VarRegion* getVarRegion(const VarDecl* vd); + + /// getElementRegion - Retrieve the memory region associated with the + /// associated element type, index, and super region. + ElementRegion* getElementRegion(QualType elementType, SVal Idx, + const MemRegion* superRegion); + + /// getFieldRegion - Retrieve or create the memory region associated with + /// a specified FieldDecl. 'superRegion' corresponds to the containing + /// memory region (which typically represents the memory representing + /// a structure or class). + FieldRegion* getFieldRegion(const FieldDecl* fd, + const MemRegion* superRegion); + + /// getObjCObjectRegion - Retrieve or create the memory region associated with + /// the instance of a specified Objective-C class. + ObjCObjectRegion* getObjCObjectRegion(const ObjCInterfaceDecl* ID, + const MemRegion* superRegion); + + /// getObjCIvarRegion - Retrieve or create the memory region associated with + /// a specified Objective-c instance variable. 'superRegion' corresponds + /// to the containing region (which typically represents the Objective-C + /// object). + ObjCIvarRegion* getObjCIvarRegion(const ObjCIvarDecl* ivd, + const MemRegion* superRegion); + + TypedViewRegion* getTypedViewRegion(QualType LValueType, + const MemRegion* superRegion); + + CodeTextRegion* getCodeTextRegion(SymbolRef sym, QualType t); + CodeTextRegion* getCodeTextRegion(const FunctionDecl* fd, QualType t); + + bool hasStackStorage(const MemRegion* R); + +private: + MemSpaceRegion* LazyAllocate(MemSpaceRegion*& region); +}; +} // end clang namespace + +namespace llvm { +static inline raw_ostream& operator<<(raw_ostream& O, + const clang::MemRegion* R) { + R->print(O); + return O; +} +} // end llvm namespace + +#endif diff --git a/include/clang/Analysis/PathSensitive/SVals.h b/include/clang/Analysis/PathSensitive/SVals.h new file mode 100644 index 000000000000..ee6d4dcf1f37 --- /dev/null +++ b/include/clang/Analysis/PathSensitive/SVals.h @@ -0,0 +1,447 @@ +//== SVals.h - Abstract Values for Static 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 defines SVal, Loc, and NonLoc, classes that represent +// abstract r-values for use with path-sensitive value tracking. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_RVALUE_H +#define LLVM_CLANG_ANALYSIS_RVALUE_H + +#include "clang/Analysis/PathSensitive/SymbolManager.h" +#include "llvm/Support/Casting.h" +#include "llvm/ADT/ImmutableList.h" + +//==------------------------------------------------------------------------==// +// Base SVal types. +//==------------------------------------------------------------------------==// + +namespace clang { + +class CompoundValData; +class BasicValueFactory; +class MemRegion; +class MemRegionManager; +class GRStateManager; + +class SVal { +public: + enum BaseKind { UndefinedKind, UnknownKind, LocKind, NonLocKind }; + enum { BaseBits = 2, BaseMask = 0x3 }; + +protected: + void* Data; + unsigned Kind; + +protected: + SVal(const void* d, bool isLoc, unsigned ValKind) + : Data(const_cast<void*>(d)), + Kind((isLoc ? LocKind : NonLocKind) | (ValKind << BaseBits)) {} + + explicit SVal(BaseKind k, void* D = NULL) + : Data(D), Kind(k) {} + +public: + SVal() : Data(0), Kind(0) {} + ~SVal() {}; + + /// BufferTy - A temporary buffer to hold a set of SVals. + typedef llvm::SmallVector<SVal,5> BufferTy; + + inline unsigned getRawKind() const { return Kind; } + inline BaseKind getBaseKind() const { return (BaseKind) (Kind & BaseMask); } + inline unsigned getSubKind() const { return (Kind & ~BaseMask) >> BaseBits; } + + inline void Profile(llvm::FoldingSetNodeID& ID) const { + ID.AddInteger((unsigned) getRawKind()); + ID.AddPointer(reinterpret_cast<void*>(Data)); + } + + inline bool operator==(const SVal& R) const { + return getRawKind() == R.getRawKind() && Data == R.Data; + } + + inline bool operator!=(const SVal& R) const { + return !(*this == R); + } + + inline bool isUnknown() const { + return getRawKind() == UnknownKind; + } + + inline bool isUndef() const { + return getRawKind() == UndefinedKind; + } + + inline bool isUnknownOrUndef() const { + return getRawKind() <= UnknownKind; + } + + inline bool isValid() const { + return getRawKind() > UnknownKind; + } + + bool isZeroConstant() const; + + /// hasConjuredSymbol - If this SVal wraps a conjured symbol, return true; + bool hasConjuredSymbol() const; + + /// getAsFunctionDecl - If this SVal is a MemRegionVal and wraps a + /// CodeTextRegion wrapping a FunctionDecl, return that FunctionDecl. + /// Otherwise return 0. + const FunctionDecl* getAsFunctionDecl() const; + + /// getAsLocSymbol - If this SVal is a location (subclasses Loc) and + /// wraps a symbol, return that SymbolRef. Otherwise return a SymbolData* + SymbolRef getAsLocSymbol() const; + + /// getAsSymbol - If this Sval wraps a symbol return that SymbolRef. + /// Otherwise return a SymbolRef where 'isValid()' returns false. + SymbolRef getAsSymbol() const; + + /// getAsSymbolicExpression - If this Sval wraps a symbolic expression then + /// return that expression. Otherwise return NULL. + const SymExpr *getAsSymbolicExpression() const; + + void print(std::ostream& OS) const; + void print(llvm::raw_ostream& OS) const; + void printStdErr() const; + + // Iterators. + class symbol_iterator { + llvm::SmallVector<const SymExpr*, 5> itr; + void expand(); + public: + symbol_iterator() {} + symbol_iterator(const SymExpr* SE); + + symbol_iterator& operator++(); + SymbolRef operator*(); + + bool operator==(const symbol_iterator& X) const; + bool operator!=(const symbol_iterator& X) const; + }; + + symbol_iterator symbol_begin() const { + const SymExpr *SE = getAsSymbolicExpression(); + if (SE) + return symbol_iterator(SE); + else + return symbol_iterator(); + } + + symbol_iterator symbol_end() const { return symbol_iterator(); } + + // Implement isa<T> support. + static inline bool classof(const SVal*) { return true; } +}; + +class UnknownVal : public SVal { +public: + UnknownVal() : SVal(UnknownKind) {} + + static inline bool classof(const SVal* V) { + return V->getBaseKind() == UnknownKind; + } +}; + +class UndefinedVal : public SVal { +public: + UndefinedVal() : SVal(UndefinedKind) {} + UndefinedVal(void* D) : SVal(UndefinedKind, D) {} + + static inline bool classof(const SVal* V) { + return V->getBaseKind() == UndefinedKind; + } + + void* getData() const { return Data; } +}; + +class NonLoc : public SVal { +protected: + NonLoc(unsigned SubKind, const void* d) : SVal(d, false, SubKind) {} + +public: + void print(llvm::raw_ostream& Out) const; + + // Utility methods to create NonLocs. + + static NonLoc MakeIntVal(BasicValueFactory& BasicVals, uint64_t X, + bool isUnsigned); + + static NonLoc MakeVal(BasicValueFactory& BasicVals, uint64_t X, + unsigned BitWidth, bool isUnsigned); + + static NonLoc MakeVal(BasicValueFactory& BasicVals, uint64_t X, QualType T); + + static NonLoc MakeVal(BasicValueFactory& BasicVals, IntegerLiteral* I); + + static NonLoc MakeVal(BasicValueFactory& BasicVals, const llvm::APInt& I, + bool isUnsigned); + + static NonLoc MakeVal(BasicValueFactory& BasicVals, const llvm::APSInt& I); + + static NonLoc MakeIntTruthVal(BasicValueFactory& BasicVals, bool b); + + static NonLoc MakeCompoundVal(QualType T, llvm::ImmutableList<SVal> Vals, + BasicValueFactory& BasicVals); + + // Implement isa<T> support. + static inline bool classof(const SVal* V) { + return V->getBaseKind() == NonLocKind; + } +}; + +class Loc : public SVal { +protected: + Loc(unsigned SubKind, const void* D) + : SVal(const_cast<void*>(D), true, SubKind) {} + +public: + void print(llvm::raw_ostream& Out) const; + + Loc(const Loc& X) : SVal(X.Data, true, X.getSubKind()) {} + Loc& operator=(const Loc& X) { memcpy(this, &X, sizeof(Loc)); return *this; } + + static Loc MakeVal(const MemRegion* R); + + static Loc MakeVal(AddrLabelExpr* E); + + static Loc MakeNull(BasicValueFactory &BasicVals); + + // Implement isa<T> support. + static inline bool classof(const SVal* V) { + return V->getBaseKind() == LocKind; + } + + static inline bool IsLocType(QualType T) { + return T->isPointerType() || T->isObjCQualifiedIdType() + || T->isBlockPointerType(); + } +}; + +//==------------------------------------------------------------------------==// +// Subclasses of NonLoc. +//==------------------------------------------------------------------------==// + +namespace nonloc { + +enum Kind { ConcreteIntKind, SymbolValKind, SymExprValKind, + LocAsIntegerKind, CompoundValKind }; + +class SymbolVal : public NonLoc { +public: + SymbolVal(SymbolRef sym) : NonLoc(SymbolValKind, sym) {} + + SymbolRef getSymbol() const { + return (const SymbolData*) Data; + } + + static inline bool classof(const SVal* V) { + return V->getBaseKind() == NonLocKind && + V->getSubKind() == SymbolValKind; + } + + static inline bool classof(const NonLoc* V) { + return V->getSubKind() == SymbolValKind; + } +}; + +class SymExprVal : public NonLoc { +public: + SymExprVal(const SymExpr *SE) + : NonLoc(SymExprValKind, reinterpret_cast<const void*>(SE)) {} + + const SymExpr *getSymbolicExpression() const { + return reinterpret_cast<SymExpr*>(Data); + } + + static inline bool classof(const SVal* V) { + return V->getBaseKind() == NonLocKind && + V->getSubKind() == SymExprValKind; + } + + static inline bool classof(const NonLoc* V) { + return V->getSubKind() == SymExprValKind; + } +}; + +class ConcreteInt : public NonLoc { +public: + ConcreteInt(const llvm::APSInt& V) : NonLoc(ConcreteIntKind, &V) {} + + const llvm::APSInt& getValue() const { + return *static_cast<llvm::APSInt*>(Data); + } + + // Transfer functions for binary/unary operations on ConcreteInts. + SVal EvalBinOp(BasicValueFactory& BasicVals, BinaryOperator::Opcode Op, + const ConcreteInt& R) const; + + ConcreteInt EvalComplement(BasicValueFactory& BasicVals) const; + + ConcreteInt EvalMinus(BasicValueFactory& BasicVals, UnaryOperator* U) const; + + // Implement isa<T> support. + static inline bool classof(const SVal* V) { + return V->getBaseKind() == NonLocKind && + V->getSubKind() == ConcreteIntKind; + } + + static inline bool classof(const NonLoc* V) { + return V->getSubKind() == ConcreteIntKind; + } +}; + +class LocAsInteger : public NonLoc { + LocAsInteger(const std::pair<SVal, uintptr_t>& data) : + NonLoc(LocAsIntegerKind, &data) { + assert (isa<Loc>(data.first)); + } + +public: + + Loc getLoc() const { + return cast<Loc>(((std::pair<SVal, uintptr_t>*) Data)->first); + } + + const Loc& getPersistentLoc() const { + const SVal& V = ((std::pair<SVal, uintptr_t>*) Data)->first; + return cast<Loc>(V); + } + + unsigned getNumBits() const { + return ((std::pair<SVal, unsigned>*) Data)->second; + } + + // Implement isa<T> support. + static inline bool classof(const SVal* V) { + return V->getBaseKind() == NonLocKind && + V->getSubKind() == LocAsIntegerKind; + } + + static inline bool classof(const NonLoc* V) { + return V->getSubKind() == LocAsIntegerKind; + } + + static LocAsInteger Make(BasicValueFactory& Vals, Loc V, unsigned Bits); +}; + +class CompoundVal : public NonLoc { + friend class NonLoc; + + CompoundVal(const CompoundValData* D) : NonLoc(CompoundValKind, D) {} + +public: + const CompoundValData* getValue() const { + return static_cast<CompoundValData*>(Data); + } + + typedef llvm::ImmutableList<SVal>::iterator iterator; + iterator begin() const; + iterator end() const; + + static bool classof(const SVal* V) { + return V->getBaseKind() == NonLocKind && V->getSubKind() == CompoundValKind; + } + + static bool classof(const NonLoc* V) { + return V->getSubKind() == CompoundValKind; + } +}; + +} // end namespace clang::nonloc + +//==------------------------------------------------------------------------==// +// Subclasses of Loc. +//==------------------------------------------------------------------------==// + +namespace loc { + +enum Kind { GotoLabelKind, MemRegionKind, ConcreteIntKind }; + +class GotoLabel : public Loc { +public: + GotoLabel(LabelStmt* Label) : Loc(GotoLabelKind, Label) {} + + LabelStmt* getLabel() const { + return static_cast<LabelStmt*>(Data); + } + + static inline bool classof(const SVal* V) { + return V->getBaseKind() == LocKind && + V->getSubKind() == GotoLabelKind; + } + + static inline bool classof(const Loc* V) { + return V->getSubKind() == GotoLabelKind; + } +}; + + +class MemRegionVal : public Loc { +public: + MemRegionVal(const MemRegion* r) : Loc(MemRegionKind, r) {} + + const MemRegion* getRegion() const { + return static_cast<MemRegion*>(Data); + } + + template <typename REGION> + const REGION* getRegionAs() const { + return llvm::dyn_cast<REGION>(getRegion()); + } + + inline bool operator==(const MemRegionVal& R) const { + return getRegion() == R.getRegion(); + } + + inline bool operator!=(const MemRegionVal& R) const { + return getRegion() != R.getRegion(); + } + + // Implement isa<T> support. + static inline bool classof(const SVal* V) { + return V->getBaseKind() == LocKind && + V->getSubKind() == MemRegionKind; + } + + static inline bool classof(const Loc* V) { + return V->getSubKind() == MemRegionKind; + } +}; + +class ConcreteInt : public Loc { +public: + ConcreteInt(const llvm::APSInt& V) : Loc(ConcreteIntKind, &V) {} + + const llvm::APSInt& getValue() const { + return *static_cast<llvm::APSInt*>(Data); + } + + // Transfer functions for binary/unary operations on ConcreteInts. + SVal EvalBinOp(BasicValueFactory& BasicVals, BinaryOperator::Opcode Op, + const ConcreteInt& R) const; + + // Implement isa<T> support. + static inline bool classof(const SVal* V) { + return V->getBaseKind() == LocKind && + V->getSubKind() == ConcreteIntKind; + } + + static inline bool classof(const Loc* V) { + return V->getSubKind() == ConcreteIntKind; + } +}; + +} // end clang::loc namespace +} // end clang namespace + +#endif diff --git a/include/clang/Analysis/PathSensitive/Store.h b/include/clang/Analysis/PathSensitive/Store.h new file mode 100644 index 000000000000..1f081f4eb0d0 --- /dev/null +++ b/include/clang/Analysis/PathSensitive/Store.h @@ -0,0 +1,204 @@ +//== Store.h - Interface for maps from Locations to 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 defined the types Store and StoreManager. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_STORE_H +#define LLVM_CLANG_ANALYSIS_STORE_H + +#include "clang/Analysis/PathSensitive/SVals.h" +#include "clang/Analysis/PathSensitive/MemRegion.h" +#include "clang/Analysis/PathSensitive/ValueManager.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/SmallVector.h" +#include <iosfwd> + +namespace clang { + +typedef const void* Store; + +class GRState; +class GRStateManager; +class Stmt; +class Expr; +class ObjCIvarDecl; +class SubRegionMap; + +class StoreManager { +protected: + ValueManager &ValMgr; + GRStateManager &StateMgr; + + /// MRMgr - Manages region objects associated with this StoreManager. + MemRegionManager &MRMgr; + + StoreManager(GRStateManager &stateMgr); + +protected: + virtual const GRState* AddRegionView(const GRState* St, + const MemRegion* View, + const MemRegion* Base) { + return St; + } + +public: + virtual ~StoreManager() {} + + /// Return the value bound to specified location in a given state. + /// \param[in] state The analysis state. + /// \param[in] loc The symbolic memory location. + /// \param[in] T An optional type that provides a hint indicating the + /// expected type of the returned value. This is used if the value is + /// lazily computed. + /// \return The value bound to the location \c loc. + virtual SVal Retrieve(const GRState* state, Loc loc, + QualType T = QualType()) = 0; + + /// Return a state with the specified value bound to the given location. + /// \param[in] state The analysis state. + /// \param[in] loc The symbolic memory location. + /// \param[in] val The value to bind to location \c loc. + /// \return A pointer to a GRState object that contains the same bindings as + /// \c state with the addition of having the value specified by \c val bound + /// to the location given for \c loc. + virtual const GRState* Bind(const GRState* state, Loc loc, SVal val) = 0; + + virtual Store Remove(Store St, Loc L) = 0; + + /// BindCompoundLiteral - Return the store that has the bindings currently + /// in 'store' plus the bindings for the CompoundLiteral. 'R' is the region + /// for the compound literal and 'BegInit' and 'EndInit' represent an + /// array of initializer values. + virtual const GRState* BindCompoundLiteral(const GRState* St, + const CompoundLiteralExpr* CL, + SVal V) = 0; + + /// getInitialStore - Returns the initial "empty" store representing the + /// value bindings upon entry to an analyzed function. + virtual Store getInitialStore() = 0; + + /// getRegionManager - Returns the internal RegionManager object that is + /// used to query and manipulate MemRegion objects. + MemRegionManager& getRegionManager() { return MRMgr; } + + /// getSubRegionMap - Returns an opaque map object that clients can query + /// to get the subregions of a given MemRegion object. It is the + // caller's responsibility to 'delete' the returned map. + virtual SubRegionMap* getSubRegionMap(const GRState *state) = 0; + + virtual SVal getLValueVar(const GRState* St, const VarDecl* VD) = 0; + + virtual SVal getLValueString(const GRState* St, const StringLiteral* S) = 0; + + virtual SVal getLValueCompoundLiteral(const GRState* St, + const CompoundLiteralExpr* CL) = 0; + + virtual SVal getLValueIvar(const GRState* St, const ObjCIvarDecl* D, + SVal Base) = 0; + + virtual SVal getLValueField(const GRState* St, SVal Base, + const FieldDecl* D) = 0; + + virtual SVal getLValueElement(const GRState* St, QualType elementType, + SVal Base, SVal Offset) = 0; + + virtual SVal getSizeInElements(const GRState* St, const MemRegion* R) { + return UnknownVal(); + } + + /// ArrayToPointer - Used by GRExprEngine::VistCast to handle implicit + /// conversions between arrays and pointers. + virtual SVal ArrayToPointer(Loc Array) = 0; + + + class CastResult { + const GRState* State; + const MemRegion* R; + public: + const GRState* getState() const { return State; } + const MemRegion* getRegion() const { return R; } + CastResult(const GRState* s, const MemRegion* r = 0) : State(s), R(r) {} + }; + + /// CastRegion - Used by GRExprEngine::VisitCast to handle casts from + /// a MemRegion* to a specific location type. 'R' is the region being + /// casted and 'CastToTy' the result type of the cast. + virtual CastResult CastRegion(const GRState* state, const MemRegion* R, + QualType CastToTy); + + /// EvalBinOp - Perform pointer arithmetic. + virtual SVal EvalBinOp(const GRState *state, + BinaryOperator::Opcode Op, Loc L, NonLoc R) { + return UnknownVal(); + } + + /// getSelfRegion - Returns the region for the 'self' (Objective-C) or + /// 'this' object (C++). When used when analyzing a normal function this + /// method returns NULL. + virtual const MemRegion* getSelfRegion(Store store) = 0; + + virtual Store + RemoveDeadBindings(const GRState* state, Stmt* Loc, SymbolReaper& SymReaper, + llvm::SmallVectorImpl<const MemRegion*>& RegionRoots) = 0; + + virtual const GRState* BindDecl(const GRState* St, const VarDecl* VD, + SVal InitVal) = 0; + + virtual const GRState* BindDeclWithNoInit(const GRState* St, + const VarDecl* VD) = 0; + + virtual const GRState* setExtent(const GRState* St, + const MemRegion* R, SVal Extent) { + return St; + } + + virtual const GRState* setDefaultValue(const GRState* St, + const MemRegion* R, SVal V) { + return St; + } + + virtual void print(Store store, std::ostream& Out, + const char* nl, const char *sep) = 0; + + class BindingsHandler { + public: + virtual ~BindingsHandler(); + virtual bool HandleBinding(StoreManager& SMgr, Store store, + const MemRegion* R, SVal val) = 0; + }; + + /// iterBindings - Iterate over the bindings in the Store. + virtual void iterBindings(Store store, BindingsHandler& f) = 0; +}; + +/// SubRegionMap - An abstract interface that represents a queryable map +/// between MemRegion objects and their subregions. +class SubRegionMap { +public: + virtual ~SubRegionMap() {} + + class Visitor { + public: + virtual ~Visitor() {}; + virtual bool Visit(const MemRegion* Parent, const MemRegion* SubRegion) = 0; + }; + + virtual bool iterSubRegions(const MemRegion* R, Visitor& V) const = 0; +}; + +StoreManager* CreateBasicStoreManager(GRStateManager& StMgr); +StoreManager* CreateRegionStoreManager(GRStateManager& StMgr); + +} // end clang namespace + +#endif diff --git a/include/clang/Analysis/PathSensitive/SymbolManager.h b/include/clang/Analysis/PathSensitive/SymbolManager.h new file mode 100644 index 000000000000..d424526d4eb0 --- /dev/null +++ b/include/clang/Analysis/PathSensitive/SymbolManager.h @@ -0,0 +1,329 @@ +//== SymbolManager.h - Management of Symbolic 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 defines SymbolManager, a class that manages symbolic values +// created for use by GRExprEngine and related classes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_SYMMGR_H +#define LLVM_CLANG_ANALYSIS_SYMMGR_H + +#include "clang/AST/Decl.h" +#include "clang/AST/Expr.h" +#include "clang/Analysis/Analyses/LiveVariables.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/Allocator.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/ImmutableSet.h" + +namespace llvm { + class raw_ostream; +} + +namespace clang { + class MemRegion; + class ASTContext; + class BasicValueFactory; +} + +namespace clang { + +class SymExpr : public llvm::FoldingSetNode { +public: + enum Kind { BEGIN_SYMBOLS, RegionValueKind, ConjuredKind, END_SYMBOLS, + SymIntKind, SymSymKind }; +private: + Kind K; + +protected: + SymExpr(Kind k) : K(k) {} + +public: + virtual ~SymExpr() {} + + Kind getKind() const { return K; } + + virtual QualType getType(ASTContext&) const = 0; + virtual void Profile(llvm::FoldingSetNodeID& profile) = 0; + + // Implement isa<T> support. + static inline bool classof(const SymExpr*) { return true; } +}; + +typedef unsigned SymbolID; + +class SymbolData : public SymExpr { +private: + const SymbolID Sym; + +protected: + SymbolData(Kind k, SymbolID sym) : SymExpr(k), Sym(sym) {} + +public: + virtual ~SymbolData() {} + + SymbolID getSymbolID() const { return Sym; } + + // Implement isa<T> support. + static inline bool classof(const SymExpr* SE) { + Kind k = SE->getKind(); + return k > BEGIN_SYMBOLS && k < END_SYMBOLS; + } +}; + +typedef const SymbolData* SymbolRef; + +class SymbolRegionValue : public SymbolData { + const MemRegion *R; +public: + SymbolRegionValue(SymbolID sym, const MemRegion *r) + : SymbolData(RegionValueKind, sym), R(r) {} + + const MemRegion* getRegion() const { return R; } + + static void Profile(llvm::FoldingSetNodeID& profile, const MemRegion* R) { + profile.AddInteger((unsigned) RegionValueKind); + profile.AddPointer(R); + } + + virtual void Profile(llvm::FoldingSetNodeID& profile) { + Profile(profile, R); + } + + QualType getType(ASTContext&) const; + + // Implement isa<T> support. + static inline bool classof(const SymExpr* SE) { + return SE->getKind() == RegionValueKind; + } +}; + +class SymbolConjured : public SymbolData { + const Stmt* S; + QualType T; + unsigned Count; + const void* SymbolTag; + +public: + SymbolConjured(SymbolID sym, const Stmt* s, QualType t, unsigned count, + const void* symbolTag) + : SymbolData(ConjuredKind, sym), S(s), T(t), Count(count), + SymbolTag(symbolTag) {} + + const Stmt* getStmt() const { return S; } + unsigned getCount() const { return Count; } + const void* getTag() const { return SymbolTag; } + + QualType getType(ASTContext&) const; + + static void Profile(llvm::FoldingSetNodeID& profile, const Stmt* S, + QualType T, unsigned Count, const void* SymbolTag) { + profile.AddInteger((unsigned) ConjuredKind); + profile.AddPointer(S); + profile.Add(T); + profile.AddInteger(Count); + profile.AddPointer(SymbolTag); + } + + virtual void Profile(llvm::FoldingSetNodeID& profile) { + Profile(profile, S, T, Count, SymbolTag); + } + + // Implement isa<T> support. + static inline bool classof(const SymExpr* SE) { + return SE->getKind() == ConjuredKind; + } +}; + +// SymIntExpr - Represents symbolic expression like 'x' + 3. +class SymIntExpr : public SymExpr { + const SymExpr *LHS; + BinaryOperator::Opcode Op; + const llvm::APSInt& RHS; + QualType T; + +public: + SymIntExpr(const SymExpr *lhs, BinaryOperator::Opcode op, + const llvm::APSInt& rhs, QualType t) + : SymExpr(SymIntKind), LHS(lhs), Op(op), RHS(rhs), T(t) {} + + // FIXME: We probably need to make this out-of-line to avoid redundant + // generation of virtual functions. + QualType getType(ASTContext& C) const { return T; } + + BinaryOperator::Opcode getOpcode() const { return Op; } + + const SymExpr *getLHS() const { return LHS; } + const llvm::APSInt &getRHS() const { return RHS; } + + static void Profile(llvm::FoldingSetNodeID& ID, const SymExpr *lhs, + BinaryOperator::Opcode op, const llvm::APSInt& rhs, + QualType t) { + ID.AddInteger((unsigned) SymIntKind); + ID.AddPointer(lhs); + ID.AddInteger(op); + ID.AddPointer(&rhs); + ID.Add(t); + } + + void Profile(llvm::FoldingSetNodeID& ID) { + Profile(ID, LHS, Op, RHS, T); + } + + // Implement isa<T> support. + static inline bool classof(const SymExpr* SE) { + return SE->getKind() == SymIntKind; + } +}; + +// SymSymExpr - Represents symbolic expression like 'x' + 'y'. +class SymSymExpr : public SymExpr { + const SymExpr *LHS; + BinaryOperator::Opcode Op; + const SymExpr *RHS; + QualType T; + +public: + SymSymExpr(const SymExpr *lhs, BinaryOperator::Opcode op, const SymExpr *rhs, + QualType t) + : SymExpr(SymSymKind), LHS(lhs), Op(op), RHS(rhs), T(t) {} + + const SymExpr *getLHS() const { return LHS; } + const SymExpr *getRHS() const { return RHS; } + + // FIXME: We probably need to make this out-of-line to avoid redundant + // generation of virtual functions. + QualType getType(ASTContext& C) const { return T; } + + static void Profile(llvm::FoldingSetNodeID& ID, const SymExpr *lhs, + BinaryOperator::Opcode op, const SymExpr *rhs, QualType t) { + ID.AddInteger((unsigned) SymSymKind); + ID.AddPointer(lhs); + ID.AddInteger(op); + ID.AddPointer(rhs); + ID.Add(t); + } + + void Profile(llvm::FoldingSetNodeID& ID) { + Profile(ID, LHS, Op, RHS, T); + } + + // Implement isa<T> support. + static inline bool classof(const SymExpr* SE) { + return SE->getKind() == SymSymKind; + } +}; + +class SymbolManager { + typedef llvm::FoldingSet<SymExpr> DataSetTy; + DataSetTy DataSet; + unsigned SymbolCounter; + llvm::BumpPtrAllocator& BPAlloc; + BasicValueFactory &BV; + ASTContext& Ctx; + +public: + SymbolManager(ASTContext& ctx, BasicValueFactory &bv, + llvm::BumpPtrAllocator& bpalloc) + : SymbolCounter(0), BPAlloc(bpalloc), BV(bv), Ctx(ctx) {} + + ~SymbolManager(); + + static bool canSymbolicate(QualType T); + + /// Make a unique symbol for MemRegion R according to its kind. + const SymbolRegionValue* getRegionValueSymbol(const MemRegion* R); + const SymbolConjured* getConjuredSymbol(const Stmt* E, QualType T, + unsigned VisitCount, + const void* SymbolTag = 0); + + const SymbolConjured* getConjuredSymbol(const Expr* E, unsigned VisitCount, + const void* SymbolTag = 0) { + return getConjuredSymbol(E, E->getType(), VisitCount, SymbolTag); + } + + const SymIntExpr *getSymIntExpr(const SymExpr *lhs, BinaryOperator::Opcode op, + const llvm::APSInt& rhs, QualType t); + + const SymIntExpr *getSymIntExpr(const SymExpr &lhs, BinaryOperator::Opcode op, + const llvm::APSInt& rhs, QualType t) { + return getSymIntExpr(&lhs, op, rhs, t); + } + + const SymSymExpr *getSymSymExpr(const SymExpr *lhs, BinaryOperator::Opcode op, + const SymExpr *rhs, QualType t); + + QualType getType(const SymExpr *SE) const { + return SE->getType(Ctx); + } + + ASTContext &getContext() { return Ctx; } + BasicValueFactory &getBasicVals() { return BV; } +}; + +class SymbolReaper { + typedef llvm::ImmutableSet<SymbolRef> SetTy; + typedef SetTy::Factory FactoryTy; + + FactoryTy F; + SetTy TheLiving; + SetTy TheDead; + LiveVariables& Liveness; + SymbolManager& SymMgr; + +public: + SymbolReaper(LiveVariables& liveness, SymbolManager& symmgr) + : TheLiving(F.GetEmptySet()), TheDead(F.GetEmptySet()), + Liveness(liveness), SymMgr(symmgr) {} + + bool isLive(SymbolRef sym); + + bool isLive(const Stmt* Loc, const Stmt* ExprVal) const { + return Liveness.isLive(Loc, ExprVal); + } + + bool isLive(const Stmt* Loc, const VarDecl* VD) const { + return Liveness.isLive(Loc, VD); + } + + void markLive(SymbolRef sym); + bool maybeDead(SymbolRef sym); + + typedef SetTy::iterator dead_iterator; + dead_iterator dead_begin() const { return TheDead.begin(); } + dead_iterator dead_end() const { return TheDead.end(); } + + bool hasDeadSymbols() const { + return !TheDead.isEmpty(); + } +}; + +class SymbolVisitor { +public: + // VisitSymbol - A visitor method invoked by + // GRStateManager::scanReachableSymbols. The method returns \c true if + // symbols should continue be scanned and \c false otherwise. + virtual bool VisitSymbol(SymbolRef sym) = 0; + virtual ~SymbolVisitor(); +}; + +} // end clang namespace + +namespace llvm { + llvm::raw_ostream& operator<<(llvm::raw_ostream& Out, + const clang::SymExpr *SE); +} +namespace std { + std::ostream& operator<<(std::ostream& Out, + const clang::SymExpr *SE); +} + +#endif diff --git a/include/clang/Analysis/PathSensitive/ValueManager.h b/include/clang/Analysis/PathSensitive/ValueManager.h new file mode 100644 index 000000000000..89af975de7af --- /dev/null +++ b/include/clang/Analysis/PathSensitive/ValueManager.h @@ -0,0 +1,103 @@ +//== ValueManager.h - Aggregate manager of symbols and SVals ----*- C++ -*--==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines ValueManager, a class that manages symbolic values +// and SVals created for use by GRExprEngine and related classes. It +// wraps SymbolManager, MemRegionManager, and BasicValueFactory. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_AGGREGATE_VALUE_MANAGER_H +#define LLVM_CLANG_ANALYSIS_AGGREGATE_VALUE_MANAGER_H + +#include "clang/Analysis/PathSensitive/MemRegion.h" +#include "clang/Analysis/PathSensitive/SVals.h" +#include "clang/Analysis/PathSensitive/BasicValueFactory.h" +#include "clang/Analysis/PathSensitive/SymbolManager.h" + +namespace llvm { class BumpPtrAllocator; } + +namespace clang { +class ValueManager { + + ASTContext &Context; + BasicValueFactory BasicVals; + + /// SymMgr - Object that manages the symbol information. + SymbolManager SymMgr; + + + MemRegionManager MemMgr; + +public: + ValueManager(llvm::BumpPtrAllocator &alloc, ASTContext &context) + : Context(context), BasicVals(Context, alloc), + SymMgr(Context, BasicVals, alloc), + MemMgr(alloc) {} + + // Accessors to submanagers. + + ASTContext &getContext() { return Context; } + const ASTContext &getContext() const { return Context; } + + BasicValueFactory &getBasicValueFactory() { return BasicVals; } + const BasicValueFactory &getBasicValueFactory() const { return BasicVals; } + + SymbolManager &getSymbolManager() { return SymMgr; } + const SymbolManager &getSymbolManager() const { return SymMgr; } + + MemRegionManager &getRegionManager() { return MemMgr; } + const MemRegionManager &getRegionManager() const { return MemMgr; } + + // Forwarding methods to SymbolManager. + + const SymbolConjured* getConjuredSymbol(const Stmt* E, QualType T, + unsigned VisitCount, + const void* SymbolTag = 0) { + return SymMgr.getConjuredSymbol(E, T, VisitCount, SymbolTag); + } + + const SymbolConjured* getConjuredSymbol(const Expr* E, unsigned VisitCount, + const void* SymbolTag = 0) { + return SymMgr.getConjuredSymbol(E, VisitCount, SymbolTag); + } + + // Aggregation methods that use multiple submanagers. + + Loc makeRegionVal(SymbolRef Sym) { + return Loc::MakeVal(MemMgr.getSymbolicRegion(Sym)); + } + + /// makeZeroVal - Construct an SVal representing '0' for the specified type. + SVal makeZeroVal(QualType T); + /// makeZeroArrayIndex - Construct an SVal representing '0' index for array + /// elements. + SVal makeZeroArrayIndex(); + + /// GetRegionValueSymbolVal - make a unique symbol for value of R. + SVal getRegionValueSymbolVal(const MemRegion* R); + + SVal getConjuredSymbolVal(const Expr *E, unsigned Count); + SVal getConjuredSymbolVal(const Expr* E, QualType T, unsigned Count); + + SVal getFunctionPointer(const FunctionDecl* FD); + + NonLoc makeNonLoc(SymbolRef sym); + + NonLoc makeNonLoc(const SymExpr *lhs, BinaryOperator::Opcode op, + const llvm::APSInt& rhs, QualType T); + + NonLoc makeNonLoc(const SymExpr *lhs, BinaryOperator::Opcode op, + const SymExpr *rhs, QualType T); + + NonLoc makeTruthVal(bool b, QualType T); +}; +} // end clang namespace +#endif + diff --git a/include/clang/Analysis/ProgramPoint.h b/include/clang/Analysis/ProgramPoint.h new file mode 100644 index 000000000000..d2b536ca1cb2 --- /dev/null +++ b/include/clang/Analysis/ProgramPoint.h @@ -0,0 +1,351 @@ +//==- ProgramPoint.h - Program Points for Path-Sensitive 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 defines the interface ProgramPoint, which identifies a +// distinct location in a function. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_PROGRAM_POINT +#define LLVM_CLANG_ANALYSIS_PROGRAM_POINT + +#include "clang/AST/CFG.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/Support/Casting.h" +#include <cassert> +#include <utility> + +namespace clang { + +class ProgramPoint { +public: + enum Kind { BlockEdgeKind = 0x0, + BlockEntranceKind = 0x1, + BlockExitKind = 0x2, + // Keep the following four together and in this order. + PostStmtKind = 0x3, + PostLocationChecksSucceedKind = 0x4, + PostOutOfBoundsCheckFailedKind = 0x5, + PostNullCheckFailedKind = 0x6, + PostUndefLocationCheckFailedKind = 0x7, + PostLoadKind = 0x8, + PostStoreKind = 0x9, + PostPurgeDeadSymbolsKind = 0x10, + PostStmtCustomKind = 0x11, + PostLValueKind = 0x12, + MinPostStmtKind = PostStmtKind, + MaxPostStmtKind = PostLValueKind }; + +private: + enum { TwoPointers = 0x1, Custom = 0x2, Mask = 0x3 }; + + std::pair<uintptr_t,uintptr_t> Data; + const void *Tag; + +protected: + ProgramPoint(const void* P, Kind k, const void *tag = 0) + : Data(reinterpret_cast<uintptr_t>(P), + (uintptr_t) k), Tag(tag) {} + + ProgramPoint(const void* P1, const void* P2, const void *tag = 0) + : Data(reinterpret_cast<uintptr_t>(P1) | TwoPointers, + reinterpret_cast<uintptr_t>(P2)), Tag(tag) {} + + ProgramPoint(const void* P1, const void* P2, bool, const void *tag = 0) + : Data(reinterpret_cast<uintptr_t>(P1) | Custom, + reinterpret_cast<uintptr_t>(P2)), Tag(tag) {} + +protected: + void* getData1NoMask() const { + Kind k = getKind(); k = k; + assert(k == BlockEntranceKind || k == BlockExitKind); + return reinterpret_cast<void*>(Data.first); + } + + void* getData1() const { + Kind k = getKind(); k = k; + assert(k == BlockEdgeKind ||(k >= MinPostStmtKind && k <= MaxPostStmtKind)); + return reinterpret_cast<void*>(Data.first & ~Mask); + } + + void* getData2() const { + Kind k = getKind(); k = k; + assert(k == BlockEdgeKind || k == PostStmtCustomKind); + return reinterpret_cast<void*>(Data.second); + } + + const void *getTag() const { return Tag; } + +public: + Kind getKind() const { + switch (Data.first & Mask) { + case TwoPointers: return BlockEdgeKind; + case Custom: return PostStmtCustomKind; + default: return (Kind) Data.second; + } + } + + // For use with DenseMap. This hash is probably slow. + unsigned getHashValue() const { + llvm::FoldingSetNodeID ID; + ID.AddPointer(reinterpret_cast<void*>(Data.first)); + ID.AddPointer(reinterpret_cast<void*>(Data.second)); + ID.AddPointer(Tag); + return ID.ComputeHash(); + } + + static bool classof(const ProgramPoint*) { return true; } + + bool operator==(const ProgramPoint & RHS) const { + return Data == RHS.Data && Tag == RHS.Tag; + } + + bool operator!=(const ProgramPoint& RHS) const { + return Data != RHS.Data || Tag != RHS.Tag; + } + + bool operator<(const ProgramPoint& RHS) const { + return Data < RHS.Data && Tag < RHS.Tag; + } + + void Profile(llvm::FoldingSetNodeID& ID) const { + ID.AddPointer(reinterpret_cast<void*>(Data.first)); + if (getKind() != PostStmtCustomKind) + ID.AddPointer(reinterpret_cast<void*>(Data.second)); + else { + const std::pair<const void*, const void*> *P = + reinterpret_cast<std::pair<const void*, const void*>*>(Data.second); + ID.AddPointer(P->first); + ID.AddPointer(P->second); + } + ID.AddPointer(Tag); + } +}; + +class BlockEntrance : public ProgramPoint { +public: + BlockEntrance(const CFGBlock* B, const void *tag = 0) + : ProgramPoint(B, BlockEntranceKind, tag) {} + + CFGBlock* getBlock() const { + return reinterpret_cast<CFGBlock*>(getData1NoMask()); + } + + Stmt* getFirstStmt() const { + CFGBlock* B = getBlock(); + return B->empty() ? NULL : B->front(); + } + + static bool classof(const ProgramPoint* Location) { + return Location->getKind() == BlockEntranceKind; + } +}; + +class BlockExit : public ProgramPoint { +public: + BlockExit(const CFGBlock* B) : ProgramPoint(B, BlockExitKind) {} + + CFGBlock* getBlock() const { + return reinterpret_cast<CFGBlock*>(getData1NoMask()); + } + + Stmt* getLastStmt() const { + CFGBlock* B = getBlock(); + return B->empty() ? NULL : B->back(); + } + + Stmt* getTerminator() const { + return getBlock()->getTerminator(); + } + + static bool classof(const ProgramPoint* Location) { + return Location->getKind() == BlockExitKind; + } +}; + +class PostStmt : public ProgramPoint { +protected: + PostStmt(const Stmt* S, Kind k,const void *tag = 0) + : ProgramPoint(S, k, tag) {} + + PostStmt(const Stmt* S, const void* data, bool, const void *tag =0) + : ProgramPoint(S, data, true, tag) {} + +public: + PostStmt(const Stmt* S, const void *tag = 0) + : ProgramPoint(S, PostStmtKind, tag) {} + + Stmt* getStmt() const { return (Stmt*) getData1(); } + + template<typename T> + T* getStmtAs() const { return llvm::dyn_cast<T>(getStmt()); } + + static bool classof(const ProgramPoint* Location) { + unsigned k = Location->getKind(); + return k >= MinPostStmtKind && k <= MaxPostStmtKind; + } +}; + +class PostLocationChecksSucceed : public PostStmt { +public: + PostLocationChecksSucceed(const Stmt* S, const void *tag = 0) + : PostStmt(S, PostLocationChecksSucceedKind, tag) {} + + static bool classof(const ProgramPoint* Location) { + return Location->getKind() == PostLocationChecksSucceedKind; + } +}; + +class PostStmtCustom : public PostStmt { +public: + PostStmtCustom(const Stmt* S, + const std::pair<const void*, const void*>* TaggedData) + : PostStmt(S, TaggedData, true) { + assert(getKind() == PostStmtCustomKind); + } + + const std::pair<const void*, const void*>& getTaggedPair() const { + return *reinterpret_cast<std::pair<const void*, const void*>*>(getData2()); + } + + const void* getTag() const { return getTaggedPair().first; } + + const void* getTaggedData() const { return getTaggedPair().second; } + + static bool classof(const ProgramPoint* Location) { + return Location->getKind() == PostStmtCustomKind; + } +}; + +class PostOutOfBoundsCheckFailed : public PostStmt { +public: + PostOutOfBoundsCheckFailed(const Stmt* S, const void *tag = 0) + : PostStmt(S, PostOutOfBoundsCheckFailedKind, tag) {} + + static bool classof(const ProgramPoint* Location) { + return Location->getKind() == PostOutOfBoundsCheckFailedKind; + } +}; + +class PostUndefLocationCheckFailed : public PostStmt { +public: + PostUndefLocationCheckFailed(const Stmt* S, const void *tag = 0) + : PostStmt(S, PostUndefLocationCheckFailedKind, tag) {} + + static bool classof(const ProgramPoint* Location) { + return Location->getKind() == PostUndefLocationCheckFailedKind; + } +}; + +class PostNullCheckFailed : public PostStmt { +public: + PostNullCheckFailed(const Stmt* S, const void *tag = 0) + : PostStmt(S, PostNullCheckFailedKind, tag) {} + + static bool classof(const ProgramPoint* Location) { + return Location->getKind() == PostNullCheckFailedKind; + } +}; + +class PostLoad : public PostStmt { +public: + PostLoad(const Stmt* S, const void *tag = 0) + : PostStmt(S, PostLoadKind, tag) {} + + static bool classof(const ProgramPoint* Location) { + return Location->getKind() == PostLoadKind; + } +}; + +class PostStore : public PostStmt { +public: + PostStore(const Stmt* S, const void *tag = 0) + : PostStmt(S, PostStoreKind, tag) {} + + static bool classof(const ProgramPoint* Location) { + return Location->getKind() == PostStoreKind; + } +}; + +class PostLValue : public PostStmt { +public: + PostLValue(const Stmt* S, const void *tag = 0) + : PostStmt(S, PostLValueKind, tag) {} + + static bool classof(const ProgramPoint* Location) { + return Location->getKind() == PostLValueKind; + } +}; + +class PostPurgeDeadSymbols : public PostStmt { +public: + PostPurgeDeadSymbols(const Stmt* S, const void *tag = 0) + : PostStmt(S, PostPurgeDeadSymbolsKind, tag) {} + + static bool classof(const ProgramPoint* Location) { + return Location->getKind() == PostPurgeDeadSymbolsKind; + } +}; + +class BlockEdge : public ProgramPoint { +public: + BlockEdge(const CFGBlock* B1, const CFGBlock* B2) + : ProgramPoint(B1, B2) {} + + CFGBlock* getSrc() const { + return static_cast<CFGBlock*>(getData1()); + } + + CFGBlock* getDst() const { + return static_cast<CFGBlock*>(getData2()); + } + + static bool classof(const ProgramPoint* Location) { + return Location->getKind() == BlockEdgeKind; + } +}; + + +} // end namespace clang + + +namespace llvm { // Traits specialization for DenseMap + +template <> struct DenseMapInfo<clang::ProgramPoint> { + +static inline clang::ProgramPoint getEmptyKey() { + uintptr_t x = + reinterpret_cast<uintptr_t>(DenseMapInfo<void*>::getEmptyKey()) & ~0x7; + return clang::BlockEntrance(reinterpret_cast<clang::CFGBlock*>(x)); +} + +static inline clang::ProgramPoint getTombstoneKey() { + uintptr_t x = + reinterpret_cast<uintptr_t>(DenseMapInfo<void*>::getTombstoneKey()) & ~0x7; + return clang::BlockEntrance(reinterpret_cast<clang::CFGBlock*>(x)); +} + +static unsigned getHashValue(const clang::ProgramPoint& Loc) { + return Loc.getHashValue(); +} + +static bool isEqual(const clang::ProgramPoint& L, + const clang::ProgramPoint& R) { + return L == R; +} + +static bool isPod() { + return true; +} +}; +} // end namespace llvm + +#endif diff --git a/include/clang/Analysis/Support/BlkExprDeclBitVector.h b/include/clang/Analysis/Support/BlkExprDeclBitVector.h new file mode 100644 index 000000000000..a592be815419 --- /dev/null +++ b/include/clang/Analysis/Support/BlkExprDeclBitVector.h @@ -0,0 +1,307 @@ +// BlkExprDeclBitVector.h - Dataflow types for Bitvector 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 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_STMTDECLBVDVAL_H +#define LLVM_CLANG_STMTDECLBVDVAL_H + +#include "clang/AST/CFG.h" +#include "clang/AST/Decl.h" // for Decl* -> NamedDecl* conversion +#include "llvm/ADT/BitVector.h" +#include "llvm/ADT/DenseMap.h" + +namespace clang { + + class Stmt; + class ASTContext; + +struct DeclBitVector_Types { + + class Idx { + unsigned I; + public: + explicit Idx(unsigned i) : I(i) {} + Idx() : I(~0U) {} + + bool isValid() const { + return I != ~0U; + } + operator unsigned() const { + assert (isValid()); + return I; + } + }; + + //===--------------------------------------------------------------------===// + // AnalysisDataTy - Whole-function meta data. + //===--------------------------------------------------------------------===// + + class AnalysisDataTy { + public: + typedef llvm::DenseMap<const NamedDecl*, unsigned > DMapTy; + typedef DMapTy::const_iterator decl_iterator; + + protected: + DMapTy DMap; + unsigned NDecls; + + public: + + AnalysisDataTy() : NDecls(0) {} + virtual ~AnalysisDataTy() {} + + bool isTracked(const NamedDecl* SD) { return DMap.find(SD) != DMap.end(); } + + Idx getIdx(const NamedDecl* SD) const { + DMapTy::const_iterator I = DMap.find(SD); + return I == DMap.end() ? Idx() : Idx(I->second); + } + + unsigned getNumDecls() const { return NDecls; } + + void Register(const NamedDecl* SD) { + if (!isTracked(SD)) DMap[SD] = NDecls++; + } + + decl_iterator begin_decl() const { return DMap.begin(); } + decl_iterator end_decl() const { return DMap.end(); } + }; + + //===--------------------------------------------------------------------===// + // ValTy - Dataflow value. + //===--------------------------------------------------------------------===// + + class ValTy { + llvm::BitVector DeclBV; + public: + + void resetDeclValues(AnalysisDataTy& AD) { + DeclBV.resize(AD.getNumDecls()); + DeclBV.reset(); + } + + void setDeclValues(AnalysisDataTy& AD) { + DeclBV.resize(AD.getNumDecls()); + DeclBV.set(); + } + + void resetValues(AnalysisDataTy& AD) { + resetDeclValues(AD); + } + + bool operator==(const ValTy& RHS) const { + assert (sizesEqual(RHS)); + return DeclBV == RHS.DeclBV; + } + + void copyValues(const ValTy& RHS) { DeclBV = RHS.DeclBV; } + + llvm::BitVector::reference getBit(unsigned i) { + return DeclBV[i]; + } + + bool getBit(unsigned i) const { + return DeclBV[i]; + } + + llvm::BitVector::reference + operator()(const NamedDecl* ND, const AnalysisDataTy& AD) { + return getBit(AD.getIdx(ND)); + } + + bool operator()(const NamedDecl* ND, const AnalysisDataTy& AD) const { + return getBit(AD.getIdx(ND)); + } + + llvm::BitVector::reference getDeclBit(unsigned i) { return DeclBV[i]; } + const llvm::BitVector::reference getDeclBit(unsigned i) const { + return const_cast<llvm::BitVector&>(DeclBV)[i]; + } + + ValTy& operator|=(const ValTy& RHS) { + assert (sizesEqual(RHS)); + DeclBV |= RHS.DeclBV; + return *this; + } + + ValTy& operator&=(const ValTy& RHS) { + assert (sizesEqual(RHS)); + DeclBV &= RHS.DeclBV; + return *this; + } + + ValTy& OrDeclBits(const ValTy& RHS) { + return operator|=(RHS); + } + + ValTy& AndDeclBits(const ValTy& RHS) { + return operator&=(RHS); + } + + bool sizesEqual(const ValTy& RHS) const { + return DeclBV.size() == RHS.DeclBV.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; } }; +}; + + +struct StmtDeclBitVector_Types { + + //===--------------------------------------------------------------------===// + // AnalysisDataTy - Whole-function meta data. + //===--------------------------------------------------------------------===// + + class AnalysisDataTy : public DeclBitVector_Types::AnalysisDataTy { + ASTContext* ctx; + CFG* cfg; + public: + AnalysisDataTy() : ctx(0), cfg(0) {} + virtual ~AnalysisDataTy() {} + + void setContext(ASTContext& c) { ctx = &c; } + ASTContext& getContext() { + assert(ctx && "ASTContext should not be NULL."); + return *ctx; + } + + void setCFG(CFG& c) { cfg = &c; } + CFG& getCFG() { assert(cfg && "CFG should not be NULL."); return *cfg; } + + bool isTracked(const Stmt* S) { return cfg->isBlkExpr(S); } + using DeclBitVector_Types::AnalysisDataTy::isTracked; + + unsigned getIdx(const Stmt* S) const { + CFG::BlkExprNumTy I = cfg->getBlkExprNum(S); + assert(I && "Stmtession not tracked for bitvector."); + return I; + } + using DeclBitVector_Types::AnalysisDataTy::getIdx; + + unsigned getNumBlkExprs() const { return cfg->getNumBlkExprs(); } + }; + + //===--------------------------------------------------------------------===// + // ValTy - Dataflow value. + //===--------------------------------------------------------------------===// + + class ValTy : public DeclBitVector_Types::ValTy { + llvm::BitVector BlkExprBV; + typedef DeclBitVector_Types::ValTy ParentTy; + + static inline ParentTy& ParentRef(ValTy& X) { + return static_cast<ParentTy&>(X); + } + + static inline const ParentTy& ParentRef(const ValTy& X) { + return static_cast<const ParentTy&>(X); + } + + public: + + void resetBlkExprValues(AnalysisDataTy& AD) { + BlkExprBV.resize(AD.getNumBlkExprs()); + BlkExprBV.reset(); + } + + void setBlkExprValues(AnalysisDataTy& AD) { + BlkExprBV.resize(AD.getNumBlkExprs()); + BlkExprBV.set(); + } + + void resetValues(AnalysisDataTy& AD) { + resetDeclValues(AD); + resetBlkExprValues(AD); + } + + void setValues(AnalysisDataTy& AD) { + setDeclValues(AD); + setBlkExprValues(AD); + } + + bool operator==(const ValTy& RHS) const { + return ParentRef(*this) == ParentRef(RHS) + && BlkExprBV == RHS.BlkExprBV; + } + + void copyValues(const ValTy& RHS) { + ParentRef(*this).copyValues(ParentRef(RHS)); + BlkExprBV = RHS.BlkExprBV; + } + + llvm::BitVector::reference + operator()(const Stmt* S, const AnalysisDataTy& AD) { + return BlkExprBV[AD.getIdx(S)]; + } + const llvm::BitVector::reference + operator()(const Stmt* S, const AnalysisDataTy& AD) const { + return const_cast<ValTy&>(*this)(S,AD); + } + + using DeclBitVector_Types::ValTy::operator(); + + + llvm::BitVector::reference getStmtBit(unsigned i) { return BlkExprBV[i]; } + const llvm::BitVector::reference getStmtBit(unsigned i) const { + return const_cast<llvm::BitVector&>(BlkExprBV)[i]; + } + + ValTy& OrBlkExprBits(const ValTy& RHS) { + BlkExprBV |= RHS.BlkExprBV; + return *this; + } + + ValTy& AndBlkExprBits(const ValTy& RHS) { + BlkExprBV &= RHS.BlkExprBV; + return *this; + } + + ValTy& operator|=(const ValTy& RHS) { + assert (sizesEqual(RHS)); + ParentRef(*this) |= ParentRef(RHS); + BlkExprBV |= RHS.BlkExprBV; + return *this; + } + + ValTy& operator&=(const ValTy& RHS) { + assert (sizesEqual(RHS)); + ParentRef(*this) &= ParentRef(RHS); + BlkExprBV &= RHS.BlkExprBV; + return *this; + } + + bool sizesEqual(const ValTy& RHS) const { + return ParentRef(*this).sizesEqual(ParentRef(RHS)) + && BlkExprBV.size() == RHS.BlkExprBV.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 diff --git a/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h b/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h new file mode 100644 index 000000000000..ee79c517030f --- /dev/null +++ b/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h @@ -0,0 +1,91 @@ +//= CFGRecStmtDeclVisitor - Recursive visitor of CFG stmts/decls -*- 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 the template class CFGRecStmtDeclVisitor, which extends +// CFGRecStmtVisitor by implementing (typed) visitation of decls. +// +// FIXME: This may not be fully complete. We currently explore only subtypes +// of ScopedDecl. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_CFG_REC_STMT_DECL_VISITOR_H +#define LLVM_CLANG_ANALYSIS_CFG_REC_STMT_DECL_VISITOR_H + +#include "clang/Analysis/Visitors/CFGRecStmtVisitor.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" + +#define DISPATCH_CASE(CASE,CLASS) \ +case Decl::CASE: \ +static_cast<ImplClass*>(this)->Visit##CLASS(static_cast<CLASS*>(D));\ +break; + +#define DEFAULT_DISPATCH(CLASS) void Visit##CLASS(CLASS* D) {} +#define DEFAULT_DISPATCH_VARDECL(CLASS) void Visit##CLASS(CLASS* D)\ + { static_cast<ImplClass*>(this)->VisitVarDecl(D); } + + +namespace clang { +template <typename ImplClass> +class CFGRecStmtDeclVisitor : public CFGRecStmtVisitor<ImplClass> { +public: + + void VisitDeclRefExpr(DeclRefExpr* DR) { + static_cast<ImplClass*>(this)->VisitDecl(DR->getDecl()); + } + + void VisitDeclStmt(DeclStmt* DS) { + for (DeclStmt::decl_iterator DI = DS->decl_begin(), DE = DS->decl_end(); + DI != DE; ++DI) { + Decl* D = *DI; + static_cast<ImplClass*>(this)->VisitDecl(D); + // Visit the initializer. + if (VarDecl* VD = dyn_cast<VarDecl>(D)) + if (Expr* I = VD->getInit()) + static_cast<ImplClass*>(this)->Visit(I); + } + } + + void VisitDecl(Decl* D) { + switch (D->getKind()) { + DISPATCH_CASE(Function,FunctionDecl) + DISPATCH_CASE(Var,VarDecl) + DISPATCH_CASE(ParmVar,ParmVarDecl) // FIXME: (same) + DISPATCH_CASE(OriginalParmVar,OriginalParmVarDecl) // FIXME: (same) + DISPATCH_CASE(ImplicitParam,ImplicitParamDecl) + DISPATCH_CASE(EnumConstant,EnumConstantDecl) + DISPATCH_CASE(Typedef,TypedefDecl) + DISPATCH_CASE(Record,RecordDecl) // FIXME: Refine. VisitStructDecl? + DISPATCH_CASE(Enum,EnumDecl) + default: + assert(false && "Subtype of ScopedDecl not handled."); + } + } + + DEFAULT_DISPATCH(VarDecl) + DEFAULT_DISPATCH(FunctionDecl) + DEFAULT_DISPATCH_VARDECL(OriginalParmVarDecl) + DEFAULT_DISPATCH_VARDECL(ParmVarDecl) + DEFAULT_DISPATCH(ImplicitParamDecl) + DEFAULT_DISPATCH(EnumConstantDecl) + DEFAULT_DISPATCH(TypedefDecl) + DEFAULT_DISPATCH(RecordDecl) + DEFAULT_DISPATCH(EnumDecl) + DEFAULT_DISPATCH(ObjCInterfaceDecl) + DEFAULT_DISPATCH(ObjCClassDecl) + DEFAULT_DISPATCH(ObjCMethodDecl) + DEFAULT_DISPATCH(ObjCProtocolDecl) + DEFAULT_DISPATCH(ObjCCategoryDecl) +}; + +} // end namespace clang + +#undef DISPATCH_CASE +#undef DEFAULT_DISPATCH +#endif diff --git a/include/clang/Analysis/Visitors/CFGRecStmtVisitor.h b/include/clang/Analysis/Visitors/CFGRecStmtVisitor.h new file mode 100644 index 000000000000..4d3201962250 --- /dev/null +++ b/include/clang/Analysis/Visitors/CFGRecStmtVisitor.h @@ -0,0 +1,35 @@ +//==- CFGRecStmtVisitor - Recursive visitor of CFG statements ---*- 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 the template class CFGRecStmtVisitor, which extends +// CFGStmtVisitor by implementing a default recursive visit of all statements. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_CFG_REC_STMT_VISITOR_H +#define LLVM_CLANG_ANALYSIS_CFG_REC_STMT_VISITOR_H + +#include "clang/Analysis/Visitors/CFGStmtVisitor.h" + +namespace clang { +template <typename ImplClass> +class CFGRecStmtVisitor : public CFGStmtVisitor<ImplClass,void> { +public: + + void VisitStmt(Stmt* S) { + static_cast< ImplClass* >(this)->VisitChildren(S); + } + + // Defining operator() allows the visitor to be used as a C++ style functor. + void operator()(Stmt* S) { static_cast<ImplClass*>(this)->BlockStmt_Visit(S);} +}; + +} // end namespace clang + +#endif diff --git a/include/clang/Analysis/Visitors/CFGStmtVisitor.h b/include/clang/Analysis/Visitors/CFGStmtVisitor.h new file mode 100644 index 000000000000..f42bbde8f148 --- /dev/null +++ b/include/clang/Analysis/Visitors/CFGStmtVisitor.h @@ -0,0 +1,156 @@ +//===--- CFGStmtVisitor.h - Visitor for Stmts in a CFG ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the CFGStmtVisitor interface, which extends +// StmtVisitor. This interface is useful for visiting statements in a CFG +// where some statements have implicit control-flow and thus should +// be treated specially. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_CFGSTMTVISITOR_H +#define LLVM_CLANG_ANALYSIS_CFGSTMTVISITOR_H + +#include "clang/AST/StmtVisitor.h" +#include "clang/AST/CFG.h" + +namespace clang { + +#define DISPATCH_CASE(CLASS) \ +case Stmt::CLASS ## Class: return \ +static_cast<ImplClass*>(this)->BlockStmt_Visit ## CLASS(static_cast<CLASS*>(S)); + +#define DEFAULT_BLOCKSTMT_VISIT(CLASS) RetTy BlockStmt_Visit ## CLASS(CLASS *S)\ +{ return\ + static_cast<ImplClass*>(this)->BlockStmt_VisitImplicitControlFlowExpr(\ + cast<Expr>(S)); } + +template <typename ImplClass, typename RetTy=void> +class CFGStmtVisitor : public StmtVisitor<ImplClass,RetTy> { + Stmt* CurrentBlkStmt; + + struct NullifyStmt { + Stmt*& S; + + NullifyStmt(Stmt*& s) : S(s) {} + ~NullifyStmt() { S = NULL; } + }; + +public: + CFGStmtVisitor() : CurrentBlkStmt(NULL) {} + + Stmt* getCurrentBlkStmt() const { return CurrentBlkStmt; } + + RetTy Visit(Stmt* S) { + if (S == CurrentBlkStmt || + !static_cast<ImplClass*>(this)->getCFG().isBlkExpr(S)) + return StmtVisitor<ImplClass,RetTy>::Visit(S); + else + return RetTy(); + } + + /// BlockVisit_XXX - Visitor methods for visiting the "root" statements in + /// CFGBlocks. Root statements are the statements that appear explicitly in + /// the list of statements in a CFGBlock. For substatements, or when there + /// is no implementation provided for a BlockStmt_XXX method, we default + /// to using StmtVisitor's Visit method. + RetTy BlockStmt_Visit(Stmt* S) { + CurrentBlkStmt = S; + NullifyStmt cleanup(CurrentBlkStmt); + + switch (S->getStmtClass()) { + + DISPATCH_CASE(StmtExpr) + DISPATCH_CASE(ConditionalOperator) + DISPATCH_CASE(ObjCForCollectionStmt) + + case Stmt::BinaryOperatorClass: { + BinaryOperator* B = cast<BinaryOperator>(S); + if (B->isLogicalOp()) + return static_cast<ImplClass*>(this)->BlockStmt_VisitLogicalOp(B); + else if (B->getOpcode() == BinaryOperator::Comma) + return static_cast<ImplClass*>(this)->BlockStmt_VisitComma(B); + // Fall through. + } + + default: + if (isa<Expr>(S)) + return + static_cast<ImplClass*>(this)->BlockStmt_VisitExpr(cast<Expr>(S)); + else + return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(S); + } + } + + DEFAULT_BLOCKSTMT_VISIT(StmtExpr) + DEFAULT_BLOCKSTMT_VISIT(ConditionalOperator) + + RetTy BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) { + return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(S); + } + + RetTy BlockStmt_VisitImplicitControlFlowExpr(Expr* E) { + return static_cast<ImplClass*>(this)->BlockStmt_VisitExpr(E); + } + + RetTy BlockStmt_VisitExpr(Expr* E) { + return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(E); + } + + RetTy BlockStmt_VisitStmt(Stmt* S) { + return static_cast<ImplClass*>(this)->Visit(S); + } + + RetTy BlockStmt_VisitLogicalOp(BinaryOperator* B) { + return + static_cast<ImplClass*>(this)->BlockStmt_VisitImplicitControlFlowExpr(B); + } + + RetTy BlockStmt_VisitComma(BinaryOperator* B) { + return + static_cast<ImplClass*>(this)->BlockStmt_VisitImplicitControlFlowExpr(B); + } + + //===--------------------------------------------------------------------===// + // Utility methods. Not called by default (but subclasses may use them). + //===--------------------------------------------------------------------===// + + /// VisitChildren: Call "Visit" on each child of S. + void VisitChildren(Stmt* S) { + + switch (S->getStmtClass()) { + default: + break; + + case Stmt::StmtExprClass: { + CompoundStmt* CS = cast<StmtExpr>(S)->getSubStmt(); + if (CS->body_empty()) return; + static_cast<ImplClass*>(this)->Visit(CS->body_back()); + return; + } + + case Stmt::BinaryOperatorClass: { + BinaryOperator* B = cast<BinaryOperator>(S); + if (B->getOpcode() != BinaryOperator::Comma) break; + static_cast<ImplClass*>(this)->Visit(B->getRHS()); + return; + } + } + + for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I != E;++I) + if (*I) static_cast<ImplClass*>(this)->Visit(*I); + } +}; + +#undef DEFAULT_BLOCKSTMT_VISIT +#undef DISPATCH_CASE + +} // end namespace clang + +#endif diff --git a/include/clang/Analysis/Visitors/CFGVarDeclVisitor.h b/include/clang/Analysis/Visitors/CFGVarDeclVisitor.h new file mode 100644 index 000000000000..25101235ddd2 --- /dev/null +++ b/include/clang/Analysis/Visitors/CFGVarDeclVisitor.h @@ -0,0 +1,64 @@ +//==- CFGVarDeclVisitor - Generic visitor of VarDecls in a CFG --*- 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 the template class CFGVarDeclVisitor, which provides +// a generic way to visit all the VarDecl's in a CFG. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_CFG_VARDECL_VISITOR_H +#define LLVM_CLANG_ANALYSIS_CFG_VARDECL_VISITOR_H + +#include "clang/Analysis/Visitors/CFGStmtVisitor.h" +#include "clang/AST/Decl.h" +#include "clang/AST/Stmt.h" +#include "clang/AST/CFG.h" + +namespace clang { + +template <typename ImplClass> +class CFGVarDeclVisitor : public CFGStmtVisitor<ImplClass> { + const CFG& cfg; +public: + CFGVarDeclVisitor(const CFG& c) : cfg(c) {} + + void VisitStmt(Stmt* S) { + static_cast<ImplClass*>(this)->VisitChildren(S); + } + + void VisitDeclRefExpr(DeclRefExpr* DR) { + static_cast<ImplClass*>(this)->VisitDeclChain(DR->getDecl()); + } + + void VisitDeclStmt(DeclStmt* DS) { + static_cast<ImplClass*>(this)->VisitDeclChain(DS->getDecl()); + } + + void VisitDeclChain(ScopedDecl* D) { + for (; D != NULL ; D = D->getNextDeclarator()) + static_cast<ImplClass*>(this)->VisitScopedDecl(D); + } + + void VisitScopedDecl(ScopedDecl* D) { + if (VarDecl* V = dyn_cast<VarDecl>(D)) + static_cast<ImplClass*>(this)->VisitVarDecl(V); + } + + void VisitVarDecl(VarDecl* D) {} + + void VisitAllDecls() { + for (CFG::const_iterator BI = cfg.begin(), BE = cfg.end(); BI != BE; ++BI) + for (CFGBlock::const_iterator SI=BI->begin(),SE = BI->end();SI != SE;++SI) + static_cast<ImplClass*>(this)->BlockStmt_Visit(const_cast<Stmt*>(*SI)); + } +}; + +} // end namespace clang + +#endif |