diff options
Diffstat (limited to 'include/clang')
5 files changed, 202 insertions, 173 deletions
diff --git a/include/clang/Analysis/PathSensitive/BugReporter.h b/include/clang/Analysis/PathSensitive/BugReporter.h index bcc28bdc5c..e0c3792323 100644 --- a/include/clang/Analysis/PathSensitive/BugReporter.h +++ b/include/clang/Analysis/PathSensitive/BugReporter.h @@ -23,6 +23,7 @@ #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/ImmutableSet.h" #include <list> namespace clang { @@ -36,100 +37,143 @@ class BugReporter; class GRExprEngine; class GRState; class Stmt; -class BugReport; +class BugType; class ParentMap; -class BugType { -public: - BugType() {} - virtual ~BugType(); +//===----------------------------------------------------------------------===// +// Interface for individual bug reports. +//===----------------------------------------------------------------------===// - virtual const char* getName() const = 0; - virtual const char* getDescription() const { return getName(); } - virtual const char* getCategory() const { return ""; } +// FIXME: Combine this with RangedBugReport and remove RangedBugReport. +class BugReport { + BugType& BT; + std::string Description; + const ExplodedNode<GRState> *EndNode; + SourceRange R; - virtual std::pair<const char**,const char**> getExtraDescriptiveText() { - return std::pair<const char**, const char**>(0, 0); +protected: + friend class BugReporter; + friend class BugReportEquivClass; + + virtual void Profile(llvm::FoldingSetNodeID& hash) const { + hash.AddInteger(getLocation().getRawEncoding()); } - - virtual void EmitWarnings(BugReporter& BR) {} - virtual void GetErrorNodes(std::vector<ExplodedNode<GRState>*>& Nodes) {} - virtual bool isCached(BugReport& R) = 0; -}; - -class BugTypeCacheLocation : public BugType { - llvm::SmallSet<ProgramPoint,10> CachedErrors; -public: - BugTypeCacheLocation() {} - virtual ~BugTypeCacheLocation() {} - virtual bool isCached(BugReport& R); - bool isCached(ProgramPoint P); -}; - - -class BugReport { - BugType& Desc; - const ExplodedNode<GRState> *EndNode; - SourceRange R; public: - BugReport(BugType& D, const ExplodedNode<GRState> *n) : Desc(D), EndNode(n) {} + BugReport(BugType& bt, const char* desc, const ExplodedNode<GRState> *n) + : BT(bt), Description(desc), EndNode(n) {} + virtual ~BugReport(); + + const BugType& getBugType() const { return BT; } + BugType& getBugType() { return BT; } - const BugType& getBugType() const { return Desc; } - BugType& getBugType() { return Desc; } - + // FIXME: Perhaps this should be moved into a subclass? const ExplodedNode<GRState>* getEndNode() const { return EndNode; } + // FIXME: Do we need this? Maybe getLocation() should return a ProgramPoint + // object. Stmt* getStmt(BugReporter& BR) const; - - const char* getName() const { return getBugType().getName(); } - - virtual const char* getDescription() const { - return getBugType().getDescription(); - } - virtual const char* getCategory() const { - return getBugType().getCategory(); - } + const std::string& getDescription() const { return Description; } + // FIXME: Is this needed? virtual std::pair<const char**,const char**> getExtraDescriptiveText() { - return getBugType().getExtraDescriptiveText(); + return std::make_pair((const char**)0,(const char**)0); } + // FIXME: Perhaps move this into a subclass. virtual PathDiagnosticPiece* getEndPath(BugReporter& BR, const ExplodedNode<GRState>* N); - virtual FullSourceLoc getLocation(SourceManager& Mgr); + /// 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); - + + // FIXME: Perhaps this should be moved into a subclass? virtual PathDiagnosticPiece* VisitNode(const ExplodedNode<GRState>* N, const ExplodedNode<GRState>* PrevN, const ExplodedGraph<GRState>& G, BugReporter& BR); }; + +//===----------------------------------------------------------------------===// +// BugTypes (collections of related reports). +//===----------------------------------------------------------------------===// + +class BugReportEquivClass : public llvm::FoldingSetNode { + // List of *owned* BugReport objects. + std::list<BugReport*> Reports; + + friend class BugReporter; + void AddReport(BugReport* R) { Reports.push_back(R); } +public: + BugReportEquivClass(BugReport* R) { Reports.push_back(R); } + ~BugReportEquivClass(); + + void Profile(llvm::FoldingSetNodeID& ID) const { + assert(!Reports.empty()); + (*Reports.begin())->Profile(ID); + } + + class iterator { + std::list<BugReport*>::iterator impl; + public: + iterator(std::list<BugReport*>::iterator i) : impl(i) {} + iterator& operator++() { ++impl; return *this; } + bool operator==(const iterator& I) const { return I.impl == impl; } + bool operator!=(const iterator& I) const { return I.impl != impl; } + BugReport* operator*() const { return *impl; } + BugReport* operator->() const { return *impl; } + }; + + iterator begin() { return iterator(Reports.begin()); } + iterator end() { return iterator(Reports.end()); } +}; + +class BugType { +private: + const std::string Name; + const std::string Category; + llvm::FoldingSet<BugReportEquivClass> EQClasses; + friend class BugReporter; +public: + BugType(const char *name, const char* cat) : Name(name), Category(cat) {} + virtual ~BugType(); + // FIXME: Should these be made strings as well? + const std::string& getName() const { return Name; } + const std::string& getCategory() const { return Category; } + + virtual void FlushReports(BugReporter& BR); + void AddReport(BugReport* BR); +}; + +//===----------------------------------------------------------------------===// +// Specialized subclasses of BugReport. +//===----------------------------------------------------------------------===// + +// FIXME: Collapse this with the default BugReport class. class RangedBugReport : public BugReport { std::vector<SourceRange> Ranges; - const char* desc; public: - RangedBugReport(BugType& D, ExplodedNode<GRState> *n, - const char* description = 0) - : BugReport(D, n), desc(description) {} + RangedBugReport(BugType& D, const char* description, ExplodedNode<GRState> *n) + : BugReport(D, description, n) {} - virtual ~RangedBugReport(); + ~RangedBugReport(); - virtual const char* getDescription() const { - return desc ? desc : BugReport::getDescription(); - } - + // FIXME: Move this out of line. void addRange(SourceRange R) { Ranges.push_back(R); } - - virtual void getRanges(BugReporter& BR,const SourceRange*& beg, - const SourceRange*& end) { + // FIXME: Move this out of line. + void getRanges(BugReporter& BR,const SourceRange*& beg, + const SourceRange*& end) { if (Ranges.empty()) { beg = NULL; @@ -142,6 +186,10 @@ public: } }; +//===----------------------------------------------------------------------===// +// BugReporter and friends. +//===----------------------------------------------------------------------===// + class BugReporterData { public: virtual ~BugReporterData(); @@ -158,16 +206,25 @@ class BugReporter { public: enum Kind { BaseBRKind, GRBugReporterKind }; -protected: - Kind kind; +private: + typedef llvm::ImmutableSet<BugType*> BugTypesTy; + BugTypesTy::Factory F; + BugTypesTy BugTypes; + + const Kind kind; BugReporterData& D; - BugReporter(BugReporterData& d, Kind k) : kind(k), D(d) {} - + void FlushReport(BugReportEquivClass& EQ); + +protected: + BugReporter(BugReporterData& d, Kind k) : BugTypes(F.GetEmptySet()), kind(k), D(d) {} + public: - BugReporter(BugReporterData& d) : kind(BaseBRKind), D(d) {} + BugReporter(BugReporterData& d) : BugTypes(F.GetEmptySet()), kind(BaseBRKind), D(d) {} virtual ~BugReporter(); + void FlushReports(); + Kind getKind() const { return kind; } Diagnostic& getDiagnostic() { @@ -178,29 +235,22 @@ public: return D.getPathDiagnosticClient(); } - ASTContext& getContext() { - return D.getContext(); - } + ASTContext& getContext() { return D.getContext(); } - SourceManager& getSourceManager() { - return D.getSourceManager(); - } + SourceManager& getSourceManager() { return D.getSourceManager(); } - CFG* getCFG() { - return D.getCFG(); - } + CFG* getCFG() { return D.getCFG(); } - ParentMap& getParentMap() { - return D.getParentMap(); - } + ParentMap& getParentMap() { return D.getParentMap(); } - LiveVariables* getLiveVariables() { - return D.getLiveVariables(); - } + LiveVariables* getLiveVariables() { return D.getLiveVariables(); } - virtual void GeneratePathDiagnostic(PathDiagnostic& PD, BugReport& R) {} + virtual void GeneratePathDiagnostic(PathDiagnostic& PD, + BugReportEquivClass& EQ) {} - void EmitWarning(BugReport& R); + void Register(BugType *BT); + + void EmitReport(BugReport *R); void EmitBasicReport(const char* BugName, const char* BugStr, SourceLocation Loc, @@ -234,11 +284,11 @@ public: static bool classof(const BugReporter* R) { return true; } }; +// FIXME: Get rid of GRBugReporter. It's the wrong abstraction. class GRBugReporter : public BugReporter { GRExprEngine& Eng; llvm::SmallSet<SymbolRef, 10> NotableSymbols; -public: - +public: GRBugReporter(BugReporterData& d, GRExprEngine& eng) : BugReporter(d, GRBugReporterKind), Eng(eng) {} @@ -246,9 +296,7 @@ public: /// 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. @@ -258,7 +306,8 @@ public: /// engine. GRStateManager& getStateManager(); - virtual void GeneratePathDiagnostic(PathDiagnostic& PD, BugReport& R); + virtual void GeneratePathDiagnostic(PathDiagnostic& PD, + BugReportEquivClass& R); void addNotableSymbol(SymbolRef Sym) { NotableSymbols.insert(Sym); @@ -273,22 +322,18 @@ public: return R->getKind() == GRBugReporterKind; } }; - class DiagBugReport : public RangedBugReport { std::list<std::string> Strs; FullSourceLoc L; - const char* description; public: - DiagBugReport(const char* desc, BugType& D, FullSourceLoc l) : - RangedBugReport(D, NULL), L(l), description(desc) {} + DiagBugReport(BugType& D, const char* desc, FullSourceLoc l) : + RangedBugReport(D, desc, 0), L(l) {} virtual ~DiagBugReport() {} - virtual FullSourceLoc getLocation(SourceManager&) { return L; } - virtual const char* getDescription() const { - return description; - } + // FIXME: Move out-of-line (virtual function). + SourceLocation getLocation() const { return L; } void addString(const std::string& s) { Strs.push_back(s); } @@ -297,39 +342,6 @@ public: str_iterator str_end() const { return Strs.end(); } }; -class DiagCollector : public DiagnosticClient { - std::list<DiagBugReport> Reports; - BugType& D; -public: - DiagCollector(BugType& d) : D(d) {} - - virtual ~DiagCollector() {} - - bool IncludeInDiagnosticCounts() const { return false; } - - void HandleDiagnostic(Diagnostic::Level DiagLevel, - const DiagnosticInfo &Info); - - // Iterators. - typedef std::list<DiagBugReport>::iterator iterator; - iterator begin() { return Reports.begin(); } - iterator end() { return Reports.end(); } -}; - -class SimpleBugType : public BugTypeCacheLocation { - const char* name; - const char* category; - const char* desc; -public: - SimpleBugType(const char* n) : name(n), category(""), desc(0) {} - SimpleBugType(const char* n, const char* c, const char* d) - : name(n), category(c), desc(d) {} - - virtual const char* getName() const { return name; } - virtual const char* getDescription() const { return desc ? desc : name; } - virtual const char* getCategory() const { return category; } -}; - } // end clang namespace #endif diff --git a/include/clang/Analysis/PathSensitive/ExplodedGraph.h b/include/clang/Analysis/PathSensitive/ExplodedGraph.h index 954b096b8e..757efdc64c 100644 --- a/include/clang/Analysis/PathSensitive/ExplodedGraph.h +++ b/include/clang/Analysis/PathSensitive/ExplodedGraph.h @@ -39,6 +39,12 @@ class GRIndirectGotoNodeBuilderImpl; class GRSwitchNodeBuilderImpl; class GREndPathNodebuilderImpl; +//===----------------------------------------------------------------------===// +// ExplodedGraph "implementation" classes. These classes are not typed to +// contain a specific kind of state. Typed-specialized versions are defined +// on top of these classes. +//===----------------------------------------------------------------------===// + class ExplodedNodeImpl : public llvm::FoldingSetNode { protected: friend class ExplodedGraphImpl; @@ -204,6 +210,7 @@ public: } }; +class InterExplodedGraphMapImpl; class ExplodedGraphImpl { protected: @@ -289,9 +296,39 @@ public: return llvm::dyn_cast<FunctionDecl>(&CodeDecl); } + typedef llvm::DenseMap<const ExplodedNodeImpl*, ExplodedNodeImpl*> NodeMap; + ExplodedGraphImpl* Trim(const ExplodedNodeImpl* const * NBeg, - const ExplodedNodeImpl* const * NEnd) const; + const ExplodedNodeImpl* const * NEnd, + InterExplodedGraphMapImpl *M) const; +}; + +class InterExplodedGraphMapImpl { + llvm::DenseMap<const ExplodedNodeImpl*, ExplodedNodeImpl*> M; + friend class ExplodedGraphImpl; + void add(const ExplodedNodeImpl* From, ExplodedNodeImpl* To); + +protected: + ExplodedNodeImpl* getMappedImplNode(const ExplodedNodeImpl* N) const; + + InterExplodedGraphMapImpl(); +public: + virtual ~InterExplodedGraphMapImpl() {} +}; + +//===----------------------------------------------------------------------===// +// Type-specialized ExplodedGraph classes. +//===----------------------------------------------------------------------===// +template <typename STATE> +class InterExplodedGraphMap : public InterExplodedGraphMapImpl { +public: + InterExplodedGraphMap() {}; + ~InterExplodedGraphMap() {}; + + ExplodedNode<STATE>* getMappedNode(const ExplodedNode<STATE>* N) const { + return static_cast<ExplodedNode<STATE>*>(getMappedImplNode(N)); + } }; template <typename STATE> @@ -409,13 +446,12 @@ public: return const_cast<ExplodedGraph>(this)->eop_end(); } - // Utility. - - ExplodedGraph* + std::pair<ExplodedGraph*, InterExplodedGraphMap<STATE>*> Trim(const NodeTy* const* NBeg, const NodeTy* const* NEnd) const { if (NBeg == NEnd) - return NULL; + return std::make_pair((ExplodedGraph*) 0, + (InterExplodedGraphMap<STATE>*) 0); assert (NBeg < NEnd); @@ -424,12 +460,15 @@ public: const ExplodedNodeImpl* const* NEndImpl = (const ExplodedNodeImpl* const*) NEnd; - return static_cast<ExplodedGraph*>(ExplodedGraphImpl::Trim(NBegImpl, - NEndImpl)); + llvm::OwningPtr<InterExplodedGraphMap<STATE> > + M(new InterExplodedGraphMap<STATE>()); + + ExplodedGraphImpl* G = ExplodedGraphImpl::Trim(NBegImpl, NEndImpl, M.get()); + + return std::make_pair(static_cast<ExplodedGraph*>(G), M.take()); } }; - - + template <typename StateTy> class ExplodedNodeSet { diff --git a/include/clang/Analysis/PathSensitive/GRExprEngine.h b/include/clang/Analysis/PathSensitive/GRExprEngine.h index 2a72794dd7..9a4ed49ffd 100644 --- a/include/clang/Analysis/PathSensitive/GRExprEngine.h +++ b/include/clang/Analysis/PathSensitive/GRExprEngine.h @@ -20,18 +20,16 @@ #include "clang/Analysis/PathSensitive/GRState.h" #include "clang/Analysis/PathSensitive/GRSimpleAPICheck.h" #include "clang/Analysis/PathSensitive/GRTransferFuncs.h" +#include "clang/Analysis/PathSensitive/BugReporter.h" #include "clang/AST/Type.h" #include "clang/AST/ExprObjC.h" namespace clang { - class BugType; class PathDiagnosticClient; class Diagnostic; - class BugReporterData; -class GRExprEngine { - +class GRExprEngine { public: typedef GRState StateTy; typedef ExplodedGraph<StateTy> GraphTy; @@ -44,7 +42,6 @@ public: typedef GRSwitchNodeBuilder<StateTy> SwitchNodeBuilder; typedef GREndPathNodeBuilder<StateTy> EndPathNodeBuilder; typedef ExplodedNodeSet<StateTy> NodeSet; - protected: GRCoreEngine<GRExprEngine> CoreEngine; @@ -62,11 +59,7 @@ protected: /// StateMgr - Object that manages the data for all created states. GRStateManager StateMgr; - - /// BugTypes - Objects used for reporting bugs. - typedef std::vector<BugType*> BugTypeSet; - BugTypeSet BugTypes; - + /// SymMgr - Object that manages the symbol information. SymbolManager& SymMgr; @@ -92,6 +85,11 @@ protected: /// 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; + public: typedef llvm::SmallPtrSet<NodeTy*,2> ErrorNodes; typedef llvm::DenseMap<NodeTy*, Expr*> UndefArgsTy; @@ -177,10 +175,11 @@ public: public: GRExprEngine(CFG& cfg, Decl& CD, ASTContext& Ctx, LiveVariables& L, + BugReporterData& BRD, bool purgeDead, StoreManagerCreator SMC = CreateBasicStoreManager, ConstraintManagerCreator CMC = CreateBasicConstraintManager); - + ~GRExprEngine(); void ExecuteWorkList(unsigned Steps = 150000) { @@ -195,6 +194,8 @@ public: GRTransferFuncs& getTF() { return *StateMgr.TF; } + BugReporter& getBugReporter() { return BR; } + /// setTransferFunctions void setTransferFunctions(GRTransferFuncs* tf); @@ -219,27 +220,9 @@ public: GraphTy& getGraph() { return G; } const GraphTy& getGraph() const { return G; } - - typedef BugTypeSet::iterator bug_type_iterator; - typedef BugTypeSet::const_iterator const_bug_type_iterator; - - bug_type_iterator bug_types_begin() { return BugTypes.begin(); } - bug_type_iterator bug_types_end() { return BugTypes.end(); } - const_bug_type_iterator bug_types_begin() const { return BugTypes.begin(); } - const_bug_type_iterator bug_types_end() const { return BugTypes.end(); } - - /// Register - Register a BugType with the analyzer engine. A registered - /// BugType object will have its 'EmitWarnings' method called when the - /// the analyzer finishes analyzing a method or function. - void Register(BugType* B) { - BugTypes.push_back(B); - } - void RegisterInternalChecks(); - void EmitWarnings(BugReporterData& BRData); - bool isRetStackAddr(const NodeTy* N) const { return N->isSink() && RetsStackAddr.count(const_cast<NodeTy*>(N)) != 0; } diff --git a/include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h b/include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h index 66b2fb1ae8..e54b31dfe8 100644 --- a/include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h +++ b/include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h @@ -33,7 +33,6 @@ class GRSimpleAPICheck : public GRAuditor<GRState> { public: GRSimpleAPICheck() {} virtual ~GRSimpleAPICheck() {} - virtual void EmitWarnings(BugReporter& BR) = 0; }; } // end namespace clang diff --git a/include/clang/Analysis/PathSensitive/GRTransferFuncs.h b/include/clang/Analysis/PathSensitive/GRTransferFuncs.h index 6f4266b9df..dba42c2515 100644 --- a/include/clang/Analysis/PathSensitive/GRTransferFuncs.h +++ b/include/clang/Analysis/PathSensitive/GRTransferFuncs.h @@ -23,28 +23,24 @@ namespace clang { class GRExprEngine; + class BugReporter; class ObjCMessageExpr; class GRTransferFuncs { - - friend class GRExprEngine; - + friend class GRExprEngine; protected: - - virtual SVal DetermEvalBinOpNN(GRExprEngine& Eng, BinaryOperator::Opcode Op, NonLoc L, NonLoc R) { return UnknownVal(); } - public: GRTransferFuncs() {} virtual ~GRTransferFuncs() {} virtual void RegisterPrinters(std::vector<GRState::Printer*>& Printers) {} - virtual void RegisterChecks(GRExprEngine& Eng); + virtual void RegisterChecks(BugReporter& BR) {} // Casts. |