diff options
-rw-r--r-- | clang/include/clang/Analysis/PathSensitive/GRExprEngine.h | 2 | ||||
-rw-r--r-- | clang/include/clang/Analysis/PathSensitive/GRExprEngineBuilders.h | 100 | ||||
-rw-r--r-- | clang/include/clang/Analysis/PathSensitive/GRTransferFuncs.h | 11 | ||||
-rw-r--r-- | clang/lib/Analysis/CFRefCount.cpp | 66 | ||||
-rw-r--r-- | clang/lib/Analysis/GRExprEngine.cpp | 54 | ||||
-rw-r--r-- | clang/lib/Analysis/GRTransferFuncs.cpp | 19 |
6 files changed, 147 insertions, 105 deletions
diff --git a/clang/include/clang/Analysis/PathSensitive/GRExprEngine.h b/clang/include/clang/Analysis/PathSensitive/GRExprEngine.h index 0150060a286..c2ff5330e4e 100644 --- a/clang/include/clang/Analysis/PathSensitive/GRExprEngine.h +++ b/clang/include/clang/Analysis/PathSensitive/GRExprEngine.h @@ -8,7 +8,7 @@ //===----------------------------------------------------------------------===// // // This file defines a meta-engine for path-sensitive dataflow analysis that -// is built on GREngine, but provides the boilerplate to execute transfer +// is built on GRCoreEngine, but provides the boilerplate to execute transfer // functions and build the ExplodedGraph at the expression level. // //===----------------------------------------------------------------------===// diff --git a/clang/include/clang/Analysis/PathSensitive/GRExprEngineBuilders.h b/clang/include/clang/Analysis/PathSensitive/GRExprEngineBuilders.h new file mode 100644 index 00000000000..074fb2233db --- /dev/null +++ b/clang/include/clang/Analysis/PathSensitive/GRExprEngineBuilders.h @@ -0,0 +1,100 @@ +//===-- GRExprEngineBuilders.h - "Builder" classes for GRExprEngine -*- C++ -*-= +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines smart builder "references" which are used to marshal +// builders between GRExprEngine objects and their related components. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_GREXPRENGINE_BUILDERS +#define LLVM_CLANG_ANALYSIS_GREXPRENGINE_BUILDERS +#include "clang/Analysis/PathSensitive/GRExprEngine.h" + +namespace clang { + + +// SaveAndRestore - A utility class that uses RAII to save and restore +// the value of a variable. +template<typename T> +struct SaveAndRestore { + SaveAndRestore(T& x) : X(x), old_value(x) {} + ~SaveAndRestore() { X = old_value; } + T get() { return old_value; } +private: + T& X; + T old_value; +}; + +// SaveOr - Similar to SaveAndRestore. Operates only on bools; the old +// value of a variable is saved, and during the dstor the old value is +// or'ed with the new value. +struct SaveOr { + SaveOr(bool& x) : X(x), old_value(x) { x = false; } + ~SaveOr() { X |= old_value; } +private: + bool& X; + const bool old_value; +}; + +class GRStmtNodeBuilderRef { + GRExprEngine::NodeSet &Dst; + GRExprEngine::StmtNodeBuilder &B; + GRExprEngine& Eng; + GRExprEngine::NodeTy* Pred; + const GRState* state; + const Stmt* stmt; + const unsigned OldSize; + const bool AutoCreateNode; + SaveAndRestore<bool> OldSink; + SaveOr OldHasGen; + +private: + friend class GRExprEngine; + + GRStmtNodeBuilderRef(); // do not implement + void operator=(const GRStmtNodeBuilderRef&); // do not implement + + GRStmtNodeBuilderRef(GRExprEngine::NodeSet &dst, + GRExprEngine::StmtNodeBuilder &builder, + GRExprEngine& eng, + GRExprEngine::NodeTy* pred, + const GRState *st, + const Stmt* s, bool auto_create_node) + : Dst(dst), B(builder), Eng(eng), Pred(pred), + state(st), stmt(s), OldSize(Dst.size()), AutoCreateNode(auto_create_node), + OldSink(B.BuildSinks), OldHasGen(B.HasGeneratedNode) {} + +public: + + ~GRStmtNodeBuilderRef() { + // Handle the case where no nodes where generated. Auto-generate that + // contains the updated state if we aren't generating sinks. + if (!B.BuildSinks && Dst.size() == OldSize && !B.HasGeneratedNode) { + if (AutoCreateNode) + B.MakeNode(Dst, const_cast<Stmt*>(stmt), Pred, state); + else + Dst.Add(Pred); + } + } + + GRStateRef getState() { + return GRStateRef(state, Eng.getStateManager()); + } + + GRStateManager& getStateManager() { + return Eng.getStateManager(); + } + + GRExprEngine::NodeTy* MakeNode(const GRState* state) { + return B.MakeNode(Dst, const_cast<Stmt*>(stmt), Pred, state); + } +}; + +} // end clang namespace +#endif diff --git a/clang/include/clang/Analysis/PathSensitive/GRTransferFuncs.h b/clang/include/clang/Analysis/PathSensitive/GRTransferFuncs.h index dba42c25156..69a7a12dd28 100644 --- a/clang/include/clang/Analysis/PathSensitive/GRTransferFuncs.h +++ b/clang/include/clang/Analysis/PathSensitive/GRTransferFuncs.h @@ -25,6 +25,7 @@ namespace clang { class GRExprEngine; class BugReporter; class ObjCMessageExpr; + class GRStmtNodeBuilderRef; class GRTransferFuncs { friend class GRExprEngine; @@ -84,15 +85,7 @@ public: // Stores. - /// EvalStore - Evaluate the effects of a store, creating a new node - /// the represents the effect of binding 'Val' to the location 'TargetLV'. - // TargetLV is guaranteed to either be an UnknownVal or an Loc. - virtual void EvalStore(ExplodedNodeSet<GRState>& Dst, - GRExprEngine& Engine, - GRStmtNodeBuilder<GRState>& Builder, - Expr* E, ExplodedNode<GRState>* Pred, - const GRState* St, SVal TargetLV, SVal Val); - + virtual void EvalBind(GRStmtNodeBuilderRef& B, SVal location, SVal val) {} // End-of-path and dead symbol notification. diff --git a/clang/lib/Analysis/CFRefCount.cpp b/clang/lib/Analysis/CFRefCount.cpp index 5d8e4f2badf..875c4e39b88 100644 --- a/clang/lib/Analysis/CFRefCount.cpp +++ b/clang/lib/Analysis/CFRefCount.cpp @@ -15,7 +15,7 @@ #include "GRSimpleVals.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/SourceManager.h" -#include "clang/Analysis/PathSensitive/GRState.h" +#include "clang/Analysis/PathSensitive/GRExprEngineBuilders.h" #include "clang/Analysis/PathSensitive/GRStateTrait.h" #include "clang/Analysis/PathDiagnostic.h" #include "clang/Analysis/LocalCheckers.h" @@ -1360,13 +1360,9 @@ public: ObjCMessageExpr* ME, ExplodedNode<GRState>* Pred); - // Stores. - - virtual void EvalStore(ExplodedNodeSet<GRState>& Dst, - GRExprEngine& Engine, - GRStmtNodeBuilder<GRState>& Builder, - Expr* E, ExplodedNode<GRState>* Pred, - const GRState* St, SVal TargetLV, SVal Val); + // Stores. + virtual void EvalBind(GRStmtNodeBuilderRef& B, SVal location, SVal val); + // End-of-path. virtual void EvalEndPath(GRExprEngine& Engine, @@ -1741,22 +1737,13 @@ void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet<GRState>& Dst, ME->arg_begin(), ME->arg_end(), Pred); } -// Stores. - -void CFRefCount::EvalStore(ExplodedNodeSet<GRState>& Dst, - GRExprEngine& Eng, - GRStmtNodeBuilder<GRState>& Builder, - Expr* E, ExplodedNode<GRState>* Pred, - const GRState* St, SVal TargetLV, SVal Val) { - +void CFRefCount::EvalBind(GRStmtNodeBuilderRef& B, SVal location, SVal val) { // Check if we have a binding for "Val" and if we are storing it to something - // we don't understand or otherwise the value "escapes" the function. - - if (!isa<loc::SymbolVal>(Val)) + // we don't understand or otherwise the value "escapes" the function. + if (!isa<loc::SymbolVal>(val)) return; - // Are we storing to something that causes the value to "escape"? - + // Are we storing to something that causes the value to "escape"? bool escapes = false; // A value escapes in three possible cases (this may change): @@ -1764,44 +1751,35 @@ void CFRefCount::EvalStore(ExplodedNodeSet<GRState>& Dst, // (1) we are binding to something that is not a memory region. // (2) we are binding to a memregion that does not have stack storage // (3) we are binding to a memregion with stack storage that the store - // does not understand. - - SymbolRef Sym = cast<loc::SymbolVal>(Val).getSymbol(); - GRStateRef state(St, Eng.getStateManager()); + // does not understand. + SymbolRef Sym = cast<loc::SymbolVal>(val).getSymbol(); + GRStateRef state = B.getState(); - if (!isa<loc::MemRegionVal>(TargetLV)) + if (!isa<loc::MemRegionVal>(location)) escapes = true; else { - const MemRegion* R = cast<loc::MemRegionVal>(TargetLV).getRegion(); - escapes = !Eng.getStateManager().hasStackStorage(R); + const MemRegion* R = cast<loc::MemRegionVal>(location).getRegion(); + escapes = !B.getStateManager().hasStackStorage(R); if (!escapes) { // To test (3), generate a new state with the binding removed. If it is // the same state, then it escapes (since the store cannot represent // the binding). - GRStateRef stateNew = state.BindLoc(cast<Loc>(TargetLV), Val); - escapes = (stateNew == state); + escapes = (state == (state.BindLoc(cast<Loc>(location), UnknownVal()))); } } - - if (!escapes) - return; - // Do we have a reference count binding? - // FIXME: Is this step even needed? We do blow away the binding anyway. - if (!state.get<RefBindings>(Sym)) + // Our store can represent the binding and we aren't storing to something + // that doesn't have local storage. Just return and have the simulation + // state continue as is. We should also just return if the tracked symbol + // is not associated with a reference count. + if (!escapes || !state.get<RefBindings>(Sym)) return; - - // Nuke the binding. - state = state.remove<RefBindings>(Sym); - // Hand of the remaining logic to the parent implementation. - GRSimpleVals::EvalStore(Dst, Eng, Builder, E, Pred, state, TargetLV, Val); + // The tracked object excapes. Stop tracking the object. + B.MakeNode(state.remove<RefBindings>(Sym)); } -// End-of-path. - - std::pair<GRStateRef,bool> CFRefCount::HandleSymbolDeath(GRStateManager& VMgr, const GRState* St, const Decl* CD, diff --git a/clang/lib/Analysis/GRExprEngine.cpp b/clang/lib/Analysis/GRExprEngine.cpp index a52437c343e..f0e93de2193 100644 --- a/clang/lib/Analysis/GRExprEngine.cpp +++ b/clang/lib/Analysis/GRExprEngine.cpp @@ -14,6 +14,8 @@ //===----------------------------------------------------------------------===// #include "clang/Analysis/PathSensitive/GRExprEngine.h" +#include "clang/Analysis/PathSensitive/GRExprEngineBuilders.h" + #include "clang/Analysis/PathSensitive/BugReporter.h" #include "clang/Basic/SourceManager.h" #include "llvm/Support/Streams.h" @@ -125,28 +127,6 @@ GRExprEngine::~GRExprEngine() { // Utility methods. //===----------------------------------------------------------------------===// -// SaveAndRestore - A utility class that uses RIIA to save and restore -// the value of a variable. -template<typename T> -struct VISIBILITY_HIDDEN SaveAndRestore { - SaveAndRestore(T& x) : X(x), old_value(x) {} - ~SaveAndRestore() { X = old_value; } - T get() { return old_value; } - - T& X; - T old_value; -}; - -// SaveOr - Similar to SaveAndRestore. Operates only on bools; the old -// value of a variable is saved, and during the dstor the old value is -// or'ed with the new value. -struct VISIBILITY_HIDDEN SaveOr { - SaveOr(bool& x) : X(x), old_value(x) { x = false; } - ~SaveOr() { X |= old_value; } - - bool& X; - bool old_value; -}; void GRExprEngine::setTransferFunctions(GRTransferFuncs* tf) { StateMgr.TF = tf; @@ -920,17 +900,27 @@ void GRExprEngine::VisitMemberExpr(MemberExpr* M, NodeTy* Pred, void GRExprEngine::EvalBind(NodeSet& Dst, Expr* Ex, NodeTy* Pred, const GRState* state, SVal location, SVal Val) { - unsigned size = Dst.size(); - SaveAndRestore<bool> OldSink(Builder->BuildSinks); - SaveOr OldHasGen(Builder->HasGeneratedNode); - - getTF().EvalStore(Dst, *this, *Builder, Ex, Pred, state, location, Val); + const GRState* newState = 0; + + if (location.isUnknown()) { + // We know that the new state will be the same as the old state since + // the location of the binding is "unknown". Consequently, there + // is no reason to just create a new node. + newState = state; + } + else { + // We are binding to a value other than 'unknown'. Perform the binding + // using the StoreManager. + newState = StateMgr.BindLoc(state, cast<Loc>(location), Val); + } - // Handle the case where no nodes where generated. Auto-generate that - // contains the updated state if we aren't generating sinks. - if (!Builder->BuildSinks && Dst.size() == size && !Builder->HasGeneratedNode) - getTF().GRTransferFuncs::EvalStore(Dst, *this, *Builder, Ex, Pred, state, - location, Val); + // The next thing to do is check if the GRTransferFuncs object wants to + // update the state based on the new binding. If the GRTransferFunc object + // doesn't do anything, just auto-propagate the current state. + GRStmtNodeBuilderRef BuilderRef(Dst, *Builder, *this, Pred, newState, Ex, + newState != state); + + getTF().EvalBind(BuilderRef, location, Val); } /// EvalStore - Handle the semantics of a store via an assignment. diff --git a/clang/lib/Analysis/GRTransferFuncs.cpp b/clang/lib/Analysis/GRTransferFuncs.cpp index d621edddc6d..c08bd8f0b19 100644 --- a/clang/lib/Analysis/GRTransferFuncs.cpp +++ b/clang/lib/Analysis/GRTransferFuncs.cpp @@ -17,25 +17,6 @@ using namespace clang; -void GRTransferFuncs::EvalStore(ExplodedNodeSet<GRState>& Dst, - GRExprEngine& Eng, - GRStmtNodeBuilder<GRState>& Builder, - Expr* E, ExplodedNode<GRState>* Pred, - const GRState* St, SVal TargetLV, SVal Val) { - - // This code basically matches the "safety-net" logic of GRExprEngine: - // bind Val to TargetLV, and create a new node. We replicate it here - // because subclasses of GRTransferFuncs may wish to call it. - - assert (!TargetLV.isUndef()); - - if (TargetLV.isUnknown()) - Builder.MakeNode(Dst, E, Pred, St); - else - Builder.MakeNode(Dst, E, Pred, - Eng.getStateManager().BindLoc(St, cast<Loc>(TargetLV), Val)); -} - void GRTransferFuncs::EvalBinOpNN(GRStateSet& OStates, GRExprEngine& Eng, const GRState *St, Expr* Ex, |