diff --git a/clang/include/clang/Analysis/PathSensitive/GRCoreEngine.h b/clang/include/clang/Analysis/PathSensitive/GRCoreEngine.h index e3a723fd637e..d656bc7cfca0 100644 --- a/clang/include/clang/Analysis/PathSensitive/GRCoreEngine.h +++ b/clang/include/clang/Analysis/PathSensitive/GRCoreEngine.h @@ -613,7 +613,8 @@ 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::MakeDFS()), + : GRCoreEngineImpl(new GraphTy(cfg, cd, ctx), + GRWorkList::MakeBFSBlockDFSContents()), SubEngine(subengine) {} /// Construct a GRCoreEngine object to analyze the provided CFG and to diff --git a/clang/include/clang/Analysis/PathSensitive/GRWorkList.h b/clang/include/clang/Analysis/PathSensitive/GRWorkList.h index 69178fb9cce3..de7ea5ebd6fb 100644 --- a/clang/include/clang/Analysis/PathSensitive/GRWorkList.h +++ b/clang/include/clang/Analysis/PathSensitive/GRWorkList.h @@ -69,6 +69,7 @@ public: GRBlockCounter getBlockCounter() const { return CurrentCounter; } static GRWorkList* MakeDFS(); + static GRWorkList* MakeBFSBlockDFSContents(); }; } // end clang namespace #endif diff --git a/clang/lib/Analysis/GRCoreEngine.cpp b/clang/lib/Analysis/GRCoreEngine.cpp index 44c9b4871f34..42ea41382eb2 100644 --- a/clang/lib/Analysis/GRCoreEngine.cpp +++ b/clang/lib/Analysis/GRCoreEngine.cpp @@ -18,11 +18,16 @@ #include "llvm/Support/Casting.h" #include "llvm/ADT/DenseMap.h" #include +#include using llvm::cast; using llvm::isa; using namespace clang; +//===----------------------------------------------------------------------===// +// Worklist classes for exploration of reachable states. +//===----------------------------------------------------------------------===// + namespace { class VISIBILITY_HIDDEN DFS : public GRWorkList { llvm::SmallVector Stack; @@ -50,6 +55,48 @@ GRWorkList::~GRWorkList() {} GRWorkList* GRWorkList::MakeDFS() { return new DFS(); } +namespace { + class VISIBILITY_HIDDEN BFSBlockDFSContents : public GRWorkList { + std::queue Queue; + llvm::SmallVector Stack; + public: + virtual bool hasWork() const { + return !Queue.empty() || !Stack.empty(); + } + + virtual void Enqueue(const GRWorkListUnit& U) { + if (isa(U.getNode()->getLocation())) + Queue.push(U); + else + Stack.push_back(U); + } + + virtual GRWorkListUnit Dequeue() { + // Process all basic blocks to completion. + if (!Stack.empty()) { + const GRWorkListUnit& U = Stack.back(); + Stack.pop_back(); // This technically "invalidates" U, but we are fine. + return U; + } + + assert(!Queue.empty()); + // Don't use const reference. The subsequent pop_back() might make it + // unsafe. + GRWorkListUnit U = Queue.front(); + Queue.pop(); + return U; + } + }; +} // end anonymous namespace + +GRWorkList* GRWorkList::MakeBFSBlockDFSContents() { + return new BFSBlockDFSContents(); +} + +//===----------------------------------------------------------------------===// +// Core analysis engine. +//===----------------------------------------------------------------------===// + /// ExecuteWorkList - Run the worklist algorithm for a maximum number of steps. bool GRCoreEngineImpl::ExecuteWorkList(unsigned Steps) { @@ -90,8 +137,7 @@ bool GRCoreEngineImpl::ExecuteWorkList(unsigned Steps) { // Dispatch on the location type. switch (Node->getLocation().getKind()) { - default: - assert (isa(Node->getLocation())); + case ProgramPoint::BlockEdgeKind: HandleBlockEdge(cast(Node->getLocation()), Node); break; @@ -102,9 +148,9 @@ bool GRCoreEngineImpl::ExecuteWorkList(unsigned Steps) { case ProgramPoint::BlockExitKind: assert (false && "BlockExit location never occur in forward analysis."); break; - - case ProgramPoint::PostLoadKind: - case ProgramPoint::PostStmtKind: + + default: + assert(isa(Node->getLocation())); HandlePostStmt(cast(Node->getLocation()), WU.getBlock(), WU.getIndex(), Node); break; @@ -332,6 +378,18 @@ static inline ProgramPoint GetPostLoc(Stmt* S, ProgramPoint::Kind K) { case ProgramPoint::PostLoadKind: return PostLoad(S); + + case ProgramPoint::PostUndefLocationCheckFailedKind: + return PostUndefLocationCheckFailed(S); + + case ProgramPoint::PostLocationChecksSucceedKind: + return PostLocationChecksSucceed(S); + + case ProgramPoint::PostOutOfBoundsCheckFailedKind: + return PostOutOfBoundsCheckFailed(S); + + case ProgramPoint::PostNullCheckFailedKind: + return PostNullCheckFailed(S); case ProgramPoint::PostStoreKind: return PostStore(S);