diff --git a/examples/wpa/clang-wpa.cpp b/examples/wpa/clang-wpa.cpp index 1caa3b9b68ccfa0a4708c8f1f820946d0e2d5f8e..af3fb6a2d2acfbb994ed1059ee95af96ec966f2f 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 45f1e9369947a45aa921d54dd19fd9894e345523..04672a5f18c6e802976897ff90cfc06e54a97612 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 3f673618cf66717ebb26979ed64d5015addde686..606dd0df6ddc458c6d28b746a4edb5dec1f056c9 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 6e3cd85b996a74cf05303e6998fefe45421c05cc..c69ef70bef4df158d2fe310617d7a7a0ca4cd04c 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 6a12d6304eb4e538be5f4a4a866e116130a73c1c..8f01ab9f7ce07238b795f3f0d6cf43efbba9830a 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 67a2caf06a13bd40a8cafc042567a2058bf56da2..2787976e743f74461cc421125ec6005c7a241dd3 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 535ffe288ce2e0044e5368d6e73615045c43c415..90f479835910fe883c7de128bd044ef42ea78064 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 b86ba3ee8a581ac4982b53aee2803c8e862f4d45..0099d630f164907a05b0506624ba4180d5e3965a 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 538d559c16cd3bee72bd096d95df1fcf92cf40e9..4a7c60d4cc9136093298adf0f40fdd0d598efea7 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 a457b37ee1d5674322fb92b75bb3251d36ff9567..b0be7096615d2f2b6c6c9ff094ffce51f35c014c 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 9e584b56148ccd88b1ba555315cdd38e39dc5176..67b3dfe0b653cba8bec6fcf925e1138fea0bb6f1 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);