diff options
Diffstat (limited to 'include/clang/Analysis')
45 files changed, 4077 insertions, 2847 deletions
diff --git a/include/clang/Analysis/Analyses/LiveVariables.h b/include/clang/Analysis/Analyses/LiveVariables.h index b41cd684e951..17f772da0c6d 100644 --- a/include/clang/Analysis/Analyses/LiveVariables.h +++ b/include/clang/Analysis/Analyses/LiveVariables.h @@ -23,7 +23,7 @@ namespace clang { class Stmt; class DeclRefExpr; class SourceManager; - + struct LiveVariables_ValueTypes { struct ObserverTy; @@ -35,77 +35,77 @@ struct LiveVariables_ValueTypes { // (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, + 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. + /// 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 diff --git a/include/clang/Analysis/Analyses/UninitializedValues.h b/include/clang/Analysis/Analyses/UninitializedValues.h index 7a9da03e4bd2..8a967c3f6edc 100644 --- a/include/clang/Analysis/Analyses/UninitializedValues.h +++ b/include/clang/Analysis/Analyses/UninitializedValues.h @@ -24,7 +24,7 @@ namespace clang { 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. @@ -32,39 +32,39 @@ class UninitializedValues_ValueTypes { public: struct ObserverTy; - - struct AnalysisDataTy : public StmtDeclBitVector_Types::AnalysisDataTy { + + 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, + 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> { +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); diff --git a/include/clang/Analysis/AnalysisDiagnostic.h b/include/clang/Analysis/AnalysisDiagnostic.h index 3ee733518595..114ae74b0c06 100644 --- a/include/clang/Analysis/AnalysisDiagnostic.h +++ b/include/clang/Analysis/AnalysisDiagnostic.h @@ -13,7 +13,7 @@ #include "clang/Basic/Diagnostic.h" namespace clang { - namespace diag { + namespace diag { enum { #define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE) ENUM, #define ANALYSISSTART diff --git a/include/clang/Analysis/CFG.h b/include/clang/Analysis/CFG.h new file mode 100644 index 000000000000..e6f4cf961be0 --- /dev/null +++ b/include/clang/Analysis/CFG.h @@ -0,0 +1,451 @@ +//===--- CFG.h - Classes for representing and building 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 defines the CFG and CFGBuilder classes for representing and +// building Control-Flow Graphs (CFGs) from ASTs. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_CFG_H +#define LLVM_CLANG_CFG_H + +#include "llvm/ADT/GraphTraits.h" +#include "llvm/Support/Allocator.h" +#include "clang/Analysis/Support/BumpVector.h" +#include <cassert> + +namespace llvm { + class raw_ostream; +} +namespace clang { + class Stmt; + class Expr; + class CFG; + class PrinterHelper; + class LangOptions; + class ASTContext; + +/// CFGBlock - Represents a single basic block in a source-level CFG. +/// It consists of: +/// +/// (1) A set of statements/expressions (which may contain subexpressions). +/// (2) A "terminator" statement (not in the set of statements). +/// (3) A list of successors and predecessors. +/// +/// Terminator: The terminator represents the type of control-flow that occurs +/// at the end of the basic block. The terminator is a Stmt* referring to an +/// AST node that has control-flow: if-statements, breaks, loops, etc. +/// If the control-flow is conditional, the condition expression will appear +/// within the set of statements in the block (usually the last statement). +/// +/// Predecessors: the order in the set of predecessors is arbitrary. +/// +/// Successors: the order in the set of successors is NOT arbitrary. We +/// currently have the following orderings based on the terminator: +/// +/// Terminator Successor Ordering +/// ----------------------------------------------------- +/// if Then Block; Else Block +/// ? operator LHS expression; RHS expression +/// &&, || expression that uses result of && or ||, RHS +/// +class CFGBlock { + class StatementList { + typedef BumpVector<Stmt*> ImplTy; + ImplTy Impl; + public: + StatementList(BumpVectorContext &C) : Impl(C, 4) {} + + typedef std::reverse_iterator<ImplTy::iterator> iterator; + typedef std::reverse_iterator<ImplTy::const_iterator> const_iterator; + typedef ImplTy::iterator reverse_iterator; + typedef ImplTy::const_iterator const_reverse_iterator; + + void push_back(Stmt *s, BumpVectorContext &C) { Impl.push_back(s, C); } + Stmt *front() const { return Impl.back(); } + Stmt *back() const { return Impl.front(); } + + iterator begin() { return Impl.rbegin(); } + iterator end() { return Impl.rend(); } + const_iterator begin() const { return Impl.rbegin(); } + const_iterator end() const { return Impl.rend(); } + reverse_iterator rbegin() { return Impl.begin(); } + reverse_iterator rend() { return Impl.end(); } + const_reverse_iterator rbegin() const { return Impl.begin(); } + const_reverse_iterator rend() const { return Impl.end(); } + + Stmt* operator[](size_t i) const { + assert(i < Impl.size()); + return Impl[Impl.size() - 1 - i]; + } + + size_t size() const { return Impl.size(); } + bool empty() const { return Impl.empty(); } + }; + + /// Stmts - The set of statements in the basic block. + StatementList Stmts; + + /// Label - An (optional) label that prefixes the executable + /// statements in the block. When this variable is non-NULL, it is + /// either an instance of LabelStmt or SwitchCase. + Stmt *Label; + + /// Terminator - The terminator for a basic block that + /// indicates the type of control-flow that occurs between a block + /// and its successors. + Stmt *Terminator; + + /// LoopTarget - Some blocks are used to represent the "loop edge" to + /// the start of a loop from within the loop body. This Stmt* will be + /// refer to the loop statement for such blocks (and be null otherwise). + const Stmt *LoopTarget; + + /// BlockID - A numerical ID assigned to a CFGBlock during construction + /// of the CFG. + unsigned BlockID; + + /// Predecessors/Successors - Keep track of the predecessor / successor + /// CFG blocks. + typedef BumpVector<CFGBlock*> AdjacentBlocks; + AdjacentBlocks Preds; + AdjacentBlocks Succs; + +public: + explicit CFGBlock(unsigned blockid, BumpVectorContext &C) + : Stmts(C), Label(NULL), Terminator(NULL), LoopTarget(NULL), + BlockID(blockid), Preds(C, 1), Succs(C, 1) {} + ~CFGBlock() {}; + + // Statement iterators + typedef StatementList::iterator iterator; + typedef StatementList::const_iterator const_iterator; + typedef StatementList::reverse_iterator reverse_iterator; + typedef StatementList::const_reverse_iterator const_reverse_iterator; + + Stmt* front() const { return Stmts.front(); } + Stmt* back() const { return Stmts.back(); } + + iterator begin() { return Stmts.begin(); } + iterator end() { return Stmts.end(); } + const_iterator begin() const { return Stmts.begin(); } + const_iterator end() const { return Stmts.end(); } + + reverse_iterator rbegin() { return Stmts.rbegin(); } + reverse_iterator rend() { return Stmts.rend(); } + const_reverse_iterator rbegin() const { return Stmts.rbegin(); } + const_reverse_iterator rend() const { return Stmts.rend(); } + + unsigned size() const { return Stmts.size(); } + bool empty() const { return Stmts.empty(); } + + Stmt* operator[](size_t i) const { return Stmts[i]; } + + + // CFG iterators + typedef AdjacentBlocks::iterator pred_iterator; + typedef AdjacentBlocks::const_iterator const_pred_iterator; + typedef AdjacentBlocks::reverse_iterator pred_reverse_iterator; + typedef AdjacentBlocks::const_reverse_iterator const_pred_reverse_iterator; + + typedef AdjacentBlocks::iterator succ_iterator; + typedef AdjacentBlocks::const_iterator const_succ_iterator; + typedef AdjacentBlocks::reverse_iterator succ_reverse_iterator; + typedef AdjacentBlocks::const_reverse_iterator const_succ_reverse_iterator; + + pred_iterator pred_begin() { return Preds.begin(); } + pred_iterator pred_end() { return Preds.end(); } + const_pred_iterator pred_begin() const { return Preds.begin(); } + const_pred_iterator pred_end() const { return Preds.end(); } + + pred_reverse_iterator pred_rbegin() { return Preds.rbegin(); } + pred_reverse_iterator pred_rend() { return Preds.rend(); } + const_pred_reverse_iterator pred_rbegin() const { return Preds.rbegin(); } + const_pred_reverse_iterator pred_rend() const { return Preds.rend(); } + + succ_iterator succ_begin() { return Succs.begin(); } + succ_iterator succ_end() { return Succs.end(); } + const_succ_iterator succ_begin() const { return Succs.begin(); } + const_succ_iterator succ_end() const { return Succs.end(); } + + succ_reverse_iterator succ_rbegin() { return Succs.rbegin(); } + succ_reverse_iterator succ_rend() { return Succs.rend(); } + const_succ_reverse_iterator succ_rbegin() const { return Succs.rbegin(); } + const_succ_reverse_iterator succ_rend() const { return Succs.rend(); } + + unsigned succ_size() const { return Succs.size(); } + bool succ_empty() const { return Succs.empty(); } + + unsigned pred_size() const { return Preds.size(); } + bool pred_empty() const { return Preds.empty(); } + + // Manipulation of block contents + + void setTerminator(Stmt* Statement) { Terminator = Statement; } + void setLabel(Stmt* Statement) { Label = Statement; } + void setLoopTarget(const Stmt *loopTarget) { LoopTarget = loopTarget; } + + Stmt* getTerminator() { return Terminator; } + const Stmt* getTerminator() const { return Terminator; } + + Stmt* getTerminatorCondition(); + + const Stmt* getTerminatorCondition() const { + return const_cast<CFGBlock*>(this)->getTerminatorCondition(); + } + + const Stmt *getLoopTarget() const { return LoopTarget; } + + bool hasBinaryBranchTerminator() const; + + Stmt* getLabel() { return Label; } + const Stmt* getLabel() const { return Label; } + + void reverseStmts(); + + unsigned getBlockID() const { return BlockID; } + + void dump(const CFG *cfg, const LangOptions &LO) const; + void print(llvm::raw_ostream &OS, const CFG* cfg, const LangOptions &LO) const; + void printTerminator(llvm::raw_ostream &OS, const LangOptions &LO) const; + + void addSuccessor(CFGBlock* Block, BumpVectorContext &C) { + if (Block) + Block->Preds.push_back(this, C); + Succs.push_back(Block, C); + } + + void appendStmt(Stmt* Statement, BumpVectorContext &C) { + Stmts.push_back(Statement, C); + } +}; + + +/// CFG - Represents a source-level, intra-procedural CFG that represents the +/// control-flow of a Stmt. The Stmt can represent an entire function body, +/// or a single expression. A CFG will always contain one empty block that +/// represents the Exit point of the CFG. A CFG will also contain a designated +/// Entry block. The CFG solely represents control-flow; it consists of +/// CFGBlocks which are simply containers of Stmt*'s in the AST the CFG +/// was constructed from. +class CFG { +public: + //===--------------------------------------------------------------------===// + // CFG Construction & Manipulation. + //===--------------------------------------------------------------------===// + + /// buildCFG - Builds a CFG from an AST. The responsibility to free the + /// constructed CFG belongs to the caller. + static CFG* buildCFG(Stmt* AST, ASTContext *C); + + /// createBlock - Create a new block in the CFG. The CFG owns the block; + /// the caller should not directly free it. + CFGBlock* createBlock(); + + /// setEntry - Set the entry block of the CFG. This is typically used + /// only during CFG construction. Most CFG clients expect that the + /// entry block has no predecessors and contains no statements. + void setEntry(CFGBlock *B) { Entry = B; } + + /// setIndirectGotoBlock - Set the block used for indirect goto jumps. + /// This is typically used only during CFG construction. + void setIndirectGotoBlock(CFGBlock* B) { IndirectGotoBlock = B; } + + //===--------------------------------------------------------------------===// + // Block Iterators + //===--------------------------------------------------------------------===// + + typedef BumpVector<CFGBlock*> CFGBlockListTy; + typedef CFGBlockListTy::iterator iterator; + typedef CFGBlockListTy::const_iterator const_iterator; + typedef std::reverse_iterator<iterator> reverse_iterator; + typedef std::reverse_iterator<const_iterator> const_reverse_iterator; + + CFGBlock& front() { return *Blocks.front(); } + CFGBlock& back() { return *Blocks.back(); } + + iterator begin() { return Blocks.begin(); } + iterator end() { return Blocks.end(); } + const_iterator begin() const { return Blocks.begin(); } + const_iterator end() const { return Blocks.end(); } + + reverse_iterator rbegin() { return Blocks.rbegin(); } + reverse_iterator rend() { return Blocks.rend(); } + const_reverse_iterator rbegin() const { return Blocks.rbegin(); } + const_reverse_iterator rend() const { return Blocks.rend(); } + + CFGBlock& getEntry() { return *Entry; } + const CFGBlock& getEntry() const { return *Entry; } + CFGBlock& getExit() { return *Exit; } + const CFGBlock& getExit() const { return *Exit; } + + CFGBlock* getIndirectGotoBlock() { return IndirectGotoBlock; } + const CFGBlock* getIndirectGotoBlock() const { return IndirectGotoBlock; } + + //===--------------------------------------------------------------------===// + // Member templates useful for various batch operations over CFGs. + //===--------------------------------------------------------------------===// + + template <typename CALLBACK> + void VisitBlockStmts(CALLBACK& O) const { + for (const_iterator I=begin(), E=end(); I != E; ++I) + for (CFGBlock::const_iterator BI=(*I)->begin(), BE=(*I)->end(); + BI != BE; ++BI) + O(*BI); + } + + //===--------------------------------------------------------------------===// + // CFG Introspection. + //===--------------------------------------------------------------------===// + + struct BlkExprNumTy { + const signed Idx; + explicit BlkExprNumTy(signed idx) : Idx(idx) {} + explicit BlkExprNumTy() : Idx(-1) {} + operator bool() const { return Idx >= 0; } + operator unsigned() const { assert(Idx >=0); return (unsigned) Idx; } + }; + + bool isBlkExpr(const Stmt* S) { return getBlkExprNum(S); } + BlkExprNumTy getBlkExprNum(const Stmt* S); + unsigned getNumBlkExprs(); + + /// getNumBlockIDs - Returns the total number of BlockIDs allocated (which + /// start at 0). + unsigned getNumBlockIDs() const { return NumBlockIDs; } + + //===--------------------------------------------------------------------===// + // CFG Debugging: Pretty-Printing and Visualization. + //===--------------------------------------------------------------------===// + + void viewCFG(const LangOptions &LO) const; + void print(llvm::raw_ostream& OS, const LangOptions &LO) const; + void dump(const LangOptions &LO) const; + + //===--------------------------------------------------------------------===// + // Internal: constructors and data. + //===--------------------------------------------------------------------===// + + CFG() : Entry(NULL), Exit(NULL), IndirectGotoBlock(NULL), NumBlockIDs(0), + BlkExprMap(NULL), Blocks(BlkBVC, 10) {}; + + ~CFG(); + + llvm::BumpPtrAllocator& getAllocator() { + return BlkBVC.getAllocator(); + } + + BumpVectorContext &getBumpVectorContext() { + return BlkBVC; + } + +private: + CFGBlock* Entry; + CFGBlock* Exit; + CFGBlock* IndirectGotoBlock; // Special block to contain collective dispatch + // for indirect gotos + unsigned NumBlockIDs; + + // BlkExprMap - An opaque pointer to prevent inclusion of DenseMap.h. + // It represents a map from Expr* to integers to record the set of + // block-level expressions and their "statement number" in the CFG. + void* BlkExprMap; + + BumpVectorContext BlkBVC; + + CFGBlockListTy Blocks; + +}; +} // end namespace clang + +//===----------------------------------------------------------------------===// +// GraphTraits specializations for CFG basic block graphs (source-level CFGs) +//===----------------------------------------------------------------------===// + +namespace llvm { + +// Traits for: CFGBlock + +template <> struct GraphTraits<clang::CFGBlock* > { + typedef clang::CFGBlock NodeType; + typedef clang::CFGBlock::succ_iterator ChildIteratorType; + + static NodeType* getEntryNode(clang::CFGBlock* BB) + { return BB; } + + static inline ChildIteratorType child_begin(NodeType* N) + { return N->succ_begin(); } + + static inline ChildIteratorType child_end(NodeType* N) + { return N->succ_end(); } +}; + +template <> struct GraphTraits<const clang::CFGBlock* > { + typedef const clang::CFGBlock NodeType; + typedef clang::CFGBlock::const_succ_iterator ChildIteratorType; + + static NodeType* getEntryNode(const clang::CFGBlock* BB) + { return BB; } + + static inline ChildIteratorType child_begin(NodeType* N) + { return N->succ_begin(); } + + static inline ChildIteratorType child_end(NodeType* N) + { return N->succ_end(); } +}; + +template <> struct GraphTraits<Inverse<const clang::CFGBlock*> > { + typedef const clang::CFGBlock NodeType; + typedef clang::CFGBlock::const_pred_iterator ChildIteratorType; + + static NodeType *getEntryNode(Inverse<const clang::CFGBlock*> G) + { return G.Graph; } + + static inline ChildIteratorType child_begin(NodeType* N) + { return N->pred_begin(); } + + static inline ChildIteratorType child_end(NodeType* N) + { return N->pred_end(); } +}; + +// Traits for: CFG + +template <> struct GraphTraits<clang::CFG* > + : public GraphTraits<clang::CFGBlock* > { + + typedef clang::CFG::iterator nodes_iterator; + + static NodeType *getEntryNode(clang::CFG* F) { return &F->getEntry(); } + static nodes_iterator nodes_begin(clang::CFG* F) { return F->begin(); } + static nodes_iterator nodes_end(clang::CFG* F) { return F->end(); } +}; + +template <> struct GraphTraits< const clang::CFG* > + : public GraphTraits< const clang::CFGBlock* > { + + typedef clang::CFG::const_iterator nodes_iterator; + + static NodeType *getEntryNode( const clang::CFG* F) { return &F->getEntry(); } + static nodes_iterator nodes_begin( const clang::CFG* F) { return F->begin(); } + static nodes_iterator nodes_end( const clang::CFG* F) { return F->end(); } +}; + +template <> struct GraphTraits<Inverse<const clang::CFG*> > + : public GraphTraits<Inverse<const clang::CFGBlock*> > { + + typedef clang::CFG::const_iterator nodes_iterator; + + static NodeType *getEntryNode(const clang::CFG* F) { return &F->getExit(); } + static nodes_iterator nodes_begin(const clang::CFG* F) { return F->begin();} + static nodes_iterator nodes_end(const clang::CFG* F) { return F->end(); } +}; + +} // end llvm namespace + +#endif diff --git a/include/clang/Analysis/CallGraph.h b/include/clang/Analysis/CallGraph.h new file mode 100644 index 000000000000..fabeea38d597 --- /dev/null +++ b/include/clang/Analysis/CallGraph.h @@ -0,0 +1,147 @@ +//== CallGraph.cpp - Call graph building ------------------------*- 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 CallGraph and CallGraphNode classes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_CALLGRAPH +#define LLVM_CLANG_ANALYSIS_CALLGRAPH + +#include "clang/Index/ASTLocation.h" +#include "clang/Index/Entity.h" +#include "clang/Index/Program.h" +#include "clang/Frontend/ASTUnit.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/GraphTraits.h" +#include "llvm/ADT/STLExtras.h" +#include <vector> +#include <map> + +namespace clang { + +class CallGraphNode { + idx::Entity F; + typedef std::pair<idx::ASTLocation, CallGraphNode*> CallRecord; + std::vector<CallRecord> CalledFunctions; + +public: + CallGraphNode(idx::Entity f) : F(f) {} + + typedef std::vector<CallRecord>::iterator iterator; + typedef std::vector<CallRecord>::const_iterator const_iterator; + + iterator begin() { return CalledFunctions.begin(); } + iterator end() { return CalledFunctions.end(); } + const_iterator begin() const { return CalledFunctions.begin(); } + const_iterator end() const { return CalledFunctions.end(); } + + void addCallee(idx::ASTLocation L, CallGraphNode *Node) { + CalledFunctions.push_back(std::make_pair(L, Node)); + } + + bool hasCallee() const { return begin() != end(); } + + std::string getName() const { return F.getPrintableName(); } + + Decl *getDecl(ASTContext &Ctx) const { return F.getDecl(Ctx); } +}; + +class CallGraph { + /// Program manages all Entities. + idx::Program Prog; + + typedef std::map<idx::Entity, CallGraphNode *> FunctionMapTy; + + /// FunctionMap owns all CallGraphNodes. + FunctionMapTy FunctionMap; + + /// CallerCtx maps a caller to its ASTContext. + llvm::DenseMap<CallGraphNode *, ASTContext *> CallerCtx; + + /// Root node is the 'main' function or 0. + CallGraphNode *Root; + + /// ExternalCallingNode has edges to all external functions. + CallGraphNode *ExternalCallingNode; + +public: + CallGraph(); + ~CallGraph(); + + typedef FunctionMapTy::iterator iterator; + typedef FunctionMapTy::const_iterator const_iterator; + + iterator begin() { return FunctionMap.begin(); } + iterator end() { return FunctionMap.end(); } + const_iterator begin() const { return FunctionMap.begin(); } + const_iterator end() const { return FunctionMap.end(); } + + CallGraphNode *getRoot() { return Root; } + + CallGraphNode *getExternalCallingNode() { return ExternalCallingNode; } + + void addTU(ASTUnit &AST); + + idx::Program &getProgram() { return Prog; } + + CallGraphNode *getOrInsertFunction(idx::Entity F); + + Decl *getDecl(CallGraphNode *Node); + + void print(llvm::raw_ostream &os); + void dump(); + + void ViewCallGraph() const; +}; + +} // end clang namespace + +namespace llvm { + +template <> struct GraphTraits<clang::CallGraph> { + typedef clang::CallGraph GraphType; + typedef clang::CallGraphNode NodeType; + + typedef std::pair<clang::idx::ASTLocation, NodeType*> CGNPairTy; + typedef std::pointer_to_unary_function<CGNPairTy, NodeType*> CGNDerefFun; + + typedef mapped_iterator<NodeType::iterator, CGNDerefFun> ChildIteratorType; + + static NodeType *getEntryNode(GraphType *CG) { + return CG->getExternalCallingNode(); + } + + static ChildIteratorType child_begin(NodeType *N) { + return map_iterator(N->begin(), CGNDerefFun(CGNDeref)); + } + static ChildIteratorType child_end(NodeType *N) { + return map_iterator(N->end(), CGNDerefFun(CGNDeref)); + } + + typedef std::pair<clang::idx::Entity, NodeType*> PairTy; + typedef std::pointer_to_unary_function<PairTy, NodeType*> DerefFun; + + typedef mapped_iterator<GraphType::const_iterator, DerefFun> nodes_iterator; + + static nodes_iterator nodes_begin(const GraphType &CG) { + return map_iterator(CG.begin(), DerefFun(CGDeref)); + } + static nodes_iterator nodes_end(const GraphType &CG) { + return map_iterator(CG.end(), DerefFun(CGDeref)); + } + + static NodeType *CGNDeref(CGNPairTy P) { return P.second; } + + static NodeType *CGDeref(PairTy P) { return P.second; } +}; + +} // end llvm namespace + +#endif diff --git a/include/clang/Analysis/FlowSensitive/DataflowSolver.h b/include/clang/Analysis/FlowSensitive/DataflowSolver.h index 38612593368b..f505bca9519c 100644 --- a/include/clang/Analysis/FlowSensitive/DataflowSolver.h +++ b/include/clang/Analysis/FlowSensitive/DataflowSolver.h @@ -14,7 +14,7 @@ #ifndef LLVM_CLANG_ANALYSES_DATAFLOW_SOLVER #define LLVM_CLANG_ANALYSES_DATAFLOW_SOLVER -#include "clang/AST/CFG.h" +#include "clang/Analysis/CFG.h" #include "clang/Analysis/ProgramPoint.h" #include "llvm/ADT/SmallPtrSet.h" #include "functional" // STL @@ -24,7 +24,7 @@ namespace clang { //===----------------------------------------------------------------------===// /// DataflowWorkListTy - Data structure representing the worklist used for /// dataflow algorithms. -//===----------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// class DataflowWorkListTy { typedef llvm::SmallPtrSet<const CFGBlock*,20> BlockSet; @@ -33,15 +33,15 @@ 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; + return B; } - + /// isEmpty - Return true if the worklist is empty. bool isEmpty() const { return wlist.empty(); } }; @@ -59,22 +59,22 @@ 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 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); + return BlockEdge(Prev, B, 0); } - + static BlockEdge NextEdge(const CFGBlock* B, const CFGBlock* Next) { - return BlockEdge(B, Next); + return BlockEdge(B, Next, 0); } }; @@ -82,22 +82,22 @@ 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 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 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 StmtItr StmtEnd(const CFGBlock* B) { return B->rend(); } + static BlockEdge PrevEdge(const CFGBlock* B, const CFGBlock* Prev) { - return BlockEdge(B, Prev); + return BlockEdge(B, Prev, 0); } - + static BlockEdge NextEdge(const CFGBlock* B, const CFGBlock* Next) { - return BlockEdge(Next, B); + return BlockEdge(Next, B, 0); } }; } // end namespace dataflow @@ -105,7 +105,7 @@ template <> struct ItrTraits<backward_analysis_tag> { //===----------------------------------------------------------------------===// /// DataflowSolverTy - Generic dataflow solver. //===----------------------------------------------------------------------===// - + template <typename _DFValuesTy, // Usually a subclass of DataflowValues typename _TransferFuncsTy, typename _MergeOperatorTy, @@ -120,7 +120,7 @@ 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; @@ -130,24 +130,24 @@ public: 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() {} - + ~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); + 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 @@ -162,10 +162,10 @@ public: ProcessBlock(B, recordStmtValues, AnalysisDirTag()); } } - + void runOnBlock(const CFGBlock& B, bool recordStmtValues) { runOnBlock(&B, recordStmtValues); - } + } void runOnBlock(CFG::iterator& I, bool recordStmtValues) { runOnBlock(*I, recordStmtValues); } @@ -177,81 +177,87 @@ public: 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); - + WorkList.enqueue(&**I); + while (!WorkList.isEmpty()) { const CFGBlock* B = WorkList.dequeue(); - ProcessMerge(cfg,B); + ProcessMerge(cfg, B); ProcessBlock(B, recordStmtValues, AnalysisDirTag()); - UpdateEdges(cfg,B,TF.getVal()); + UpdateEdges(cfg, B, TF.getVal()); } - } - + } + void ProcessMerge(CFG& cfg, const CFGBlock* B) { - ValTy& V = TF.getVal(); + 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){ + CFGBlock *PrevBlk = *I; + + if (!PrevBlk) + continue; + typename EdgeDataMapTy::iterator EI = - M.find(ItrTraits::PrevEdge(B, *I)); + M.find(ItrTraits::PrevEdge(B, PrevBlk)); if (EI != M.end()) { if (firstMerge) { firstMerge = false; V.copyValues(EI->second); } - else Merge(V,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)); + + 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)); + 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(); @@ -263,14 +269,15 @@ private: // 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); + if (CFGBlock *NextBlk = *I) + UpdateEdgeValue(ItrTraits::NextEdge(B, NextBlk),V, NextBlk); } - + /// 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); @@ -280,7 +287,7 @@ private: WorkList.enqueue(TargetBlock); } } - + private: DFValuesTy& D; DataflowWorkListTy WorkList; diff --git a/include/clang/Analysis/FlowSensitive/DataflowValues.h b/include/clang/Analysis/FlowSensitive/DataflowValues.h index d6427a5cab47..648fe33ab0d4 100644 --- a/include/clang/Analysis/FlowSensitive/DataflowValues.h +++ b/include/clang/Analysis/FlowSensitive/DataflowValues.h @@ -16,7 +16,7 @@ #ifndef LLVM_CLANG_ANALYSES_DATAFLOW_VALUES #define LLVM_CLANG_ANALYSES_DATAFLOW_VALUES -#include "clang/AST/CFG.h" +#include "clang/Analysis/CFG.h" #include "clang/Analysis/ProgramPoint.h" #include "llvm/ADT/DenseMap.h" @@ -24,7 +24,7 @@ /// 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 { @@ -34,19 +34,19 @@ 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 typename ValueTypes::AnalysisDataTy AnalysisDataTy; typedef _AnalysisDirTag AnalysisDirTag; typedef llvm::DenseMap<ProgramPoint, ValTy> EdgeDataMapTy; typedef llvm::DenseMap<const CFGBlock*, ValTy> BlockDataMapTy; @@ -60,15 +60,15 @@ 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; } - + bool isForwardAnalysis(dataflow::backward_analysis_tag) { return false; } + //===--------------------------------------------------------------------===// // Initialization and accessors methods. //===--------------------------------------------------------------------===// @@ -76,10 +76,10 @@ private: 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) {}; + void InitializeValues(const CFG& cfg) {}; /// getEdgeData - Retrieves the dataflow values associated with a @@ -89,28 +89,28 @@ public: 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 + /// 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. + /// 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 + + /// 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. + /// 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. @@ -120,11 +120,11 @@ public: 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. @@ -138,35 +138,35 @@ public: /// 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. + /// 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 index 9ff3f52f89aa..1da15fbae6c4 100644 --- a/include/clang/Analysis/LocalCheckers.h +++ b/include/clang/Analysis/LocalCheckers.h @@ -31,23 +31,29 @@ class BugReporter; class ObjCImplementationDecl; class LangOptions; class GRExprEngine; - -void CheckDeadStores(LiveVariables& L, BugReporter& BR); - + +void CheckDeadStores(CFG &cfg, LiveVariables &L, ParentMap &map, + BugReporter& BR); + void CheckUninitializedValues(CFG& cfg, ASTContext& Ctx, Diagnostic& Diags, bool FullUninitTaint=false); - + GRTransferFuncs* MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled, - const LangOptions& lopts); - -void CheckObjCDealloc(ObjCImplementationDecl* D, const LangOptions& L, + const LangOptions& lopts); + +void CheckObjCDealloc(const ObjCImplementationDecl* D, const LangOptions& L, BugReporter& BR); - -void CheckObjCInstMethSignature(ObjCImplementationDecl* ID, BugReporter& BR); -void CheckObjCUnusedIvar(ObjCImplementationDecl* D, BugReporter& BR); - -void RegisterAppleChecks(GRExprEngine& Eng); - + +void CheckObjCInstMethSignature(const ObjCImplementationDecl *ID, + BugReporter& BR); + +void CheckObjCUnusedIvar(const ObjCImplementationDecl *D, BugReporter& BR); + +void RegisterAppleChecks(GRExprEngine& Eng, const Decl &D); + +void CheckSecuritySyntaxOnly(const Decl *D, BugReporter &BR); + + } // end namespace clang #endif diff --git a/include/clang/Analysis/PathDiagnostic.h b/include/clang/Analysis/PathDiagnostic.h index 994b35e5efda..a08afe2bb90b 100644 --- a/include/clang/Analysis/PathDiagnostic.h +++ b/include/clang/Analysis/PathDiagnostic.h @@ -17,6 +17,7 @@ #include "clang/Basic/SourceManager.h" #include "clang/Basic/Diagnostic.h" #include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/FoldingSet.h" #include <vector> #include <deque> @@ -24,12 +25,17 @@ #include <algorithm> namespace clang { - + +class Stmt; +class Decl; +class Preprocessor; + //===----------------------------------------------------------------------===// // High-level interface for handlers of path-sensitive diagnostics. //===----------------------------------------------------------------------===// class PathDiagnostic; + class Stmt; class Decl; class Preprocessor; @@ -38,21 +44,18 @@ 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; } + + 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. //===----------------------------------------------------------------------===// @@ -60,11 +63,11 @@ public: 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; @@ -75,27 +78,27 @@ private: 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; @@ -104,27 +107,29 @@ public: 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; } + + void Profile(llvm::FoldingSetNodeID &ID) const; }; class PathDiagnosticLocationPair { @@ -134,19 +139,24 @@ 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(); } + + void Profile(llvm::FoldingSetNodeID &ID) const { + Start.Profile(ID); + End.Profile(ID); + } }; //===----------------------------------------------------------------------===// // Path "pieces" for path-sensitive diagnostics. -//===----------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// class PathDiagnosticPiece { public: @@ -159,7 +169,7 @@ private: const Kind kind; const DisplayHint Hint; std::vector<SourceRange> ranges; - + // Do not implement: PathDiagnosticPiece(); PathDiagnosticPiece(const PathDiagnosticPiece &P); @@ -167,42 +177,42 @@ private: 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 { + + range_iterator ranges_end() const { return ranges_begin() + ranges.size(); } @@ -213,15 +223,17 @@ public: } code_modifications_iterator code_modifications_end() const { - return CodeModificationHints.empty()? 0 + return CodeModificationHints.empty()? 0 : &CodeModificationHints[0] + CodeModificationHints.size(); } static inline bool classof(const PathDiagnosticPiece* P) { return true; } -}; + virtual void Profile(llvm::FoldingSetNodeID &ID) const; +}; + class PathDiagnosticSpotPiece : public PathDiagnosticPiece { private: PathDiagnosticLocation Pos; @@ -234,30 +246,32 @@ public: 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(); } -}; + virtual void Profile(llvm::FoldingSetNodeID &ID) const; +}; + 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: @@ -267,40 +281,40 @@ public: : 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(); } @@ -308,7 +322,7 @@ public: 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(); } @@ -317,171 +331,177 @@ public: static inline bool classof(const PathDiagnosticPiece* P) { return P->getKind() == ControlFlow; } -}; + virtual void Profile(llvm::FoldingSetNodeID &ID) const; +}; + 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; } + + virtual void Profile(llvm::FoldingSetNodeID &ID) const; }; /// 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 { +class PathDiagnostic : public llvm::FoldingSetNode { std::deque<PathDiagnosticPiece*> path; unsigned Size; std::string BugType; std::string Desc; std::string Category; std::deque<std::string> OtherDesc; - -public: + +public: PathDiagnostic(); - + PathDiagnostic(const char* bugtype, const char* desc, const char* category); - - PathDiagnostic(const std::string& bugtype, const std::string& desc, + + 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; } - + 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) { + assert(piece); path.push_front(piece); ++Size; } - + void push_back(PathDiagnosticPiece* piece) { + assert(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: + 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: + 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(); } -}; - + void Profile(llvm::FoldingSetNodeID &ID) const; +}; } //end clang namespace #endif diff --git a/include/clang/Analysis/PathSensitive/AnalysisContext.h b/include/clang/Analysis/PathSensitive/AnalysisContext.h new file mode 100644 index 000000000000..ffe282d3caa3 --- /dev/null +++ b/include/clang/Analysis/PathSensitive/AnalysisContext.h @@ -0,0 +1,167 @@ +//=== AnalysisContext.h - Analysis context 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 AnalysisContext, a class that manages the analysis context +// data for path sensitive analysis. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_ANALYSISCONTEXT_H +#define LLVM_CLANG_ANALYSIS_ANALYSISCONTEXT_H + +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/DenseMap.h" + +namespace clang { + +class Decl; +class Stmt; +class CFG; +class LiveVariables; +class ParentMap; +class ImplicitParamDecl; + +/// AnalysisContext contains the context data for the function or method under +/// analysis. +class AnalysisContext { + const Decl *D; + + // AnalysisContext owns the following data. + CFG *cfg; + LiveVariables *liveness; + ParentMap *PM; + +public: + AnalysisContext(const Decl *d) : D(d), cfg(0), liveness(0), PM(0) {} + ~AnalysisContext(); + + const Decl *getDecl() { return D; } + Stmt *getBody(); + CFG *getCFG(); + ParentMap &getParentMap(); + LiveVariables *getLiveVariables(); + + /// Return the ImplicitParamDecl* associated with 'self' if this + /// AnalysisContext wraps an ObjCMethodDecl. Returns NULL otherwise. + const ImplicitParamDecl *getSelfDecl() const; +}; + +class AnalysisContextManager { + typedef llvm::DenseMap<const Decl*, AnalysisContext*> ContextMap; + ContextMap Contexts; +public: + ~AnalysisContextManager(); + + AnalysisContext *getContext(const Decl *D); +}; + +class LocationContext : public llvm::FoldingSetNode { +public: + enum ContextKind { StackFrame, Scope }; + +private: + ContextKind Kind; + AnalysisContext *Ctx; + const LocationContext *Parent; + +protected: + LocationContext(ContextKind k, AnalysisContext *ctx, + const LocationContext *parent) + : Kind(k), Ctx(ctx), Parent(parent) {} + +public: + ContextKind getKind() const { return Kind; } + + AnalysisContext *getAnalysisContext() const { return Ctx; } + + const LocationContext *getParent() const { return Parent; } + + const Decl *getDecl() const { return getAnalysisContext()->getDecl(); } + + CFG *getCFG() const { return getAnalysisContext()->getCFG(); } + + LiveVariables *getLiveVariables() const { + return getAnalysisContext()->getLiveVariables(); + } + + ParentMap &getParentMap() const { + return getAnalysisContext()->getParentMap(); + } + + const ImplicitParamDecl *getSelfDecl() const { + return Ctx->getSelfDecl(); + } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, Kind, Ctx, Parent); + } + + static void Profile(llvm::FoldingSetNodeID &ID, ContextKind k, + AnalysisContext *ctx, const LocationContext *parent); + + static bool classof(const LocationContext*) { return true; } +}; + +class StackFrameContext : public LocationContext { + const Stmt *CallSite; + +public: + StackFrameContext(AnalysisContext *ctx, const LocationContext *parent, + const Stmt *s) + : LocationContext(StackFrame, ctx, parent), CallSite(s) {} + + Stmt const *getCallSite() const { return CallSite; } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getAnalysisContext(), getParent(), CallSite); + } + + static void Profile(llvm::FoldingSetNodeID &ID, AnalysisContext *ctx, + const LocationContext *parent, const Stmt *s); + + static bool classof(const LocationContext* Ctx) { + return Ctx->getKind() == StackFrame; + } +}; + +class ScopeContext : public LocationContext { + const Stmt *Enter; + +public: + ScopeContext(AnalysisContext *ctx, const LocationContext *parent, + const Stmt *s) + : LocationContext(Scope, ctx, parent), Enter(s) {} + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getAnalysisContext(), getParent(), Enter); + } + + static void Profile(llvm::FoldingSetNodeID &ID, AnalysisContext *ctx, + const LocationContext *parent, const Stmt *s); + + static bool classof(const LocationContext* Ctx) { + return Ctx->getKind() == Scope; + } +}; + +class LocationContextManager { + llvm::FoldingSet<LocationContext> Contexts; + +public: + StackFrameContext *getStackFrame(AnalysisContext *ctx, + const LocationContext *parent, + const Stmt *s); + + ScopeContext *getScope(AnalysisContext *ctx, const LocationContext *parent, + const Stmt *s); +}; + +} // end clang namespace +#endif diff --git a/include/clang/Analysis/PathSensitive/AnalysisManager.h b/include/clang/Analysis/PathSensitive/AnalysisManager.h new file mode 100644 index 000000000000..e97f80576a8b --- /dev/null +++ b/include/clang/Analysis/PathSensitive/AnalysisManager.h @@ -0,0 +1,140 @@ +//== AnalysisManager.h - Path sensitive analysis data manager ------*- 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 AnalysisManager class that manages the data and policy +// for path sensitive analysis. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_ANALYSISMANAGER_H +#define LLVM_CLANG_ANALYSIS_ANALYSISMANAGER_H + +#include "clang/Analysis/PathSensitive/BugReporter.h" +#include "clang/Analysis/PathSensitive/AnalysisContext.h" +#include "clang/Analysis/PathDiagnostic.h" + +namespace clang { + +class AnalysisManager : public BugReporterData { + AnalysisContextManager AnaCtxMgr; + LocationContextManager LocCtxMgr; + + ASTContext &Ctx; + Diagnostic &Diags; + const LangOptions &LangInfo; + + llvm::OwningPtr<PathDiagnosticClient> PD; + + // Configurable components creators. + StoreManagerCreator CreateStoreMgr; + ConstraintManagerCreator CreateConstraintMgr; + + enum AnalysisScope { ScopeTU, ScopeDecl } AScope; + + bool DisplayedFunction; + bool VisualizeEGDot; + bool VisualizeEGUbi; + bool PurgeDead; + + /// 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. + bool EagerlyAssume; + bool TrimGraph; + +public: + AnalysisManager(ASTContext &ctx, Diagnostic &diags, + const LangOptions &lang, PathDiagnosticClient *pd, + StoreManagerCreator storemgr, + ConstraintManagerCreator constraintmgr, + bool displayProgress, bool vizdot, bool vizubi, + bool purge, bool eager, bool trim) + + : Ctx(ctx), Diags(diags), LangInfo(lang), PD(pd), + CreateStoreMgr(storemgr), CreateConstraintMgr(constraintmgr), + AScope(ScopeDecl), DisplayedFunction(!displayProgress), + VisualizeEGDot(vizdot), VisualizeEGUbi(vizubi), PurgeDead(purge), + EagerlyAssume(eager), TrimGraph(trim) {} + + StoreManagerCreator getStoreManagerCreator() { + return CreateStoreMgr; + }; + + ConstraintManagerCreator getConstraintManagerCreator() { + return CreateConstraintMgr; + } + + virtual ASTContext &getASTContext() { + return Ctx; + } + + virtual SourceManager &getSourceManager() { + return getASTContext().getSourceManager(); + } + + virtual Diagnostic &getDiagnostic() { + return Diags; + } + + const LangOptions &getLangOptions() const { + return LangInfo; + } + + virtual PathDiagnosticClient *getPathDiagnosticClient() { + return PD.get(); + } + + bool shouldVisualizeGraphviz() const { return VisualizeEGDot; } + + bool shouldVisualizeUbigraph() const { return VisualizeEGUbi; } + + bool shouldVisualize() const { + return VisualizeEGDot || VisualizeEGUbi; + } + + bool shouldTrimGraph() const { return TrimGraph; } + + bool shouldPurgeDead() const { return PurgeDead; } + + bool shouldEagerlyAssume() const { return EagerlyAssume; } + + void DisplayFunction(Decl *D); + + CFG *getCFG(Decl const *D) { + return AnaCtxMgr.getContext(D)->getCFG(); + } + + LiveVariables *getLiveVariables(Decl const *D) { + return AnaCtxMgr.getContext(D)->getLiveVariables(); + } + + ParentMap &getParentMap(Decl const *D) { + return AnaCtxMgr.getContext(D)->getParentMap(); + } + + // Get the top level stack frame. + StackFrameContext *getStackFrame(Decl const *D) { + return LocCtxMgr.getStackFrame(AnaCtxMgr.getContext(D), 0, 0); + } + + // Get a stack frame with parent. + StackFrameContext const *getStackFrame(Decl const *D, + LocationContext const *Parent, + Stmt const *S) { + return LocCtxMgr.getStackFrame(AnaCtxMgr.getContext(D), Parent, S); + } +}; + +} + +#endif diff --git a/include/clang/Analysis/PathSensitive/BasicValueFactory.h b/include/clang/Analysis/PathSensitive/BasicValueFactory.h index b694e9b29940..12f0ce2d50b7 100644 --- a/include/clang/Analysis/PathSensitive/BasicValueFactory.h +++ b/include/clang/Analysis/PathSensitive/BasicValueFactory.h @@ -8,7 +8,7 @@ //===----------------------------------------------------------------------===// // // This file defines BasicValueFactory, a class that manages the lifetime -// of APSInt objects and symbolic constraints used by GRExprEngine +// of APSInt objects and symbolic constraints used by GRExprEngine // and related classes. // //===----------------------------------------------------------------------===// @@ -24,25 +24,43 @@ #include "llvm/ADT/ImmutableList.h" namespace clang { - + + class GRState; + class CompoundValData : public llvm::FoldingSetNode { QualType T; llvm::ImmutableList<SVal> L; public: - CompoundValData(QualType t, llvm::ImmutableList<SVal> l) + 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(); } - + 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 LazyCompoundValData : public llvm::FoldingSetNode { + const GRState *state; + const TypedRegion *region; +public: + LazyCompoundValData(const GRState *st, const TypedRegion *r) + : state(st), region(r) {} + + const GRState *getState() const { return state; } + const TypedRegion *getRegion() const { return region; } + + static void Profile(llvm::FoldingSetNodeID& ID, const GRState *state, + const TypedRegion *region); + + void Profile(llvm::FoldingSetNodeID& ID) { Profile(ID, state, region); } +}; + class BasicValueFactory { typedef llvm::FoldingSet<llvm::FoldingSetNodeWrapper<llvm::APSInt> > APSIntSetTy; @@ -56,44 +74,54 @@ class BasicValueFactory { llvm::ImmutableList<SVal>::Factory SValListFactory; llvm::FoldingSet<CompoundValData> CompoundValDataSet; + llvm::FoldingSet<LazyCompoundValData> LazyCompoundValDataSet; public: - BasicValueFactory(ASTContext& ctx, llvm::BumpPtrAllocator& Alloc) + BasicValueFactory(ASTContext& ctx, llvm::BumpPtrAllocator& Alloc) : Ctx(ctx), BPAlloc(Alloc), PersistentSVals(0), PersistentSValPairs(0), SValListFactory(Alloc) {} ~BasicValueFactory(); - ASTContext& getContext() const { return Ctx; } + 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 &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 &Convert(QualType T, const llvm::APSInt &From) { + assert(T->isIntegerType() || Loc::IsLocType(T)); + unsigned bitwidth = Ctx.getTypeSize(T); + bool isUnsigned = T->isUnsignedIntegerType() || Loc::IsLocType(T); - return getValue(From.getSExtValue(), - To.getBitWidth(), - To.isUnsigned()); + if (isUnsigned == From.isUnsigned() && bitwidth == From.getBitWidth()) + return From; + + return getValue(From.getSExtValue(), bitwidth, 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())); } @@ -103,44 +131,51 @@ public: 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 &getIntWithPtrWidth(uint64_t X, bool isUnsigned) { + return getValue(X, 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, + + const CompoundValData *getCompoundValData(QualType T, llvm::ImmutableList<SVal> Vals); - + + const LazyCompoundValData *getLazyCompoundValData(const GRState *state, + const TypedRegion *region); + llvm::ImmutableList<SVal> getEmptySValList() { return SValListFactory.GetEmptyList(); } - + llvm::ImmutableList<SVal> consVals(SVal X, llvm::ImmutableList<SVal> L) { return SValListFactory.Add(X, L); } @@ -148,13 +183,13 @@ public: 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); - + getPersistentSValPair(const SVal& V1, const SVal& V2); + const SVal* getPersistentSVal(SVal X); }; diff --git a/include/clang/Analysis/PathSensitive/BugReporter.h b/include/clang/Analysis/PathSensitive/BugReporter.h index 90fd9d8ebf45..1434fce811d1 100644 --- a/include/clang/Analysis/PathSensitive/BugReporter.h +++ b/include/clang/Analysis/PathSensitive/BugReporter.h @@ -27,7 +27,7 @@ #include <list> namespace clang { - + class PathDiagnostic; class PathDiagnosticPiece; class PathDiagnosticClient; @@ -40,7 +40,7 @@ class GRState; class Stmt; class BugType; class ParentMap; - + //===----------------------------------------------------------------------===// // Interface for individual bug reports. //===----------------------------------------------------------------------===// @@ -48,22 +48,22 @@ class ParentMap; class BugReporterVisitor { public: virtual ~BugReporterVisitor(); - virtual PathDiagnosticPiece* VisitNode(const ExplodedNode<GRState>* N, - const ExplodedNode<GRState>* PrevN, + virtual PathDiagnosticPiece* VisitNode(const ExplodedNode* N, + const ExplodedNode* 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; + const ExplodedNode *EndNode; SourceRange R; - + protected: friend class BugReporter; friend class BugReportEquivClass; @@ -71,79 +71,78 @@ protected: 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; + virtual const ExplodedNode* + getOriginalNode(const ExplodedNode* N) = 0; }; - - BugReport(BugType& bt, const char* desc, const ExplodedNode<GRState> *n) + + BugReport(BugType& bt, const char* desc, const ExplodedNode *n) : BT(bt), Description(desc), EndNode(n) {} - + BugReport(BugType& bt, const char* shortDesc, const char* desc, - const ExplodedNode<GRState> *n) + const ExplodedNode *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; } - + const ExplodedNode* 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 Stmt* getStmt() 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); - + const ExplodedNode* 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 void getRanges(const SourceRange*& beg, const SourceRange*& end); - virtual PathDiagnosticPiece* VisitNode(const ExplodedNode<GRState>* N, - const ExplodedNode<GRState>* PrevN, + virtual PathDiagnosticPiece* VisitNode(const ExplodedNode* N, + const ExplodedNode* PrevN, BugReporterContext& BR); - + virtual void registerInitialVisitors(BugReporterContext& BRC, - const ExplodedNode<GRState>* N) {} + const ExplodedNode* 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: @@ -165,7 +164,7 @@ public: BugReport* operator*() const { return *impl; } BugReport* operator->() const { return *impl; } }; - + class const_iterator { std::list<BugReport*>::const_iterator impl; public: @@ -176,64 +175,70 @@ public: 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; + bool SuppressonSink; public: - BugType(const char *name, const char* cat) : Name(name), Category(cat) {} + BugType(const char *name, const char* cat) + : Name(name), Category(cat), SuppressonSink(false) {} 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); + /// isSuppressOnSink - Returns true if bug reports associated with this bug + /// type should be suppressed if the end node of the report is post-dominated + /// by a sink node. + bool isSuppressOnSink() const { return SuppressonSink; } + void setSuppressOnSink(bool x) { SuppressonSink = x; } + + virtual void FlushReports(BugReporter& 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) + RangedBugReport(BugType& D, const char* description, ExplodedNode *n) : BugReport(D, description, n) {} - + RangedBugReport(BugType& D, const char *shortDescription, - const char *description, ExplodedNode<GRState> *n) + const char *description, ExplodedNode *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) { - + void getRanges(const SourceRange*& beg, const SourceRange*& end) { + if (Ranges.empty()) { beg = NULL; end = NULL; @@ -244,7 +249,36 @@ public: } } }; - + +class EnhancedBugReport : public RangedBugReport { +public: + typedef void (*VisitorCreator)(BugReporterContext &BRcC, const void *data, + const ExplodedNode *N); + +private: + typedef std::vector<std::pair<VisitorCreator, const void*> > Creators; + Creators creators; + +public: + EnhancedBugReport(BugType& D, const char* description, ExplodedNode *n) + : RangedBugReport(D, description, n) {} + + EnhancedBugReport(BugType& D, const char *shortDescription, + const char *description, ExplodedNode *n) + : RangedBugReport(D, shortDescription, description, n) {} + + ~EnhancedBugReport() {} + + void registerInitialVisitors(BugReporterContext& BRC, const ExplodedNode* N) { + for (Creators::iterator I = creators.begin(), E = creators.end(); I!=E; ++I) + I->first(BRC, I->second, N); + } + + void addVisitorCreator(VisitorCreator creator, const void *data) { + creators.push_back(std::make_pair(creator, data)); + } +}; + //===----------------------------------------------------------------------===// // BugReporter and friends. //===----------------------------------------------------------------------===// @@ -252,15 +286,12 @@ public: class BugReporterData { public: virtual ~BugReporterData(); - virtual Diagnostic& getDiagnostic() = 0; - virtual PathDiagnosticClient* getPathDiagnosticClient() = 0; - virtual ASTContext& getContext() = 0; + virtual Diagnostic& getDiagnostic() = 0; + virtual PathDiagnosticClient* getPathDiagnosticClient() = 0; + virtual ASTContext& getASTContext() = 0; virtual SourceManager& getSourceManager() = 0; - virtual CFG* getCFG() = 0; - virtual ParentMap& getParentMap() = 0; - virtual LiveVariables* getLiveVariables() = 0; }; - + class BugReporter { public: enum Kind { BaseBRKind, GRBugReporterKind }; @@ -270,9 +301,9 @@ private: BugTypesTy::Factory F; BugTypesTy BugTypes; - const Kind kind; + const Kind kind; BugReporterData& D; - + void FlushReport(BugReportEquivClass& EQ); protected: @@ -281,40 +312,34 @@ protected: 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(); } - + + ASTContext& getContext() { return D.getASTContext(); } + 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); @@ -322,28 +347,28 @@ public: 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; } }; @@ -351,95 +376,87 @@ public: class GRBugReporter : public BugReporter { GRExprEngine& Eng; llvm::SmallSet<SymbolRef, 10> NotableSymbols; -public: +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; } + GRExprEngine &getEngine() { return Eng; } /// getGraph - Get the exploded graph created by the analysis engine /// for the analyzed method or function. - ExplodedGraph<GRState>& getGraph(); - + ExplodedGraph &getGraph(); + /// getStateManager - Return the state manager used by the analysis /// engine. - GRStateManager& getStateManager(); - + 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(); } - + visitor_iterator visitor_end() { return Callbacks.end(); } + + GRBugReporter& getBugReporter() { return BR; } + + ExplodedGraph &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; + + virtual BugReport::NodeResolver& getNodeResolver() = 0; }; class DiagBugReport : public RangedBugReport { @@ -448,19 +465,37 @@ class DiagBugReport : public RangedBugReport { 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); } - + + 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(); } }; +//===----------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// + +namespace bugreporter { + +const Stmt *GetDerefExpr(const ExplodedNode *N); +const Stmt *GetReceiverExpr(const ExplodedNode *N); +const Stmt *GetDenomExpr(const ExplodedNode *N); +const Stmt *GetCalleeExpr(const ExplodedNode *N); +const Stmt *GetRetValExpr(const ExplodedNode *N); + +void registerTrackNullOrUndefValue(BugReporterContext& BRC, const void *stmt, + const ExplodedNode* N); + +} // end namespace clang::bugreporter + +//===----------------------------------------------------------------------===// + } // end clang namespace #endif diff --git a/include/clang/Analysis/PathSensitive/Checker.h b/include/clang/Analysis/PathSensitive/Checker.h new file mode 100644 index 000000000000..4e00d69cdba1 --- /dev/null +++ b/include/clang/Analysis/PathSensitive/Checker.h @@ -0,0 +1,122 @@ +//== Checker.h - Abstract interface for 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 Checker and CheckerVisitor, classes used for creating +// domain-specific checks. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_CHECKER +#define LLVM_CLANG_ANALYSIS_CHECKER +#include "clang/Analysis/Support/SaveAndRestore.h" +#include "clang/Analysis/PathSensitive/GRCoreEngine.h" +#include "clang/Analysis/PathSensitive/GRState.h" +#include "clang/Analysis/PathSensitive/GRExprEngine.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/ExprObjC.h" +#include "clang/AST/StmtCXX.h" +#include "clang/AST/StmtObjC.h" + +//===----------------------------------------------------------------------===// +// Checker interface. +//===----------------------------------------------------------------------===// + +namespace clang { + class GRExprEngine; + +class CheckerContext { + ExplodedNodeSet &Dst; + GRStmtNodeBuilder &B; + GRExprEngine &Eng; + ExplodedNode *Pred; + SaveAndRestore<bool> OldSink; + SaveAndRestore<const void*> OldTag; + SaveAndRestore<ProgramPoint::Kind> OldPointKind; + SaveOr OldHasGen; + +public: + CheckerContext(ExplodedNodeSet &dst, + GRStmtNodeBuilder &builder, + GRExprEngine &eng, + ExplodedNode *pred, + const void *tag, bool preVisit) + : Dst(dst), B(builder), Eng(eng), Pred(pred), + OldSink(B.BuildSinks), OldTag(B.Tag), + OldPointKind(B.PointKind), OldHasGen(B.HasGeneratedNode) { + //assert(Dst.empty()); // This is a fake assertion. + // See GRExprEngine::CheckerVisit(), CurrSet is repeatedly used. + B.Tag = tag; + if (preVisit) + B.PointKind = ProgramPoint::PreStmtKind; + } + + ~CheckerContext() { + if (!B.BuildSinks && !B.HasGeneratedNode) + Dst.Add(Pred); + } + + ConstraintManager &getConstraintManager() { + return Eng.getConstraintManager(); + } + ExplodedNodeSet &getNodeSet() { return Dst; } + GRStmtNodeBuilder &getNodeBuilder() { return B; } + ExplodedNode *&getPredecessor() { return Pred; } + const GRState *getState() { return B.GetState(Pred); } + + ASTContext &getASTContext() { + return Eng.getContext(); + } + + ExplodedNode *GenerateNode(const Stmt *S, bool markAsSink = false) { + return GenerateNode(S, getState(), markAsSink); + } + + ExplodedNode *GenerateNode(const Stmt* S, const GRState *state, + bool markAsSink = false) { + ExplodedNode *node = B.generateNode(S, state, Pred); + + if (markAsSink && node) + node->markAsSink(); + + return node; + } + + void addTransition(ExplodedNode *node) { + Dst.Add(node); + } + + void EmitReport(BugReport *R) { + Eng.getBugReporter().EmitReport(R); + } +}; + +class Checker { +private: + friend class GRExprEngine; + + void GR_Visit(ExplodedNodeSet &Dst, + GRStmtNodeBuilder &Builder, + GRExprEngine &Eng, + const Stmt *stmt, + ExplodedNode *Pred, bool isPrevisit) { + CheckerContext C(Dst, Builder, Eng, Pred, getTag(), isPrevisit); + assert(isPrevisit && "Only previsit supported for now."); + _PreVisit(C, stmt); + } + +public: + virtual ~Checker() {} + virtual void _PreVisit(CheckerContext &C, const Stmt *stmt) = 0; + virtual const void *getTag() = 0; +}; + +} // end clang namespace + +#endif + diff --git a/include/clang/Analysis/PathSensitive/CheckerVisitor.def b/include/clang/Analysis/PathSensitive/CheckerVisitor.def new file mode 100644 index 000000000000..ff6528dae8f5 --- /dev/null +++ b/include/clang/Analysis/PathSensitive/CheckerVisitor.def @@ -0,0 +1,18 @@ +//===-- CheckerVisitor.def - Metadata for CheckerVisitor ----------------*-===// +// +// 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 AST nodes accepted by the CheckerVisitor class. +// +//===---------------------------------------------------------------------===// + +PREVISIT(CallExpr) +PREVISIT(ObjCMessageExpr) +PREVISIT(BinaryOperator) + +#undef PREVISIT diff --git a/include/clang/Analysis/PathSensitive/CheckerVisitor.h b/include/clang/Analysis/PathSensitive/CheckerVisitor.h new file mode 100644 index 000000000000..e74f49c9a761 --- /dev/null +++ b/include/clang/Analysis/PathSensitive/CheckerVisitor.h @@ -0,0 +1,59 @@ +//== CheckerVisitor.h - Abstract visitor for 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 CheckerVisitor. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_CHECKERVISITOR +#define LLVM_CLANG_ANALYSIS_CHECKERVISITOR +#include "clang/Analysis/PathSensitive/Checker.h" + +namespace clang { + +//===----------------------------------------------------------------------===// +// Checker visitor interface. Used by subclasses of Checker to specify their +// own checker visitor logic. +//===----------------------------------------------------------------------===// + +/// CheckerVisitor - This class implements a simple visitor for Stmt subclasses. +/// Since Expr derives from Stmt, this also includes support for visiting Exprs. +template<typename ImplClass> +class CheckerVisitor : public Checker { +public: + virtual void _PreVisit(CheckerContext &C, const Stmt *stmt) { + PreVisit(C, stmt); + } + + void PreVisit(CheckerContext &C, const Stmt *S) { + switch (S->getStmtClass()) { + default: + assert(false && "Unsupport statement."); + return; + case Stmt::CompoundAssignOperatorClass: + static_cast<ImplClass*>(this)->PreVisitBinaryOperator(C, + static_cast<const BinaryOperator*>(S)); + break; +#define PREVISIT(NAME) \ +case Stmt::NAME ## Class:\ +static_cast<ImplClass*>(this)->PreVisit ## NAME(C,static_cast<const NAME*>(S));\ +break; +#include "clang/Analysis/PathSensitive/CheckerVisitor.def" + } + } + +#define PREVISIT(NAME) \ +void PreVisit ## NAME(CheckerContext &C, const NAME* S) {} +#include "clang/Analysis/PathSensitive/CheckerVisitor.def" +}; + +} // end clang namespace + +#endif + diff --git a/include/clang/Analysis/PathSensitive/ConstraintManager.h b/include/clang/Analysis/PathSensitive/ConstraintManager.h index 689bebb450f4..37a14083ac55 100644 --- a/include/clang/Analysis/PathSensitive/ConstraintManager.h +++ b/include/clang/Analysis/PathSensitive/ConstraintManager.h @@ -30,26 +30,32 @@ class SVal; class ConstraintManager { public: virtual ~ConstraintManager(); - virtual const GRState *Assume(const GRState *state, SVal Cond, + virtual const GRState *Assume(const GRState *state, DefinedSVal Cond, bool Assumption) = 0; - virtual const GRState *AssumeInBound(const GRState *state, SVal Idx, - SVal UpperBound, bool Assumption) = 0; + virtual const GRState *AssumeInBound(const GRState *state, DefinedSVal Idx, + DefinedSVal UpperBound, bool Assumption) = 0; + + std::pair<const GRState*, const GRState*> AssumeDual(const GRState *state, + DefinedSVal Cond) { + return std::make_pair(Assume(state, Cond, true), + Assume(state, Cond, false)); + } virtual const llvm::APSInt* getSymVal(const GRState *state, SymbolRef sym) const = 0; - virtual bool isEqual(const GRState *state, SymbolRef sym, + virtual bool isEqual(const GRState *state, SymbolRef sym, const llvm::APSInt& V) const = 0; virtual const GRState *RemoveDeadBindings(const GRState *state, SymbolReaper& SymReaper) = 0; - virtual void print(const GRState *state, llvm::raw_ostream& Out, + virtual void print(const GRState *state, llvm::raw_ostream& Out, const char* nl, const char *sep) = 0; virtual void EndPath(const GRState *state) {} - + /// 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 diff --git a/include/clang/Analysis/PathSensitive/Environment.h b/include/clang/Analysis/PathSensitive/Environment.h index 6f8a12642769..6d5c5678e59b 100644 --- a/include/clang/Analysis/PathSensitive/Environment.h +++ b/include/clang/Analysis/PathSensitive/Environment.h @@ -26,125 +26,78 @@ namespace clang { +class AnalysisContext; class EnvironmentManager; class ValueManager; class LiveVariables; + class Environment { private: friend class EnvironmentManager; - + // Type definitions. typedef llvm::ImmutableMap<const Stmt*,SVal> BindingsTy; // Data. - BindingsTy SubExprBindings; - BindingsTy BlkExprBindings; - - Environment(BindingsTy seb, BindingsTy beb) - : SubExprBindings(seb), BlkExprBindings(beb) {} - + BindingsTy ExprBindings; + AnalysisContext *ACtx; + + Environment(BindingsTy eb, AnalysisContext *aCtx) + : ExprBindings(eb), ACtx(aCtx) {} + 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(const Stmt* E) const { - const SVal* X = SubExprBindings.lookup(cast<Expr>(E)); - return X ? *X : UnknownVal(); - } - - SVal LookupBlkExpr(const Stmt* E) const { - const SVal* X = BlkExprBindings.lookup(E); - return X ? *X : UnknownVal(); - } - + typedef BindingsTy::iterator iterator; + iterator begin() const { return ExprBindings.begin(); } + iterator end() const { return ExprBindings.end(); } + SVal LookupExpr(const Stmt* E) const { - const SVal* X = SubExprBindings.lookup(E); - if (X) return *X; - X = BlkExprBindings.lookup(E); + const SVal* X = ExprBindings.lookup(E); return X ? *X : UnknownVal(); } - + SVal GetSVal(const Stmt* Ex, ValueManager& ValMgr) const; - SVal GetBlkExprSVal(const Stmt* Ex, ValueManager& ValMgr) const; - + + AnalysisContext &getAnalysisContext() const { return *ACtx; } + /// 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); + E->ExprBindings.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; + return ExprBindings == RHS.ExprBindings; } }; - + 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, const Stmt* E) { - return Environment(Env.SubExprBindings, F.Remove(Env.BlkExprBindings, E)); - } - - Environment RemoveSubExpr(const Environment& Env, const Stmt* E) { - return Environment(F.Remove(Env.SubExprBindings, E), Env.BlkExprBindings); + Environment getInitialEnvironment(AnalysisContext *ACtx) { + return Environment(F.GetEmptyMap(), ACtx); } - - Environment AddBlkExpr(const Environment& Env, const Stmt *E, SVal V) { - return Environment(Env.SubExprBindings, F.Add(Env.BlkExprBindings, E, V)); - } - - Environment AddSubExpr(const Environment& Env, const 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, const 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); + Environment BindExpr(Environment Env, const Stmt *S, SVal V, + bool Invalidate); + Environment RemoveDeadBindings(Environment Env, const Stmt *S, + SymbolReaper &SymReaper, const GRState *ST, + llvm::SmallVectorImpl<const MemRegion*>& RegionRoots); }; - + } // end clang namespace #endif diff --git a/include/clang/Analysis/PathSensitive/ExplodedGraph.h b/include/clang/Analysis/PathSensitive/ExplodedGraph.h index 8494d935650d..a7bbdf939f87 100644 --- a/include/clang/Analysis/PathSensitive/ExplodedGraph.h +++ b/include/clang/Analysis/PathSensitive/ExplodedGraph.h @@ -16,6 +16,7 @@ #define LLVM_CLANG_ANALYSIS_EXPLODEDGRAPH #include "clang/Analysis/ProgramPoint.h" +#include "clang/Analysis/PathSensitive/AnalysisContext.h" #include "clang/AST/Decl.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/FoldingSet.h" @@ -25,193 +26,158 @@ #include "llvm/ADT/GraphTraits.h" #include "llvm/ADT/DepthFirstIterator.h" #include "llvm/Support/Casting.h" +#include "clang/Analysis/Support/BumpVector.h" namespace clang { -class GRCoreEngineImpl; -class ExplodedNodeImpl; +class GRState; class CFG; class ASTContext; - -class GRStmtNodeBuilderImpl; -class GRBranchNodeBuilderImpl; -class GRIndirectGotoNodeBuilderImpl; -class GRSwitchNodeBuilderImpl; -class GREndPathNodebuilderImpl; +class ExplodedGraph; //===----------------------------------------------------------------------===// // 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 ExplodedNode : public llvm::FoldingSetNode { + friend class ExplodedGraph; + friend class GRCoreEngine; + friend class GRStmtNodeBuilder; + friend class GRBranchNodeBuilder; + friend class GRIndirectGotoNodeBuilder; + friend class GRSwitchNodeBuilder; + friend class GREndPathNodeBuilder; + 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()); + ExplodedNode *getNode() const { + return reinterpret_cast<ExplodedNode*>(getPtr()); } - + public: NodeGroup() : P(0) {} - - ~NodeGroup(); - - ExplodedNodeImpl** begin() const; - - ExplodedNodeImpl** end() const; - + + ExplodedNode **begin() const; + + ExplodedNode **end() const; + unsigned size() const; - - bool empty() const { return size() == 0; } - - void addNode(ExplodedNodeImpl* N); - + + bool empty() const { return (P & ~Mask) == 0; } + + void addNode(ExplodedNode* N, ExplodedGraph &G); + void setFlag() { - assert (P == 0); + 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; - + const GRState* 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: - + + explicit ExplodedNode(const ProgramPoint& loc, const GRState* state) + : Location(loc), State(state) {} + /// 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); + const LocationContext *getLocationContext() const { + return getLocation().getLocationContext(); } -}; + const Decl &getCodeDecl() const { return *getLocationContext()->getDecl(); } -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); + CFG &getCFG() const { return *getLocationContext()->getCFG(); } + + ParentMap &getParentMap() const {return getLocationContext()->getParentMap();} + + LiveVariables &getLiveVariables() const { + return *getLocationContext()->getLiveVariables(); } - - // Profiling (for FoldingSet). - - static inline void Profile(llvm::FoldingSetNodeID& ID, - const ProgramPoint& Loc, - const StateTy* state) { + + const GRState* getState() const { return State; } + + template <typename T> + const T* getLocationAs() const { return llvm::dyn_cast<T>(&Location); } + + static void Profile(llvm::FoldingSetNodeID &ID, + const ProgramPoint& Loc, const GRState* state) { ID.Add(Loc); - GRTrait<StateTy>::Profile(ID, state); + ID.AddPointer(state); } - - inline void Profile(llvm::FoldingSetNodeID& ID) const { + + void Profile(llvm::FoldingSetNodeID& ID) const { Profile(ID, getLocation(), getState()); } - - void addPredecessor(ExplodedNode* V) { - ExplodedNodeImpl::addPredecessor(V); - } - + + /// addPredeccessor - Adds a predecessor to the current node, and + /// in tandem add this node as a successor of the other node. + void addPredecessor(ExplodedNode* V, ExplodedGraph &G); + + 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(); } + 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(); } + pred_iterator pred_begin() { return Preds.begin(); } + pred_iterator pred_end() { return 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(); } + succ_iterator succ_begin() { return Succs.begin(); } + succ_iterator succ_end() { return Succs.end(); } const_succ_iterator succ_begin() const { return const_cast<ExplodedNode*>(this)->succ_begin(); @@ -219,23 +185,40 @@ public: const_succ_iterator succ_end() const { return const_cast<ExplodedNode*>(this)->succ_end(); } + + // For debugging. + +public: + + class Auditor { + public: + virtual ~Auditor(); + virtual void AddEdge(ExplodedNode* Src, ExplodedNode* Dst) = 0; + }; + + static void SetAuditor(Auditor* A); }; -class InterExplodedGraphMapImpl; +// FIXME: Is this class necessary? +class InterExplodedGraphMap { + llvm::DenseMap<const ExplodedNode*, ExplodedNode*> M; + friend class ExplodedGraph; + +public: + ExplodedNode* getMappedNode(const ExplodedNode* N) const; -class ExplodedGraphImpl { + InterExplodedGraphMap() {}; + virtual ~InterExplodedGraphMap() {} +}; + +class ExplodedGraph { protected: - friend class GRCoreEngineImpl; - friend class GRStmtNodeBuilderImpl; - friend class GRBranchNodeBuilderImpl; - friend class GRIndirectGotoNodeBuilderImpl; - friend class GRSwitchNodeBuilderImpl; - friend class GREndPathNodeBuilderImpl; - + friend class GRCoreEngine; + // Type definitions. - typedef llvm::SmallVector<ExplodedNodeImpl*,2> RootsTy; - typedef llvm::SmallVector<ExplodedNodeImpl*,10> EndNodesTy; - + typedef llvm::SmallVector<ExplodedNode*,2> RootsTy; + typedef llvm::SmallVector<ExplodedNode*,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 @@ -245,338 +228,199 @@ protected: /// 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; - + + /// Nodes - The nodes in the graph. + llvm::FoldingSet<ExplodedNode> Nodes; + + /// BVC - Allocator and context for allocating nodes and their predecessor + /// and successor groups. + BumpVectorContext BVC; + /// 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; +public: + /// 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. + + ExplodedNode* getNode(const ProgramPoint& L, const GRState *State, + bool* IsNew = 0); + + ExplodedGraph* MakeEmptyGraph() const { + return new ExplodedGraph(Ctx); + } /// addRoot - Add an untyped node to the set of roots. - ExplodedNodeImpl* addRoot(ExplodedNodeImpl* V) { + ExplodedNode* addRoot(ExplodedNode* V) { Roots.push_back(V); return V; } /// addEndOfPath - Add an untyped node to the set of EOP nodes. - ExplodedNodeImpl* addEndOfPath(ExplodedNodeImpl* V) { + ExplodedNode* addEndOfPath(ExplodedNode* 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() {} + ExplodedGraph(ASTContext& ctx) : Ctx(ctx), NumNodes(0) {} + + ~ExplodedGraph() {} 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; } + // Iterators. + typedef ExplodedNode NodeTy; + typedef llvm::FoldingSet<ExplodedNode> AllNodesTy; + typedef NodeTy** roots_iterator; + typedef NodeTy* const * const_roots_iterator; + typedef NodeTy** eop_iterator; + typedef NodeTy* const * const_eop_iterator; + typedef AllNodesTy::iterator node_iterator; + typedef AllNodesTy::const_iterator const_node_iterator; - const FunctionDecl* getFunctionDecl() const { - return llvm::dyn_cast<FunctionDecl>(&CodeDecl); - } - - typedef llvm::DenseMap<const ExplodedNodeImpl*, ExplodedNodeImpl*> NodeMap; + node_iterator nodes_begin() { return Nodes.begin(); } - 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() {}; + node_iterator nodes_end() { return Nodes.end(); } - 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); + const_node_iterator nodes_begin() const { return Nodes.begin(); } - 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; + const_node_iterator nodes_end() const { return Nodes.end(); } - 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(); - } + roots_iterator roots_begin() { return Roots.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(); - } + roots_iterator roots_end() { return 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>()); + const_roots_iterator roots_begin() const { return Roots.begin(); } - ExplodedGraphImpl* G = ExplodedGraphImpl::Trim(NBegImpl, NEndImpl, M.get(), - InverseMap); + const_roots_iterator roots_end() const { return Roots.end(); } - return std::make_pair(static_cast<ExplodedGraph*>(G), M.take()); - } + eop_iterator eop_begin() { return EndNodes.begin(); } + + eop_iterator eop_end() { return EndNodes.end(); } + + const_eop_iterator eop_begin() const { return EndNodes.begin(); } + + const_eop_iterator eop_end() const { return EndNodes.end(); } + + llvm::BumpPtrAllocator & getAllocator() { return BVC.getAllocator(); } + BumpVectorContext &getNodeAllocator() { return BVC; } + + ASTContext& getContext() { return Ctx; } + + typedef llvm::DenseMap<const ExplodedNode*, ExplodedNode*> NodeMap; + + std::pair<ExplodedGraph*, InterExplodedGraphMap*> + Trim(const NodeTy* const* NBeg, const NodeTy* const* NEnd, + llvm::DenseMap<const void*, const void*> *InverseMap = 0) const; + + ExplodedGraph* TrimInternal(const ExplodedNode* const * NBeg, + const ExplodedNode* const * NEnd, + InterExplodedGraphMap *M, + llvm::DenseMap<const void*, const void*> *InverseMap) const; }; -template <typename StateTy> class ExplodedNodeSet { - - typedef ExplodedNode<StateTy> NodeTy; - typedef llvm::SmallPtrSet<NodeTy*,5> ImplTy; + typedef llvm::SmallPtrSet<ExplodedNode*,5> ImplTy; ImplTy Impl; - + public: - ExplodedNodeSet(NodeTy* N) { - assert (N && !static_cast<ExplodedNodeImpl*>(N)->isSink()); + ExplodedNodeSet(ExplodedNode* N) { + assert (N && !static_cast<ExplodedNode*>(N)->isSink()); Impl.insert(N); } - + ExplodedNodeSet() {} - - inline void Add(NodeTy* N) { - if (N && !static_cast<ExplodedNodeImpl*>(N)->isSink()) Impl.insert(N); + + inline void Add(ExplodedNode* N) { + if (N && !static_cast<ExplodedNode*>(N)->isSink()) Impl.insert(N); + } + + ExplodedNodeSet& operator=(const ExplodedNodeSet &X) { + Impl = X.Impl; + return *this; } - - typedef typename ImplTy::iterator iterator; - typedef typename ImplTy::const_iterator const_iterator; + + typedef ImplTy::iterator iterator; + typedef 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; + template<> struct GraphTraits<clang::ExplodedNode*> { + typedef clang::ExplodedNode NodeType; + typedef 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; + + template<> struct GraphTraits<const clang::ExplodedNode*> { + typedef const clang::ExplodedNode NodeType; + typedef NodeType::const_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 index eca591d4af0e..015c82e80bb5 100644 --- a/include/clang/Analysis/PathSensitive/GRAuditor.h +++ b/include/clang/Analysis/PathSensitive/GRAuditor.h @@ -1,5 +1,5 @@ //==- GRAuditor.h - Observers of the creation of ExplodedNodes------*- C++ -*-// -// +// // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source @@ -18,22 +18,18 @@ #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 ExplodedNode; +class GRStateManager; + class GRAuditor { public: - typedef ExplodedNode<STATE> NodeTy; - typedef typename STATE::ManagerTy ManagerTy; - virtual ~GRAuditor() {} - virtual bool Audit(NodeTy* N, ManagerTy& M) = 0; + virtual bool Audit(ExplodedNode* N, GRStateManager& M) = 0; }; - - + + } // end clang namespace #endif diff --git a/include/clang/Analysis/PathSensitive/GRBlockCounter.h b/include/clang/Analysis/PathSensitive/GRBlockCounter.h index b4fd2704b81a..67ed9532db02 100644 --- a/include/clang/Analysis/PathSensitive/GRBlockCounter.h +++ b/include/clang/Analysis/PathSensitive/GRBlockCounter.h @@ -1,5 +1,5 @@ //==- GRBlockCounter.h - ADT for counting block visits -------------*- C++ -*-// -// +// // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source @@ -24,27 +24,27 @@ namespace clang { class GRBlockCounter { void* Data; - - GRBlockCounter(void* D) : Data(D) {} + + 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 index 0fbdbde55bd5..02e0b0275e4e 100644 --- a/include/clang/Analysis/PathSensitive/GRCoreEngine.h +++ b/include/clang/Analysis/PathSensitive/GRCoreEngine.h @@ -1,5 +1,5 @@ -//==- GRCoreEngine.h - Path-Sensitive Dataflow Engine ------------------*- C++ -*-// -// +//==- GRCoreEngine.h - Path-Sensitive Dataflow Engine --------------*- C++ -*-// +// // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source @@ -20,646 +20,416 @@ #include "clang/Analysis/PathSensitive/GRWorkList.h" #include "clang/Analysis/PathSensitive/GRBlockCounter.h" #include "clang/Analysis/PathSensitive/GRAuditor.h" +#include "clang/Analysis/PathSensitive/GRSubEngine.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 +/// GRCoreEngine - 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) +/// The template class GRCoreEngine (which subclasses GRCoreEngine) /// 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; - +class GRCoreEngine { + friend class GRStmtNodeBuilder; + friend class GRBranchNodeBuilder; + friend class GRIndirectGotoNodeBuilder; + friend class GRSwitchNodeBuilder; + friend class GREndPathNodeBuilder; + + GRSubEngine& SubEngine; + /// G - The simulation graph. Each node is a (location,state) pair. - llvm::OwningPtr<ExplodedGraphImpl> G; - + llvm::OwningPtr<ExplodedGraph> 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 GenerateNode(const ProgramPoint& Loc, const GRState* State, + ExplodedNode* Pred); + + void HandleBlockEdge(const BlockEdge& E, ExplodedNode* Pred); + void HandleBlockEntrance(const BlockEntrance& E, ExplodedNode* Pred); + void HandleBlockExit(CFGBlock* B, ExplodedNode* Pred); void HandlePostStmt(const PostStmt& S, CFGBlock* B, - unsigned StmtIdx, ExplodedNodeImpl *Pred); - + unsigned StmtIdx, ExplodedNode *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; + ExplodedNode* Pred); + + /// Get the initial state from the subengine. + const GRState* getInitialState(const LocationContext *InitLoc) { + return SubEngine.getInitialState(InitLoc); + } + + void ProcessEndPath(GREndPathNodeBuilder& Builder); + + void ProcessStmt(Stmt* S, GRStmtNodeBuilder& Builder); + - virtual void ProcessStmt(Stmt* S, GRStmtNodeBuilderImpl& Builder) = 0; + bool ProcessBlockEntrance(CFGBlock* Blk, const GRState* State, + GRBlockCounter BC); - virtual void ProcessBranch(Stmt* Condition, Stmt* Terminator, - GRBranchNodeBuilderImpl& Builder) = 0; - virtual void ProcessIndirectGoto(GRIndirectGotoNodeBuilderImpl& Builder) = 0; - - virtual void ProcessSwitch(GRSwitchNodeBuilderImpl& Builder) = 0; + void ProcessBranch(Stmt* Condition, Stmt* Terminator, + GRBranchNodeBuilder& Builder); + + + void ProcessIndirectGoto(GRIndirectGotoNodeBuilder& Builder); + + + void ProcessSwitch(GRSwitchNodeBuilder& Builder); private: - GRCoreEngineImpl(const GRCoreEngineImpl&); // Do not implement. - GRCoreEngineImpl& operator=(const GRCoreEngineImpl&); - -protected: - GRCoreEngineImpl(ExplodedGraphImpl* g, GRWorkList* wl) - : G(g), WList(wl), BCounterFactory(g->getAllocator()) {} - + GRCoreEngine(const GRCoreEngine&); // Do not implement. + GRCoreEngine& operator=(const GRCoreEngine&); + public: + /// Construct a GRCoreEngine object to analyze the provided CFG using + /// a DFS exploration of the exploded graph. + GRCoreEngine(ASTContext& ctx, GRSubEngine& subengine) + : SubEngine(subengine), G(new ExplodedGraph(ctx)), + WList(GRWorkList::MakeBFS()), + BCounterFactory(G->getAllocator()) {} + + /// 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(ASTContext& ctx, GRWorkList* wlist, GRSubEngine& subengine) + : SubEngine(subengine), G(new ExplodedGraph(ctx)), WList(wlist), + BCounterFactory(G->getAllocator()) {} + + ~GRCoreEngine() { + delete WList; + } + + /// getGraph - Returns the exploded graph. + ExplodedGraph& getGraph() { return *G.get(); } + + /// takeGraph - Returns the exploded graph. Ownership of the graph is + /// transfered to the caller. + ExplodedGraph* takeGraph() { return G.take(); } + /// 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(); } + bool ExecuteWorkList(const LocationContext *L, unsigned Steps); }; - -class GRStmtNodeBuilderImpl { - GRCoreEngineImpl& Eng; + +class GRStmtNodeBuilder { + GRCoreEngine& Eng; CFGBlock& B; const unsigned Idx; - ExplodedNodeImpl* Pred; - ExplodedNodeImpl* LastNode; - - typedef llvm::SmallPtrSet<ExplodedNodeImpl*,5> DeferredTy; + ExplodedNode* Pred; + ExplodedNode* LastNode; + GRStateManager& Mgr; + GRAuditor* Auditor; + +public: + bool PurgingDeadSymbols; + bool BuildSinks; + bool HasGeneratedNode; + ProgramPoint::Kind PointKind; + const void *Tag; + + const GRState* CleanedState; + + + typedef llvm::SmallPtrSet<ExplodedNode*,5> DeferredTy; DeferredTy Deferred; - - void GenerateAutoTransition(ExplodedNodeImpl* N); - + + void GenerateAutoTransition(ExplodedNode* N); + public: - GRStmtNodeBuilderImpl(CFGBlock* b, unsigned idx, - ExplodedNodeImpl* N, GRCoreEngineImpl* e); - - ~GRStmtNodeBuilderImpl(); - - ExplodedNodeImpl* getBasePredecessor() const { return Pred; } - - ExplodedNodeImpl* getLastNode() const { + GRStmtNodeBuilder(CFGBlock* b, unsigned idx, ExplodedNode* N, + GRCoreEngine* e, GRStateManager &mgr); + + ~GRStmtNodeBuilder(); + + ExplodedNode* getBasePredecessor() const { return Pred; } + + ExplodedNode* getLastNode() const { return LastNode ? (LastNode->isSink() ? NULL : LastNode) : NULL; } - + + // FIXME: This should not be exposed. + GRWorkList *getWorkList() { return Eng.WList; } + + void SetCleanedState(const GRState* St) { + CleanedState = St; + } + 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); + ExplodedNode* generateNode(PostStmt PP,const GRState* St,ExplodedNode* Pred) { + HasGeneratedNode = true; + return generateNodeInternal(PP, St, Pred); } - - 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); + + ExplodedNode* generateNode(const Stmt *S, const GRState *St, + ExplodedNode *Pred, ProgramPoint::Kind K) { + HasGeneratedNode = true; + + if (PurgingDeadSymbols) + K = ProgramPoint::PostPurgeDeadSymbolsKind; + + return generateNodeInternal(S, St, Pred, K, Tag); } - + + ExplodedNode* generateNode(const Stmt *S, const GRState *St, + ExplodedNode *Pred) { + return generateNode(S, St, Pred, PointKind); + } + + ExplodedNode* + generateNodeInternal(const ProgramPoint &PP, const GRState* State, + ExplodedNode* Pred); + + ExplodedNode* + generateNodeInternal(const Stmt* S, const GRState* State, ExplodedNode* Pred, + ProgramPoint::Kind K = ProgramPoint::PostStmtKind, + const void *tag = 0); + /// 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); - } + void setAuditor(GRAuditor* A) { Auditor = A; } - - GRBlockCounter getBlockCounter() const { - return NB.getBlockCounter(); - } - - unsigned getCurrentBlockCount() const { - return NB.getCurrentBlockCount(); - } - - const StateTy* GetState(NodeTy* Pred) const { - if ((ExplodedNodeImpl*) Pred == NB.getBasePredecessor()) + const GRState* GetState(ExplodedNode* Pred) const { + if ((ExplodedNode*) Pred == 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) { + + ExplodedNode* MakeNode(ExplodedNodeSet& Dst, Stmt* S, ExplodedNode* Pred, + const GRState* 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); - + + ExplodedNode* MakeNode(ExplodedNodeSet& Dst, Stmt* S, ExplodedNode* Pred, + const GRState* St, ProgramPoint::Kind K) { + + const GRState* 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) { + + ExplodedNode* 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) { + + ExplodedNode* MakeSinkNode(ExplodedNodeSet& Dst, Stmt* S, + ExplodedNode* Pred, const GRState* St) { bool Tmp = BuildSinks; BuildSinks = true; - NodeTy* N = MakeNode(Dst, S, Pred, St); + ExplodedNode* 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; + +class GRBranchNodeBuilder { + GRCoreEngine& Eng; CFGBlock* Src; CFGBlock* DstT; CFGBlock* DstF; - ExplodedNodeImpl* Pred; + ExplodedNode* Pred; - typedef llvm::SmallVector<ExplodedNodeImpl*,3> DeferredTy; + typedef llvm::SmallVector<ExplodedNode*,3> DeferredTy; DeferredTy Deferred; - + bool GeneratedTrue; bool GeneratedFalse; - + bool InFeasibleTrue; + bool InFeasibleFalse; + public: - GRBranchNodeBuilderImpl(CFGBlock* src, CFGBlock* dstT, CFGBlock* dstF, - ExplodedNodeImpl* pred, GRCoreEngineImpl* e) + GRBranchNodeBuilder(CFGBlock* src, CFGBlock* dstT, CFGBlock* dstF, + ExplodedNode* pred, GRCoreEngine* 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; } + GeneratedTrue(false), GeneratedFalse(false), + InFeasibleTrue(!DstT), InFeasibleFalse(!DstF) {} + + ~GRBranchNodeBuilder(); + + ExplodedNode* getPredecessor() const { return Pred; } + + const ExplodedGraph& getGraph() const { return *Eng.G; } + GRBlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();} - - ExplodedNodeImpl* generateNodeImpl(const void* State, bool branch); - + + ExplodedNode* generateNode(const GRState* 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(); + void markInfeasible(bool branch) { + if (branch) + InFeasibleTrue = GeneratedTrue = true; + else + InFeasibleFalse = GeneratedFalse = true; } - NodeTy* generateNode(const StateTy* St, bool branch) { - return static_cast<NodeTy*>(NB.generateNodeImpl(St, branch)); - } - - GRBlockCounter getBlockCounter() const { - return NB.getBlockCounter(); + bool isFeasible(bool branch) { + return branch ? !InFeasibleTrue : !InFeasibleFalse; } - - CFGBlock* getTargetBlock(bool branch) const { - return NB.getTargetBlock(branch); - } - - void markInfeasible(bool branch) { - NB.markInfeasible(branch); + + const GRState* getState() const { + return getPredecessor()->getState(); } }; - -class GRIndirectGotoNodeBuilderImpl { - GRCoreEngineImpl& Eng; + +class GRIndirectGotoNodeBuilder { + GRCoreEngine& Eng; CFGBlock* Src; CFGBlock& DispatchBlock; Expr* E; - ExplodedNodeImpl* Pred; + ExplodedNode* Pred; + public: - GRIndirectGotoNodeBuilderImpl(ExplodedNodeImpl* pred, CFGBlock* src, - Expr* e, CFGBlock* dispatch, - GRCoreEngineImpl* eng) + GRIndirectGotoNodeBuilder(ExplodedNode* pred, CFGBlock* src, Expr* e, + CFGBlock* dispatch, GRCoreEngine* eng) : Eng(*eng), Src(src), DispatchBlock(*dispatch), E(e), Pred(pred) {} - - class Iterator { + class iterator { CFGBlock::succ_iterator I; - - friend class GRIndirectGotoNodeBuilderImpl; - Iterator(CFGBlock::succ_iterator i) : I(i) {} + + friend class GRIndirectGotoNodeBuilder; + iterator(CFGBlock::succ_iterator i) : I(i) {} public: - - Iterator& operator++() { ++I; return *this; } - bool operator!=(const Iterator& X) const { return I != X.I; } - + + 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; + iterator begin() { return iterator(DispatchBlock.succ_begin()); } + iterator end() { return iterator(DispatchBlock.succ_end()); } -public: - GRIndirectGotoNodeBuilder(GRIndirectGotoNodeBuilderImpl& nb) : NB(nb) {} - - typedef GRIndirectGotoNodeBuilderImpl::Iterator iterator; + ExplodedNode* generateNode(const iterator& I, const GRState* State, + bool isSink = false); - 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()); - } + Expr* getTarget() const { return E; } + + const GRState* getState() const { return Pred->State; } }; - -class GRSwitchNodeBuilderImpl { - GRCoreEngineImpl& Eng; + +class GRSwitchNodeBuilder { + GRCoreEngine& Eng; CFGBlock* Src; Expr* Condition; - ExplodedNodeImpl* Pred; + ExplodedNode* Pred; + public: - GRSwitchNodeBuilderImpl(ExplodedNodeImpl* pred, CFGBlock* src, - Expr* condition, GRCoreEngineImpl* eng) + GRSwitchNodeBuilder(ExplodedNode* pred, CFGBlock* src, + Expr* condition, GRCoreEngine* eng) : Eng(*eng), Src(src), Condition(condition), Pred(pred) {} - - class Iterator { + + class iterator { CFGBlock::succ_reverse_iterator I; - - friend class GRSwitchNodeBuilderImpl; - Iterator(CFGBlock::succ_reverse_iterator i) : I(i) {} + + friend class GRSwitchNodeBuilder; + iterator(CFGBlock::succ_reverse_iterator i) : I(i) {} + public: - - Iterator& operator++() { ++I; return *this; } - bool operator!=(const Iterator& X) const { return I != X.I; } - + 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); - + + iterator begin() { return iterator(Src->succ_rbegin()+1); } + iterator end() { return iterator(Src->succ_rend()); } + + ExplodedNode* generateCaseStmtNode(const iterator& I, const GRState* State); + + ExplodedNode* generateDefaultCaseNode(const GRState* State, + bool isSink = false); + 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()); - } + const GRState* getState() const { return Pred->State; } }; - -class GREndPathNodeBuilderImpl { - GRCoreEngineImpl& Eng; +class GREndPathNodeBuilder { + GRCoreEngine& Eng; CFGBlock& B; - ExplodedNodeImpl* Pred; + ExplodedNode* 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; } -}; + GREndPathNodeBuilder(CFGBlock* b, ExplodedNode* N, GRCoreEngine* e) + : Eng(*e), B(*b), Pred(N), HasGeneratedNode(false) {} + ~GREndPathNodeBuilder(); + + ExplodedNode* getPredecessor() const { return Pred; } -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(); + return Eng.WList->getBlockCounter(); } - - const StateTy* getState() const { - return getPredecessor()->getState(); - } - - NodeTy* MakeNode(const StateTy* St, const void *tag = 0) { - return static_cast<NodeTy*>(NB.generateNodeImpl(St, tag)); + + unsigned getCurrentBlockCount() const { + return getBlockCounter().getNumVisited(B.getBlockID()); } - - 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; + ExplodedNode* generateNode(const GRState* State, const void *tag = 0, + ExplodedNode *P = 0); -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); - } + CFGBlock* getBlock() const { return &B; } - 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()); + const GRState* getState() const { + return getPredecessor()->getState(); } }; diff --git a/include/clang/Analysis/PathSensitive/GRExprEngine.h b/include/clang/Analysis/PathSensitive/GRExprEngine.h index f05bc680a7e2..e5c61e68c77c 100644 --- a/include/clang/Analysis/PathSensitive/GRExprEngine.h +++ b/include/clang/Analysis/PathSensitive/GRExprEngine.h @@ -16,111 +16,86 @@ #ifndef LLVM_CLANG_ANALYSIS_GREXPRENGINE #define LLVM_CLANG_ANALYSIS_GREXPRENGINE +#include "clang/Analysis/PathSensitive/AnalysisManager.h" +#include "clang/Analysis/PathSensitive/GRSubEngine.h" #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/SValuator.h" #include "clang/Analysis/PathSensitive/BugReporter.h" #include "clang/AST/Type.h" #include "clang/AST/ExprObjC.h" -namespace clang { - +namespace clang { + class PathDiagnosticClient; class Diagnostic; class ObjCForCollectionStmt; + class Checker; + +class GRExprEngine : public GRSubEngine { + AnalysisManager &AMgr; + + GRCoreEngine CoreEngine; -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; + ExplodedGraph& G; /// Builder - The current GRStmtNodeBuilder which is used when building the /// nodes for a given statement. - StmtNodeBuilder* Builder; - + GRStmtNodeBuilder* 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; - + /// SVator - SValuator object that creates SVals from expressions. - llvm::OwningPtr<SValuator> SVator; - + SValuator &SVator; + /// EntryNode - The immediate predecessor node. - NodeTy* EntryNode; + ExplodedNode* EntryNode; /// CleanedState - The state for EntryNode "cleaned" of all dead /// variables and symbols (as determined by a liveness analysis). - const GRState* CleanedState; - + 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; + std::vector<Checker*> Checkers; - /// 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; - + typedef llvm::SmallPtrSet<ExplodedNode*,2> ErrorNodes; + typedef llvm::DenseMap<ExplodedNode*, 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). @@ -130,7 +105,7 @@ public: /// 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; @@ -138,65 +113,55 @@ public: /// 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 + + /// UndefDeref - 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 + /// 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 + + /// 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. @@ -209,136 +174,124 @@ public: /// 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(AnalysisManager &mgr); ~GRExprEngine(); - - void ExecuteWorkList(unsigned Steps = 150000) { - CoreEngine.ExecuteWorkList(Steps); + + void ExecuteWorkList(const LocationContext *L, unsigned Steps = 150000) { + CoreEngine.ExecuteWorkList(L, 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(); } - + + AnalysisManager &getAnalysisManager() const { return AMgr; } + + SValuator &getSValuator() { return SVator; } + 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; } - + + void ViewGraph(ExplodedNode** Beg, ExplodedNode** End); + /// 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; } + const GRState* getInitialState(const LocationContext *InitLoc); + + ExplodedGraph& getGraph() { return G; } + const ExplodedGraph& 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; + + void registerCheck(Checker *check) { + Checkers.push_back(check); } - - bool isUndefStore(const NodeTy* N) const { - return N->isSink() && UndefStores.count(const_cast<NodeTy*>(N)) != 0; + + bool isRetStackAddr(const ExplodedNode* N) const { + return N->isSink() && RetsStackAddr.count(const_cast<ExplodedNode*>(N)) != 0; } - - bool isImplicitNullDeref(const NodeTy* N) const { - return N->isSink() && ImplicitNullDeref.count(const_cast<NodeTy*>(N)) != 0; + + bool isUndefControlFlow(const ExplodedNode* N) const { + return N->isSink() && UndefBranches.count(const_cast<ExplodedNode*>(N)) != 0; } - - bool isExplicitNullDeref(const NodeTy* N) const { - return N->isSink() && ExplicitNullDeref.count(const_cast<NodeTy*>(N)) != 0; + + bool isUndefStore(const ExplodedNode* N) const { + return N->isSink() && UndefStores.count(const_cast<ExplodedNode*>(N)) != 0; } - - bool isUndefDeref(const NodeTy* N) const { - return N->isSink() && UndefDeref.count(const_cast<NodeTy*>(N)) != 0; + + bool isImplicitNullDeref(const ExplodedNode* N) const { + return N->isSink() && ImplicitNullDeref.count(const_cast<ExplodedNode*>(N)) != 0; } - - bool isImplicitBadDivide(const NodeTy* N) const { - return N->isSink() && ImplicitBadDivides.count(const_cast<NodeTy*>(N)) != 0; + + bool isExplicitNullDeref(const ExplodedNode* N) const { + return N->isSink() && ExplicitNullDeref.count(const_cast<ExplodedNode*>(N)) != 0; } - - bool isExplicitBadDivide(const NodeTy* N) const { - return N->isSink() && ExplicitBadDivides.count(const_cast<NodeTy*>(N)) != 0; + + bool isUndefDeref(const ExplodedNode* N) const { + return N->isSink() && UndefDeref.count(const_cast<ExplodedNode*>(N)) != 0; } - - bool isNoReturnCall(const NodeTy* N) const { - return N->isSink() && NoReturnCalls.count(const_cast<NodeTy*>(N)) != 0; + + bool isNoReturnCall(const ExplodedNode* N) const { + return N->isSink() && NoReturnCalls.count(const_cast<ExplodedNode*>(N)) != 0; } - - bool isUndefResult(const NodeTy* N) const { - return N->isSink() && UndefResults.count(const_cast<NodeTy*>(N)) != 0; + + bool isUndefResult(const ExplodedNode* N) const { + return N->isSink() && UndefResults.count(const_cast<ExplodedNode*>(N)) != 0; } - - bool isBadCall(const NodeTy* N) const { - return N->isSink() && BadCalls.count(const_cast<NodeTy*>(N)) != 0; + + bool isBadCall(const ExplodedNode* N) const { + return N->isSink() && BadCalls.count(const_cast<ExplodedNode*>(N)) != 0; } - - bool isUndefArg(const NodeTy* N) const { + + bool isUndefArg(const ExplodedNode* N) const { return N->isSink() && - (UndefArgs.find(const_cast<NodeTy*>(N)) != UndefArgs.end() || - MsgExprUndefArgs.find(const_cast<NodeTy*>(N)) != MsgExprUndefArgs.end()); + (UndefArgs.find(const_cast<ExplodedNode*>(N)) != UndefArgs.end() || + MsgExprUndefArgs.find(const_cast<ExplodedNode*>(N)) != MsgExprUndefArgs.end()); } - - bool isUndefReceiver(const NodeTy* N) const { - return N->isSink() && UndefReceivers.count(const_cast<NodeTy*>(N)) != 0; + + bool isUndefReceiver(const ExplodedNode* N) const { + return N->isSink() && UndefReceivers.count(const_cast<ExplodedNode*>(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(); } - + 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(); } - + 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(); } @@ -346,9 +299,9 @@ public: 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(); @@ -358,60 +311,42 @@ public: 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(); } - + 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 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() { + oob_memacc_iterator implicit_oob_memacc_begin() { return ImplicitOOBMemAccesses.begin(); } oob_memacc_iterator implicit_oob_memacc_end() { @@ -426,45 +361,45 @@ public: 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); - + /// nodes by processing the 'effects' of a block-level statement. + void ProcessStmt(Stmt* S, GRStmtNodeBuilder& 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); - + void ProcessBranch(Stmt* Condition, Stmt* Term, GRBranchNodeBuilder& builder); + /// ProcessIndirectGoto - Called by GRCoreEngine. Used to generate successor /// nodes by processing the 'effects' of a computed goto jump. - void ProcessIndirectGoto(IndirectGotoNodeBuilder& builder); - + void ProcessIndirectGoto(GRIndirectGotoNodeBuilder& builder); + /// ProcessSwitch - Called by GRCoreEngine. Used to generate successor /// nodes by processing the 'effects' of a switch statement. - void ProcessSwitch(SwitchNodeBuilder& builder); - + void ProcessSwitch(GRSwitchNodeBuilder& 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) { + void ProcessEndPath(GREndPathNodeBuilder& 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(); @@ -472,204 +407,198 @@ public: const BasicValueFactory& getBasicVals() const { return StateMgr.getBasicVals(); } - - ValueManager &getValueManager() { return ValMgr; } + + 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) { + const GRState* GetState(ExplodedNode* N) { return N == EntryNode ? CleanedState : N->getState(); } - + public: - NodeTy* MakeNode(NodeSet& Dst, Stmt* S, NodeTy* Pred, const GRState* St, + ExplodedNode* MakeNode(ExplodedNodeSet& Dst, Stmt* S, ExplodedNode* Pred, const GRState* St, ProgramPoint::Kind K = ProgramPoint::PostStmtKind, const void *tag = 0); protected: - + /// CheckerVisit - Dispatcher for performing checker-specific logic + /// at specific statements. + void CheckerVisit(Stmt *S, ExplodedNodeSet &Dst, ExplodedNodeSet &Src, bool isPrevisit); + /// 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); - + void Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& 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); - + void VisitLValue(Expr* Ex, ExplodedNode* Pred, ExplodedNodeSet& Dst); + /// VisitArraySubscriptExpr - Transfer function for array accesses. - void VisitArraySubscriptExpr(ArraySubscriptExpr* Ex, NodeTy* Pred, - NodeSet& Dst, bool asLValue); - + void VisitArraySubscriptExpr(ArraySubscriptExpr* Ex, ExplodedNode* Pred, + ExplodedNodeSet& Dst, bool asLValue); + /// VisitAsmStmt - Transfer function logic for inline asm. - void VisitAsmStmt(AsmStmt* A, NodeTy* Pred, NodeSet& Dst); - + void VisitAsmStmt(AsmStmt* A, ExplodedNode* Pred, ExplodedNodeSet& Dst); + void VisitAsmStmtHelperOutputs(AsmStmt* A, AsmStmt::outputs_iterator I, AsmStmt::outputs_iterator E, - NodeTy* Pred, NodeSet& Dst); - + ExplodedNode* Pred, ExplodedNodeSet& Dst); + void VisitAsmStmtHelperInputs(AsmStmt* A, AsmStmt::inputs_iterator I, AsmStmt::inputs_iterator E, - NodeTy* Pred, NodeSet& Dst); - + ExplodedNode* Pred, ExplodedNodeSet& Dst); + /// VisitBinaryOperator - Transfer function logic for binary operators. - void VisitBinaryOperator(BinaryOperator* B, NodeTy* Pred, NodeSet& Dst); + void VisitBinaryOperator(BinaryOperator* B, ExplodedNode* Pred, ExplodedNodeSet& Dst); + - /// VisitCall - Transfer function for function calls. - void VisitCall(CallExpr* CE, NodeTy* Pred, + void VisitCall(CallExpr* CE, ExplodedNode* Pred, CallExpr::arg_iterator AI, CallExpr::arg_iterator AE, - NodeSet& Dst); - void VisitCallRec(CallExpr* CE, NodeTy* Pred, + ExplodedNodeSet& Dst); + void VisitCallRec(CallExpr* CE, ExplodedNode* Pred, CallExpr::arg_iterator AI, CallExpr::arg_iterator AE, - NodeSet& Dst, const FunctionProtoType *, + ExplodedNodeSet& 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); + void VisitCast(Expr* CastE, Expr* Ex, ExplodedNode* Pred, ExplodedNodeSet& 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); - + void VisitCompoundLiteralExpr(CompoundLiteralExpr* CL, ExplodedNode* Pred, + ExplodedNodeSet& Dst, bool asLValue); + /// VisitDeclRefExpr - Transfer function logic for DeclRefExprs. - void VisitDeclRefExpr(DeclRefExpr* DR, NodeTy* Pred, NodeSet& Dst, - bool asLValue); - + void VisitDeclRefExpr(DeclRefExpr* DR, ExplodedNode* Pred, ExplodedNodeSet& Dst, + bool asLValue); + /// VisitDeclStmt - Transfer function logic for DeclStmts. - void VisitDeclStmt(DeclStmt* DS, NodeTy* Pred, NodeSet& Dst); - + void VisitDeclStmt(DeclStmt* DS, ExplodedNode* Pred, ExplodedNodeSet& Dst); + /// VisitGuardedExpr - Transfer function logic for ?, __builtin_choose - void VisitGuardedExpr(Expr* Ex, Expr* L, Expr* R, NodeTy* Pred, NodeSet& Dst); + void VisitGuardedExpr(Expr* Ex, Expr* L, Expr* R, ExplodedNode* Pred, ExplodedNodeSet& Dst); - void VisitInitListExpr(InitListExpr* E, NodeTy* Pred, NodeSet& Dst); + void VisitInitListExpr(InitListExpr* E, ExplodedNode* Pred, ExplodedNodeSet& Dst); /// VisitLogicalExpr - Transfer function logic for '&&', '||' - void VisitLogicalExpr(BinaryOperator* B, NodeTy* Pred, NodeSet& Dst); - + void VisitLogicalExpr(BinaryOperator* B, ExplodedNode* Pred, ExplodedNodeSet& Dst); + /// VisitMemberExpr - Transfer function for member expressions. - void VisitMemberExpr(MemberExpr* M, NodeTy* Pred, NodeSet& Dst,bool asLValue); - + void VisitMemberExpr(MemberExpr* M, ExplodedNode* Pred, ExplodedNodeSet& Dst,bool asLValue); + /// VisitObjCIvarRefExpr - Transfer function logic for ObjCIvarRefExprs. - void VisitObjCIvarRefExpr(ObjCIvarRefExpr* DR, NodeTy* Pred, NodeSet& Dst, - bool asLValue); + void VisitObjCIvarRefExpr(ObjCIvarRefExpr* DR, ExplodedNode* Pred, ExplodedNodeSet& 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); - + void VisitObjCForCollectionStmt(ObjCForCollectionStmt* S, ExplodedNode* Pred, + ExplodedNodeSet& Dst); + + void VisitObjCForCollectionStmtAux(ObjCForCollectionStmt* S, ExplodedNode* Pred, + ExplodedNodeSet& Dst, SVal ElementV); + /// VisitObjCMessageExpr - Transfer function for ObjC message expressions. - void VisitObjCMessageExpr(ObjCMessageExpr* ME, NodeTy* Pred, NodeSet& Dst); - + void VisitObjCMessageExpr(ObjCMessageExpr* ME, ExplodedNode* Pred, ExplodedNodeSet& 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); - + ExplodedNode* Pred, ExplodedNodeSet& Dst); + + void VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME, ExplodedNode* Pred, + ExplodedNodeSet& Dst); + /// VisitReturnStmt - Transfer function logic for return statements. - void VisitReturnStmt(ReturnStmt* R, NodeTy* Pred, NodeSet& Dst); - + void VisitReturnStmt(ReturnStmt* R, ExplodedNode* Pred, ExplodedNodeSet& Dst); + /// VisitSizeOfAlignOfExpr - Transfer function for sizeof. - void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr* Ex, NodeTy* Pred, - NodeSet& Dst); - + void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr* Ex, ExplodedNode* Pred, + ExplodedNodeSet& Dst); + /// VisitUnaryOperator - Transfer function logic for unary operators. - void VisitUnaryOperator(UnaryOperator* B, NodeTy* Pred, NodeSet& Dst, + void VisitUnaryOperator(UnaryOperator* B, ExplodedNode* Pred, ExplodedNodeSet& Dst, bool asLValue); - - const GRState* CheckDivideZero(Expr* Ex, const GRState* St, NodeTy* Pred, - SVal Denom); - + + const GRState* CheckDivideZero(Expr* Ex, const GRState* St, ExplodedNode* 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 SVator->EvalCast(cast<Loc>(X), CastT); - else - return SVator->EvalCast(cast<NonLoc>(X), CastT); - } - + void EvalEagerlyAssume(ExplodedNodeSet& Dst, ExplodedNodeSet& Src, Expr *Ex); + SVal EvalMinus(SVal X) { - return X.isValid() ? SVator->EvalMinus(cast<NonLoc>(X)) : X; + return X.isValid() ? SVator.EvalMinus(cast<NonLoc>(X)) : X; } - + SVal EvalComplement(SVal X) { - return X.isValid() ? SVator->EvalComplement(cast<NonLoc>(X)) : X; + return X.isValid() ? SVator.EvalComplement(cast<NonLoc>(X)) : X; } - + + bool EvalBuiltinFunction(const FunctionDecl *FD, CallExpr *CE, + ExplodedNode *Pred, ExplodedNodeSet &Dst); + public: - - SVal EvalBinOp(BinaryOperator::Opcode op, NonLoc L, NonLoc R, QualType T) { - return SVator->EvalBinOpNN(op, L, R, T); - } - SVal EvalBinOp(BinaryOperator::Opcode op, NonLoc L, SVal R, QualType T) { - return R.isValid() ? SVator->EvalBinOpNN(op, L, cast<NonLoc>(R), T) : R; + SVal EvalBinOp(const GRState *state, BinaryOperator::Opcode op, + NonLoc L, NonLoc R, QualType T) { + return SVator.EvalBinOpNN(state, op, L, R, T); } - + SVal EvalBinOp(const GRState *state, BinaryOperator::Opcode op, - SVal lhs, SVal rhs, QualType T); + NonLoc L, SVal R, QualType T) { + return R.isValid() ? SVator.EvalBinOpNN(state, op, L, cast<NonLoc>(R), T) : R; + } -protected: - - void EvalCall(NodeSet& Dst, CallExpr* CE, SVal L, NodeTy* Pred); + SVal EvalBinOp(const GRState *ST, BinaryOperator::Opcode Op, + SVal LHS, SVal RHS, QualType T) { + return SVator.EvalBinOp(ST, Op, LHS, RHS, T); + } - void EvalObjCMessageExpr(NodeSet& Dst, ObjCMessageExpr* ME, NodeTy* Pred) { +protected: + void EvalCall(ExplodedNodeSet& Dst, CallExpr* CE, SVal L, ExplodedNode* Pred); + + void EvalObjCMessageExpr(ExplodedNodeSet& Dst, ObjCMessageExpr* ME, ExplodedNode* 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, + void EvalReturn(ExplodedNodeSet& Dst, ReturnStmt* s, ExplodedNode* 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, + void EvalBind(ExplodedNodeSet& Dst, Expr* Ex, ExplodedNode* Pred, const GRState* St, SVal location, SVal Val); - + public: - void EvalLoad(NodeSet& Dst, Expr* Ex, NodeTy* Pred, + void EvalLoad(ExplodedNodeSet& Dst, Expr* Ex, ExplodedNode* Pred, const GRState* St, SVal location, const void *tag = 0); - - NodeTy* EvalLocation(Stmt* Ex, NodeTy* Pred, + + ExplodedNode* EvalLocation(Stmt* Ex, ExplodedNode* Pred, const GRState* St, SVal location, const void *tag = 0); - - void EvalStore(NodeSet& Dst, Expr* E, NodeTy* Pred, const GRState* St, + + void EvalStore(ExplodedNodeSet& Dst, Expr* E, ExplodedNode* Pred, const GRState* St, SVal TargetLV, SVal Val, const void *tag = 0); - - void EvalStore(NodeSet& Dst, Expr* E, Expr* StoreE, NodeTy* Pred, + + void EvalStore(ExplodedNodeSet& Dst, Expr* E, Expr* StoreE, ExplodedNode* 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 index 0f3a1372a0f0..60db406cd13d 100644 --- a/include/clang/Analysis/PathSensitive/GRExprEngineBuilders.h +++ b/include/clang/Analysis/PathSensitive/GRExprEngineBuilders.h @@ -15,38 +15,15 @@ #ifndef LLVM_CLANG_ANALYSIS_GREXPRENGINE_BUILDERS #define LLVM_CLANG_ANALYSIS_GREXPRENGINE_BUILDERS #include "clang/Analysis/PathSensitive/GRExprEngine.h" +#include "clang/Analysis/Support/SaveAndRestore.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; + ExplodedNodeSet &Dst; + GRStmtNodeBuilder &B; GRExprEngine& Eng; - GRExprEngine::NodeTy* Pred; + ExplodedNode* Pred; const GRState* state; const Stmt* stmt; const unsigned OldSize; @@ -57,25 +34,25 @@ class GRStmtNodeBuilderRef { private: friend class GRExprEngine; - + GRStmtNodeBuilderRef(); // do not implement void operator=(const GRStmtNodeBuilderRef&); // do not implement - - GRStmtNodeBuilderRef(GRExprEngine::NodeSet &dst, - GRExprEngine::StmtNodeBuilder &builder, + + GRStmtNodeBuilderRef(ExplodedNodeSet &dst, + GRStmtNodeBuilder &builder, GRExprEngine& eng, - GRExprEngine::NodeTy* pred, + ExplodedNode* 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. + // 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); @@ -85,14 +62,14 @@ public: } const GRState *getState() { return state; } - + GRStateManager& getStateManager() { return Eng.getStateManager(); } - - GRExprEngine::NodeTy* MakeNode(const GRState* state) { - return B.MakeNode(Dst, const_cast<Stmt*>(stmt), Pred, state); - } + + ExplodedNode* MakeNode(const GRState* state) { + return B.MakeNode(Dst, const_cast<Stmt*>(stmt), Pred, state); + } }; } // end clang namespace diff --git a/include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h b/include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h index e54b31dfe883..978ff0889e64 100644 --- a/include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h +++ b/include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h @@ -20,16 +20,16 @@ #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> { +class ExplodedGraph; + + +class GRSimpleAPICheck : public GRAuditor { public: GRSimpleAPICheck() {} virtual ~GRSimpleAPICheck() {} diff --git a/include/clang/Analysis/PathSensitive/GRState.h b/include/clang/Analysis/PathSensitive/GRState.h index 0da8f5243e9c..d8b9d560ccd8 100644 --- a/include/clang/Analysis/PathSensitive/GRState.h +++ b/include/clang/Analysis/PathSensitive/GRState.h @@ -49,12 +49,12 @@ 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* 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; @@ -66,68 +66,78 @@ template <typename T> struct GRStateTrait { //===----------------------------------------------------------------------===// class GRStateManager; - + /// 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. +public: typedef llvm::ImmutableSet<llvm::APSInt*> IntSetTy; - typedef llvm::ImmutableMap<void*, void*> GenericDataMap; - - typedef GRStateManager ManagerTy; - + typedef llvm::ImmutableMap<void*, void*> GenericDataMap; + private: void operator=(const GRState& R) const; - + friend class GRStateManager; - GRStateManager *Mgr; + GRStateManager *StateMgr; Environment Env; Store St; // FIXME: Make these private. public: GenericDataMap GDM; - + public: - + /// This ctor is used when creating the first GRState object. - GRState(GRStateManager *mgr, const Environment& env, Store st, - GenericDataMap gdm) - : Mgr(mgr), + GRState(GRStateManager *mgr, const Environment& env, + Store st, GenericDataMap gdm) + : StateMgr(mgr), 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(), - Mgr(RHS.Mgr), + StateMgr(RHS.StateMgr), Env(RHS.Env), St(RHS.St), GDM(RHS.GDM) {} - + /// getStateManager - Return the GRStateManager associated with this state. - GRStateManager &getStateManager() const { return *Mgr; } - + GRStateManager &getStateManager() const { + return *StateMgr; + } + + /// getAnalysisContext - Return the AnalysisContext associated with this + /// state. + AnalysisContext &getAnalysisContext() const { + return Env.getAnalysisContext(); + } + /// 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; } - + + void setStore(Store s) { St = s; } + /// getGDM - Return the generic data map associated with this state. GenericDataMap getGDM() const { return GDM; } - + + void setGDM(GenericDataMap gdm) { GDM = gdm; } + /// Profile - Profile the contents of a GRState object for use /// in a FoldingSet. static void Profile(llvm::FoldingSetNodeID& ID, const GRState* V) { + // FIXME: Do we need to include the AnalysisContext in the profile? V->Env.Profile(ID); ID.AddPointer(V->St); V->GDM.Profile(ID); @@ -138,28 +148,19 @@ public: void Profile(llvm::FoldingSetNodeID& ID) const { Profile(ID, this); } - + SVal LookupExpr(Expr* E) const { return Env.LookupExpr(E); } - + /// makeWithStore - Return a GRState with the same values as the current /// state with the exception of using the specified Store. const GRState *makeWithStore(Store store) const; - - // 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(); } - + BasicValueFactory &getBasicVals() const; SymbolManager &getSymbolManager() const; GRTransferFuncs &getTransferFuncs() const; - + //==---------------------------------------------------------------------==// // Constraints on values. //==---------------------------------------------------------------------==// @@ -192,91 +193,85 @@ public: // FIXME: (a) should probably disappear since it is redundant with (b). // (i.e., (b) could just be set to NULL). // - - const GRState *assume(SVal condition, bool assumption) const; - - const GRState *assumeInBound(SVal idx, SVal upperBound, + + const GRState *Assume(DefinedOrUnknownSVal cond, bool assumption) const; + + const GRState *AssumeInBound(DefinedOrUnknownSVal idx, + DefinedOrUnknownSVal upperBound, bool assumption) const; - + //==---------------------------------------------------------------------==// // Utility methods for getting regions. //==---------------------------------------------------------------------==// - const VarRegion* getRegion(const VarDecl* D) const; - - const MemRegion* getSelfRegion() const; + const VarRegion* getRegion(const VarDecl *D, const LocationContext *LC) const; //==---------------------------------------------------------------------==// // Binding and retrieving values to/from the environment and symbolic store. //==---------------------------------------------------------------------==// - + /// 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 CompoundLiteralExpr* CL, SVal V) const; - - const GRState *bindExpr(const Stmt* Ex, SVal V, bool isBlkExpr, - bool Invalidate) const; - - const GRState *bindExpr(const Stmt* Ex, SVal V, bool Invalidate = true) const; - - const GRState *bindBlkExpr(const Stmt *Ex, SVal V) const { - return bindExpr(Ex, V, true, false); - } - - const GRState *bindDecl(const VarDecl* VD, SVal IVal) const; - - const GRState *bindDeclWithNoInit(const VarDecl* VD) const; - + + const GRState *BindExpr(const Stmt *S, SVal V, bool Invalidate = true) const; + + const GRState *bindDecl(const VarDecl *VD, const LocationContext *LC, + SVal V) const; + + const GRState *bindDeclWithNoInit(const VarDecl *VD, + const LocationContext *LC) const; + const GRState *bindLoc(Loc location, SVal V) const; - + const GRState *bindLoc(SVal location, SVal V) const; - + const GRState *unbindLoc(Loc LV) const; /// Get the lvalue for a variable reference. - SVal getLValue(const VarDecl *decl) const; - + SVal getLValue(const VarDecl *D, const LocationContext *LC) const; + /// Get the lvalue for a StringLiteral. SVal getLValue(const StringLiteral *literal) const; - + SVal getLValue(const CompoundLiteralExpr *literal) const; - + /// Get the lvalue for an ivar reference. SVal getLValue(const ObjCIvarDecl *decl, SVal base) const; - + /// Get the lvalue for a field reference. - SVal getLValue(SVal Base, const FieldDecl *decl) const; - + SVal getLValue(const FieldDecl *decl, SVal Base) const; + /// Get the lvalue for an array index. - SVal getLValue(QualType ElementType, SVal Base, SVal Idx) const; - + SVal getLValue(QualType ElementType, SVal Idx, SVal Base) const; + const llvm::APSInt *getSymVal(SymbolRef sym) const; SVal getSVal(const Stmt* Ex) const; - - SVal getBlkExprSVal(const Stmt* Ex) const; - + SVal getSValAsScalarOrLoc(const Stmt *Ex) const; - + SVal getSVal(Loc LV, QualType T = QualType()) const; - + SVal getSVal(const MemRegion* R) const; - + SVal getSValAsScalarOrLoc(const MemRegion *R) const; + const llvm::APSInt *getSymVal(SymbolRef sym); + bool scanReachableSymbols(SVal val, SymbolVisitor& visitor) const; template <typename CB> CB scanReachableSymbols(SVal val) const; - + //==---------------------------------------------------------------------==// // Accessing the Generic Data Map (GDM). //==---------------------------------------------------------------------==// void* const* FindGDM(void* K) const; - + template<typename T> const GRState *add(typename GRStateTrait<T>::key_type K) const; @@ -285,31 +280,31 @@ public: 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> typename GRStateTrait<T>::context_type get_context() const; - - + + template<typename T> const GRState *remove(typename GRStateTrait<T>::key_type K) const; template<typename T> const GRState *remove(typename GRStateTrait<T>::key_type K, typename GRStateTrait<T>::context_type C) const; - + template<typename T> const GRState *set(typename GRStateTrait<T>::data_type D) const; - + template<typename T> const GRState *set(typename GRStateTrait<T>::key_type K, - typename GRStateTrait<T>::value_type E) const; + typename GRStateTrait<T>::value_type E) const; template<typename T> const GRState *set(typename GRStateTrait<T>::key_type K, @@ -321,7 +316,7 @@ public: void* const* d = FindGDM(GRStateTrait<T>::GDMIndex()); return GRStateTrait<T>::Contains(GRStateTrait<T>::MakeData(d), key); } - + // State pretty-printing. class Printer { public: @@ -329,66 +324,55 @@ public: virtual void Print(llvm::raw_ostream& Out, const GRState* state, const char* nl, const char* sep) = 0; }; - + // Pretty-printing. void print(llvm::raw_ostream& Out, const char *nl = "\n", - const char *sep = "") const; + const char *sep = "") const; + + void printStdErr() const; + + void printDOT(llvm::raw_ostream& Out) const; - void printStdErr() const; - - void printDOT(llvm::raw_ostream& Out) 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; + 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) + 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. //===----------------------------------------------------------------------===// @@ -396,22 +380,21 @@ public: class GRStateManager { friend class GRExprEngine; friend class GRState; - + 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; @@ -421,52 +404,36 @@ private: /// 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; - 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)); + llvm::BumpPtrAllocator& alloc) + : EnvMgr(alloc), + GDMFactory(alloc), + ValueMgr(alloc, Ctx, *this), + Alloc(alloc) { + StoreMgr.reset((*CreateStoreManager)(*this)); + ConstraintMgr.reset((*CreateConstraintManager)(*this)); } - + ~GRStateManager(); - const GRState *getInitialState(); - + const GRState *getInitialState(const LocationContext *InitLoc); + ASTContext &getContext() { return ValueMgr.getContext(); } - const ASTContext &getContext() const { return ValueMgr.getContext(); } - - const Decl &getCodeDecl() { return codedecl; } + const ASTContext &getContext() const { return ValueMgr.getContext(); } + GRTransferFuncs& getTransferFuncs() { return *TF; } BasicValueFactory &getBasicVals() { @@ -475,18 +442,17 @@ public: 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() { @@ -495,28 +461,22 @@ public: const MemRegionManager& getRegionManager() const { return ValueMgr.getRegionManager(); } - + StoreManager& getStoreManager() { return *StoreMgr; } ConstraintManager& getConstraintManager() { return *ConstraintMgr; } - const GRState* RemoveDeadBindings(const GRState* St, Stmt* Loc, + 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); - } - public: 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 & manipulate the Store. void iterBindings(const GRState* state, StoreManager::BindingsHandler& F) { @@ -525,9 +485,9 @@ public: const GRState* getPersistentState(GRState& Impl); - bool isEqual(const GRState* state, Expr* Ex, const llvm::APSInt& V); - bool isEqual(const GRState* state, Expr* Ex, uint64_t); - + bool isEqual(const GRState* state, const Expr* Ex, const llvm::APSInt& V); + bool isEqual(const GRState* state, const Expr* Ex, uint64_t); + //==---------------------------------------------------------------------==// // Generic Data Map methods. //==---------------------------------------------------------------------==// @@ -545,21 +505,21 @@ public: // 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. + + // 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(), + + return addGDM(st, GRStateTrait<T>::GDMIndex(), GRStateTrait<T>::MakeVoidPtr(GRStateTrait<T>::Set(st->get<T>(), K, V, C))); } @@ -575,22 +535,22 @@ public: const GRState* remove(const GRState* st, typename GRStateTrait<T>::key_type K, typename GRStateTrait<T>::context_type C) { - - return addGDM(st, GRStateTrait<T>::GDMIndex(), + + 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); } @@ -602,84 +562,96 @@ public: ConstraintMgr->EndPath(St); } }; - + //===----------------------------------------------------------------------===// // Out-of-line method definitions for GRState. //===----------------------------------------------------------------------===// -inline const VarRegion* GRState::getRegion(const VarDecl* D) const { - return Mgr->getRegionManager().getVarRegion(D); +inline const llvm::APSInt *GRState::getSymVal(SymbolRef sym) { + return getStateManager().getSymVal(this, sym); } - -inline const MemRegion* GRState::getSelfRegion() const { - return Mgr->StoreMgr->getSelfRegion(getStore()); + +inline const VarRegion* GRState::getRegion(const VarDecl *D, + const LocationContext *LC) const { + return getStateManager().getRegionManager().getVarRegion(D, LC); } + +inline const GRState *GRState::Assume(DefinedOrUnknownSVal Cond, + bool Assumption) const { + if (Cond.isUnknown()) + return this; -inline const GRState *GRState::assume(SVal Cond, bool Assumption) const { - return Mgr->ConstraintMgr->Assume(this, Cond, Assumption); + return getStateManager().ConstraintMgr->Assume(this, cast<DefinedSVal>(Cond), + Assumption); } -inline const GRState *GRState::assumeInBound(SVal Idx, SVal UpperBound, +inline const GRState *GRState::AssumeInBound(DefinedOrUnknownSVal Idx, + DefinedOrUnknownSVal UpperBound, bool Assumption) const { - return Mgr->ConstraintMgr->AssumeInBound(this, Idx, UpperBound, Assumption); -} + if (Idx.isUnknown() || UpperBound.isUnknown()) + return this; + + ConstraintManager &CM = *getStateManager().ConstraintMgr; + return CM.AssumeInBound(this, cast<DefinedSVal>(Idx), + cast<DefinedSVal>(UpperBound), Assumption); +} inline const GRState *GRState::bindCompoundLiteral(const CompoundLiteralExpr* CL, SVal V) const { - return Mgr->StoreMgr->BindCompoundLiteral(this, CL, V); + return getStateManager().StoreMgr->BindCompoundLiteral(this, CL, V); } - -inline const GRState *GRState::bindDecl(const VarDecl* VD, SVal IVal) const { - return Mgr->StoreMgr->BindDecl(this, VD, IVal); + +inline const GRState *GRState::bindDecl(const VarDecl* VD, + const LocationContext *LC, + SVal IVal) const { + return getStateManager().StoreMgr->BindDecl(this, VD, LC, IVal); } -inline const GRState *GRState::bindDeclWithNoInit(const VarDecl* VD) const { - return Mgr->StoreMgr->BindDeclWithNoInit(this, VD); +inline const GRState *GRState::bindDeclWithNoInit(const VarDecl* VD, + const LocationContext *LC) const { + return getStateManager().StoreMgr->BindDeclWithNoInit(this, VD, LC); } - + inline const GRState *GRState::bindLoc(Loc LV, SVal V) const { - return Mgr->StoreMgr->Bind(this, LV, V); + return getStateManager().StoreMgr->Bind(this, LV, V); } inline const GRState *GRState::bindLoc(SVal LV, SVal V) const { return !isa<Loc>(LV) ? this : bindLoc(cast<Loc>(LV), V); } - -inline SVal GRState::getLValue(const VarDecl* VD) const { - return Mgr->StoreMgr->getLValueVar(this, VD); + +inline SVal GRState::getLValue(const VarDecl* VD, + const LocationContext *LC) const { + return getStateManager().StoreMgr->getLValueVar(VD, LC); } inline SVal GRState::getLValue(const StringLiteral *literal) const { - return Mgr->StoreMgr->getLValueString(this, literal); + return getStateManager().StoreMgr->getLValueString(literal); } - + inline SVal GRState::getLValue(const CompoundLiteralExpr *literal) const { - return Mgr->StoreMgr->getLValueCompoundLiteral(this, literal); + return getStateManager().StoreMgr->getLValueCompoundLiteral(literal); } inline SVal GRState::getLValue(const ObjCIvarDecl *D, SVal Base) const { - return Mgr->StoreMgr->getLValueIvar(this, D, Base); + return getStateManager().StoreMgr->getLValueIvar(D, Base); } - -inline SVal GRState::getLValue(SVal Base, const FieldDecl* D) const { - return Mgr->StoreMgr->getLValueField(this, Base, D); + +inline SVal GRState::getLValue(const FieldDecl* D, SVal Base) const { + return getStateManager().StoreMgr->getLValueField(D, Base); } - -inline SVal GRState::getLValue(QualType ElementType, SVal Base, SVal Idx) const{ - return Mgr->StoreMgr->getLValueElement(this, ElementType, Base, Idx); + +inline SVal GRState::getLValue(QualType ElementType, SVal Idx, SVal Base) const{ + return getStateManager().StoreMgr->getLValueElement(ElementType, Idx, Base); } - + inline const llvm::APSInt *GRState::getSymVal(SymbolRef sym) const { - return Mgr->getSymVal(this, sym); -} - -inline SVal GRState::getSVal(const Stmt* Ex) const { - return Env.GetSVal(Ex, Mgr->ValueMgr); + return getStateManager().getSymVal(this, sym); } -inline SVal GRState::getBlkExprSVal(const Stmt* Ex) const { - return Env.GetBlkExprSVal(Ex, Mgr->ValueMgr); +inline SVal GRState::getSVal(const Stmt* Ex) const { + return Env.GetSVal(Ex, getStateManager().ValueMgr); } inline SVal GRState::getSValAsScalarOrLoc(const Stmt *S) const { @@ -688,69 +660,69 @@ inline SVal GRState::getSValAsScalarOrLoc(const Stmt *S) const { if (Loc::IsLocType(T) || T->isIntegerType()) return getSVal(S); } - + return UnknownVal(); } inline SVal GRState::getSVal(Loc LV, QualType T) const { - return Mgr->StoreMgr->Retrieve(this, LV, T); + return getStateManager().StoreMgr->Retrieve(this, LV, T).getSVal(); } inline SVal GRState::getSVal(const MemRegion* R) const { - return Mgr->StoreMgr->Retrieve(this, loc::MemRegionVal(R)); + return getStateManager().StoreMgr->Retrieve(this, loc::MemRegionVal(R)).getSVal(); } - + inline BasicValueFactory &GRState::getBasicVals() const { - return Mgr->getBasicVals(); + return getStateManager().getBasicVals(); } inline SymbolManager &GRState::getSymbolManager() const { - return Mgr->getSymbolManager(); + return getStateManager().getSymbolManager(); } - + inline GRTransferFuncs &GRState::getTransferFuncs() const { - return Mgr->getTransferFuncs(); + return getStateManager().getTransferFuncs(); } template<typename T> const GRState *GRState::add(typename GRStateTrait<T>::key_type K) const { - return Mgr->add<T>(this, K, get_context<T>()); + return getStateManager().add<T>(this, K, get_context<T>()); } - + template <typename T> typename GRStateTrait<T>::context_type GRState::get_context() const { - return Mgr->get_context<T>(); + return getStateManager().get_context<T>(); } - + template<typename T> const GRState *GRState::remove(typename GRStateTrait<T>::key_type K) const { - return Mgr->remove<T>(this, K, get_context<T>()); + return getStateManager().remove<T>(this, K, get_context<T>()); } template<typename T> const GRState *GRState::remove(typename GRStateTrait<T>::key_type K, typename GRStateTrait<T>::context_type C) const { - return Mgr->remove<T>(this, K, C); + return getStateManager().remove<T>(this, K, C); } - + template<typename T> const GRState *GRState::set(typename GRStateTrait<T>::data_type D) const { - return Mgr->set<T>(this, D); + return getStateManager().set<T>(this, D); } - + template<typename T> const GRState *GRState::set(typename GRStateTrait<T>::key_type K, typename GRStateTrait<T>::value_type E) const { - return Mgr->set<T>(this, K, E, get_context<T>()); + return getStateManager().set<T>(this, K, E, get_context<T>()); } - + template<typename T> const GRState *GRState::set(typename GRStateTrait<T>::key_type K, typename GRStateTrait<T>::value_type E, typename GRStateTrait<T>::context_type C) const { - return Mgr->set<T>(this, K, E, C); + return getStateManager().set<T>(this, K, E, C); } - + template <typename CB> CB GRState::scanReachableSymbols(SVal val) const { CB cb(this); diff --git a/include/clang/Analysis/PathSensitive/GRStateTrait.h b/include/clang/Analysis/PathSensitive/GRStateTrait.h index ce43cda31e9e..5189a1f5aa7e 100644 --- a/include/clang/Analysis/PathSensitive/GRStateTrait.h +++ b/include/clang/Analysis/PathSensitive/GRStateTrait.h @@ -1,5 +1,5 @@ //==- GRStateTrait.h - Partial implementations of GRStateTrait -----*- C++ -*-// -// +// // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source @@ -27,59 +27,59 @@ namespace llvm { 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 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); + 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 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(); @@ -88,60 +88,60 @@ namespace clang { 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); + 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; - + 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) + 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); + return new typename data_type::Factory(Alloc); } - + static void DeleteContext(void* Ctx) { delete (typename data_type::Factory*) Ctx; - } + } }; } // end clang namespace diff --git a/include/clang/Analysis/PathSensitive/GRSubEngine.h b/include/clang/Analysis/PathSensitive/GRSubEngine.h new file mode 100644 index 000000000000..62e36f9e641e --- /dev/null +++ b/include/clang/Analysis/PathSensitive/GRSubEngine.h @@ -0,0 +1,68 @@ +//== GRSubEngine.h - Interface of the subengine of 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 the interface of a subengine of the GRCoreEngine. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_ANALYSIS_GRSUBENGINE_H +#define LLVM_CLANG_ANALYSIS_GRSUBENGINE_H + +namespace clang { + +class Stmt; +class CFGBlock; +class GRState; +class GRStateManager; +class GRBlockCounter; +class GRStmtNodeBuilder; +class GRBranchNodeBuilder; +class GRIndirectGotoNodeBuilder; +class GRSwitchNodeBuilder; +class GREndPathNodeBuilder; +class LocationContext; + +class GRSubEngine { +public: + virtual ~GRSubEngine() {} + + virtual const GRState* getInitialState(const LocationContext *InitLoc) = 0; + + virtual GRStateManager& getStateManager() = 0; + + /// ProcessStmt - Called by GRCoreEngine. Used to generate new successor + /// nodes by processing the 'effects' of a block-level statement. + virtual void ProcessStmt(Stmt* S, GRStmtNodeBuilder& builder) = 0; + + /// 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. + virtual bool ProcessBlockEntrance(CFGBlock* B, const GRState* St, + GRBlockCounter BC) = 0; + + /// ProcessBranch - Called by GRCoreEngine. Used to generate successor + /// nodes by processing the 'effects' of a branch condition. + virtual void ProcessBranch(Stmt* Condition, Stmt* Term, + GRBranchNodeBuilder& builder) = 0; + + /// ProcessIndirectGoto - Called by GRCoreEngine. Used to generate successor + /// nodes by processing the 'effects' of a computed goto jump. + virtual void ProcessIndirectGoto(GRIndirectGotoNodeBuilder& builder) = 0; + + /// ProcessSwitch - Called by GRCoreEngine. Used to generate successor + /// nodes by processing the 'effects' of a switch statement. + virtual void ProcessSwitch(GRSwitchNodeBuilder& builder) = 0; + + /// ProcessEndPath - Called by GRCoreEngine. Used to generate end-of-path + /// nodes when the control reaches the end of a function. + virtual void ProcessEndPath(GREndPathNodeBuilder& builder) = 0; +}; + +} + +#endif diff --git a/include/clang/Analysis/PathSensitive/GRTransferFuncs.h b/include/clang/Analysis/PathSensitive/GRTransferFuncs.h index db23f81e2d67..5f7b2cb0e327 100644 --- a/include/clang/Analysis/PathSensitive/GRTransferFuncs.h +++ b/include/clang/Analysis/PathSensitive/GRTransferFuncs.h @@ -21,66 +21,68 @@ #include <vector> namespace clang { - + class GRExprEngine; class BugReporter; class ObjCMessageExpr; class GRStmtNodeBuilderRef; - + class GRTransferFuncs { public: GRTransferFuncs() {} virtual ~GRTransferFuncs() {} - + virtual void RegisterPrinters(std::vector<GRState::Printer*>& Printers) {} virtual void RegisterChecks(BugReporter& BR) {} - + // Calls. - - virtual void EvalCall(ExplodedNodeSet<GRState>& Dst, + + virtual void EvalCall(ExplodedNodeSet& Dst, GRExprEngine& Engine, - GRStmtNodeBuilder<GRState>& Builder, + GRStmtNodeBuilder& Builder, CallExpr* CE, SVal L, - ExplodedNode<GRState>* Pred) {} - - virtual void EvalObjCMessageExpr(ExplodedNodeSet<GRState>& Dst, + ExplodedNode* Pred) {} + + virtual void EvalObjCMessageExpr(ExplodedNodeSet& Dst, GRExprEngine& Engine, - GRStmtNodeBuilder<GRState>& Builder, + GRStmtNodeBuilder& Builder, ObjCMessageExpr* ME, - ExplodedNode<GRState>* Pred) {} - + ExplodedNode* 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, + GREndPathNodeBuilder& Builder) {} + + + virtual void EvalDeadSymbols(ExplodedNodeSet& Dst, GRExprEngine& Engine, - GRStmtNodeBuilder<GRState>& Builder, - ExplodedNode<GRState>* Pred, + GRStmtNodeBuilder& Builder, + ExplodedNode* Pred, Stmt* S, const GRState* state, SymbolReaper& SymReaper) {} - - // Return statements. - virtual void EvalReturn(ExplodedNodeSet<GRState>& Dst, + + // Return statements. + virtual void EvalReturn(ExplodedNodeSet& Dst, GRExprEngine& Engine, - GRStmtNodeBuilder<GRState>& Builder, + GRStmtNodeBuilder& Builder, ReturnStmt* S, - ExplodedNode<GRState>* Pred) {} + ExplodedNode* Pred) {} - // Assumptions. + // Assumptions. virtual const GRState* EvalAssume(const GRState *state, SVal Cond, bool Assumption) { return state; } }; - + +GRTransferFuncs *CreateCallInliner(ASTContext &ctx); + } // end clang namespace #endif diff --git a/include/clang/Analysis/PathSensitive/GRWorkList.h b/include/clang/Analysis/PathSensitive/GRWorkList.h index c76532294c1f..17b83fdf9fdc 100644 --- a/include/clang/Analysis/PathSensitive/GRWorkList.h +++ b/include/clang/Analysis/PathSensitive/GRWorkList.h @@ -1,5 +1,5 @@ //==- GRWorkList.h - Worklist class used by GRCoreEngine -----------*- C++ -*-// -// +// // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source @@ -17,31 +17,31 @@ #include "clang/Analysis/PathSensitive/GRBlockCounter.h" -namespace clang { +namespace clang { class ExplodedNodeImpl; - + class GRWorkListUnit { - ExplodedNodeImpl* Node; + ExplodedNode* Node; GRBlockCounter Counter; CFGBlock* Block; unsigned BlockIdx; - + public: - GRWorkListUnit(ExplodedNodeImpl* N, GRBlockCounter C, + GRWorkListUnit(ExplodedNode* N, GRBlockCounter C, CFGBlock* B, unsigned idx) : Node(N), Counter(C), Block(B), BlockIdx(idx) {} - - explicit GRWorkListUnit(ExplodedNodeImpl* N, GRBlockCounter C) + + explicit GRWorkListUnit(ExplodedNode* N, GRBlockCounter C) : Node(N), Counter(C), Block(NULL), BlockIdx(0) {} - - ExplodedNodeImpl* getNode() const { return Node; } + + ExplodedNode* getNode() const { return Node; } GRBlockCounter getBlockCounter() const { return Counter; } CFGBlock* getBlock() const { return Block; } unsigned getIndex() const { return BlockIdx; } @@ -52,25 +52,25 @@ class GRWorkList { public: virtual ~GRWorkList(); virtual bool hasWork() const = 0; - + virtual void Enqueue(const GRWorkListUnit& U) = 0; - void Enqueue(ExplodedNodeImpl* N, CFGBlock& B, unsigned idx) { + void Enqueue(ExplodedNode* N, CFGBlock& B, unsigned idx) { Enqueue(GRWorkListUnit(N, CurrentCounter, &B, idx)); } - - void Enqueue(ExplodedNodeImpl* N) { + + void Enqueue(ExplodedNode* 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 +} // end clang namespace #endif diff --git a/include/clang/Analysis/PathSensitive/MemRegion.h b/include/clang/Analysis/PathSensitive/MemRegion.h index 5926229e517c..0e487691a891 100644 --- a/include/clang/Analysis/PathSensitive/MemRegion.h +++ b/include/clang/Analysis/PathSensitive/MemRegion.h @@ -31,10 +31,15 @@ namespace llvm { class raw_ostream; } namespace clang { - + class MemRegionManager; -class MemSpaceRegion; - +class MemSpaceRegion; +class LocationContext; + +//===----------------------------------------------------------------------===// +// Base region classes. +//===----------------------------------------------------------------------===// + /// MemRegion - The root abstract class for all memory regions. class MemRegion : public llvm::FoldingSetNode { public: @@ -46,55 +51,57 @@ public: CodeTextRegionKind, CompoundLiteralRegionKind, StringRegionKind, ElementRegionKind, - TypedViewRegionKind, // Decl Regions. BEG_DECL_REGIONS, VarRegionKind, FieldRegionKind, ObjCIvarRegionKind, ObjCObjectRegionKind, END_DECL_REGIONS, - END_TYPED_REGIONS }; + END_TYPED_REGIONS }; private: const Kind kind; - + protected: MemRegion(Kind k) : kind(k) {} virtual ~MemRegion(); - ASTContext &getContext() const; public: + ASTContext &getContext() const; + virtual void Profile(llvm::FoldingSetNodeID& ID) const = 0; virtual MemRegionManager* getMemRegionManager() const = 0; std::string getString() const; - + const MemSpaceRegion *getMemorySpace() const; - + + const MemRegion *getBaseRegion() const; + bool hasStackStorage() const; - + bool hasParametersStorage() const; - + bool hasGlobalsStorage() const; - + bool hasGlobalsOrParametersStorage() const; - + bool hasHeapStorage() const; - + bool hasHeapOrStackStorage() const; - virtual void print(llvm::raw_ostream& os) const; + virtual void dumpToStream(llvm::raw_ostream& os) const; + + void dump() const; + + Kind getKind() const { return kind; } - void printStdErr() const; - - Kind getKind() const { return kind; } - template<typename RegionTy> const RegionTy* getAs() const; - + virtual bool isBoundable() const { return false; } 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 { @@ -105,7 +112,7 @@ protected: MemSpaceRegion(MemRegionManager *mgr) : MemRegion(MemSpaceRegionKind), Mgr(mgr) {} - + MemRegionManager* getMemRegionManager() const { return Mgr; } @@ -124,13 +131,13 @@ public: /// are subclasses of SubRegion. class SubRegion : public MemRegion { protected: - const MemRegion* superRegion; + const MemRegion* superRegion; SubRegion(const MemRegion* sReg, Kind k) : MemRegion(k), superRegion(sReg) {} public: const MemRegion* getSuperRegion() const { return superRegion; } - + MemRegionManager* getMemRegionManager() const; bool isSubRegionOf(const MemRegion* R) const; @@ -140,6 +147,32 @@ public: } }; +//===----------------------------------------------------------------------===// +// Auxillary data classes for use with MemRegions. +//===----------------------------------------------------------------------===// + +class ElementRegion; + +class RegionRawOffset : public std::pair<const MemRegion*, int64_t> { +private: + friend class ElementRegion; + + RegionRawOffset(const MemRegion* reg, int64_t offset = 0) + : std::pair<const MemRegion*, int64_t>(reg, offset) {} + +public: + // FIXME: Eventually support symbolic offsets. + int64_t getByteOffset() const { return second; } + const MemRegion *getRegion() const { return first; } + + void dumpToStream(llvm::raw_ostream& os) const; + void dump() const; +}; + +//===----------------------------------------------------------------------===// +// MemRegion subclasses. +//===----------------------------------------------------------------------===// + /// AllocaRegion - A region that represents an untyped blob of bytes created /// by a call to 'alloca'. class AllocaRegion : public SubRegion { @@ -151,43 +184,45 @@ protected: AllocaRegion(const Expr* ex, unsigned cnt, const MemRegion *superRegion) : SubRegion(superRegion, AllocaRegionKind), Cnt(cnt), Ex(ex) {} - + public: - + const Expr* getExpr() const { return Ex; } - + + bool isBoundable() const { return true; } + void Profile(llvm::FoldingSetNodeID& ID) const; static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Expr* Ex, unsigned Cnt, const MemRegion *superRegion); - - void print(llvm::raw_ostream& os) const; - + + void dumpToStream(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; + return T.getTypePtr() ? T.getDesugaredType() : T; } - + QualType getDesugaredLocationType(ASTContext& C) const { - return getLocationType(C)->getDesugaredType(); + return getLocationType(C).getDesugaredType(); } bool isBoundable() const { @@ -205,32 +240,12 @@ public: /// 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; + const FunctionDecl *FD; 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) {} + CodeTextRegion(const FunctionDecl* fd, const MemRegion* sreg) + : TypedRegion(sreg, CodeTextRegionKind), FD(fd) {} QualType getValueType(ASTContext &C) const { // Do not get the object type of a CodeTextRegion. @@ -239,30 +254,21 @@ public: } QualType getLocationType(ASTContext &C) const { - return LocationType; + return C.getPointerType(FD->getType()); } - 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); + const FunctionDecl *getDecl() const { + return FD; } - - SymbolRef getSymbol() const { - assert(codekind == Symbolic); - return const_cast<SymbolRef>(static_cast<const SymbolRef>(Data)); - } - + bool isBoundable() const { return false; } - - virtual void print(llvm::raw_ostream& os) const; + + virtual void dumpToStream(llvm::raw_ostream& os) const; void Profile(llvm::FoldingSetNodeID& ID) const; - static void ProfileRegion(llvm::FoldingSetNodeID& ID, - const void* data, QualType t, const MemRegion*); + static void ProfileRegion(llvm::FoldingSetNodeID& ID, const FunctionDecl *FD, + const MemRegion*); static bool classof(const MemRegion* R) { return R->getKind() == CodeTextRegionKind; @@ -279,25 +285,27 @@ protected: const SymbolRef sym; public: - SymbolicRegion(const SymbolRef s, const MemRegion* sreg) + SymbolicRegion(const SymbolRef s, const MemRegion* sreg) : SubRegion(sreg, SymbolicRegionKind), sym(s) {} - + SymbolRef getSymbol() const { return sym; } + bool isBoundable() const { return true; } + void Profile(llvm::FoldingSetNodeID& ID) const; static void ProfileRegion(llvm::FoldingSetNodeID& ID, SymbolRef sym, const MemRegion* superRegion); - - void print(llvm::raw_ostream& os) const; - + + void dumpToStream(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 { @@ -315,7 +323,7 @@ protected: public: const StringLiteral* getStringLiteral() const { return Str; } - + QualType getValueType(ASTContext& C) const { return Str->getType(); } @@ -326,53 +334,13 @@ public: ProfileRegion(ID, Str, superRegion); } - void print(llvm::raw_ostream& os) const; + void dumpToStream(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() 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. @@ -383,7 +351,7 @@ private: CompoundLiteralRegion(const CompoundLiteralExpr* cl, const MemRegion* sReg) : TypedRegion(sReg, CompoundLiteralRegionKind), CL(cl) {} - + static void ProfileRegion(llvm::FoldingSetNodeID& ID, const CompoundLiteralExpr* CL, const MemRegion* superRegion); @@ -395,11 +363,11 @@ public: bool isBoundable() const { return !CL->isFileScope(); } void Profile(llvm::FoldingSetNodeID& ID) const; - - void print(llvm::raw_ostream& os) const; + + void dumpToStream(llvm::raw_ostream& os) const; const CompoundLiteralExpr* getLiteralExpr() const { return CL; } - + static bool classof(const MemRegion* R) { return R->getKind() == CompoundLiteralRegionKind; } @@ -414,41 +382,51 @@ protected: 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) {} + + // Data. + const LocationContext *LC; + + // Constructors and private methods. + VarRegion(const VarDecl* vd, const LocationContext *lC, const MemRegion* sReg) + : DeclRegion(vd, sReg, VarRegionKind), LC(lC) {} static void ProfileRegion(llvm::FoldingSetNodeID& ID, const VarDecl* VD, - const MemRegion* superRegion) { + const LocationContext *LC, + const MemRegion *superRegion) { DeclRegion::ProfileRegion(ID, VD, superRegion, VarRegionKind); + ID.AddPointer(LC); } - -public: - const VarDecl* getDecl() const { return cast<VarDecl>(D); } - - QualType getValueType(ASTContext& C) const { + + void Profile(llvm::FoldingSetNodeID& ID) const; + +public: + const VarDecl *getDecl() const { return cast<VarDecl>(D); } + + const LocationContext *getLocationContext() const { return LC; } + + QualType getValueType(ASTContext& C) const { // FIXME: We can cache this if needed. return C.getCanonicalType(getDecl()->getType()); - } - - void print(llvm::raw_ostream& os) const; - + } + + void dumpToStream(llvm::raw_ostream& os) const; + static bool classof(const MemRegion* R) { return R->getKind() == VarRegionKind; - } + } }; class FieldRegion : public DeclRegion { @@ -458,57 +436,57 @@ class FieldRegion : public DeclRegion { : DeclRegion(fd, sReg, FieldRegionKind) {} public: - - void print(llvm::raw_ostream& os) const; - + + void dumpToStream(llvm::raw_ostream& os) const; + const FieldDecl* getDecl() const { return cast<FieldDecl>(D); } - - QualType getValueType(ASTContext& C) const { + + QualType getValueType(ASTContext& C) const { // FIXME: We can cache this if needed. return C.getCanonicalType(getDecl()->getType()); - } + } static void ProfileRegion(llvm::FoldingSetNodeID& ID, const 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, const 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) {} @@ -516,11 +494,13 @@ class ObjCIvarRegion : public DeclRegion { 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(); } - + + void dumpToStream(llvm::raw_ostream& os) const; + static bool classof(const MemRegion* R) { return R->getKind() == ObjCIvarRegionKind; } @@ -539,7 +519,7 @@ class ElementRegion : public TypedRegion { cast<nonloc::ConcreteInt>(&Idx)->getValue().isSigned()) && "The index must be signed"); } - + static void ProfileRegion(llvm::FoldingSetNodeID& ID, QualType elementType, SVal Idx, const MemRegion* superRegion); @@ -550,12 +530,14 @@ public: QualType getValueType(ASTContext&) const { return ElementType; } - + QualType getElementType() const { return ElementType; } - - void print(llvm::raw_ostream& os) const; + + RegionRawOffset getAsRawOffset() const; + + void dumpToStream(llvm::raw_ostream& os) const; void Profile(llvm::FoldingSetNodeID& ID) const; @@ -563,25 +545,13 @@ public: 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; + if (const RegionTy* RT = dyn_cast<RegionTy>(this)) + return RT; + + return NULL; } //===----------------------------------------------------------------------===// @@ -592,7 +562,7 @@ class MemRegionManager { ASTContext &C; llvm::BumpPtrAllocator& A; llvm::FoldingSet<MemRegion> Regions; - + MemSpaceRegion *globals; MemSpaceRegion *stack; MemSpaceRegion *stackArguments; @@ -604,11 +574,11 @@ public: MemRegionManager(ASTContext &c, llvm::BumpPtrAllocator& a) : C(c), A(a), globals(0), stack(0), stackArguments(0), heap(0), unknown(0), code(0) {} - + ~MemRegionManager() {} - + ASTContext &getContext() { return C; } - + /// getStackRegion - Retrieve the memory region associated with the /// current stack frame. MemSpaceRegion *getStackRegion(); @@ -616,11 +586,11 @@ public: /// getStackArgumentsRegion - Retrieve the memory region associated with /// function/method arguments of the current stack frame. MemSpaceRegion *getStackArgumentsRegion(); - + /// getGlobalsRegion - Retrieve the memory region associated with /// all global variables. MemSpaceRegion *getGlobalsRegion(); - + /// getHeapRegion - Retrieve the memory region associated with the /// generic "heap". MemSpaceRegion *getHeapRegion(); @@ -633,69 +603,77 @@ public: /// 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); - + 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); - + /// a specified VarDecl and LocationContext. + VarRegion* getVarRegion(const VarDecl *D, const LocationContext *LC); + /// getElementRegion - Retrieve the memory region associated with the /// associated element type, index, and super region. - ElementRegion* getElementRegion(QualType elementType, SVal Idx, - const MemRegion* superRegion,ASTContext &Ctx); + ElementRegion *getElementRegion(QualType elementType, SVal Idx, + const MemRegion *superRegion, + ASTContext &Ctx); + + ElementRegion *getElementRegionWithSuper(const ElementRegion *ER, + const MemRegion *superRegion) { + return getElementRegion(ER->getElementType(), ER->getIndex(), + superRegion, ER->getContext()); + } /// 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, + FieldRegion *getFieldRegion(const FieldDecl* fd, const MemRegion* superRegion); - + + FieldRegion *getFieldRegionWithSuper(const FieldRegion *FR, + const MemRegion *superRegion) { + return getFieldRegion(FR->getDecl(), 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, + ObjCIvarRegion *getObjCIvarRegion(const ObjCIvarDecl* ivd, const MemRegion* superRegion); - TypedViewRegion* getTypedViewRegion(QualType LValueType, - const MemRegion* superRegion); + CodeTextRegion *getCodeTextRegion(const FunctionDecl *FD); - CodeTextRegion* getCodeTextRegion(SymbolRef sym, QualType t); - CodeTextRegion* getCodeTextRegion(const FunctionDecl* fd, QualType t); - template <typename RegionTy, typename A1> RegionTy* getRegion(const A1 a1); - + template <typename RegionTy, typename A1> - RegionTy* getRegion(const A1 a1, const MemRegion* superRegion); - + RegionTy* getSubRegion(const A1 a1, const MemRegion* superRegion); + template <typename RegionTy, typename A1, typename A2> RegionTy* getRegion(const A1 a1, const A2 a2); - bool isGlobalsRegion(const MemRegion* R) { + bool isGlobalsRegion(const MemRegion* R) { assert(R); - return R == globals; + return R == globals; } - + private: MemSpaceRegion* LazyAllocate(MemSpaceRegion*& region); }; - + //===----------------------------------------------------------------------===// // Out-of-line member definitions. //===----------------------------------------------------------------------===// @@ -703,69 +681,69 @@ private: inline ASTContext& MemRegion::getContext() const { return getMemRegionManager()->getContext(); } - + template<typename RegionTy> struct MemRegionManagerTrait; - + template <typename RegionTy, typename A1> RegionTy* MemRegionManager::getRegion(const A1 a1) { const typename MemRegionManagerTrait<RegionTy>::SuperRegionTy *superRegion = MemRegionManagerTrait<RegionTy>::getSuperRegion(*this, a1); - - llvm::FoldingSetNodeID ID; - RegionTy::ProfileRegion(ID, a1, superRegion); + + llvm::FoldingSetNodeID ID; + RegionTy::ProfileRegion(ID, a1, superRegion); void* InsertPos; RegionTy* R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID, InsertPos)); - + if (!R) { R = (RegionTy*) A.Allocate<RegionTy>(); new (R) RegionTy(a1, superRegion); Regions.InsertNode(R, InsertPos); } - + return R; } template <typename RegionTy, typename A1> -RegionTy* MemRegionManager::getRegion(const A1 a1, const MemRegion *superRegion) -{ - llvm::FoldingSetNodeID ID; - RegionTy::ProfileRegion(ID, a1, superRegion); +RegionTy* MemRegionManager::getSubRegion(const A1 a1, + const MemRegion *superRegion) { + llvm::FoldingSetNodeID ID; + RegionTy::ProfileRegion(ID, a1, superRegion); void* InsertPos; RegionTy* R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID, InsertPos)); - + if (!R) { R = (RegionTy*) A.Allocate<RegionTy>(); new (R) RegionTy(a1, superRegion); Regions.InsertNode(R, InsertPos); } - + return R; } - + template <typename RegionTy, typename A1, typename A2> RegionTy* MemRegionManager::getRegion(const A1 a1, const A2 a2) { - + const typename MemRegionManagerTrait<RegionTy>::SuperRegionTy *superRegion = MemRegionManagerTrait<RegionTy>::getSuperRegion(*this, a1, a2); - - llvm::FoldingSetNodeID ID; - RegionTy::ProfileRegion(ID, a1, a2, superRegion); + + llvm::FoldingSetNodeID ID; + RegionTy::ProfileRegion(ID, a1, a2, superRegion); void* InsertPos; RegionTy* R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID, InsertPos)); - + if (!R) { R = (RegionTy*) A.Allocate<RegionTy>(); new (R) RegionTy(a1, a2, superRegion); Regions.InsertNode(R, InsertPos); } - + return R; } - + //===----------------------------------------------------------------------===// // Traits for constructing regions. //===----------------------------------------------------------------------===// @@ -776,18 +754,18 @@ template <> struct MemRegionManagerTrait<AllocaRegion> { const Expr *, unsigned) { return MRMgr.getStackRegion(); } -}; - +}; + template <> struct MemRegionManagerTrait<CompoundLiteralRegion> { typedef MemRegion SuperRegionTy; static const SuperRegionTy* getSuperRegion(MemRegionManager& MRMgr, const CompoundLiteralExpr *CL) { - - return CL->isFileScope() ? MRMgr.getGlobalsRegion() + + return CL->isFileScope() ? MRMgr.getGlobalsRegion() : MRMgr.getStackRegion(); } }; - + template <> struct MemRegionManagerTrait<StringRegion> { typedef MemSpaceRegion SuperRegionTy; static const SuperRegionTy* getSuperRegion(MemRegionManager& MRMgr, @@ -795,20 +773,24 @@ template <> struct MemRegionManagerTrait<StringRegion> { return MRMgr.getGlobalsRegion(); } }; - + template <> struct MemRegionManagerTrait<VarRegion> { typedef MemRegion SuperRegionTy; - static const SuperRegionTy* getSuperRegion(MemRegionManager& MRMgr, - const VarDecl *d) { - if (d->hasLocalStorage()) { - return isa<ParmVarDecl>(d) || isa<ImplicitParamDecl>(d) + static const SuperRegionTy* getSuperRegion(MemRegionManager &MRMgr, + const VarDecl *D, + const LocationContext *LC) { + + // FIXME: Make stack regions have a location context? + + if (D->hasLocalStorage()) { + return isa<ParmVarDecl>(D) || isa<ImplicitParamDecl>(D) ? MRMgr.getStackArgumentsRegion() : MRMgr.getStackRegion(); } - + return MRMgr.getGlobalsRegion(); } }; - + template <> struct MemRegionManagerTrait<SymbolicRegion> { typedef MemRegion SuperRegionTy; static const SuperRegionTy* getSuperRegion(MemRegionManager& MRMgr, @@ -820,7 +802,7 @@ template <> struct MemRegionManagerTrait<SymbolicRegion> { template<> struct MemRegionManagerTrait<CodeTextRegion> { typedef MemSpaceRegion SuperRegionTy; static const SuperRegionTy* getSuperRegion(MemRegionManager& MRMgr, - const FunctionDecl*, QualType) { + const FunctionDecl*) { return MRMgr.getCodeRegion(); } static const SuperRegionTy* getSuperRegion(MemRegionManager& MRMgr, @@ -828,7 +810,7 @@ template<> struct MemRegionManagerTrait<CodeTextRegion> { return MRMgr.getCodeRegion(); } }; - + } // end clang namespace //===----------------------------------------------------------------------===// @@ -836,10 +818,10 @@ template<> struct MemRegionManagerTrait<CodeTextRegion> { //===----------------------------------------------------------------------===// namespace llvm { -static inline raw_ostream& operator<<(raw_ostream& O, - const clang::MemRegion* R) { - R->print(O); - return O; +static inline raw_ostream& operator<<(raw_ostream& os, + const clang::MemRegion* R) { + R->dumpToStream(os); + return os; } } // end llvm namespace diff --git a/include/clang/Analysis/PathSensitive/SVals.h b/include/clang/Analysis/PathSensitive/SVals.h index 4bc5e27aacf0..4ba3c7396822 100644 --- a/include/clang/Analysis/PathSensitive/SVals.h +++ b/include/clang/Analysis/PathSensitive/SVals.h @@ -18,7 +18,11 @@ #include "clang/Analysis/PathSensitive/SymbolManager.h" #include "llvm/Support/Casting.h" #include "llvm/ADT/ImmutableList.h" - + +namespace llvm { + class raw_ostream; +} + //==------------------------------------------------------------------------==// // Base SVal types. //==------------------------------------------------------------------------==// @@ -26,40 +30,43 @@ namespace clang { class CompoundValData; +class LazyCompoundValData; +class GRState; class BasicValueFactory; class MemRegion; +class TypedRegion; class MemRegionManager; class GRStateManager; class ValueManager; - + 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)); @@ -68,7 +75,7 @@ public: inline bool operator==(const SVal& R) const { return getRawKind() == R.getRawKind() && Data == R.Data; } - + inline bool operator!=(const SVal& R) const { return !(*this == R); } @@ -84,25 +91,25 @@ public: 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. + /// CodeTextRegion wrapping a FunctionDecl, return that FunctionDecl. /// Otherwise return 0. const FunctionDecl* getAsFunctionDecl() const; - - /// getAsLocSymbol - If this SVal is a location (subclasses Loc) and + + /// 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; @@ -112,9 +119,9 @@ public: const SymExpr *getAsSymbolicExpression() const; const MemRegion *getAsRegion() const; - - void print(llvm::raw_ostream& OS) const; - void printStdErr() const; + + void dumpToStream(llvm::raw_ostream& OS) const; + void dump() const; // Iterators. class symbol_iterator { @@ -123,14 +130,14 @@ public: 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) @@ -138,97 +145,135 @@ public: 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; } + + void* getData() const { return Data; } }; -class NonLoc : public SVal { +class DefinedOrUnknownSVal : public SVal { +private: + // Do not implement. We want calling these methods to be a compiler + // error since they are tautologically false. + bool isUndef() const; + bool isValid() const; + protected: - NonLoc(unsigned SubKind, const void* d) : SVal(d, false, SubKind) {} + explicit DefinedOrUnknownSVal(const void* d, bool isLoc, unsigned ValKind) + : SVal(d, isLoc, ValKind) {} + + explicit DefinedOrUnknownSVal(BaseKind k, void *D = NULL) + : SVal(k, D) {} public: - void print(llvm::raw_ostream& Out) const; + // Implement isa<T> support. + static inline bool classof(const SVal *V) { + return !V->isUndef(); + } +}; + +class UnknownVal : public DefinedOrUnknownSVal { +public: + UnknownVal() : DefinedOrUnknownSVal(UnknownKind) {} + + static inline bool classof(const SVal *V) { + return V->getBaseKind() == UnknownKind; + } +}; +class DefinedSVal : public DefinedOrUnknownSVal { +private: + // Do not implement. We want calling these methods to be a compiler + // error since they are tautologically true/false. + bool isUnknown() const; + bool isUnknownOrUndef() const; + bool isValid() const; +protected: + DefinedSVal(const void* d, bool isLoc, unsigned ValKind) + : DefinedOrUnknownSVal(d, isLoc, ValKind) {} +public: + // Implement isa<T> support. + static inline bool classof(const SVal *V) { + return !V->isUnknownOrUndef(); + } +}; + +class NonLoc : public DefinedSVal { +protected: + NonLoc(unsigned SubKind, const void* d) : DefinedSVal(d, false, SubKind) {} + +public: + void dumpToStream(llvm::raw_ostream& Out) const; + // Implement isa<T> support. static inline bool classof(const SVal* V) { return V->getBaseKind() == NonLocKind; } }; -class Loc : public SVal { +class Loc : public DefinedSVal { protected: Loc(unsigned SubKind, const void* D) - : SVal(const_cast<void*>(D), true, SubKind) {} + : DefinedSVal(const_cast<void*>(D), true, SubKind) {} public: - void print(llvm::raw_ostream& Out) const; + void dumpToStream(llvm::raw_ostream& Out) const; - Loc(const Loc& X) : SVal(X.Data, true, X.getSubKind()) {} + Loc(const Loc& X) : DefinedSVal(X.Data, true, X.getSubKind()) {} Loc& operator=(const Loc& X) { memcpy(this, &X, sizeof(Loc)); return *this; } - + // 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(); + return T->isAnyPointerType() || T->isBlockPointerType(); } }; - + //==------------------------------------------------------------------------==// // Subclasses of NonLoc. //==------------------------------------------------------------------------==// namespace nonloc { - + enum Kind { ConcreteIntKind, SymbolValKind, SymExprValKind, - LocAsIntegerKind, CompoundValKind }; + LocAsIntegerKind, CompoundValKind, LazyCompoundValKind }; 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 && + return V->getBaseKind() == NonLocKind && V->getSubKind() == SymbolValKind; } - + static inline bool classof(const NonLoc* V) { return V->getSubKind() == SymbolValKind; } }; -class SymExprVal : public NonLoc { +class SymExprVal : public NonLoc { public: SymExprVal(const SymExpr *SE) : NonLoc(SymExprValKind, reinterpret_cast<const void*>(SE)) {} @@ -236,12 +281,12 @@ public: 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; } @@ -250,30 +295,30 @@ public: 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(ValueManager &ValMgr, BinaryOperator::Opcode Op, const ConcreteInt& R) const; - + ConcreteInt evalComplement(ValueManager &ValMgr) const; - + ConcreteInt evalMinus(ValueManager &ValMgr) 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 { friend class clang::ValueManager; @@ -281,28 +326,28 @@ class LocAsInteger : public NonLoc { 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; } @@ -317,10 +362,10 @@ public: const CompoundValData* getValue() const { return static_cast<CompoundValData*>(Data); } - + typedef llvm::ImmutableList<SVal>::iterator iterator; iterator begin() const; - iterator end() const; + iterator end() const; static bool classof(const SVal* V) { return V->getBaseKind() == NonLocKind && V->getSubKind() == CompoundValKind; @@ -330,7 +375,28 @@ public: return V->getSubKind() == CompoundValKind; } }; - + +class LazyCompoundVal : public NonLoc { + friend class clang::ValueManager; + + LazyCompoundVal(const LazyCompoundValData *D) + : NonLoc(LazyCompoundValKind, D) {} +public: + const LazyCompoundValData *getCVData() const { + return static_cast<const LazyCompoundValData*>(Data); + } + const GRState *getState() const; + const TypedRegion *getRegion() const; + + static bool classof(const SVal *V) { + return V->getBaseKind() == NonLocKind && + V->getSubKind() == LazyCompoundValKind; + } + static bool classof(const NonLoc *V) { + return V->getSubKind() == LazyCompoundValKind; + } +}; + } // end namespace clang::nonloc //==------------------------------------------------------------------------==// @@ -338,27 +404,27 @@ public: //==------------------------------------------------------------------------==// 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: @@ -367,35 +433,37 @@ public: const MemRegion* getRegion() const { return static_cast<MemRegion*>(Data); } - + + const MemRegion* getBaseRegion() const; + 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); } @@ -403,19 +471,26 @@ public: // 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 +} // end clang namespace +namespace llvm { +static inline llvm::raw_ostream& operator<<(llvm::raw_ostream& os, + clang::SVal V) { + V.dumpToStream(os); + return os; +} +} // end llvm namespace #endif diff --git a/include/clang/Analysis/PathSensitive/SValuator.h b/include/clang/Analysis/PathSensitive/SValuator.h index 490c04e5978e..e63eb12cf8ea 100644 --- a/include/clang/Analysis/PathSensitive/SValuator.h +++ b/include/clang/Analysis/PathSensitive/SValuator.h @@ -9,7 +9,7 @@ // // This file defines SValuator, a class that defines the interface for // "symbolical evaluators" which construct an SVal from an expression. -// +// //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_ANALYSIS_SVALUATOR @@ -24,32 +24,66 @@ class GRState; class ValueManager; class SValuator { + friend class ValueManager; protected: ValueManager &ValMgr; - + + virtual SVal EvalCastNL(NonLoc val, QualType castTy) = 0; + + virtual SVal EvalCastL(Loc val, QualType castTy) = 0; + public: SValuator(ValueManager &valMgr) : ValMgr(valMgr) {} virtual ~SValuator() {} + + template <typename T> + class GenericCastResult : public std::pair<const GRState *, T> { + public: + const GRState *getState() const { return this->first; } + T getSVal() const { return this->second; } + GenericCastResult(const GRState *s, T v) + : std::pair<const GRState*,T>(s, v) {} + }; - virtual SVal EvalCast(NonLoc val, QualType castTy) = 0; + class CastResult : public GenericCastResult<SVal> { + public: + CastResult(const GRState *s, SVal v) : GenericCastResult<SVal>(s, v) {} + }; + + class DefinedOrUnknownCastResult : + public GenericCastResult<DefinedOrUnknownSVal> { + public: + DefinedOrUnknownCastResult(const GRState *s, DefinedOrUnknownSVal v) + : GenericCastResult<DefinedOrUnknownSVal>(s, v) {} + }; - virtual SVal EvalCast(Loc val, QualType castTy) = 0; + CastResult EvalCast(SVal V, const GRState *ST, + QualType castTy, QualType originalType); + DefinedOrUnknownCastResult EvalCast(DefinedOrUnknownSVal V, const GRState *ST, + QualType castTy, QualType originalType); + virtual SVal EvalMinus(NonLoc val) = 0; - + virtual SVal EvalComplement(NonLoc val) = 0; - virtual SVal EvalBinOpNN(BinaryOperator::Opcode Op, NonLoc lhs, - NonLoc rhs, QualType resultTy) = 0; + virtual SVal EvalBinOpNN(const GRState *state, BinaryOperator::Opcode Op, + NonLoc lhs, NonLoc rhs, QualType resultTy) = 0; virtual SVal EvalBinOpLL(BinaryOperator::Opcode Op, Loc lhs, Loc rhs, QualType resultTy) = 0; virtual SVal EvalBinOpLN(const GRState *state, BinaryOperator::Opcode Op, - Loc lhs, NonLoc rhs, QualType resultTy) = 0; -}; + Loc lhs, NonLoc rhs, QualType resultTy) = 0; -SValuator* CreateSimpleSValuator(ValueManager &valMgr); + SVal EvalBinOp(const GRState *ST, BinaryOperator::Opcode Op, + SVal L, SVal R, QualType T); + DefinedOrUnknownSVal EvalEQ(const GRState *ST, DefinedOrUnknownSVal L, + DefinedOrUnknownSVal R); +}; + +SValuator* CreateSimpleSValuator(ValueManager &valMgr); + } // end clang namespace #endif diff --git a/include/clang/Analysis/PathSensitive/Store.h b/include/clang/Analysis/PathSensitive/Store.h index 5aa53507fd14..3ff253d0abf3 100644 --- a/include/clang/Analysis/PathSensitive/Store.h +++ b/include/clang/Analysis/PathSensitive/Store.h @@ -23,16 +23,17 @@ #include "llvm/ADT/SmallVector.h" namespace clang { - + typedef const void* Store; -class GRState; +class GRState; class GRStateManager; class Stmt; class Expr; class ObjCIvarDecl; class SubRegionMap; - +class StackFrameContext; + class StoreManager { protected: ValueManager &ValMgr; @@ -43,37 +44,30 @@ protected: StoreManager(GRStateManager &stateMgr); -protected: - virtual const GRState *AddRegionView(const GRState *state, - const MemRegion *view, - const MemRegion *base) { - return state; - } - -public: +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 + /// \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; + virtual SValuator::CastResult 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 + /// \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 @@ -81,36 +75,31 @@ public: virtual const GRState *BindCompoundLiteral(const GRState *state, 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; - + virtual Store getInitialStore(const LocationContext *InitLoc) = 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 *state, const VarDecl *vd) = 0; + virtual SVal getLValueVar(const VarDecl *VD, const LocationContext *LC) = 0; + + virtual SVal getLValueString(const StringLiteral* sl) = 0; + + virtual SVal getLValueCompoundLiteral(const CompoundLiteralExpr* cl) = 0; - virtual SVal getLValueString(const GRState *state, - const StringLiteral* sl) = 0; + virtual SVal getLValueIvar(const ObjCIvarDecl* decl, SVal base) = 0; - virtual SVal getLValueCompoundLiteral(const GRState *state, - const CompoundLiteralExpr* cl) = 0; - - virtual SVal getLValueIvar(const GRState *state, const ObjCIvarDecl* decl, - SVal base) = 0; - - virtual SVal getLValueField(const GRState *state, SVal base, - const FieldDecl* D) = 0; - - virtual SVal getLValueElement(const GRState *state, QualType elementType, - SVal base, SVal offset) = 0; + virtual SVal getLValueField(const FieldDecl* D, SVal Base) = 0; + + virtual SVal getLValueElement(QualType elementType, SVal offset, SVal Base)=0; // FIXME: Make out-of-line. virtual SVal getSizeInElements(const GRState *state, const MemRegion *region){ @@ -120,7 +109,7 @@ public: /// 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 *region; @@ -129,33 +118,32 @@ public: const MemRegion* getRegion() const { return region; } CastResult(const GRState *s, const MemRegion* r = 0) : state(s), region(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 *region, - QualType CastToTy); + const MemRegion *CastRegion(const MemRegion *region, QualType CastToTy); /// EvalBinOp - Perform pointer arithmetic. virtual SVal EvalBinOp(const GRState *state, BinaryOperator::Opcode Op, Loc lhs, NonLoc rhs, QualType resultTy) { 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, + virtual void RemoveDeadBindings(GRState &state, Stmt* Loc, + SymbolReaper& SymReaper, llvm::SmallVectorImpl<const MemRegion*>& RegionRoots) = 0; - virtual const GRState *BindDecl(const GRState *state, const VarDecl *vd, - SVal initVal) = 0; + virtual const GRState *BindDecl(const GRState *ST, const VarDecl *VD, + const LocationContext *LC, SVal initVal) = 0; + + virtual const GRState *BindDeclWithNoInit(const GRState *ST, + const VarDecl *VD, + const LocationContext *LC) = 0; - virtual const GRState *BindDeclWithNoInit(const GRState *state, - const VarDecl *vd) = 0; + virtual const GRState *InvalidateRegion(const GRState *state, + const MemRegion *R, + const Expr *E, unsigned Count) = 0; // FIXME: Make out-of-line. virtual const GRState *setExtent(const GRState *state, @@ -163,25 +151,35 @@ public: return state; } - // FIXME: Make out-of-line. - virtual const GRState *setDefaultValue(const GRState *state, - const MemRegion *region, - SVal val) { + /// EnterStackFrame - Let the StoreManager to do something when execution + /// engine is about to execute into a callee. + virtual const GRState *EnterStackFrame(const GRState *state, + const StackFrameContext *frame) { return state; } virtual void print(Store store, llvm::raw_ostream& Out, const char* nl, const char *sep) = 0; - + class BindingsHandler { - public: + public: virtual ~BindingsHandler(); virtual bool HandleBinding(StoreManager& SMgr, Store store, const MemRegion *region, SVal val) = 0; }; - + /// iterBindings - Iterate over the bindings in the Store. - virtual void iterBindings(Store store, BindingsHandler& f) = 0; + virtual void iterBindings(Store store, BindingsHandler& f) = 0; + +protected: + const MemRegion *MakeElementRegion(const MemRegion *Base, + QualType pointeeTy, uint64_t index = 0); + + /// CastRetrievedVal - Used by subclasses of StoreManager to implement + /// implicit casts that arise from loads from regions that are reinterpreted + /// as another region. + SValuator::CastResult CastRetrievedVal(SVal val, const GRState *state, + const TypedRegion *R, QualType castTy); }; // FIXME: Do we still need this? @@ -190,14 +188,14 @@ public: 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 *region, Visitor& V) const = 0; + + virtual bool iterSubRegions(const MemRegion *region, Visitor& V) const = 0; }; // FIXME: Do we need to pass GRStateManager anymore? diff --git a/include/clang/Analysis/PathSensitive/SymbolManager.h b/include/clang/Analysis/PathSensitive/SymbolManager.h index f32a7e3481dd..d3996c6330a2 100644 --- a/include/clang/Analysis/PathSensitive/SymbolManager.h +++ b/include/clang/Analysis/PathSensitive/SymbolManager.h @@ -21,66 +21,72 @@ #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" +#include "llvm/ADT/DenseSet.h" namespace llvm { class raw_ostream; } -namespace clang { +namespace clang { class MemRegion; + class TypedRegion; class ASTContext; class BasicValueFactory; } namespace clang { - + class SymExpr : public llvm::FoldingSetNode { public: - enum Kind { BEGIN_SYMBOLS, RegionValueKind, ConjuredKind, END_SYMBOLS, + enum Kind { BEGIN_SYMBOLS, + RegionValueKind, ConjuredKind, DerivedKind, + END_SYMBOLS, SymIntKind, SymSymKind }; private: Kind K; protected: - SymExpr(Kind k) : K(k) {} - + SymExpr(Kind k) : K(k) {} + public: virtual ~SymExpr() {} - - Kind getKind() const { return K; } - - virtual QualType getType(ASTContext&) const = 0; + + Kind getKind() const { return K; } + + void dump() const; + + virtual void dumpToStream(llvm::raw_ostream &os) const = 0; + + 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) {} + 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) { + 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; // We may cast the region to another type, so the expected type of the symbol @@ -90,7 +96,7 @@ class SymbolRegionValue : public SymbolData { public: SymbolRegionValue(SymbolID sym, const MemRegion *r, QualType t = QualType()) : SymbolData(RegionValueKind, sym), R(r), T(t) {} - + const MemRegion* getRegion() const { return R; } static void Profile(llvm::FoldingSetNodeID& profile, const MemRegion* R, @@ -99,11 +105,13 @@ public: profile.AddPointer(R); T.Profile(profile); } - + virtual void Profile(llvm::FoldingSetNodeID& profile) { Profile(profile, R, T); } - + + void dumpToStream(llvm::raw_ostream &os) const; + QualType getType(ASTContext&) const; // Implement isa<T> support. @@ -123,15 +131,17 @@ public: 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; - + + void dumpToStream(llvm::raw_ostream &os) const; + static void Profile(llvm::FoldingSetNodeID& profile, const Stmt* S, - QualType T, unsigned Count, const void* SymbolTag) { + QualType T, unsigned Count, const void* SymbolTag) { profile.AddInteger((unsigned) ConjuredKind); profile.AddPointer(S); profile.Add(T); @@ -146,7 +156,39 @@ public: // Implement isa<T> support. static inline bool classof(const SymExpr* SE) { return SE->getKind() == ConjuredKind; - } + } +}; + +class SymbolDerived : public SymbolData { + SymbolRef parentSymbol; + const TypedRegion *R; + +public: + SymbolDerived(SymbolID sym, SymbolRef parent, const TypedRegion *r) + : SymbolData(DerivedKind, sym), parentSymbol(parent), R(r) {} + + SymbolRef getParentSymbol() const { return parentSymbol; } + const TypedRegion *getRegion() const { return R; } + + QualType getType(ASTContext&) const; + + void dumpToStream(llvm::raw_ostream &os) const; + + static void Profile(llvm::FoldingSetNodeID& profile, SymbolRef parent, + const TypedRegion *r) { + profile.AddInteger((unsigned) DerivedKind); + profile.AddPointer(r); + profile.AddPointer(parent); + } + + virtual void Profile(llvm::FoldingSetNodeID& profile) { + Profile(profile, parentSymbol, R); + } + + // Implement isa<T> support. + static inline bool classof(const SymExpr* SE) { + return SE->getKind() == DerivedKind; + } }; // SymIntExpr - Represents symbolic expression like 'x' + 3. @@ -163,14 +205,16 @@ public: // FIXME: We probably need to make this out-of-line to avoid redundant // generation of virtual functions. - QualType getType(ASTContext& C) const { return T; } - + QualType getType(ASTContext& C) const { return T; } + BinaryOperator::Opcode getOpcode() const { return Op; } - + + void dumpToStream(llvm::raw_ostream &os) const; + const SymExpr *getLHS() const { return LHS; } const llvm::APSInt &getRHS() const { return RHS; } - static void Profile(llvm::FoldingSetNodeID& ID, const SymExpr *lhs, + static void Profile(llvm::FoldingSetNodeID& ID, const SymExpr *lhs, BinaryOperator::Opcode op, const llvm::APSInt& rhs, QualType t) { ID.AddInteger((unsigned) SymIntKind); @@ -183,11 +227,11 @@ public: 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'. @@ -204,11 +248,13 @@ public: 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; } + void dumpToStream(llvm::raw_ostream &os) const; + static void Profile(llvm::FoldingSetNodeID& ID, const SymExpr *lhs, BinaryOperator::Opcode op, const SymExpr *rhs, QualType t) { ID.AddInteger((unsigned) SymSymKind); @@ -221,45 +267,48 @@ public: 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; + DataSetTy DataSet; unsigned SymbolCounter; llvm::BumpPtrAllocator& BPAlloc; BasicValueFactory &BV; ASTContext& Ctx; - + public: - SymbolManager(ASTContext& ctx, BasicValueFactory &bv, + 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 SymbolRegionValue* getRegionValueSymbol(const MemRegion* R, QualType T = QualType()); 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) { + const void* SymbolTag = 0) { return getConjuredSymbol(E, E->getType(), VisitCount, SymbolTag); } + const SymbolDerived *getDerivedSymbol(SymbolRef parentSymbol, + const TypedRegion *R); + 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); @@ -267,29 +316,28 @@ public: 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; + typedef llvm::DenseSet<SymbolRef> SetTy; + SetTy TheLiving; SetTy TheDead; LiveVariables& Liveness; SymbolManager& SymMgr; - + public: SymbolReaper(LiveVariables& liveness, SymbolManager& symmgr) - : TheLiving(F.GetEmptySet()), TheDead(F.GetEmptySet()), - Liveness(liveness), SymMgr(symmgr) {} + : Liveness(liveness), SymMgr(symmgr) {} + + ~SymbolReaper() {} bool isLive(SymbolRef sym); @@ -300,19 +348,19 @@ public: 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; + + typedef SetTy::const_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(); + return !TheDead.empty(); } }; - + class SymbolVisitor { public: // VisitSymbol - A visitor method invoked by @@ -321,11 +369,14 @@ public: 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); +static inline llvm::raw_ostream& operator<<(llvm::raw_ostream& os, + const clang::SymExpr *SE) { + SE->dumpToStream(os); + return os; } +} // end llvm namespace #endif diff --git a/include/clang/Analysis/PathSensitive/ValueManager.h b/include/clang/Analysis/PathSensitive/ValueManager.h index 36d1df2150df..8d162a681c44 100644 --- a/include/clang/Analysis/PathSensitive/ValueManager.h +++ b/include/clang/Analysis/PathSensitive/ValueManager.h @@ -16,82 +16,123 @@ #ifndef LLVM_CLANG_ANALYSIS_AGGREGATE_VALUE_MANAGER_H #define LLVM_CLANG_ANALYSIS_AGGREGATE_VALUE_MANAGER_H +#include "llvm/ADT/OwningPtr.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" +#include "clang/Analysis/PathSensitive/SValuator.h" namespace llvm { class BumpPtrAllocator; } -namespace clang { +namespace clang { + +class GRStateManager; + class ValueManager { - ASTContext &Context; + ASTContext &Context; BasicValueFactory BasicVals; - + /// SymMgr - Object that manages the symbol information. SymbolManager SymMgr; + /// SVator - SValuator object that creates SVals from expressions. + llvm::OwningPtr<SValuator> SVator; MemRegionManager MemMgr; - + + GRStateManager &StateMgr; + + const QualType ArrayIndexTy; + const unsigned ArrayIndexWidth; + public: - ValueManager(llvm::BumpPtrAllocator &alloc, ASTContext &context) - : Context(context), BasicVals(Context, alloc), - SymMgr(Context, BasicVals, alloc), - MemMgr(Context, alloc) {} + ValueManager(llvm::BumpPtrAllocator &alloc, ASTContext &context, + GRStateManager &stateMgr) + : Context(context), BasicVals(context, alloc), + SymMgr(context, BasicVals, alloc), + MemMgr(context, alloc), StateMgr(stateMgr), + ArrayIndexTy(context.IntTy), + ArrayIndexWidth(context.getTypeSize(ArrayIndexTy)) { + // FIXME: Generalize later. + SVator.reset(clang::CreateSimpleSValuator(*this)); + } // Accessors to submanagers. - + ASTContext &getContext() { return Context; } const ASTContext &getContext() const { return Context; } - + + GRStateManager &getStateManager() { return StateMgr; } + BasicValueFactory &getBasicValueFactory() { return BasicVals; } const BasicValueFactory &getBasicValueFactory() const { return BasicVals; } - + SymbolManager &getSymbolManager() { return SymMgr; } const SymbolManager &getSymbolManager() const { return SymMgr; } + SValuator &getSValuator() { return *SVator.get(); } + 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) { + const void* SymbolTag = 0) { return SymMgr.getConjuredSymbol(E, VisitCount, SymbolTag); } /// makeZeroVal - Construct an SVal representing '0' for the specified type. - SVal makeZeroVal(QualType T); + DefinedOrUnknownSVal makeZeroVal(QualType T); /// getRegionValueSymbolVal - make a unique symbol for value of R. - SVal getRegionValueSymbolVal(const MemRegion *R, QualType T = QualType()); - - SVal getRegionValueSymbolValOrUnknown(const MemRegion *R, QualType T) { - return SymMgr.canSymbolicate(T) ? getRegionValueSymbolVal(R, T) - : UnknownVal(); + DefinedOrUnknownSVal getRegionValueSymbolVal(const MemRegion *R, + QualType T = QualType()); + + DefinedOrUnknownSVal getRegionValueSymbolValOrUnknown(const MemRegion *R, + QualType T) { + if (SymMgr.canSymbolicate(T)) + return getRegionValueSymbolVal(R, T); + return UnknownVal(); } - - SVal getConjuredSymbolVal(const Expr *E, unsigned Count); - SVal getConjuredSymbolVal(const Expr* E, QualType T, unsigned Count); - SVal getFunctionPointer(const FunctionDecl* FD); + DefinedOrUnknownSVal getConjuredSymbolVal(const void *SymbolTag, + const Expr *E, unsigned Count); + DefinedOrUnknownSVal getConjuredSymbolVal(const void *SymbolTag, + const Expr *E, QualType T, + unsigned Count); + + DefinedOrUnknownSVal getDerivedRegionValueSymbolVal(SymbolRef parentSymbol, + const TypedRegion *R); + + DefinedSVal getFunctionPointer(const FunctionDecl *FD); NonLoc makeCompoundVal(QualType T, llvm::ImmutableList<SVal> Vals) { return nonloc::CompoundVal(BasicVals.getCompoundValData(T, Vals)); } + NonLoc makeLazyCompoundVal(const GRState *state, const TypedRegion *R) { + return nonloc::LazyCompoundVal(BasicVals.getLazyCompoundValData(state, R)); + } + NonLoc makeZeroArrayIndex() { - return nonloc::ConcreteInt(BasicVals.getZeroWithPtrWidth(false)); + return nonloc::ConcreteInt(BasicVals.getValue(0, ArrayIndexTy)); + } + + NonLoc makeArrayIndex(uint64_t idx) { + return nonloc::ConcreteInt(BasicVals.getValue(idx, ArrayIndexTy)); } + SVal convertToArrayIndex(SVal V); + nonloc::ConcreteInt makeIntVal(const IntegerLiteral* I) { return nonloc::ConcreteInt(BasicVals.getValue(I->getValue(), I->getType()->isUnsignedIntegerType())); @@ -100,7 +141,7 @@ public: nonloc::ConcreteInt makeIntVal(const llvm::APSInt& V) { return nonloc::ConcreteInt(BasicVals.getValue(V)); } - + loc::ConcreteInt makeIntLocVal(const llvm::APSInt &v) { return loc::ConcreteInt(BasicVals.getValue(v)); } @@ -109,7 +150,10 @@ public: return nonloc::ConcreteInt(BasicVals.getValue(V, isUnsigned)); } - NonLoc makeIntVal(uint64_t X, QualType T) { + DefinedSVal makeIntVal(uint64_t X, QualType T) { + if (Loc::IsLocType(T)) + return loc::ConcreteInt(BasicVals.getValue(X, T)); + return nonloc::ConcreteInt(BasicVals.getValue(X, T)); } @@ -117,6 +161,10 @@ public: return nonloc::ConcreteInt(BasicVals.getIntValue(X, isUnsigned)); } + NonLoc makeIntValWithPtrWidth(uint64_t X, bool isUnsigned) { + return nonloc::ConcreteInt(BasicVals.getIntWithPtrWidth(X, isUnsigned)); + } + NonLoc makeIntVal(uint64_t X, unsigned BitWidth, bool isUnsigned) { return nonloc::ConcreteInt(BasicVals.getValue(X, BitWidth, isUnsigned)); } @@ -127,10 +175,10 @@ public: 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) { return nonloc::ConcreteInt(BasicVals.getTruthValue(b, T)); } diff --git a/include/clang/Analysis/ProgramPoint.h b/include/clang/Analysis/ProgramPoint.h index d2b536ca1cb2..666e45b847cf 100644 --- a/include/clang/Analysis/ProgramPoint.h +++ b/include/clang/Analysis/ProgramPoint.h @@ -15,7 +15,7 @@ #ifndef LLVM_CLANG_ANALYSIS_PROGRAM_POINT #define LLVM_CLANG_ANALYSIS_PROGRAM_POINT -#include "clang/AST/CFG.h" +#include "clang/Analysis/CFG.h" #include "llvm/Support/DataTypes.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/FoldingSet.h" @@ -24,123 +24,95 @@ #include <utility> namespace clang { - + +class LocationContext; + 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, + enum Kind { BlockEdgeKind, + BlockEntranceKind, + BlockExitKind, + PreStmtKind, + // Keep the following together and in this order. + PostStmtKind, + PostLocationChecksSucceedKind, + PostOutOfBoundsCheckFailedKind, + PostNullCheckFailedKind, + PostUndefLocationCheckFailedKind, + PostLoadKind, + PostStoreKind, + PostPurgeDeadSymbolsKind, + PostStmtCustomKind, + PostLValueKind, MinPostStmtKind = PostStmtKind, MaxPostStmtKind = PostLValueKind }; private: - enum { TwoPointers = 0x1, Custom = 0x2, Mask = 0x3 }; - - std::pair<uintptr_t,uintptr_t> Data; + std::pair<const void *, const void *> Data; + Kind K; + + // The LocationContext could be NULL to allow ProgramPoint to be used in + // context insensitive analysis. + const LocationContext *L; 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* P, Kind k, const LocationContext *l, + const void *tag = 0) + : Data(P, NULL), K(k), L(l), 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) {} + ProgramPoint(const void* P1, const void* P2, Kind k, const LocationContext *l, + const void *tag = 0) + : Data(P1, P2), K(k), L(l), 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* getData1() const { return Data.first; } + const void* getData2() const { return 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; - } - } + +public: + Kind getKind() const { return K; } + + const LocationContext *getLocationContext() const { return L; } // 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); + Profile(ID); return ID.ComputeHash(); } - + static bool classof(const ProgramPoint*) { return true; } bool operator==(const ProgramPoint & RHS) const { - return Data == RHS.Data && Tag == RHS.Tag; + return K == RHS.K && Data == RHS.Data && L == RHS.L && 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; + return K != RHS.K || Data != RHS.Data || L != RHS.L || 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.AddInteger((unsigned) K); + ID.AddPointer(Data.first); + ID.AddPointer(Data.second); + ID.AddPointer(L); ID.AddPointer(Tag); } }; - + class BlockEntrance : public ProgramPoint { public: - BlockEntrance(const CFGBlock* B, const void *tag = 0) - : ProgramPoint(B, BlockEntranceKind, tag) {} - + BlockEntrance(const CFGBlock* B, const LocationContext *L, + const void *tag = 0) + : ProgramPoint(B, BlockEntranceKind, L, tag) {} + CFGBlock* getBlock() const { - return reinterpret_cast<CFGBlock*>(getData1NoMask()); + return const_cast<CFGBlock*>(reinterpret_cast<const CFGBlock*>(getData1())); } - + Stmt* getFirstStmt() const { - CFGBlock* B = getBlock(); + const CFGBlock* B = getBlock(); return B->empty() ? NULL : B->front(); } @@ -151,42 +123,70 @@ public: class BlockExit : public ProgramPoint { public: - BlockExit(const CFGBlock* B) : ProgramPoint(B, BlockExitKind) {} - + BlockExit(const CFGBlock* B, const LocationContext *L) + : ProgramPoint(B, BlockExitKind, L) {} + CFGBlock* getBlock() const { - return reinterpret_cast<CFGBlock*>(getData1NoMask()); + return const_cast<CFGBlock*>(reinterpret_cast<const CFGBlock*>(getData1())); } Stmt* getLastStmt() const { - CFGBlock* B = getBlock(); + 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) {} +class StmtPoint : public ProgramPoint { +public: + StmtPoint(const Stmt *S, const void *p2, Kind k, const LocationContext *L, + const void *tag) + : ProgramPoint(S, p2, k, L, tag) {} + + const Stmt *getStmt() const { return (const Stmt*) getData1(); } - PostStmt(const Stmt* S, const void* data, bool, const void *tag =0) - : ProgramPoint(S, data, true, tag) {} - + template <typename T> + const T* getStmtAs() const { return llvm::dyn_cast<T>(getStmt()); } + + static bool classof(const ProgramPoint* Location) { + unsigned k = Location->getKind(); + return k >= PreStmtKind && k <= MaxPostStmtKind; + } +}; + + +class PreStmt : public StmtPoint { public: - PostStmt(const Stmt* S, const void *tag = 0) - : ProgramPoint(S, PostStmtKind, tag) {} + PreStmt(const Stmt *S, const LocationContext *L, const void *tag, + const Stmt *SubStmt = 0) + : StmtPoint(S, SubStmt, PreStmtKind, L, tag) {} + + const Stmt *getSubStmt() const { return (const Stmt*) getData2(); } - Stmt* getStmt() const { return (Stmt*) getData1(); } - - template<typename T> - T* getStmtAs() const { return llvm::dyn_cast<T>(getStmt()); } + static bool classof(const ProgramPoint* Location) { + return Location->getKind() == PreStmtKind; + } +}; + +class PostStmt : public StmtPoint { +protected: + PostStmt(const Stmt* S, Kind k, const LocationContext *L, const void *tag = 0) + : StmtPoint(S, NULL, k, L, tag) {} + + PostStmt(const Stmt* S, const void* data, Kind k, const LocationContext *L, + const void *tag =0) + : StmtPoint(S, data, k, L, tag) {} + +public: + explicit PostStmt(const Stmt* S, const LocationContext *L,const void *tag = 0) + : StmtPoint(S, NULL, PostStmtKind, L, tag) {} static bool classof(const ProgramPoint* Location) { unsigned k = Location->getKind(); @@ -196,40 +196,42 @@ public: class PostLocationChecksSucceed : public PostStmt { public: - PostLocationChecksSucceed(const Stmt* S, const void *tag = 0) - : PostStmt(S, PostLocationChecksSucceedKind, tag) {} - + PostLocationChecksSucceed(const Stmt* S, const LocationContext *L, + const void *tag = 0) + : PostStmt(S, PostLocationChecksSucceedKind, L, 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*>* TaggedData,\ + const LocationContext *L) + : PostStmt(S, TaggedData, PostStmtCustomKind, L) {} const std::pair<const void*, const void*>& getTaggedPair() const { - return *reinterpret_cast<std::pair<const void*, const void*>*>(getData2()); + return + *reinterpret_cast<const 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) {} - + PostOutOfBoundsCheckFailed(const Stmt* S, const LocationContext *L, + const void *tag = 0) + : PostStmt(S, PostOutOfBoundsCheckFailedKind, L, tag) {} + static bool classof(const ProgramPoint* Location) { return Location->getKind() == PostOutOfBoundsCheckFailedKind; } @@ -237,39 +239,41 @@ public: class PostUndefLocationCheckFailed : public PostStmt { public: - PostUndefLocationCheckFailed(const Stmt* S, const void *tag = 0) - : PostStmt(S, PostUndefLocationCheckFailedKind, tag) {} - + PostUndefLocationCheckFailed(const Stmt* S, const LocationContext *L, + const void *tag = 0) + : PostStmt(S, PostUndefLocationCheckFailedKind, L, 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) {} - + PostNullCheckFailed(const Stmt* S, const LocationContext *L, + const void *tag = 0) + : PostStmt(S, PostNullCheckFailedKind, L, 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) {} - + PostLoad(const Stmt* S, const LocationContext *L, const void *tag = 0) + : PostStmt(S, PostLoadKind, L, 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) {} - + PostStore(const Stmt* S, const LocationContext *L, const void *tag = 0) + : PostStmt(S, PostStoreKind, L, tag) {} + static bool classof(const ProgramPoint* Location) { return Location->getKind() == PostStoreKind; } @@ -277,60 +281,61 @@ public: class PostLValue : public PostStmt { public: - PostLValue(const Stmt* S, const void *tag = 0) - : PostStmt(S, PostLValueKind, tag) {} - + PostLValue(const Stmt* S, const LocationContext *L, const void *tag = 0) + : PostStmt(S, PostLValueKind, L, 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) {} - + PostPurgeDeadSymbols(const Stmt* S, const LocationContext *L, + const void *tag = 0) + : PostStmt(S, PostPurgeDeadSymbolsKind, L, 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) {} - + BlockEdge(const CFGBlock* B1, const CFGBlock* B2, const LocationContext *L) + : ProgramPoint(B1, B2, BlockEdgeKind, L) {} + CFGBlock* getSrc() const { - return static_cast<CFGBlock*>(getData1()); + return const_cast<CFGBlock*>(static_cast<const CFGBlock*>(getData1())); } - + CFGBlock* getDst() const { - return static_cast<CFGBlock*>(getData2()); + return const_cast<CFGBlock*>(static_cast<const CFGBlock*>(getData2())); } - + static bool classof(const ProgramPoint* Location) { return Location->getKind() == BlockEdgeKind; } }; - + } // end namespace clang -namespace llvm { // Traits specialization for DenseMap - +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)); + reinterpret_cast<uintptr_t>(DenseMapInfo<void*>::getEmptyKey()) & ~0x7; + return clang::BlockEntrance(reinterpret_cast<clang::CFGBlock*>(x), 0); } static inline clang::ProgramPoint getTombstoneKey() { uintptr_t x = - reinterpret_cast<uintptr_t>(DenseMapInfo<void*>::getTombstoneKey()) & ~0x7; - return clang::BlockEntrance(reinterpret_cast<clang::CFGBlock*>(x)); + reinterpret_cast<uintptr_t>(DenseMapInfo<void*>::getTombstoneKey()) & ~0x7; + return clang::BlockEntrance(reinterpret_cast<clang::CFGBlock*>(x), 0); } static unsigned getHashValue(const clang::ProgramPoint& Loc) { diff --git a/include/clang/Analysis/Support/BlkExprDeclBitVector.h b/include/clang/Analysis/Support/BlkExprDeclBitVector.h index a592be815419..27ecc66e66e3 100644 --- a/include/clang/Analysis/Support/BlkExprDeclBitVector.h +++ b/include/clang/Analysis/Support/BlkExprDeclBitVector.h @@ -17,24 +17,24 @@ #ifndef LLVM_CLANG_STMTDECLBVDVAL_H #define LLVM_CLANG_STMTDECLBVDVAL_H -#include "clang/AST/CFG.h" +#include "clang/Analysis/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; } @@ -42,35 +42,35 @@ struct DeclBitVector_Types { 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; + 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++; } @@ -78,44 +78,44 @@ struct DeclBitVector_Types { 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.resize(AD.getNumDecls()); DeclBV.reset(); } void setDeclValues(AnalysisDataTy& AD) { - DeclBV.resize(AD.getNumDecls()); + DeclBV.resize(AD.getNumDecls()); DeclBV.set(); } - + void resetValues(AnalysisDataTy& AD) { resetDeclValues(AD); - } - - bool operator==(const ValTy& RHS) const { + } + + 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)); @@ -124,48 +124,48 @@ struct DeclBitVector_Types { bool operator()(const NamedDecl* ND, const AnalysisDataTy& AD) const { return getBit(AD.getIdx(ND)); } - - llvm::BitVector::reference getDeclBit(unsigned i) { return DeclBV[i]; } + + 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. //===--------------------------------------------------------------------===// @@ -179,13 +179,13 @@ struct StmtDeclBitVector_Types { void setContext(ASTContext& c) { ctx = &c; } ASTContext& getContext() { - assert(ctx && "ASTContext should not be NULL."); + 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; @@ -195,7 +195,7 @@ struct StmtDeclBitVector_Types { return I; } using DeclBitVector_Types::AnalysisDataTy::getIdx; - + unsigned getNumBlkExprs() const { return cfg->getNumBlkExprs(); } }; @@ -206,101 +206,101 @@ struct StmtDeclBitVector_Types { 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) + + 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)]; - } + 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]; } + + 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 diff --git a/include/clang/Analysis/Support/BumpVector.h b/include/clang/Analysis/Support/BumpVector.h new file mode 100644 index 000000000000..a5e11a100665 --- /dev/null +++ b/include/clang/Analysis/Support/BumpVector.h @@ -0,0 +1,215 @@ +//===-- BumpVector.h - Vector-like ADT that uses bump allocation --*- 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 BumpVector, a vector-like ADT whose contents are +// allocated from a BumpPtrAllocator. +// +//===----------------------------------------------------------------------===// + +// FIXME: Most of this is copy-and-paste from SmallVector.h. We can +// refactor this core logic into something common that is shared between +// the two. The main thing that is different is the allocation strategy. + +#ifndef LLVM_CLANG_BUMP_VECTOR +#define LLVM_CLANG_BUMP_VECTOR + +#include "llvm/Support/type_traits.h" +#include "llvm/Support/Allocator.h" +#include "llvm/ADT/PointerIntPair.h" +#include <algorithm> + +namespace clang { + +class BumpVectorContext { + llvm::PointerIntPair<llvm::BumpPtrAllocator*, 1, bool> Alloc; +public: + /// Construct a new BumpVectorContext that creates a new BumpPtrAllocator + /// and destroys it when the BumpVectorContext object is destroyed. + BumpVectorContext() : Alloc(new llvm::BumpPtrAllocator(), true) {} + + /// Construct a new BumpVectorContext that reuses an existing + /// BumpPtrAllocator. This BumpPtrAllocator is not destroyed when the + /// BumpVectorContext object is destroyed. + BumpVectorContext(llvm::BumpPtrAllocator &A) : Alloc(&A, false) {} + + ~BumpVectorContext() { + if (Alloc.getInt()) + delete Alloc.getPointer(); + } + + llvm::BumpPtrAllocator &getAllocator() { return *Alloc.getPointer(); } +}; + +template<typename T> +class BumpVector { + T *Begin, *End, *Capacity; +public: + // Default ctor - Initialize to empty. + explicit BumpVector(BumpVectorContext &C, unsigned N) + : Begin(NULL), End(NULL), Capacity(NULL) { + reserve(C, N); + } + + ~BumpVector() { + if (llvm::is_class<T>::value) { + // Destroy the constructed elements in the vector. + destroy_range(Begin, End); + } + } + + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef T value_type; + typedef T* iterator; + typedef const T* const_iterator; + + typedef std::reverse_iterator<const_iterator> const_reverse_iterator; + typedef std::reverse_iterator<iterator> reverse_iterator; + + typedef T& reference; + typedef const T& const_reference; + typedef T* pointer; + typedef const T* const_pointer; + + // forward iterator creation methods. + iterator begin() { return Begin; } + const_iterator begin() const { return Begin; } + iterator end() { return End; } + const_iterator end() const { return 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());} + + bool empty() const { return Begin == End; } + size_type size() const { return End-Begin; } + + reference operator[](unsigned idx) { + assert(Begin + idx < End); + return Begin[idx]; + } + const_reference operator[](unsigned idx) const { + assert(Begin + idx < End); + return Begin[idx]; + } + + reference front() { + return begin()[0]; + } + const_reference front() const { + return begin()[0]; + } + + reference back() { + return end()[-1]; + } + const_reference back() const { + return end()[-1]; + } + + void pop_back() { + --End; + End->~T(); + } + + T pop_back_val() { + T Result = back(); + pop_back(); + return Result; + } + + void clear() { + if (llvm::is_class<T>::value) { + destroy_range(Begin, End); + } + End = Begin; + } + + /// data - Return a pointer to the vector's buffer, even if empty(). + pointer data() { + return pointer(Begin); + } + + /// data - Return a pointer to the vector's buffer, even if empty(). + const_pointer data() const { + return const_pointer(Begin); + } + + void push_back(const_reference Elt, BumpVectorContext &C) { + if (End < Capacity) { + Retry: + new (End) T(Elt); + ++End; + return; + } + grow(C); + goto Retry; + } + + void reserve(BumpVectorContext &C, unsigned N) { + if (unsigned(Capacity-Begin) < N) + grow(C, N); + } + + /// capacity - Return the total number of elements in the currently allocated + /// buffer. + size_t capacity() const { return Capacity - Begin; } + +private: + /// grow - double the size of the allocated memory, guaranteeing space for at + /// least one more element or MinSize if specified. + void grow(BumpVectorContext &C, size_type MinSize = 0); + + void construct_range(T *S, T *E, const T &Elt) { + for (; S != E; ++S) + new (S) T(Elt); + } + + void destroy_range(T *S, T *E) { + while (S != E) { + --E; + E->~T(); + } + } +}; + +// Define this out-of-line to dissuade the C++ compiler from inlining it. +template <typename T> +void BumpVector<T>::grow(BumpVectorContext &C, size_t MinSize) { + size_t CurCapacity = Capacity-Begin; + size_t CurSize = size(); + size_t NewCapacity = 2*CurCapacity; + if (NewCapacity < MinSize) + NewCapacity = MinSize; + + // Allocate the memory from the BumpPtrAllocator. + T *NewElts = C.getAllocator().template Allocate<T>(NewCapacity); + + // Copy the elements over. + if (llvm::is_class<T>::value) { + std::uninitialized_copy(Begin, End, NewElts); + // Destroy the original elements. + destroy_range(Begin, End); + } + else { + // Use memcpy for PODs (std::uninitialized_copy optimizes to memmove). + memcpy(NewElts, Begin, CurSize * sizeof(T)); + } + + // For now, leak 'Begin'. We can add it back to a freelist in + // BumpVectorContext. + Begin = NewElts; + End = NewElts+CurSize; + Capacity = Begin+NewCapacity; +} + +} // end: clang namespace +#endif // end: LLVM_CLANG_BUMP_VECTOR diff --git a/include/clang/Analysis/Support/Optional.h b/include/clang/Analysis/Support/Optional.h new file mode 100644 index 000000000000..3940007bb574 --- /dev/null +++ b/include/clang/Analysis/Support/Optional.h @@ -0,0 +1,55 @@ +//===-- Optional.h - Simple variant for passing optional 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 provides Optional, a template class modeled in the spirit of +// OCaml's 'opt' variant. The idea is to strongly type whether or not +// a value can be optional. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_OPTIONAL +#define LLVM_CLANG_ANALYSIS_OPTIONAL + +namespace clang { + +template<typename T> +class Optional { + const T x; + unsigned hasVal : 1; +public: + explicit Optional() : hasVal(false) {} + Optional(const T &y) : x(y), hasVal(true) {} + + static inline Optional create(const T* y) { + return y ? Optional(*y) : Optional(); + } + + const T* getPointer() const { assert(hasVal); return &x; } + + operator bool() const { return hasVal; } + const T* operator->() const { return getPointer(); } + const T& operator*() const { assert(hasVal); return x; } +}; +} //end clang namespace + +namespace llvm { +template <typename T> +struct simplify_type<const ::clang::Optional<T> > { + typedef const T* SimpleType; + static SimpleType getSimplifiedValue(const ::clang::Optional<T> &Val) { + return Val.getPointer(); + } +}; + +template <typename T> +struct simplify_type< ::clang::Optional<T> > + : public simplify_type<const ::clang::Optional<T> > {}; +} // end llvm namespace + +#endif diff --git a/include/clang/Analysis/Support/SaveAndRestore.h b/include/clang/Analysis/Support/SaveAndRestore.h new file mode 100644 index 000000000000..4720c22d990e --- /dev/null +++ b/include/clang/Analysis/Support/SaveAndRestore.h @@ -0,0 +1,44 @@ +//===-- SaveAndRestore.h - Utility -------------------------------*- 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 utility classes that uses RAII to save and restore +// values. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_SAVERESTORE +#define LLVM_CLANG_ANALYSIS_SAVERESTORE + +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; +}; + +} +#endif diff --git a/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h b/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h index ee79c517030f..3826d3a3acd6 100644 --- a/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h +++ b/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h @@ -30,28 +30,28 @@ break; #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: +public: void VisitDeclRefExpr(DeclRefExpr* DR) { - static_cast<ImplClass*>(this)->VisitDecl(DR->getDecl()); + 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); + 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) @@ -67,7 +67,7 @@ public: assert(false && "Subtype of ScopedDecl not handled."); } } - + DEFAULT_DISPATCH(VarDecl) DEFAULT_DISPATCH(FunctionDecl) DEFAULT_DISPATCH_VARDECL(OriginalParmVarDecl) diff --git a/include/clang/Analysis/Visitors/CFGRecStmtVisitor.h b/include/clang/Analysis/Visitors/CFGRecStmtVisitor.h index 4d3201962250..83700a3a346d 100644 --- a/include/clang/Analysis/Visitors/CFGRecStmtVisitor.h +++ b/include/clang/Analysis/Visitors/CFGRecStmtVisitor.h @@ -20,12 +20,12 @@ namespace clang { template <typename ImplClass> class CFGRecStmtVisitor : public CFGStmtVisitor<ImplClass,void> { -public: +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);} }; diff --git a/include/clang/Analysis/Visitors/CFGStmtVisitor.h b/include/clang/Analysis/Visitors/CFGStmtVisitor.h index f42bbde8f148..426b9ccd8a23 100644 --- a/include/clang/Analysis/Visitors/CFGStmtVisitor.h +++ b/include/clang/Analysis/Visitors/CFGStmtVisitor.h @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// // -// This file defines the CFGStmtVisitor interface, which extends +// 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. @@ -18,13 +18,13 @@ #define LLVM_CLANG_ANALYSIS_CFGSTMTVISITOR_H #include "clang/AST/StmtVisitor.h" -#include "clang/AST/CFG.h" +#include "clang/Analysis/CFG.h" namespace clang { #define DISPATCH_CASE(CLASS) \ case Stmt::CLASS ## Class: return \ -static_cast<ImplClass*>(this)->BlockStmt_Visit ## CLASS(static_cast<CLASS*>(S)); +static_cast<ImplClass*>(this)->BlockStmt_Visit ## CLASS(static_cast<CLASS*>(S)); #define DEFAULT_BLOCKSTMT_VISIT(CLASS) RetTy BlockStmt_Visit ## CLASS(CLASS *S)\ { return\ @@ -36,40 +36,40 @@ class CFGStmtVisitor : public StmtVisitor<ImplClass,RetTy> { Stmt* CurrentBlkStmt; struct NullifyStmt { - Stmt*& S; - + Stmt*& S; + NullifyStmt(Stmt*& s) : S(s) {} ~NullifyStmt() { S = NULL; } }; - + public: - CFGStmtVisitor() : CurrentBlkStmt(NULL) {} - + CFGStmtVisitor() : CurrentBlkStmt(NULL) {} + Stmt* getCurrentBlkStmt() const { return CurrentBlkStmt; } - + RetTy Visit(Stmt* S) { - if (S == CurrentBlkStmt || + 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 + /// 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()) @@ -78,40 +78,40 @@ public: return static_cast<ImplClass*>(this)->BlockStmt_VisitComma(B); // Fall through. } - + default: if (isa<Expr>(S)) - return + return static_cast<ImplClass*>(this)->BlockStmt_VisitExpr(cast<Expr>(S)); else - return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(S); + 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 + return static_cast<ImplClass*>(this)->BlockStmt_VisitImplicitControlFlowExpr(B); } - + RetTy BlockStmt_VisitComma(BinaryOperator* B) { return static_cast<ImplClass*>(this)->BlockStmt_VisitImplicitControlFlowExpr(B); @@ -120,21 +120,21 @@ public: //===--------------------------------------------------------------------===// // 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; @@ -142,12 +142,12 @@ public: return; } } - + for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I != E;++I) - if (*I) static_cast<ImplClass*>(this)->Visit(*I); + if (*I) static_cast<ImplClass*>(this)->Visit(*I); } -}; - +}; + #undef DEFAULT_BLOCKSTMT_VISIT #undef DISPATCH_CASE diff --git a/include/clang/Analysis/Visitors/CFGVarDeclVisitor.h b/include/clang/Analysis/Visitors/CFGVarDeclVisitor.h index 25101235ddd2..1bc798f4e79e 100644 --- a/include/clang/Analysis/Visitors/CFGVarDeclVisitor.h +++ b/include/clang/Analysis/Visitors/CFGVarDeclVisitor.h @@ -18,44 +18,43 @@ #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: +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) { + + 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)); + static_cast<ImplClass*>(this)->BlockStmt_Visit(const_cast<Stmt*>(*SI)); } }; |
