diff options
author | dim <dim@FreeBSD.org> | 2013-04-08 18:45:10 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2013-04-08 18:45:10 +0000 |
commit | c72c57c9e9b69944e3e009cd5e209634839581d3 (patch) | |
tree | 4fc2f184c499d106f29a386c452b49e5197bf63d /include/clang/StaticAnalyzer/Core/PathSensitive | |
parent | 5b20025c30d23d521e12c1f33ec8fa6b821952cd (diff) | |
download | FreeBSD-src-c72c57c9e9b69944e3e009cd5e209634839581d3.zip FreeBSD-src-c72c57c9e9b69944e3e009cd5e209634839581d3.tar.gz |
Vendor import of clang trunk r178860:
http://llvm.org/svn/llvm-project/cfe/trunk@178860
Diffstat (limited to 'include/clang/StaticAnalyzer/Core/PathSensitive')
21 files changed, 593 insertions, 322 deletions
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h b/include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h index 27f3677..9502900 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h @@ -81,9 +81,12 @@ public: /// Tests whether a given value is losslessly representable using this type. /// - /// Note that signedness conversions will be rejected, even with the same bit - /// pattern. For example, -1s8 is not in range for 'unsigned char' (u8). - RangeTestResultKind testInRange(const llvm::APSInt &Val) const LLVM_READONLY; + /// \param Val The value to test. + /// \param AllowMixedSign Whether or not to allow signedness conversions. + /// This determines whether -1s8 is considered in range + /// for 'unsigned char' (u8). + RangeTestResultKind testInRange(const llvm::APSInt &Val, + bool AllowMixedSign) const LLVM_READONLY; bool operator==(const APSIntType &Other) const { return BitWidth == Other.BitWidth && IsUnsigned == Other.IsUnsigned; diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h index 9038ae5..458c896 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h @@ -100,7 +100,7 @@ public: } bool shouldInlineCall() const { - return options.IPAMode != None; + return options.getIPAMode() != IPAK_None; } CFG *getCFG(Decl const *D) { diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h b/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h index fb39354..1135b51 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h @@ -16,9 +16,10 @@ #ifndef LLVM_CLANG_GR_BASICVALUEFACTORY_H #define LLVM_CLANG_GR_BASICVALUEFACTORY_H +#include "clang/AST/ASTContext.h" #include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h" namespace clang { namespace ento { diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h index a6a91e2..f990b8d 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h @@ -16,11 +16,11 @@ #ifndef LLVM_CLANG_STATICANALYZER_PATHSENSITIVE_CALL #define LLVM_CLANG_STATICANALYZER_PATHSENSITIVE_CALL -#include "clang/Basic/SourceManager.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" #include "clang/Analysis/AnalysisContext.h" +#include "clang/Basic/SourceManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" #include "llvm/ADT/PointerIntPair.h" @@ -162,11 +162,11 @@ protected: } - typedef SmallVectorImpl<const MemRegion *> RegionList; + typedef SmallVectorImpl<SVal> ValueList; /// \brief Used to specify non-argument regions that will be invalidated as a /// result of this call. - virtual void getExtraInvalidatedRegions(RegionList &Regions) const {} + virtual void getExtraInvalidatedValues(ValueList &Values) const {} public: virtual ~CallEvent() {} @@ -181,7 +181,7 @@ public: } /// \brief The state in which the call is being evaluated. - ProgramStateRef getState() const { + const ProgramStateRef &getState() const { return State; } @@ -228,6 +228,11 @@ public: return false; } + /// \brief Returns true if this is a call to a variadic function or method. + virtual bool isVariadic() const { + return false; + } + /// \brief Returns a source range for the entire call, suitable for /// outputting in diagnostics. virtual SourceRange getSourceRange() const { @@ -331,7 +336,9 @@ public: /// of some kind. static bool isCallStmt(const Stmt *S); - /// \brief Returns the result type of a function, method declaration. + /// \brief Returns the result type of a function or method declaration. + /// + /// This will return a null QualType if the result type cannot be determined. static QualType getDeclaredResultType(const Decl *D); // Iterator access to formal parameters and their types. @@ -416,6 +423,10 @@ public: return RuntimeDefinition(); } + virtual bool isVariadic() const { + return getDecl()->isVariadic(); + } + virtual bool argumentsMayEscape() const; virtual void getInitialStackFrameContents(const StackFrameContext *CalleeCtx, @@ -493,7 +504,7 @@ protected: BlockCall(const BlockCall &Other) : SimpleCall(Other) {} virtual void cloneTo(void *Dest) const { new (Dest) BlockCall(*this); } - virtual void getExtraInvalidatedRegions(RegionList &Regions) const; + virtual void getExtraInvalidatedValues(ValueList &Values) const; public: /// \brief Returns the region associated with this instance of the block. @@ -516,6 +527,10 @@ public: return RuntimeDefinition(getBlockDecl()); } + virtual bool isVariadic() const { + return getBlockDecl()->isVariadic(); + } + virtual void getInitialStackFrameContents(const StackFrameContext *CalleeCtx, BindingsTy &Bindings) const; @@ -533,7 +548,7 @@ public: /// it is written. class CXXInstanceCall : public AnyFunctionCall { protected: - virtual void getExtraInvalidatedRegions(RegionList &Regions) const; + virtual void getExtraInvalidatedValues(ValueList &Values) const; CXXInstanceCall(const CallExpr *CE, ProgramStateRef St, const LocationContext *LCtx) @@ -716,7 +731,7 @@ protected: CXXConstructorCall(const CXXConstructorCall &Other) : AnyFunctionCall(Other){} virtual void cloneTo(void *Dest) const { new (Dest) CXXConstructorCall(*this); } - virtual void getExtraInvalidatedRegions(RegionList &Regions) const; + virtual void getExtraInvalidatedValues(ValueList &Values) const; public: virtual const CXXConstructExpr *getOriginExpr() const { @@ -815,7 +830,7 @@ protected: ObjCMethodCall(const ObjCMethodCall &Other) : CallEvent(Other) {} virtual void cloneTo(void *Dest) const { new (Dest) ObjCMethodCall(*this); } - virtual void getExtraInvalidatedRegions(RegionList &Regions) const; + virtual void getExtraInvalidatedValues(ValueList &Values) const; /// Check if the selector may have multiple definitions (may have overrides). virtual bool canBeOverridenInSubclass(ObjCInterfaceDecl *IDecl, @@ -834,6 +849,9 @@ public: virtual const Expr *getArgExpr(unsigned Index) const { return getOriginExpr()->getArg(Index); } + virtual bool isVariadic() const { + return getDecl()->isVariadic(); + } bool isInstanceMessage() const { return getOriginExpr()->isInstanceMessage(); @@ -1024,7 +1042,7 @@ namespace llvm { typedef const T *SimpleType; static SimpleType - getSimplifiedValue(const clang::ento::CallEventRef<T>& Val) { + getSimplifiedValue(clang::ento::CallEventRef<T> Val) { return Val.getPtr(); } }; diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h index 4558cd9..cda1366 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h @@ -119,7 +119,7 @@ public: /// the state of the program before the checker ran. Note, checkers should /// not retain the node in their state since the nodes might get invalidated. ExplodedNode *getPredecessor() { return Pred; } - ProgramStateRef getState() const { return Pred->getState(); } + const ProgramStateRef &getState() const { return Pred->getState(); } /// \brief Check if the checker changed the state of the execution; ex: added /// a new transition or a bug report. @@ -185,7 +185,7 @@ public: /// example, for finding variables that the given symbol was assigned to. static const MemRegion *getLocationRegionIfPostStore(const ExplodedNode *N) { ProgramPoint L = N->getLocation(); - if (const PostStore *PSL = dyn_cast<PostStore>(&L)) + if (Optional<PostStore> PSL = L.getAs<PostStore>()) return reinterpret_cast<const MemRegion*>(PSL->getLocationValue()); return 0; } @@ -303,14 +303,6 @@ private: } }; -/// \brief A helper class which wraps a boolean value set to false by default. -struct DefaultBool { - bool Val; - DefaultBool() : Val(false) {} - operator bool() const { return Val; } - DefaultBool &operator=(bool b) { Val = b; return *this; } -}; - } // end GR namespace } // end clang namespace diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h index 4a78849..1e76ea6 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h @@ -14,8 +14,8 @@ #ifndef LLVM_CLANG_GR_CONSTRAINT_MANAGER_H #define LLVM_CLANG_GR_CONSTRAINT_MANAGER_H -#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h" #include "llvm/Support/SaveAndRestore.h" namespace llvm { @@ -28,7 +28,7 @@ namespace ento { class SubEngine; class ConditionTruthVal { - llvm::Optional<bool> Val; + Optional<bool> Val; public: /// Construct a ConditionTruthVal indicating the constraint is constrained /// to either true or false, depending on the boolean value provided. @@ -78,9 +78,13 @@ public: // If StTrue is infeasible, asserting the falseness of Cond is unnecessary // because the existing constraints already establish this. if (!StTrue) { - // FIXME: This is fairly expensive and should be disabled even in - // Release+Asserts builds. +#ifndef __OPTIMIZE__ + // This check is expensive and should be disabled even in Release+Asserts + // builds. + // FIXME: __OPTIMIZE__ is a GNU extension that Clang implements but MSVC + // does not. Is there a good equivalent there? assert(assume(State, Cond, false) && "System is over constrained."); +#endif return ProgramStatePair((ProgramStateRef)NULL, State); } @@ -118,7 +122,7 @@ public: /// Convenience method to query the state to see if a symbol is null or /// not null, or if neither assumption can be made. ConditionTruthVal isNull(ProgramStateRef State, SymbolRef Sym) { - llvm::SaveAndRestore<bool> DisableNotify(NotifyAssumeClients, false); + SaveAndRestore<bool> DisableNotify(NotifyAssumeClients, false); return checkNull(State, Sym); } diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h index b668640..a2e211e 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h @@ -17,10 +17,10 @@ #include "clang/AST/Expr.h" #include "clang/Analysis/AnalysisContext.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" #include "clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h" #include "clang/StaticAnalyzer/Core/PathSensitive/WorkList.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h" #include "llvm/ADT/OwningPtr.h" namespace clang { @@ -96,6 +96,10 @@ private: void HandleBranch(const Stmt *Cond, const Stmt *Term, const CFGBlock *B, ExplodedNode *Pred); + /// Handle conditional logic for running static initializers. + void HandleStaticInit(const DeclStmt *DS, const CFGBlock *B, + ExplodedNode *Pred); + private: CoreEngine(const CoreEngine &) LLVM_DELETED_FUNCTION; void operator=(const CoreEngine &) LLVM_DELETED_FUNCTION; @@ -463,7 +467,7 @@ public: bool operator!=(const iterator &X) const { return I != X.I; } const LabelDecl *getLabel() const { - return llvm::cast<LabelStmt>((*I)->getLabel())->getDecl(); + return cast<LabelStmt>((*I)->getLabel())->getDecl(); } const CFGBlock *getBlock() const { @@ -510,7 +514,7 @@ public: bool operator==(const iterator &X) const { return I == X.I; } const CaseStmt *getCase() const { - return llvm::cast<CaseStmt>((*I)->getLabel()); + return cast<CaseStmt>((*I)->getLabel()); } const CFGBlock *getBlock() const { @@ -522,7 +526,7 @@ public: iterator end() { return iterator(Src->succ_rend()); } const SwitchStmt *getSwitch() const { - return llvm::cast<SwitchStmt>(Src->getTerminator()); + return cast<SwitchStmt>(Src->getTerminator()); } ExplodedNode *generateCaseStmtNode(const iterator &I, diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h index eb9bd85..f3a582d 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h @@ -33,9 +33,6 @@ class SValBuilder; /// other things. class EnvironmentEntry : public std::pair<const Stmt*, const StackFrameContext *> { - friend class EnvironmentManager; - EnvironmentEntry makeLocation() const; - public: EnvironmentEntry(const Stmt *s, const LocationContext *L); @@ -118,13 +115,6 @@ public: /// Bind a symbolic value to the given environment entry. Environment bindExpr(Environment Env, const EnvironmentEntry &E, SVal V, bool Invalidate); - - /// Bind the location 'location' and value 'V' to the specified - /// environment entry. - Environment bindExprAndLocation(Environment Env, - const EnvironmentEntry &E, - SVal location, - SVal V); Environment removeDeadBindings(Environment Env, SymbolReaper &SymReaper, diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h index b112e66..5211916 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h @@ -19,19 +19,19 @@ #ifndef LLVM_CLANG_GR_EXPLODEDGRAPH #define LLVM_CLANG_GR_EXPLODEDGRAPH -#include "clang/Analysis/ProgramPoint.h" -#include "clang/Analysis/AnalysisContext.h" #include "clang/AST/Decl.h" -#include "llvm/ADT/SmallVector.h" +#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/ProgramPoint.h" +#include "clang/Analysis/Support/BumpVector.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" +#include "llvm/ADT/DepthFirstIterator.h" #include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/GraphTraits.h" +#include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/Support/Allocator.h" -#include "llvm/ADT/OwningPtr.h" -#include "llvm/ADT/GraphTraits.h" -#include "llvm/ADT/DepthFirstIterator.h" #include "llvm/Support/Casting.h" -#include "clang/Analysis/Support/BumpVector.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" #include <vector> namespace clang { @@ -152,10 +152,12 @@ public: return *getLocationContext()->getAnalysis<T>(); } - ProgramStateRef getState() const { return State; } + const ProgramStateRef &getState() const { return State; } template <typename T> - const T* getLocationAs() const { return llvm::dyn_cast<T>(&Location); } + Optional<T> getLocationAs() const LLVM_LVALUE_FUNCTION { + return Location.getAs<T>(); + } static void Profile(llvm::FoldingSetNodeID &ID, const ProgramPoint &Loc, @@ -167,7 +169,8 @@ public: } void Profile(llvm::FoldingSetNodeID& ID) const { - Profile(ID, getLocation(), getState(), isSink()); + // We avoid copy constructors by not using accessors. + Profile(ID, Location, State, isSink()); } /// addPredeccessor - Adds a predecessor to the current node, and @@ -236,18 +239,8 @@ private: void replacePredecessor(ExplodedNode *node) { Preds.replaceNode(node); } }; -// FIXME: Is this class necessary? -class InterExplodedGraphMap { - virtual void anchor(); - llvm::DenseMap<const ExplodedNode*, ExplodedNode*> M; - friend class ExplodedGraph; - -public: - ExplodedNode *getMappedNode(const ExplodedNode *N) const; - - InterExplodedGraphMap() {} - virtual ~InterExplodedGraphMap() {} -}; +typedef llvm::DenseMap<const ExplodedNode *, const ExplodedNode *> + InterExplodedGraphMap; class ExplodedGraph { protected: @@ -365,14 +358,19 @@ public: 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; + /// Creates a trimmed version of the graph that only contains paths leading + /// to the given nodes. + /// + /// \param Nodes The nodes which must appear in the final graph. Presumably + /// these are end-of-path nodes (i.e. they have no successors). + /// \param[out] ForwardMap A optional map from nodes in this graph to nodes in + /// the returned graph. + /// \param[out] InverseMap An optional map from nodes in the returned graph to + /// nodes in this graph. + /// \returns The trimmed graph + ExplodedGraph *trim(ArrayRef<const NodeTy *> Nodes, + InterExplodedGraphMap *ForwardMap = 0, + InterExplodedGraphMap *InverseMap = 0) const; /// Enable tracking of recently allocated nodes for potential reclamation /// when calling reclaimRecentlyAllocatedNodes(). @@ -384,6 +382,10 @@ public: /// was called. void reclaimRecentlyAllocatedNodes(); + /// \brief Returns true if nodes for the given expression kind are always + /// kept around. + static bool isInterestingLValueExpr(const Expr *Ex); + private: bool shouldCollect(const ExplodedNode *node); void collectNode(ExplodedNode *node); diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h index 78b2542..33e4431 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h @@ -16,15 +16,15 @@ #ifndef LLVM_CLANG_GR_EXPRENGINE #define LLVM_CLANG_GR_EXPRENGINE +#include "clang/AST/Expr.h" +#include "clang/AST/Type.h" #include "clang/Analysis/DomainSpecific/ObjCNoReturn.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" -#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" -#include "clang/AST/Expr.h" -#include "clang/AST/Type.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h" namespace clang { @@ -44,8 +44,19 @@ namespace ento { class AnalysisManager; class CallEvent; class SimpleCall; +class CXXConstructorCall; class ExprEngine : public SubEngine { +public: + /// The modes of inlining, which override the default analysis-wide settings. + enum InliningModes { + /// Follow the default settings for inlining callees. + Inline_Regular = 0, + /// Do minimal inlining of callees. + Inline_Minimal = 0x1 + }; + +private: AnalysisManager &AMgr; AnalysisDeclContextManager &AnalysisDeclContexts; @@ -64,15 +75,6 @@ class ExprEngine : public SubEngine { /// svalBuilder - SValBuilder object that creates SVals from expressions. SValBuilder &svalBuilder; - /// EntryNode - The immediate predecessor node. - ExplodedNode *EntryNode; - - /// CleanedState - The state for EntryNode "cleaned" of all dead - /// variables and symbols (as determined by a liveness analysis). - ProgramStateRef CleanedState; - - /// currStmt - The current block-level statement. - const Stmt *currStmt; unsigned int currStmtIdx; const NodeBuilderContext *currBldrCtx; @@ -92,10 +94,14 @@ class ExprEngine : public SubEngine { /// AnalysisConsumer. It can be null. SetOfConstDecls *VisitedCallees; + /// The flag, which specifies the mode of inlining for the engine. + InliningModes HowToInline; + public: ExprEngine(AnalysisManager &mgr, bool gcEnabled, SetOfConstDecls *VisitedCalleesIn, - FunctionSummariesTy *FS); + FunctionSummariesTy *FS, + InliningModes HowToInlineIn); ~ExprEngine(); @@ -140,11 +146,12 @@ public: void enqueueEndOfPath(ExplodedNodeSet &S); void GenerateCallExitNode(ExplodedNode *N); - /// ViewGraph - Visualize the ExplodedGraph created by executing the - /// simulation. + /// Visualize the ExplodedGraph created by executing the simulation. void ViewGraph(bool trim = false); - void ViewGraph(ExplodedNode** Beg, ExplodedNode** End); + /// Visualize a trimmed ExplodedGraph that only contains paths to the given + /// nodes. + void ViewGraph(ArrayRef<const ExplodedNode*> Nodes); /// getInitialState - Return the initial state used for the root vertex /// in the ExplodedGraph. @@ -154,26 +161,33 @@ public: const ExplodedGraph& getGraph() const { return G; } /// \brief Run the analyzer's garbage collection - remove dead symbols and - /// bindings. + /// bindings from the state. /// - /// \param Node - The predecessor node, from which the processing should - /// start. - /// \param Out - The returned set of output nodes. - /// \param ReferenceStmt - Run garbage collection using the symbols, - /// which are live before the given statement. - /// \param LC - The location context of the ReferenceStmt. - /// \param DiagnosticStmt - the statement used to associate the diagnostic - /// message, if any warnings should occur while removing the dead (leaks - /// are usually reported here). - /// \param K - In some cases it is possible to use PreStmt kind. (Do - /// not use it unless you know what you are doing.) - /// If the ReferenceStmt is NULL, everything is this and parent contexts is - /// considered live. - /// If the stack frame context is NULL, everything on stack is considered - /// dead. + /// Checkers can participate in this process with two callbacks: + /// \c checkLiveSymbols and \c checkDeadSymbols. See the CheckerDocumentation + /// class for more information. + /// + /// \param Node The predecessor node, from which the processing should start. + /// \param Out The returned set of output nodes. + /// \param ReferenceStmt The statement which is about to be processed. + /// Everything needed for this statement should be considered live. + /// A null statement means that everything in child LocationContexts + /// is dead. + /// \param LC The location context of the \p ReferenceStmt. A null location + /// context means that we have reached the end of analysis and that + /// all statements and local variables should be considered dead. + /// \param DiagnosticStmt Used as a location for any warnings that should + /// occur while removing the dead (e.g. leaks). By default, the + /// \p ReferenceStmt is used. + /// \param K Denotes whether this is a pre- or post-statement purge. This + /// must only be ProgramPoint::PostStmtPurgeDeadSymbolsKind if an + /// entire location context is being cleared, in which case the + /// \p ReferenceStmt must either be a ReturnStmt or \c NULL. Otherwise, + /// it must be ProgramPoint::PreStmtPurgeDeadSymbolsKind (the default) + /// and \p ReferenceStmt must be valid (non-null). void removeDead(ExplodedNode *Node, ExplodedNodeSet &Out, - const Stmt *ReferenceStmt, const StackFrameContext *LC, - const Stmt *DiagnosticStmt, + const Stmt *ReferenceStmt, const LocationContext *LC, + const Stmt *DiagnosticStmt = 0, ProgramPoint::Kind K = ProgramPoint::PreStmtPurgeDeadSymbolsKind); /// processCFGElement - Called by CoreEngine. Used to generate new successor @@ -210,6 +224,15 @@ public: const CFGBlock *DstT, const CFGBlock *DstF); + /// Called by CoreEngine. Used to processing branching behavior + /// at static initalizers. + void processStaticInitializer(const DeclStmt *DS, + NodeBuilderContext& BuilderCtx, + ExplodedNode *Pred, + ExplodedNodeSet &Dst, + const CFGBlock *DstT, + const CFGBlock *DstF); + /// processIndirectGoto - Called by CoreEngine. Used to generate successor /// nodes by processing the 'effects' of a computed goto jump. void processIndirectGoto(IndirectGotoNodeBuilder& builder); @@ -218,8 +241,8 @@ public: /// nodes by processing the 'effects' of a switch statement. void processSwitch(SwitchNodeBuilder& builder); - /// ProcessEndPath - Called by CoreEngine. Used to generate end-of-path - /// nodes when the control reaches the end of a function. + /// Called by CoreEngine. Used to generate end-of-path + /// nodes when the control reaches the end of a function. void processEndOfFunction(NodeBuilderContext& BC, ExplodedNode *Pred); @@ -250,7 +273,7 @@ public: /// to the store. Used to update checkers that track region values. ProgramStateRef processRegionChanges(ProgramStateRef state, - const StoreManager::InvalidatedSymbols *invalidated, + const InvalidatedSymbols *invalidated, ArrayRef<const MemRegion *> ExplicitRegions, ArrayRef<const MemRegion *> Regions, const CallEvent *Call); @@ -416,11 +439,11 @@ public: geteagerlyAssumeBinOpBifurcationTags(); SVal evalMinus(SVal X) { - return X.isValid() ? svalBuilder.evalMinus(cast<NonLoc>(X)) : X; + return X.isValid() ? svalBuilder.evalMinus(X.castAs<NonLoc>()) : X; } SVal evalComplement(SVal X) { - return X.isValid() ? svalBuilder.evalComplement(cast<NonLoc>(X)) : X; + return X.isValid() ? svalBuilder.evalComplement(X.castAs<NonLoc>()) : X; } public: @@ -432,7 +455,8 @@ public: SVal evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op, NonLoc L, SVal R, QualType T) { - return R.isValid() ? svalBuilder.evalBinOpNN(state,op,L, cast<NonLoc>(R), T) : R; + return R.isValid() ? svalBuilder.evalBinOpNN(state, op, L, + R.castAs<NonLoc>(), T) : R; } SVal evalBinOp(ProgramStateRef ST, BinaryOperator::Opcode Op, @@ -447,6 +471,20 @@ protected: SVal location, SVal Val, bool atDeclInit = false, const ProgramPoint *PP = 0); + /// Call PointerEscape callback when a value escapes as a result of bind. + ProgramStateRef processPointerEscapedOnBind(ProgramStateRef State, + SVal Loc, SVal Val); + /// Call PointerEscape callback when a value escapes as a result of + /// region invalidation. + /// \param[in] IsConst Specifies that the pointer is const. + ProgramStateRef notifyCheckersOfPointerEscape( + ProgramStateRef State, + const InvalidatedSymbols *Invalidated, + ArrayRef<const MemRegion *> ExplicitRegions, + ArrayRef<const MemRegion *> Regions, + const CallEvent *Call, + bool IsConst); + public: // FIXME: 'tag' should be removed, and a LocationContext should be used // instead. @@ -506,7 +544,10 @@ private: void examineStackFrames(const Decl *D, const LocationContext *LCtx, bool &IsRecursive, unsigned &StackDepth); - bool shouldInlineDecl(const Decl *D, ExplodedNode *Pred); + /// Checks our policies and decides weither the given call should be inlined. + bool shouldInlineCall(const CallEvent &Call, const Decl *D, + const ExplodedNode *Pred); + bool inlineCall(const CallEvent &Call, const Decl *D, NodeBuilder &Bldr, ExplodedNode *Pred, ProgramStateRef State); @@ -522,6 +563,22 @@ private: ExplodedNode *Pred); bool replayWithoutInlining(ExplodedNode *P, const LocationContext *CalleeLC); + + /// Models a trivial copy or move constructor or trivial assignment operator + /// call with a simple bind. + void performTrivialCopy(NodeBuilder &Bldr, ExplodedNode *Pred, + const CallEvent &Call); + + /// If the value of the given expression is a NonLoc, copy it into a new + /// temporary object region, and replace the value of the expression with + /// that. + /// + /// If \p ResultE is provided, the new region will be bound to this expression + /// instead of \p E. + ProgramStateRef createTemporaryRegionIfNeeded(ProgramStateRef State, + const LocationContext *LC, + const Expr *E, + const Expr *ResultE = 0); }; /// Traits for storing the call processing policy inside GDM. @@ -531,7 +588,7 @@ private: struct ReplayWithoutInlining{}; template <> struct ProgramStateTrait<ReplayWithoutInlining> : - public ProgramStatePartialTrait<void*> { + public ProgramStatePartialTrait<const void*> { static void *GDMIndex() { static int index = 0; return &index; } }; diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h b/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h index cf4a692..169af93 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h @@ -7,94 +7,126 @@ // //===----------------------------------------------------------------------===// // -// This file defines a summary of a function gathered/used by static analyzes. +// This file defines a summary of a function gathered/used by static analysis. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_GR_FUNCTIONSUMMARY_H #define LLVM_CLANG_GR_FUNCTIONSUMMARY_H -#include <deque> -#include "clang/AST/Decl.h" +#include "clang/Basic/LLVM.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" -#include "llvm/ADT/BitVector.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/SmallBitVector.h" +#include <deque> namespace clang { +class Decl; + namespace ento { typedef std::deque<Decl*> SetOfDecls; typedef llvm::DenseSet<const Decl*> SetOfConstDecls; class FunctionSummariesTy { - struct FunctionSummary { - /// True if this function has reached a max block count while inlined from - /// at least one call site. - bool MayReachMaxBlockCount; + class FunctionSummary { + public: + /// Marks the IDs of the basic blocks visited during the analyzes. + llvm::SmallBitVector VisitedBasicBlocks; /// Total number of blocks in the function. - unsigned TotalBasicBlocks; + unsigned TotalBasicBlocks : 30; - /// Marks the IDs of the basic blocks visited during the analyzes. - llvm::BitVector VisitedBasicBlocks; + /// True if this function has been checked against the rules for which + /// functions may be inlined. + unsigned InlineChecked : 1; + + /// True if this function may be inlined. + unsigned MayInline : 1; + + /// The number of times the function has been inlined. + unsigned TimesInlined : 32; FunctionSummary() : - MayReachMaxBlockCount(false), TotalBasicBlocks(0), - VisitedBasicBlocks(0) {} + InlineChecked(0), + TimesInlined(0) {} }; - typedef llvm::DenseMap<const Decl*, FunctionSummary*> MapTy; + typedef llvm::DenseMap<const Decl *, FunctionSummary> MapTy; MapTy Map; public: - ~FunctionSummariesTy(); - MapTy::iterator findOrInsertSummary(const Decl *D) { MapTy::iterator I = Map.find(D); if (I != Map.end()) return I; - FunctionSummary *DS = new FunctionSummary(); - I = Map.insert(std::pair<const Decl*, FunctionSummary*>(D, DS)).first; + + typedef std::pair<const Decl *, FunctionSummary> KVPair; + I = Map.insert(KVPair(D, FunctionSummary())).first; assert(I != Map.end()); return I; } - void markReachedMaxBlockCount(const Decl* D) { + void markMayInline(const Decl *D) { MapTy::iterator I = findOrInsertSummary(D); - I->second->MayReachMaxBlockCount = true; + I->second.InlineChecked = 1; + I->second.MayInline = 1; } - bool hasReachedMaxBlockCount(const Decl* D) { - MapTy::const_iterator I = Map.find(D); - if (I != Map.end()) - return I->second->MayReachMaxBlockCount; - return false; + void markShouldNotInline(const Decl *D) { + MapTy::iterator I = findOrInsertSummary(D); + I->second.InlineChecked = 1; + I->second.MayInline = 0; + } + + void markReachedMaxBlockCount(const Decl *D) { + markShouldNotInline(D); + } + + Optional<bool> mayInline(const Decl *D) { + MapTy::const_iterator I = Map.find(D); + if (I != Map.end() && I->second.InlineChecked) + return I->second.MayInline; + return None; } void markVisitedBasicBlock(unsigned ID, const Decl* D, unsigned TotalIDs) { MapTy::iterator I = findOrInsertSummary(D); - llvm::BitVector &Blocks = I->second->VisitedBasicBlocks; + llvm::SmallBitVector &Blocks = I->second.VisitedBasicBlocks; assert(ID < TotalIDs); if (TotalIDs > Blocks.size()) { Blocks.resize(TotalIDs); - I->second->TotalBasicBlocks = TotalIDs; + I->second.TotalBasicBlocks = TotalIDs; } - Blocks[ID] = true; + Blocks.set(ID); } unsigned getNumVisitedBasicBlocks(const Decl* D) { MapTy::const_iterator I = Map.find(D); - if (I != Map.end()) - return I->second->VisitedBasicBlocks.count(); + if (I != Map.end()) + return I->second.VisitedBasicBlocks.count(); return 0; } + unsigned getNumTimesInlined(const Decl* D) { + MapTy::const_iterator I = Map.find(D); + if (I != Map.end()) + return I->second.TimesInlined; + return 0; + } + + void bumpNumTimesInlined(const Decl* D) { + MapTy::iterator I = findOrInsertSummary(D); + I->second.TimesInlined++; + } + /// Get the percentage of the reachable blocks. unsigned getPercentBlocksReachable(const Decl *D) { MapTy::const_iterator I = Map.find(D); if (I != Map.end()) - return ((I->second->VisitedBasicBlocks.count() * 100) / - I->second->TotalBasicBlocks); + return ((I->second.VisitedBasicBlocks.count() * 100) / + I->second.TotalBasicBlocks); return 0; } diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h index 34fbc3c..af2f365 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h @@ -22,8 +22,8 @@ #include "clang/AST/ExprObjC.h" #include "clang/Basic/LLVM.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" -#include "llvm/Support/ErrorHandling.h" #include "llvm/ADT/FoldingSet.h" +#include "llvm/Support/ErrorHandling.h" #include <string> namespace llvm { @@ -642,26 +642,20 @@ public: explicit referenced_vars_iterator(const MemRegion * const *r, const MemRegion * const *originalR) : R(r), OriginalR(originalR) {} - - operator const MemRegion * const *() const { - return R; - } - - const MemRegion *getCapturedRegion() const { - return *R; - } - const MemRegion *getOriginalRegion() const { - return *OriginalR; - } - const VarRegion* operator*() const { + const VarRegion *getCapturedRegion() const { return cast<VarRegion>(*R); } - + const VarRegion *getOriginalRegion() const { + return cast<VarRegion>(*OriginalR); + } + bool operator==(const referenced_vars_iterator &I) const { + assert((R == 0) == (I.R == 0)); return I.R == R; } bool operator!=(const referenced_vars_iterator &I) const { + assert((R == 0) == (I.R == 0)); return I.R != R; } referenced_vars_iterator &operator++() { @@ -670,6 +664,10 @@ public: return *this; } }; + + /// Return the original region for a captured region, if + /// one exists. + const VarRegion *getOriginalRegion(const VarRegion *VR) const; referenced_vars_iterator referenced_vars_begin() const; referenced_vars_iterator referenced_vars_end() const; @@ -686,6 +684,8 @@ public: } private: void LazyInitializeReferencedVars(); + std::pair<const VarRegion *, const VarRegion *> + getCaptureRegions(const VarDecl *VD); }; /// SymbolicRegion - A special, "non-concrete" region. Unlike other region @@ -952,6 +952,9 @@ public: const ObjCIvarDecl *getDecl() const; QualType getValueType() const; + bool canPrintPretty() const; + void printPretty(raw_ostream &os) const; + void dumpToStream(raw_ostream &os) const; static bool classof(const MemRegion* R) { @@ -993,8 +996,8 @@ class ElementRegion : public TypedValueRegion { ElementRegion(QualType elementType, NonLoc Idx, const MemRegion* sReg) : TypedValueRegion(sReg, ElementRegionKind), ElementType(elementType), Index(Idx) { - assert((!isa<nonloc::ConcreteInt>(&Idx) || - cast<nonloc::ConcreteInt>(&Idx)->getValue().isSigned()) && + assert((!Idx.getAs<nonloc::ConcreteInt>() || + Idx.castAs<nonloc::ConcreteInt>().getValue().isSigned()) && "The index must be signed"); } @@ -1057,16 +1060,18 @@ public: class CXXBaseObjectRegion : public TypedValueRegion { friend class MemRegionManager; - const CXXRecordDecl *decl; + llvm::PointerIntPair<const CXXRecordDecl *, 1, bool> Data; - CXXBaseObjectRegion(const CXXRecordDecl *d, const MemRegion *sReg) - : TypedValueRegion(sReg, CXXBaseObjectRegionKind), decl(d) {} + CXXBaseObjectRegion(const CXXRecordDecl *RD, bool IsVirtual, + const MemRegion *SReg) + : TypedValueRegion(SReg, CXXBaseObjectRegionKind), Data(RD, IsVirtual) {} - static void ProfileRegion(llvm::FoldingSetNodeID &ID, - const CXXRecordDecl *decl, const MemRegion *sReg); + static void ProfileRegion(llvm::FoldingSetNodeID &ID, const CXXRecordDecl *RD, + bool IsVirtual, const MemRegion *SReg); public: - const CXXRecordDecl *getDecl() const { return decl; } + const CXXRecordDecl *getDecl() const { return Data.getPointer(); } + bool isVirtual() const { return Data.getInt(); } QualType getValueType() const; @@ -1216,15 +1221,21 @@ public: const CXXTempObjectRegion *getCXXTempObjectRegion(Expr const *Ex, LocationContext const *LC); - const CXXBaseObjectRegion *getCXXBaseObjectRegion(const CXXRecordDecl *decl, - const MemRegion *superRegion); + /// Create a CXXBaseObjectRegion with the given base class for region + /// \p Super. + /// + /// The type of \p Super is assumed be a class deriving from \p BaseClass. + const CXXBaseObjectRegion * + getCXXBaseObjectRegion(const CXXRecordDecl *BaseClass, const MemRegion *Super, + bool IsVirtual); /// Create a CXXBaseObjectRegion with the same CXXRecordDecl but a different /// super region. const CXXBaseObjectRegion * getCXXBaseObjectRegionWithSuper(const CXXBaseObjectRegion *baseReg, const MemRegion *superRegion) { - return getCXXBaseObjectRegion(baseReg->getDecl(), superRegion); + return getCXXBaseObjectRegion(baseReg->getDecl(), superRegion, + baseReg->isVirtual()); } const FunctionTextRegion *getFunctionTextRegion(const NamedDecl *FD); diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h index 86c94de..6ea7211 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h @@ -18,13 +18,13 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h" #include "clang/StaticAnalyzer/Core/PathSensitive/Environment.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h" #include "clang/StaticAnalyzer/Core/PathSensitive/TaintTag.h" -#include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/ImmutableMap.h" +#include "llvm/ADT/PointerIntPair.h" namespace llvm { class APSInt; @@ -170,19 +170,30 @@ public: // If no new state is feasible, NULL is returned. // + /// Assumes that the value of \p cond is zero (if \p assumption is "false") + /// or non-zero (if \p assumption is "true"). + /// + /// This returns a new state with the added constraint on \p cond. + /// If no new state is feasible, NULL is returned. ProgramStateRef assume(DefinedOrUnknownSVal cond, bool assumption) const; - /// This method assumes both "true" and "false" for 'cond', and - /// returns both corresponding states. It's shorthand for doing - /// 'assume' twice. - std::pair<ProgramStateRef , ProgramStateRef > + /// Assumes both "true" and "false" for \p cond, and returns both + /// corresponding states (respectively). + /// + /// This is more efficient than calling assume() twice. Note that one (but not + /// both) of the returned states may be NULL. + std::pair<ProgramStateRef, ProgramStateRef> assume(DefinedOrUnknownSVal cond) const; ProgramStateRef assumeInBound(DefinedOrUnknownSVal idx, DefinedOrUnknownSVal upperBound, bool assumption, QualType IndexType = QualType()) const; - + + /// \brief Check if the given SVal is constrained to zero or is a zero + /// constant. + ConditionTruthVal isNull(SVal V) const; + /// Utility method for getting regions. const VarRegion* getRegion(const VarDecl *D, const LocationContext *LC) const; @@ -203,12 +214,6 @@ public: ProgramStateRef BindExpr(const Stmt *S, const LocationContext *LCtx, SVal V, bool Invalidate = true) const; - /// Create a new state by binding the value 'V' and location 'locaton' to the - /// statement 'S' in the state's environment. - ProgramStateRef bindExprAndLocation(const Stmt *S, - const LocationContext *LCtx, - SVal location, SVal V) const; - ProgramStateRef bindLoc(Loc location, SVal V, bool notifyChanges = true) const; @@ -219,14 +224,38 @@ public: ProgramStateRef killBinding(Loc LV) const; - /// invalidateRegions - Returns the state with bindings for the given regions - /// cleared from the store. The regions are provided as a continuous array - /// from Begin to End. Optionally invalidates global regions as well. - ProgramStateRef invalidateRegions(ArrayRef<const MemRegion *> Regions, - const Expr *E, unsigned BlockCount, - const LocationContext *LCtx, - StoreManager::InvalidatedSymbols *IS = 0, - const CallEvent *Call = 0) const; + /// \brief Returns the state with bindings for the given regions + /// cleared from the store. + /// + /// Optionally invalidates global regions as well. + /// + /// \param Regions the set of regions to be invalidated. + /// \param E the expression that caused the invalidation. + /// \param BlockCount The number of times the current basic block has been + // visited. + /// \param CausesPointerEscape the flag is set to true when + /// the invalidation entails escape of a symbol (representing a + /// pointer). For example, due to it being passed as an argument in a + /// call. + /// \param IS the set of invalidated symbols. + /// \param Call if non-null, the invalidated regions represent parameters to + /// the call and should be considered directly invalidated. + /// \param ConstRegions the set of regions whose contents are accessible, + /// even though the regions themselves should not be invalidated. + ProgramStateRef + invalidateRegions(ArrayRef<const MemRegion *> Regions, const Expr *E, + unsigned BlockCount, const LocationContext *LCtx, + bool CausesPointerEscape, InvalidatedSymbols *IS = 0, + const CallEvent *Call = 0, + ArrayRef<const MemRegion *> ConstRegions = + ArrayRef<const MemRegion *>()) const; + + ProgramStateRef + invalidateRegions(ArrayRef<SVal> Regions, const Expr *E, + unsigned BlockCount, const LocationContext *LCtx, + bool CausesPointerEscape, InvalidatedSymbols *IS = 0, + const CallEvent *Call = 0, + ArrayRef<SVal> ConstRegions = ArrayRef<SVal>()) const; /// enterStackFrame - Returns the state for entry to the given stack frame, /// preserving the current state. @@ -396,13 +425,17 @@ public: private: friend void ProgramStateRetain(const ProgramState *state); friend void ProgramStateRelease(const ProgramState *state); - - ProgramStateRef - invalidateRegionsImpl(ArrayRef<const MemRegion *> Regions, + + /// \sa invalidateValues() + /// \sa invalidateRegions() + ProgramStateRef + invalidateRegionsImpl(ArrayRef<SVal> Values, const Expr *E, unsigned BlockCount, const LocationContext *LCtx, - StoreManager::InvalidatedSymbols &IS, - const CallEvent *Call) const; + bool ResultsInSymbolEscape, + InvalidatedSymbols &IS, + const CallEvent *Call, + ArrayRef<SVal> ConstValues) const; }; //===----------------------------------------------------------------------===// @@ -611,22 +644,24 @@ inline ProgramStateRef ProgramState::assume(DefinedOrUnknownSVal Cond, bool Assumption) const { if (Cond.isUnknown()) return this; - - return getStateManager().ConstraintMgr->assume(this, cast<DefinedSVal>(Cond), - Assumption); + + return getStateManager().ConstraintMgr + ->assume(this, Cond.castAs<DefinedSVal>(), Assumption); } inline std::pair<ProgramStateRef , ProgramStateRef > ProgramState::assume(DefinedOrUnknownSVal Cond) const { if (Cond.isUnknown()) return std::make_pair(this, this); - - return getStateManager().ConstraintMgr->assumeDual(this, - cast<DefinedSVal>(Cond)); + + return getStateManager().ConstraintMgr + ->assumeDual(this, Cond.castAs<DefinedSVal>()); } inline ProgramStateRef ProgramState::bindLoc(SVal LV, SVal V) const { - return !isa<Loc>(LV) ? this : bindLoc(cast<Loc>(LV), V); + if (Optional<Loc> L = LV.getAs<Loc>()) + return bindLoc(*L, V); + return this; } inline Loc ProgramState::getLValue(const VarDecl *VD, @@ -660,7 +695,7 @@ inline SVal ProgramState::getLValue(const IndirectFieldDecl *D, } inline SVal ProgramState::getLValue(QualType ElementType, SVal Idx, SVal Base) const{ - if (NonLoc *N = dyn_cast<NonLoc>(&Idx)) + if (Optional<NonLoc> N = Idx.getAs<NonLoc>()) return getStateManager().StoreMgr->getLValueElement(ElementType, *N, Base); return UnknownVal(); } diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h index ea2a852..eb52ae4 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h @@ -18,6 +18,8 @@ #ifndef LLVM_CLANG_GR_PROGRAMSTATETRAIT_H #define LLVM_CLANG_GR_PROGRAMSTATETRAIT_H +#include "llvm/Support/DataTypes.h" + namespace llvm { class BumpPtrAllocator; template <typename K, typename D, typename I> class ImmutableMap; @@ -165,7 +167,7 @@ namespace ento { } static inline void *MakeVoidPtr(data_type D) { - return (void*) D.getInternalPointer(); + return const_cast<llvm::ImmutableListImpl<T> *>(D.getInternalPointer()); } static inline context_type MakeContext(void *p) { @@ -221,7 +223,20 @@ namespace ento { } }; -} // end GR namespace + // Partial specialization for const void *. + template <> struct ProgramStatePartialTrait<const void *> { + typedef const void *data_type; + + static inline data_type MakeData(void * const *p) { + return p ? *p : data_type(); + } + + static inline void *MakeVoidPtr(data_type d) { + return const_cast<void *>(d); + } + }; + +} // end ento namespace } // end clang namespace diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h index 5d72e73..f7e49a3 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h @@ -17,11 +17,10 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/Expr.h" -#include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" #include "clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h" #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" namespace clang { @@ -124,7 +123,7 @@ public: ProgramStateManager &getStateManager() { return StateMgr; } QualType getConditionType() const { - return getContext().IntTy; + return Context.getLangOpts().CPlusPlus ? Context.BoolTy : Context.IntTy; } QualType getArrayIndexType() const { diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h index c2134cf..1c5519e 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h @@ -16,8 +16,8 @@ #define LLVM_CLANG_GR_RVALUE_H #include "clang/Basic/LLVM.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h" #include "llvm/ADT/ImmutableList.h" //==------------------------------------------------------------------------==// @@ -33,7 +33,7 @@ class LazyCompoundValData; class ProgramState; class BasicValueFactory; class MemRegion; -class TypedRegion; +class TypedValueRegion; class MemRegionManager; class ProgramStateManager; class SValBuilder; @@ -69,6 +69,29 @@ protected: public: explicit SVal() : Data(0), Kind(0) {} + /// \brief Convert to the specified SVal type, asserting that this SVal is of + /// the desired type. + template<typename T> + T castAs() const { + assert(T::isKind(*this)); + T t; + SVal& sv = t; + sv = *this; + return t; + } + + /// \brief Convert to the specified SVal type, returning None if this SVal is + /// not of the desired type. + template<typename T> + Optional<T> getAs() const { + if (!T::isKind(*this)) + return None; + T t; + SVal& sv = t; + sv = *this; + return t; + } + /// BufferTy - A temporary buffer to hold a set of SVals. typedef SmallVector<SVal,5> BufferTy; @@ -161,29 +184,32 @@ class UndefinedVal : public SVal { public: UndefinedVal() : SVal(UndefinedKind) {} - static inline bool classof(const SVal* V) { - return V->getBaseKind() == UndefinedKind; +private: + friend class SVal; + static bool isKind(const SVal& V) { + return V.getBaseKind() == UndefinedKind; } }; 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; + // We want calling these methods to be a compiler error since they are + // tautologically false. + bool isUndef() const LLVM_DELETED_FUNCTION; + bool isValid() const LLVM_DELETED_FUNCTION; protected: + DefinedOrUnknownSVal() {} explicit DefinedOrUnknownSVal(const void *d, bool isLoc, unsigned ValKind) : SVal(d, isLoc, ValKind) {} explicit DefinedOrUnknownSVal(BaseKind k, void *D = NULL) : SVal(k, D) {} -public: - // Implement isa<T> support. - static inline bool classof(const SVal *V) { - return !V->isUndef(); +private: + friend class SVal; + static bool isKind(const SVal& V) { + return !V.isUndef(); } }; @@ -191,61 +217,79 @@ class UnknownVal : public DefinedOrUnknownSVal { public: explicit UnknownVal() : DefinedOrUnknownSVal(UnknownKind) {} - static inline bool classof(const SVal *V) { - return V->getBaseKind() == UnknownKind; +private: + friend class SVal; + static bool isKind(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; + // We want calling these methods to be a compiler error since they are + // tautologically true/false. + bool isUnknown() const LLVM_DELETED_FUNCTION; + bool isUnknownOrUndef() const LLVM_DELETED_FUNCTION; + bool isValid() const LLVM_DELETED_FUNCTION; protected: + DefinedSVal() {} explicit 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(); +private: + friend class SVal; + static bool isKind(const SVal& V) { + return !V.isUnknownOrUndef(); + } +}; + + +/// \brief Represents an SVal that is guaranteed to not be UnknownVal. +class KnownSVal : public SVal { + KnownSVal() {} + friend class SVal; + static bool isKind(const SVal &V) { + return !V.isUnknown(); } +public: + KnownSVal(const DefinedSVal &V) : SVal(V) {} + KnownSVal(const UndefinedVal &V) : SVal(V) {} }; class NonLoc : public DefinedSVal { protected: + NonLoc() {} explicit NonLoc(unsigned SubKind, const void *d) : DefinedSVal(d, false, SubKind) {} public: void dumpToStream(raw_ostream &Out) const; - // Implement isa<T> support. - static inline bool classof(const SVal* V) { - return V->getBaseKind() == NonLocKind; +private: + friend class SVal; + static bool isKind(const SVal& V) { + return V.getBaseKind() == NonLocKind; } }; class Loc : public DefinedSVal { protected: + Loc() {} explicit Loc(unsigned SubKind, const void *D) : DefinedSVal(const_cast<void*>(D), true, SubKind) {} public: void dumpToStream(raw_ostream &Out) const; - Loc(const Loc& X) : DefinedSVal(X.Data, true, X.getSubKind()) {} - - // Implement isa<T> support. - static inline bool classof(const SVal* V) { - return V->getBaseKind() == LocKind; - } - static inline bool isLocType(QualType T) { return T->isAnyPointerType() || T->isBlockPointerType() || T->isReferenceType(); } + +private: + friend class SVal; + static bool isKind(const SVal& V) { + return V.getBaseKind() == LocKind; + } }; //==------------------------------------------------------------------------==// @@ -266,17 +310,20 @@ public: return (const SymExpr*) Data; } - bool isExpression() { + bool isExpression() const { return !isa<SymbolData>(getSymbol()); } - static inline bool classof(const SVal* V) { - return V->getBaseKind() == NonLocKind && - V->getSubKind() == SymbolValKind; +private: + friend class SVal; + SymbolVal() {} + static bool isKind(const SVal& V) { + return V.getBaseKind() == NonLocKind && + V.getSubKind() == SymbolValKind; } - static inline bool classof(const NonLoc* V) { - return V->getSubKind() == SymbolValKind; + static bool isKind(const NonLoc& V) { + return V.getSubKind() == SymbolValKind; } }; @@ -297,38 +344,40 @@ public: ConcreteInt evalMinus(SValBuilder &svalBuilder) const; - // Implement isa<T> support. - static inline bool classof(const SVal* V) { - return V->getBaseKind() == NonLocKind && - V->getSubKind() == ConcreteIntKind; +private: + friend class SVal; + ConcreteInt() {} + static bool isKind(const SVal& V) { + return V.getBaseKind() == NonLocKind && + V.getSubKind() == ConcreteIntKind; } - static inline bool classof(const NonLoc* V) { - return V->getSubKind() == ConcreteIntKind; + static bool isKind(const NonLoc& V) { + return V.getSubKind() == ConcreteIntKind; } }; class LocAsInteger : public NonLoc { friend class ento::SValBuilder; - explicit LocAsInteger(const std::pair<SVal, uintptr_t>& data) : - NonLoc(LocAsIntegerKind, &data) { - assert (isa<Loc>(data.first)); - } + explicit LocAsInteger(const std::pair<SVal, uintptr_t> &data) + : NonLoc(LocAsIntegerKind, &data) { + assert (data.first.getAs<Loc>()); + } public: Loc getLoc() const { const std::pair<SVal, uintptr_t> *D = static_cast<const std::pair<SVal, uintptr_t> *>(Data); - return cast<Loc>(D->first); + return D->first.castAs<Loc>(); } - const Loc& getPersistentLoc() const { + Loc getPersistentLoc() const { const std::pair<SVal, uintptr_t> *D = static_cast<const std::pair<SVal, uintptr_t> *>(Data); const SVal& V = D->first; - return cast<Loc>(V); + return V.castAs<Loc>(); } unsigned getNumBits() const { @@ -337,14 +386,16 @@ public: return D->second; } - // Implement isa<T> support. - static inline bool classof(const SVal* V) { - return V->getBaseKind() == NonLocKind && - V->getSubKind() == LocAsIntegerKind; +private: + friend class SVal; + LocAsInteger() {} + static bool isKind(const SVal& V) { + return V.getBaseKind() == NonLocKind && + V.getSubKind() == LocAsIntegerKind; } - static inline bool classof(const NonLoc* V) { - return V->getSubKind() == LocAsIntegerKind; + static bool isKind(const NonLoc& V) { + return V.getSubKind() == LocAsIntegerKind; } }; @@ -362,12 +413,15 @@ public: iterator begin() const; iterator end() const; - static bool classof(const SVal* V) { - return V->getBaseKind() == NonLocKind && V->getSubKind() == CompoundValKind; +private: + friend class SVal; + CompoundVal() {} + static bool isKind(const SVal& V) { + return V.getBaseKind() == NonLocKind && V.getSubKind() == CompoundValKind; } - static bool classof(const NonLoc* V) { - return V->getSubKind() == CompoundValKind; + static bool isKind(const NonLoc& V) { + return V.getSubKind() == CompoundValKind; } }; @@ -381,14 +435,17 @@ public: return static_cast<const LazyCompoundValData*>(Data); } const void *getStore() const; - const TypedRegion *getRegion() const; + const TypedValueRegion *getRegion() const; - static bool classof(const SVal *V) { - return V->getBaseKind() == NonLocKind && - V->getSubKind() == LazyCompoundValKind; +private: + friend class SVal; + LazyCompoundVal() {} + static bool isKind(const SVal& V) { + return V.getBaseKind() == NonLocKind && + V.getSubKind() == LazyCompoundValKind; } - static bool classof(const NonLoc *V) { - return V->getSubKind() == LazyCompoundValKind; + static bool isKind(const NonLoc& V) { + return V.getSubKind() == LazyCompoundValKind; } }; @@ -410,12 +467,15 @@ public: return static_cast<const LabelDecl*>(Data); } - static inline bool classof(const SVal* V) { - return V->getBaseKind() == LocKind && V->getSubKind() == GotoLabelKind; +private: + friend class SVal; + GotoLabel() {} + static bool isKind(const SVal& V) { + return V.getBaseKind() == LocKind && V.getSubKind() == GotoLabelKind; } - static inline bool classof(const Loc* V) { - return V->getSubKind() == GotoLabelKind; + static bool isKind(const Loc& V) { + return V.getSubKind() == GotoLabelKind; } }; @@ -434,7 +494,7 @@ public: template <typename REGION> const REGION* getRegionAs() const { - return llvm::dyn_cast<REGION>(getRegion()); + return dyn_cast<REGION>(getRegion()); } inline bool operator==(const MemRegionVal& R) const { @@ -445,14 +505,16 @@ public: return getRegion() != R.getRegion(); } - // Implement isa<T> support. - static inline bool classof(const SVal* V) { - return V->getBaseKind() == LocKind && - V->getSubKind() == MemRegionKind; +private: + friend class SVal; + MemRegionVal() {} + static bool isKind(const SVal& V) { + return V.getBaseKind() == LocKind && + V.getSubKind() == MemRegionKind; } - static inline bool classof(const Loc* V) { - return V->getSubKind() == MemRegionKind; + static bool isKind(const Loc& V) { + return V.getSubKind() == MemRegionKind; } }; @@ -468,19 +530,22 @@ public: 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; +private: + friend class SVal; + ConcreteInt() {} + static bool isKind(const SVal& V) { + return V.getBaseKind() == LocKind && + V.getSubKind() == ConcreteIntKind; } - static inline bool classof(const Loc* V) { - return V->getSubKind() == ConcreteIntKind; + static bool isKind(const Loc& V) { + return V.getSubKind() == ConcreteIntKind; } }; } // end ento::loc namespace -} // end GR namespace + +} // end ento namespace } // end clang namespace @@ -491,6 +556,11 @@ static inline raw_ostream &operator<<(raw_ostream &os, return os; } +template <typename T> struct isPodLike; +template <> struct isPodLike<clang::ento::SVal> { + static const bool value = true; +}; + } // end llvm namespace #endif diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h index 979546b..bbfd579 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h @@ -14,9 +14,9 @@ #ifndef LLVM_CLANG_GR_STORE_H #define LLVM_CLANG_GR_STORE_H -#include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h" #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/Optional.h" @@ -35,6 +35,8 @@ class ProgramState; class ProgramStateManager; class ScanReachableSymbols; +typedef llvm::DenseSet<SymbolRef> InvalidatedSymbols; + class StoreManager { protected: SValBuilder &svalBuilder; @@ -134,7 +136,8 @@ public: SVal evalDerivedToBase(SVal Derived, const CXXBasePath &CastPath); /// Evaluates a derived-to-base cast through a single level of derivation. - SVal evalDerivedToBase(SVal Derived, QualType DerivedPtrType); + SVal evalDerivedToBase(SVal Derived, QualType DerivedPtrType, + bool IsVirtual); /// \brief Evaluates C++ dynamic_cast cast. /// The callback may result in the following 3 scenarios: @@ -168,7 +171,6 @@ public: /// associated with the object is recycled. virtual void decrementReferenceCount(Store store) {} - typedef llvm::DenseSet<SymbolRef> InvalidatedSymbols; typedef SmallVector<const MemRegion *, 8> InvalidatedRegions; /// invalidateRegions - Clears out the specified regions from the store, @@ -176,26 +178,40 @@ public: /// invalidate additional regions that may have changed based on accessing /// the given regions. Optionally, invalidates non-static globals as well. /// \param[in] store The initial store - /// \param[in] Regions The regions to invalidate. + /// \param[in] Values The values to invalidate. + /// \param[in] ConstValues The values to invalidate; these are known to be + /// const, so only regions accesible from them should be invalidated. /// \param[in] E The current statement being evaluated. Used to conjure /// symbols to mark the values of invalidated regions. /// \param[in] Count The current block count. Used to conjure /// symbols to mark the values of invalidated regions. - /// \param[in,out] IS A set to fill with any symbols that are no longer - /// accessible. Pass \c NULL if this information will not be used. /// \param[in] Call The call expression which will be used to determine which /// globals should get invalidated. + /// \param[in,out] IS A set to fill with any symbols that are no longer + /// accessible. Pass \c NULL if this information will not be used. + /// \param[in,out] ConstIS A set to fill with any symbols corresponding to + /// the ConstValues. + /// \param[in,out] InvalidatedTopLevel A vector to fill with regions + //// explicitely being invalidated. Pass \c NULL if this + /// information will not be used. + /// \param[in,out] InvalidatedTopLevelConst A vector to fill with const + //// regions explicitely being invalidated. Pass \c NULL if this + /// information will not be used. /// \param[in,out] Invalidated A vector to fill with any regions being /// invalidated. This should include any regions explicitly invalidated /// even if they do not currently have bindings. Pass \c NULL if this /// information will not be used. virtual StoreRef invalidateRegions(Store store, - ArrayRef<const MemRegion *> Regions, - const Expr *E, unsigned Count, - const LocationContext *LCtx, - InvalidatedSymbols &IS, - const CallEvent *Call, - InvalidatedRegions *Invalidated) = 0; + ArrayRef<SVal> Values, + ArrayRef<SVal> ConstValues, + const Expr *E, unsigned Count, + const LocationContext *LCtx, + const CallEvent *Call, + InvalidatedSymbols &IS, + InvalidatedSymbols &ConstIS, + InvalidatedRegions *InvalidatedTopLevel, + InvalidatedRegions *InvalidatedTopLevelConst, + InvalidatedRegions *Invalidated) = 0; /// enterStackFrame - Let the StoreManager to do something when execution /// engine is about to execute into a callee. diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h index 1e71077..d410063 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h @@ -72,6 +72,15 @@ public: const CFGBlock *DstT, const CFGBlock *DstF) = 0; + /// Called by CoreEngine. Used to processing branching behavior + /// at static initalizers. + virtual void processStaticInitializer(const DeclStmt *DS, + NodeBuilderContext& BuilderCtx, + ExplodedNode *Pred, + ExplodedNodeSet &Dst, + const CFGBlock *DstT, + const CFGBlock *DstF) = 0; + /// Called by CoreEngine. Used to generate successor /// nodes by processing the 'effects' of a computed goto jump. virtual void processIndirectGoto(IndirectGotoNodeBuilder& builder) = 0; @@ -104,7 +113,7 @@ public: /// made to the store. Used to update checkers that track region values. virtual ProgramStateRef processRegionChanges(ProgramStateRef state, - const StoreManager::InvalidatedSymbols *invalidated, + const InvalidatedSymbols *invalidated, ArrayRef<const MemRegion *> ExplicitRegions, ArrayRef<const MemRegion *> Regions, const CallEvent *Call) = 0; @@ -116,6 +125,17 @@ public: return processRegionChanges(state, 0, MR, MR, 0); } + virtual ProgramStateRef + processPointerEscapedOnBind(ProgramStateRef State, SVal Loc, SVal Val) = 0; + + virtual ProgramStateRef + notifyCheckersOfPointerEscape(ProgramStateRef State, + const InvalidatedSymbols *Invalidated, + ArrayRef<const MemRegion *> ExplicitRegions, + ArrayRef<const MemRegion *> Regions, + const CallEvent *Call, + bool IsConst = false) = 0; + /// printState - Called by ProgramStateManager to print checker-specific data. virtual void printState(raw_ostream &Out, ProgramStateRef State, const char *NL, const char *Sep) = 0; diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h index 873f773..56afca2 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h @@ -20,10 +20,10 @@ #include "clang/Analysis/AnalysisContext.h" #include "clang/Basic/LLVM.h" #include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h" -#include "llvm/Support/DataTypes.h" -#include "llvm/ADT/FoldingSet.h" -#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/Support/DataTypes.h" namespace llvm { class BumpPtrAllocator; @@ -96,7 +96,7 @@ public: }; typedef const SymExpr* SymbolRef; -typedef llvm::SmallVector<SymbolRef, 2> SymbolRefSmallVectorTy; +typedef SmallVector<SymbolRef, 2> SymbolRefSmallVectorTy; typedef unsigned SymbolID; /// \brief A symbol representing data which can be stored in a memory location diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h index c274cea..4c58d4b 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h @@ -14,7 +14,11 @@ #ifndef LLVM_CLANG_TAINTMANAGER_H #define LLVM_CLANG_TAINTMANAGER_H +#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" #include "clang/StaticAnalyzer/Core/PathSensitive/TaintTag.h" +#include "llvm/ADT/ImmutableMap.h" namespace clang { namespace ento { diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h b/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h index 51aa753..d12a151 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h @@ -16,7 +16,8 @@ #define LLVM_CLANG_GR_WORKLIST #include "clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h" -#include <cstddef> +#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" +#include <cassert> namespace clang { @@ -24,9 +25,6 @@ class CFGBlock; namespace ento { -class ExplodedNode; -class ExplodedNodeImpl; - class WorkListUnit { ExplodedNode *node; BlockCounter counter; |