aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--examples/wpa/clang-wpa.cpp4
-rw-r--r--include/clang/Analysis/AnalysisContext.h10
-rw-r--r--include/clang/Checker/PathSensitive/AnalysisManager.h10
-rw-r--r--include/clang/Checker/PathSensitive/GRCoreEngine.h6
-rw-r--r--include/clang/Checker/PathSensitive/GRExprEngine.h16
-rw-r--r--include/clang/Checker/PathSensitive/GRState.h4
-rw-r--r--include/clang/Checker/PathSensitive/GRSubEngine.h4
-rw-r--r--include/clang/Index/TranslationUnit.h2
-rw-r--r--lib/Analysis/AnalysisContext.cpp2
-rw-r--r--lib/Checker/GRCoreEngine.cpp77
-rw-r--r--lib/Checker/GRState.cpp11
11 files changed, 128 insertions, 18 deletions
diff --git a/examples/wpa/clang-wpa.cpp b/examples/wpa/clang-wpa.cpp
index 1caa3b9b68..af3fb6a2d2 100644
--- a/examples/wpa/clang-wpa.cpp
+++ b/examples/wpa/clang-wpa.cpp
@@ -62,6 +62,10 @@ public:
return AST->getPreprocessor();
}
+ virtual Diagnostic &getDiagnostic() {
+ return AST->getDiagnostics();
+ }
+
virtual DeclReferenceMap &getDeclReferenceMap() {
return DeclRefMap;
}
diff --git a/include/clang/Analysis/AnalysisContext.h b/include/clang/Analysis/AnalysisContext.h
index 45f1e93699..04672a5f18 100644
--- a/include/clang/Analysis/AnalysisContext.h
+++ b/include/clang/Analysis/AnalysisContext.h
@@ -42,7 +42,7 @@ class AnalysisContext {
const Decl *D;
// TranslationUnit is NULL if we don't have multiple translation units.
- const idx::TranslationUnit *TU;
+ idx::TranslationUnit *TU;
// AnalysisContext owns the following data.
CFG *cfg;
@@ -53,7 +53,7 @@ class AnalysisContext {
llvm::BumpPtrAllocator A;
bool AddEHEdges;
public:
- AnalysisContext(const Decl *d, const idx::TranslationUnit *tu,
+ AnalysisContext(const Decl *d, idx::TranslationUnit *tu,
bool addehedges = false)
: D(d), TU(tu), cfg(0), builtCFG(false), liveness(0), PM(0),
ReferencedBlockVars(0), AddEHEdges(addehedges) {}
@@ -63,7 +63,7 @@ public:
ASTContext &getASTContext() { return D->getASTContext(); }
const Decl *getDecl() const { return D; }
- const idx::TranslationUnit *getTranslationUnit() const { return TU; }
+ idx::TranslationUnit *getTranslationUnit() const { return TU; }
/// getAddEHEdges - Return true iff we are adding exceptional edges from
/// callExprs. If this is false, then try/catch statements and blocks
@@ -91,7 +91,7 @@ class AnalysisContextManager {
public:
~AnalysisContextManager();
- AnalysisContext *getContext(const Decl *D,const idx::TranslationUnit *TU = 0);
+ AnalysisContext *getContext(const Decl *D, idx::TranslationUnit *TU = 0);
// Discard all previously created AnalysisContexts.
void clear();
@@ -121,7 +121,7 @@ public:
AnalysisContext *getAnalysisContext() const { return Ctx; }
- const idx::TranslationUnit *getTranslationUnit() const {
+ idx::TranslationUnit *getTranslationUnit() const {
return Ctx->getTranslationUnit();
}
diff --git a/include/clang/Checker/PathSensitive/AnalysisManager.h b/include/clang/Checker/PathSensitive/AnalysisManager.h
index 3f673618cf..606dd0df6d 100644
--- a/include/clang/Checker/PathSensitive/AnalysisManager.h
+++ b/include/clang/Checker/PathSensitive/AnalysisManager.h
@@ -99,6 +99,8 @@ public:
return CreateConstraintMgr;
}
+ idx::Indexer *getIndexer() const { return Idxer; }
+
virtual ASTContext &getASTContext() {
return Ctx;
}
@@ -160,10 +162,14 @@ public:
return AnaCtxMgr.getContext(D)->getParentMap();
}
- const AnalysisContext *getAnalysisContext(const Decl *D) {
+ AnalysisContext *getAnalysisContext(const Decl *D) {
return AnaCtxMgr.getContext(D);
}
+ AnalysisContext *getAnalysisContext(const Decl *D, idx::TranslationUnit *TU) {
+ return AnaCtxMgr.getContext(D, TU);
+ }
+
const StackFrameContext *getStackFrame(AnalysisContext *Ctx,
LocationContext const *Parent,
Stmt const *S, const CFGBlock *Blk,
@@ -173,7 +179,7 @@ public:
// Get the top level stack frame.
const StackFrameContext *getStackFrame(Decl const *D,
- const idx::TranslationUnit *TU) {
+ idx::TranslationUnit *TU) {
return LocCtxMgr.getStackFrame(AnaCtxMgr.getContext(D, TU), 0, 0, 0, 0);
}
diff --git a/include/clang/Checker/PathSensitive/GRCoreEngine.h b/include/clang/Checker/PathSensitive/GRCoreEngine.h
index 6e3cd85b99..c69ef70bef 100644
--- a/include/clang/Checker/PathSensitive/GRCoreEngine.h
+++ b/include/clang/Checker/PathSensitive/GRCoreEngine.h
@@ -153,7 +153,11 @@ public:
/// ExecuteWorkList - Run the worklist algorithm for a maximum number of
/// steps. Returns true if there is still simulation state on the worklist.
- bool ExecuteWorkList(const LocationContext *L, unsigned Steps);
+ bool ExecuteWorkList(const LocationContext *L, unsigned Steps,
+ const GRState *InitState);
+ void ExecuteWorkListWithInitialState(const LocationContext *L, unsigned Steps,
+ const GRState *InitState,
+ ExplodedNodeSet &Dst);
};
class GRStmtNodeBuilder {
diff --git a/include/clang/Checker/PathSensitive/GRExprEngine.h b/include/clang/Checker/PathSensitive/GRExprEngine.h
index 6a12d6304e..8f01ab9f7c 100644
--- a/include/clang/Checker/PathSensitive/GRExprEngine.h
+++ b/include/clang/Checker/PathSensitive/GRExprEngine.h
@@ -114,13 +114,22 @@ public:
~GRExprEngine();
void ExecuteWorkList(const LocationContext *L, unsigned Steps = 150000) {
- CoreEngine.ExecuteWorkList(L, Steps);
+ CoreEngine.ExecuteWorkList(L, Steps, 0);
+ }
+
+ /// Execute the work list with an initial state. Nodes that reaches the exit
+ /// of the function are added into the Dst set, which represent the exit
+ /// state of the function call.
+ void ExecuteWorkListWithInitialState(const LocationContext *L, unsigned Steps,
+ const GRState *InitState,
+ ExplodedNodeSet &Dst) {
+ CoreEngine.ExecuteWorkListWithInitialState(L, Steps, InitState, Dst);
}
/// getContext - Return the ASTContext associated with this analysis.
ASTContext& getContext() const { return AMgr.getASTContext(); }
- AnalysisManager &getAnalysisManager() const { return AMgr; }
+ virtual AnalysisManager &getAnalysisManager() { return AMgr; }
SValuator &getSValuator() { return SVator; }
@@ -204,8 +213,7 @@ public:
/// making assumptions about state values.
const GRState *ProcessAssume(const GRState *state, SVal cond,bool assumption);
- GRStateManager& getStateManager() { return StateMgr; }
- const GRStateManager& getStateManager() const { return StateMgr; }
+ virtual GRStateManager& getStateManager() { return StateMgr; }
StoreManager& getStoreManager() { return StateMgr.getStoreManager(); }
diff --git a/include/clang/Checker/PathSensitive/GRState.h b/include/clang/Checker/PathSensitive/GRState.h
index 67a2caf06a..2787976e74 100644
--- a/include/clang/Checker/PathSensitive/GRState.h
+++ b/include/clang/Checker/PathSensitive/GRState.h
@@ -452,6 +452,10 @@ public:
const StackFrameContext *LCtx,
SymbolReaper& SymReaper);
+ /// Marshal a new state for the callee in another translation unit.
+ /// 'state' is owned by the caller's engine.
+ const GRState *MarshalState(const GRState *state, const LocationContext *L);
+
public:
SVal ArrayToPointer(Loc Array) {
diff --git a/include/clang/Checker/PathSensitive/GRSubEngine.h b/include/clang/Checker/PathSensitive/GRSubEngine.h
index 535ffe288c..90f4798359 100644
--- a/include/clang/Checker/PathSensitive/GRSubEngine.h
+++ b/include/clang/Checker/PathSensitive/GRSubEngine.h
@@ -39,7 +39,9 @@ public:
virtual const GRState* getInitialState(const LocationContext *InitLoc) = 0;
- virtual GRStateManager& getStateManager() = 0;
+ virtual AnalysisManager &getAnalysisManager() = 0;
+
+ virtual GRStateManager &getStateManager() = 0;
/// Called by GRCoreEngine. Used to generate new successor
/// nodes by processing the 'effects' of a block-level statement.
diff --git a/include/clang/Index/TranslationUnit.h b/include/clang/Index/TranslationUnit.h
index b86ba3ee8a..0099d630f1 100644
--- a/include/clang/Index/TranslationUnit.h
+++ b/include/clang/Index/TranslationUnit.h
@@ -16,6 +16,7 @@
namespace clang {
class ASTContext;
+ class Diagnostic;
class Preprocessor;
namespace idx {
@@ -28,6 +29,7 @@ public:
virtual ~TranslationUnit();
virtual ASTContext &getASTContext() = 0;
virtual Preprocessor &getPreprocessor() = 0;
+ virtual Diagnostic &getDiagnostic() = 0;
virtual DeclReferenceMap &getDeclReferenceMap() = 0;
virtual SelectorMap &getSelectorMap() = 0;
};
diff --git a/lib/Analysis/AnalysisContext.cpp b/lib/Analysis/AnalysisContext.cpp
index 538d559c16..4a7c60d4cc 100644
--- a/lib/Analysis/AnalysisContext.cpp
+++ b/lib/Analysis/AnalysisContext.cpp
@@ -84,7 +84,7 @@ LiveVariables *AnalysisContext::getLiveVariables() {
}
AnalysisContext *AnalysisContextManager::getContext(const Decl *D,
- const idx::TranslationUnit *TU) {
+ idx::TranslationUnit *TU) {
AnalysisContext *&AC = Contexts[D];
if (!AC)
AC = new AnalysisContext(D, TU);
diff --git a/lib/Checker/GRCoreEngine.cpp b/lib/Checker/GRCoreEngine.cpp
index a457b37ee1..b0be709661 100644
--- a/lib/Checker/GRCoreEngine.cpp
+++ b/lib/Checker/GRCoreEngine.cpp
@@ -12,8 +12,10 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/Checker/PathSensitive/AnalysisManager.h"
#include "clang/Checker/PathSensitive/GRCoreEngine.h"
#include "clang/Checker/PathSensitive/GRExprEngine.h"
+#include "clang/Index/TranslationUnit.h"
#include "clang/AST/Expr.h"
#include "llvm/Support/Casting.h"
#include "llvm/ADT/DenseMap.h"
@@ -24,6 +26,12 @@ using llvm::cast;
using llvm::isa;
using namespace clang;
+// This should be removed in the future.
+namespace clang {
+GRTransferFuncs* MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled,
+ const LangOptions& lopts);
+}
+
//===----------------------------------------------------------------------===//
// Worklist classes for exploration of reachable states.
//===----------------------------------------------------------------------===//
@@ -120,7 +128,8 @@ GRWorkList* GRWorkList::MakeBFSBlockDFSContents() {
//===----------------------------------------------------------------------===//
/// ExecuteWorkList - Run the worklist algorithm for a maximum number of steps.
-bool GRCoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps) {
+bool GRCoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps,
+ const GRState *InitState) {
if (G->num_roots() == 0) { // Initialize the analysis by constructing
// the root if none exists.
@@ -143,8 +152,11 @@ bool GRCoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps) {
// Set the current block counter to being empty.
WList->setBlockCounter(BCounterFactory.GetEmptyCounter());
- // Generate the root.
- GenerateNode(StartLoc, getInitialState(L), 0);
+ if (!InitState)
+ // Generate the root.
+ GenerateNode(StartLoc, getInitialState(L), 0);
+ else
+ GenerateNode(StartLoc, InitState, 0);
}
while (Steps && WList->hasWork()) {
@@ -192,6 +204,17 @@ bool GRCoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps) {
return WList->hasWork();
}
+void GRCoreEngine::ExecuteWorkListWithInitialState(const LocationContext *L,
+ unsigned Steps,
+ const GRState *InitState,
+ ExplodedNodeSet &Dst) {
+ ExecuteWorkList(L, Steps, InitState);
+ for (llvm::SmallVectorImpl<ExplodedNode*>::iterator I = G->EndNodes.begin(),
+ E = G->EndNodes.end(); I != E; ++I) {
+ Dst.Add(*I);
+ }
+}
+
void GRCoreEngine::HandleCallEnter(const CallEnter &L, const CFGBlock *Block,
unsigned Index, ExplodedNode *Pred) {
GRCallEnterNodeBuilder Builder(*this, Pred, L.getCallExpr(),
@@ -662,7 +685,53 @@ void GRCallEnterNodeBuilder::GenerateNode(const GRState *state,
// Check if the callee is in the same translation unit.
if (CalleeCtx->getTranslationUnit() !=
Pred->getLocationContext()->getTranslationUnit()) {
- assert(0 && "to be implemented");
+ // Create a new engine. We must be careful that the new engine should not
+ // reference data structures owned by the old engine.
+
+ AnalysisManager &OldMgr = Eng.SubEngine.getAnalysisManager();
+
+ // Get the callee's translation unit.
+ idx::TranslationUnit *TU = CalleeCtx->getTranslationUnit();
+
+ // Create a new AnalysisManager with components of the callee's
+ // TranslationUnit.
+ // The Diagnostic is actually shared when we create ASTUnits from PCH files.
+ AnalysisManager AMgr(TU->getASTContext(), TU->getDiagnostic(),
+ OldMgr.getLangOptions(),
+ OldMgr.getPathDiagnosticClient(),
+ OldMgr.getStoreManagerCreator(),
+ OldMgr.getConstraintManagerCreator(),
+ OldMgr.getIndexer(),
+ OldMgr.getMaxNodes(), OldMgr.getMaxLoop(),
+ OldMgr.shouldVisualizeGraphviz(),
+ OldMgr.shouldVisualizeUbigraph(),
+ OldMgr.shouldPurgeDead(),
+ OldMgr.shouldEagerlyAssume(),
+ OldMgr.shouldTrimGraph(),
+ OldMgr.shouldInlineCall());
+ llvm::OwningPtr<GRTransferFuncs> TF(MakeCFRefCountTF(AMgr.getASTContext(),
+ /* GCEnabled */ false,
+ AMgr.getLangOptions()));
+ // Create the new engine.
+ GRExprEngine NewEng(AMgr, TF.take());
+
+ // Create the new LocationContext.
+ AnalysisContext *NewAnaCtx = AMgr.getAnalysisContext(CalleeCtx->getDecl(),
+ CalleeCtx->getTranslationUnit());
+ const StackFrameContext *OldLocCtx = cast<StackFrameContext>(LocCtx);
+ const StackFrameContext *NewLocCtx = AMgr.getStackFrame(NewAnaCtx,
+ OldLocCtx->getParent(),
+ OldLocCtx->getCallSite(),
+ OldLocCtx->getCallSiteBlock(),
+ OldLocCtx->getIndex());
+
+ // Now create an initial state for the new engine.
+ const GRState *NewState = NewEng.getStateManager().MarshalState(state,
+ NewLocCtx);
+ ExplodedNodeSet ReturnNodes;
+ NewEng.ExecuteWorkListWithInitialState(NewLocCtx, AMgr.getMaxNodes(),
+ NewState, ReturnNodes);
+ return;
}
// Get the callee entry block.
diff --git a/lib/Checker/GRState.cpp b/lib/Checker/GRState.cpp
index 9e584b5614..67b3dfe0b6 100644
--- a/lib/Checker/GRState.cpp
+++ b/lib/Checker/GRState.cpp
@@ -57,6 +57,17 @@ GRStateManager::RemoveDeadBindings(const GRState* state,
return ConstraintMgr->RemoveDeadBindings(s, SymReaper);
}
+const GRState *GRStateManager::MarshalState(const GRState *state,
+ const LocationContext *InitLoc) {
+ // make up an empty state for now.
+ GRState State(this,
+ EnvMgr.getInitialEnvironment(),
+ StoreMgr->getInitialStore(InitLoc),
+ GDMFactory.GetEmptyMap());
+
+ return getPersistentState(State);
+}
+
const GRState *GRState::unbindLoc(Loc LV) const {
Store OldStore = getStore();
Store NewStore = getStateManager().StoreMgr->Remove(OldStore, LV);