diff options
author | Roman Divacky <rdivacky@FreeBSD.org> | 2010-07-13 17:21:42 +0000 |
---|---|---|
committer | Roman Divacky <rdivacky@FreeBSD.org> | 2010-07-13 17:21:42 +0000 |
commit | 4ba675006b5a8edfc48b6a9bd3dcf54a70cc08f2 (patch) | |
tree | 48b44512b5db8ced345df4a1a56b5065cf2a14d9 /include/clang/Checker/PathSensitive | |
parent | d7279c4c177bca357ef96ff1379fd9bc420bfe83 (diff) |
Notes
Diffstat (limited to 'include/clang/Checker/PathSensitive')
-rw-r--r-- | include/clang/Checker/PathSensitive/Checker.h | 30 | ||||
-rw-r--r-- | include/clang/Checker/PathSensitive/CheckerVisitor.h | 9 | ||||
-rw-r--r-- | include/clang/Checker/PathSensitive/Environment.h | 2 | ||||
-rw-r--r-- | include/clang/Checker/PathSensitive/ExplodedGraph.h | 10 | ||||
-rw-r--r-- | include/clang/Checker/PathSensitive/GRCoreEngine.h | 18 | ||||
-rw-r--r-- | include/clang/Checker/PathSensitive/GRExprEngine.h | 31 | ||||
-rw-r--r-- | include/clang/Checker/PathSensitive/GRState.h | 27 | ||||
-rw-r--r-- | include/clang/Checker/PathSensitive/GRSubEngine.h | 28 | ||||
-rw-r--r-- | include/clang/Checker/PathSensitive/GRTransferFuncs.h | 2 | ||||
-rw-r--r-- | include/clang/Checker/PathSensitive/MemRegion.h | 77 | ||||
-rw-r--r-- | include/clang/Checker/PathSensitive/SVals.h | 4 | ||||
-rw-r--r-- | include/clang/Checker/PathSensitive/SValuator.h | 8 | ||||
-rw-r--r-- | include/clang/Checker/PathSensitive/Store.h | 31 | ||||
-rw-r--r-- | include/clang/Checker/PathSensitive/SymbolManager.h | 43 |
14 files changed, 224 insertions, 96 deletions
diff --git a/include/clang/Checker/PathSensitive/Checker.h b/include/clang/Checker/PathSensitive/Checker.h index 8cb9cc8337c6a..49dc3fa7dc44e 100644 --- a/include/clang/Checker/PathSensitive/Checker.h +++ b/include/clang/Checker/PathSensitive/Checker.h @@ -38,16 +38,20 @@ class CheckerContext { const unsigned size; bool DoneEvaluating; // FIXME: This is not a permanent API change. public: + bool *respondsToCallback; +public: CheckerContext(ExplodedNodeSet &dst, GRStmtNodeBuilder &builder, GRExprEngine &eng, ExplodedNode *pred, const void *tag, ProgramPoint::Kind K, + bool *respondsToCB = 0, const Stmt *stmt = 0, const GRState *st = 0) : Dst(dst), B(builder), Eng(eng), Pred(pred), OldSink(B.BuildSinks), OldTag(B.Tag, tag), OldPointKind(B.PointKind, K), OldHasGen(B.HasGeneratedNode), - ST(st), statement(stmt), size(Dst.size()) {} + ST(st), statement(stmt), size(Dst.size()), + respondsToCallback(respondsToCB) {} ~CheckerContext(); @@ -144,6 +148,7 @@ public: // If the 'state' is not new, we need to check if the cached state 'ST' // is new. if (state != getState() || (ST && ST != B.GetState(Pred))) + // state is new or equals to ST. GenerateNode(state, true); else Dst.Add(Pred); @@ -188,10 +193,11 @@ private: GRStmtNodeBuilder &Builder, GRExprEngine &Eng, const Stmt *S, - ExplodedNode *Pred, void *tag, bool isPrevisit) { + ExplodedNode *Pred, void *tag, bool isPrevisit, + bool& respondsToCallback) { CheckerContext C(Dst, Builder, Eng, Pred, tag, isPrevisit ? ProgramPoint::PreStmtKind : - ProgramPoint::PostStmtKind, S); + ProgramPoint::PostStmtKind, &respondsToCallback, S); if (isPrevisit) _PreVisit(C, S); else @@ -202,7 +208,7 @@ private: GRExprEngine &Eng, const ObjCMessageExpr *ME, ExplodedNode *Pred, const GRState *state, void *tag) { CheckerContext C(Dst, Builder, Eng, Pred, tag, ProgramPoint::PostStmtKind, - ME, state); + 0, ME, state); return EvalNilReceiver(C, ME); } @@ -210,7 +216,7 @@ private: GRExprEngine &Eng, const CallExpr *CE, ExplodedNode *Pred, void *tag) { CheckerContext C(Dst, Builder, Eng, Pred, tag, ProgramPoint::PostStmtKind, - CE); + 0, CE); return EvalCallExpr(C, CE); } @@ -223,7 +229,7 @@ private: bool isPrevisit) { CheckerContext C(Dst, Builder, Eng, Pred, tag, isPrevisit ? ProgramPoint::PreStmtKind : - ProgramPoint::PostStmtKind, StoreE); + ProgramPoint::PostStmtKind, 0, StoreE); assert(isPrevisit && "Only previsit supported for now."); PreVisitBind(C, AssignE, StoreE, location, val); } @@ -238,7 +244,7 @@ private: void *tag, bool isLoad) { CheckerContext C(Dst, Builder, Eng, Pred, tag, isLoad ? ProgramPoint::PreLoadKind : - ProgramPoint::PreStoreKind, S, state); + ProgramPoint::PreStoreKind, 0, S, state); VisitLocation(C, S, location); } @@ -246,8 +252,8 @@ private: GRExprEngine &Eng, const Stmt *S, ExplodedNode *Pred, SymbolReaper &SymReaper, void *tag) { CheckerContext C(Dst, Builder, Eng, Pred, tag, - ProgramPoint::PostPurgeDeadSymbolsKind, S); - EvalDeadSymbols(C, S, SymReaper); + ProgramPoint::PostPurgeDeadSymbolsKind, 0, S); + EvalDeadSymbols(C, SymReaper); } public: @@ -257,8 +263,7 @@ public: virtual void VisitLocation(CheckerContext &C, const Stmt *S, SVal location) {} virtual void PreVisitBind(CheckerContext &C, const Stmt *AssignE, const Stmt *StoreE, SVal location, SVal val) {} - virtual void EvalDeadSymbols(CheckerContext &C, const Stmt *S, - SymbolReaper &SymReaper) {} + virtual void EvalDeadSymbols(CheckerContext &C, SymbolReaper &SymReaper) {} virtual void EvalEndPath(GREndPathNodeBuilder &B, void *tag, GRExprEngine &Eng) {} @@ -278,6 +283,9 @@ public: bool Assumption) { return state; } + + virtual void VisitEndAnalysis(ExplodedGraph &G, BugReporter &B, + bool hasWorkRemaining) {} }; } // end clang namespace diff --git a/include/clang/Checker/PathSensitive/CheckerVisitor.h b/include/clang/Checker/PathSensitive/CheckerVisitor.h index 72f0ae1375e89..e2ba89bca1b86 100644 --- a/include/clang/Checker/PathSensitive/CheckerVisitor.h +++ b/include/clang/Checker/PathSensitive/CheckerVisitor.h @@ -79,8 +79,13 @@ break; } } - void PreVisitStmt(CheckerContext &C, const Stmt *S) {} - void PostVisitStmt(CheckerContext &C, const Stmt *S) {} + void PreVisitStmt(CheckerContext &C, const Stmt *S) { + *C.respondsToCallback = false; + } + + void PostVisitStmt(CheckerContext &C, const Stmt *S) { + *C.respondsToCallback = false; + } void PreVisitCastExpr(CheckerContext &C, const CastExpr *E) { static_cast<ImplClass*>(this)->PreVisitStmt(C, E); diff --git a/include/clang/Checker/PathSensitive/Environment.h b/include/clang/Checker/PathSensitive/Environment.h index b9bbebc652f24..2981731f863c6 100644 --- a/include/clang/Checker/PathSensitive/Environment.h +++ b/include/clang/Checker/PathSensitive/Environment.h @@ -86,7 +86,7 @@ public: Environment BindExpr(Environment Env, const Stmt *S, SVal V, bool Invalidate); - Environment RemoveDeadBindings(Environment Env, const Stmt *S, + Environment RemoveDeadBindings(Environment Env, SymbolReaper &SymReaper, const GRState *ST, llvm::SmallVectorImpl<const MemRegion*>& RegionRoots); }; diff --git a/include/clang/Checker/PathSensitive/ExplodedGraph.h b/include/clang/Checker/PathSensitive/ExplodedGraph.h index c09c89312e106..c875a2308ba38 100644 --- a/include/clang/Checker/PathSensitive/ExplodedGraph.h +++ b/include/clang/Checker/PathSensitive/ExplodedGraph.h @@ -36,7 +36,6 @@ namespace clang { class GRState; class CFG; -class ASTContext; class ExplodedGraph; //===----------------------------------------------------------------------===// @@ -240,9 +239,6 @@ protected: /// and successor groups. BumpVectorContext BVC; - /// Ctx - The ASTContext used to "interpret" CodeDecl. - ASTContext& Ctx; - /// NumNodes - The number of nodes in the graph. unsigned NumNodes; @@ -256,7 +252,7 @@ public: bool* IsNew = 0); ExplodedGraph* MakeEmptyGraph() const { - return new ExplodedGraph(Ctx); + return new ExplodedGraph(); } /// addRoot - Add an untyped node to the set of roots. @@ -271,7 +267,7 @@ public: return V; } - ExplodedGraph(ASTContext& ctx) : Ctx(ctx), NumNodes(0) {} + ExplodedGraph() : NumNodes(0) {} ~ExplodedGraph() {} @@ -318,8 +314,6 @@ public: llvm::BumpPtrAllocator & getAllocator() { return BVC.getAllocator(); } BumpVectorContext &getNodeAllocator() { return BVC; } - ASTContext& getContext() { return Ctx; } - typedef llvm::DenseMap<const ExplodedNode*, ExplodedNode*> NodeMap; std::pair<ExplodedGraph*, InterExplodedGraphMap*> diff --git a/include/clang/Checker/PathSensitive/GRCoreEngine.h b/include/clang/Checker/PathSensitive/GRCoreEngine.h index 2d8afeeb0da61..7f101dca97e5d 100644 --- a/include/clang/Checker/PathSensitive/GRCoreEngine.h +++ b/include/clang/Checker/PathSensitive/GRCoreEngine.h @@ -57,6 +57,10 @@ class GRCoreEngine { /// These are used to record for key nodes in the ExplodedGraph the /// number of times different CFGBlocks have been visited along a path. GRBlockCounter::Factory BCounterFactory; + + /// A flag that indicates whether paths were halted because + /// ProcessBlockEntrace returned false. + bool BlockAborted; void GenerateNode(const ProgramPoint& Loc, const GRState* State, ExplodedNode* Pred); @@ -105,17 +109,19 @@ private: public: /// Construct a GRCoreEngine object to analyze the provided CFG using /// a DFS exploration of the exploded graph. - GRCoreEngine(ASTContext& ctx, GRSubEngine& subengine) - : SubEngine(subengine), G(new ExplodedGraph(ctx)), + GRCoreEngine(GRSubEngine& subengine) + : SubEngine(subengine), G(new ExplodedGraph()), WList(GRWorkList::MakeBFS()), - BCounterFactory(G->getAllocator()) {} + BCounterFactory(G->getAllocator()), + BlockAborted(false) {} /// Construct a GRCoreEngine object to analyze the provided CFG and to /// use the provided worklist object to execute the worklist algorithm. /// The GRCoreEngine object assumes ownership of 'wlist'. - GRCoreEngine(ASTContext& ctx, GRWorkList* wlist, GRSubEngine& subengine) - : SubEngine(subengine), G(new ExplodedGraph(ctx)), WList(wlist), - BCounterFactory(G->getAllocator()) {} + GRCoreEngine(GRWorkList* wlist, GRSubEngine& subengine) + : SubEngine(subengine), G(new ExplodedGraph()), WList(wlist), + BCounterFactory(G->getAllocator()), + BlockAborted(false) {} ~GRCoreEngine() { delete WList; diff --git a/include/clang/Checker/PathSensitive/GRExprEngine.h b/include/clang/Checker/PathSensitive/GRExprEngine.h index ac407f6933c86..8eaf3f4a97d70 100644 --- a/include/clang/Checker/PathSensitive/GRExprEngine.h +++ b/include/clang/Checker/PathSensitive/GRExprEngine.h @@ -16,6 +16,7 @@ #ifndef LLVM_CLANG_ANALYSIS_GREXPRENGINE #define LLVM_CLANG_ANALYSIS_GREXPRENGINE +#include "clang/Checker/PathSensitive/AnalysisManager.h" #include "clang/Checker/PathSensitive/GRSubEngine.h" #include "clang/Checker/PathSensitive/GRCoreEngine.h" #include "clang/Checker/PathSensitive/GRState.h" @@ -75,14 +76,25 @@ class GRExprEngine : public GRSubEngine { llvm::OwningPtr<GRSimpleAPICheck> BatchAuditor; typedef llvm::DenseMap<void *, unsigned> CheckerMap; - CheckerMap CheckerM; - typedef std::vector<std::pair<void *, Checker*> > CheckersOrdered; + typedef llvm::DenseMap<std::pair<unsigned, unsigned>, CheckersOrdered *> + CheckersOrderedCache; + + /// A registration map from checker tag to the index into the + /// ordered checkers vector. + CheckerMap CheckerM; + + /// An ordered vector of checkers that are called when evaluating + /// various expressions and statements. CheckersOrdered Checkers; - /// BR - The BugReporter associated with this engine. It is important that - // this object be placed at the very end of member variables so that its - // destructor is called before the rest of the GRExprEngine is destroyed. + /// A map used for caching the checkers that respond to the callback for + /// a particular statement and visitation order. + CheckersOrderedCache COCache; + + /// The BugReporter associated with this engine. It is important that + /// this object be placed at the very end of member variables so that its + /// destructor is called before the rest of the GRExprEngine is destroyed. GRBugReporter BR; llvm::OwningPtr<GRTransferFuncs> TF; @@ -106,7 +118,7 @@ public: } /// getContext - Return the ASTContext associated with this analysis. - ASTContext& getContext() const { return G.getContext(); } + ASTContext& getContext() const { return AMgr.getASTContext(); } AnalysisManager &getAnalysisManager() const { return AMgr; } @@ -178,12 +190,15 @@ public: /// nodes when the control reaches the end of a function. void ProcessEndPath(GREndPathNodeBuilder& builder); - // Generate the entry node of the callee. + /// Generate the entry node of the callee. void ProcessCallEnter(GRCallEnterNodeBuilder &builder); - // Generate the first post callsite node. + /// Generate the first post callsite node. void ProcessCallExit(GRCallExitNodeBuilder &builder); + /// Called by GRCoreEngine when the analysis worklist has terminated. + void ProcessEndWorklist(bool hasWorkRemaining); + /// EvalAssume - Callback function invoked by the ConstraintManager when /// making assumptions about state values. const GRState *ProcessAssume(const GRState *state, SVal cond, bool assumption); diff --git a/include/clang/Checker/PathSensitive/GRState.h b/include/clang/Checker/PathSensitive/GRState.h index 25ba1f85fdff5..67a2caf06a13b 100644 --- a/include/clang/Checker/PathSensitive/GRState.h +++ b/include/clang/Checker/PathSensitive/GRState.h @@ -211,16 +211,18 @@ public: const GRState *bindLoc(SVal location, SVal V) const; + const GRState *bindDefault(SVal loc, SVal V) const; + const GRState *unbindLoc(Loc LV) const; /// Get the lvalue for a variable reference. - SVal getLValue(const VarDecl *D, const LocationContext *LC) const; + Loc getLValue(const VarDecl *D, const LocationContext *LC) const; /// Get the lvalue for a StringLiteral. - SVal getLValue(const StringLiteral *literal) const; + Loc getLValue(const StringLiteral *literal) const; - SVal getLValue(const CompoundLiteralExpr *literal, - const LocationContext *LC) const; + Loc getLValue(const CompoundLiteralExpr *literal, + const LocationContext *LC) const; /// Get the lvalue for an ivar reference. SVal getLValue(const ObjCIvarDecl *decl, SVal base) const; @@ -446,7 +448,7 @@ public: StoreManager& getStoreManager() { return *StoreMgr; } ConstraintManager& getConstraintManager() { return *ConstraintMgr; } - const GRState* RemoveDeadBindings(const GRState* St, Stmt* Loc, + const GRState* RemoveDeadBindings(const GRState* St, const StackFrameContext *LCtx, SymbolReaper& SymReaper); @@ -468,9 +470,6 @@ public: const GRState* getPersistentState(GRState& Impl); - bool isEqual(const GRState* state, const Expr* Ex, const llvm::APSInt& V); - bool isEqual(const GRState* state, const Expr* Ex, uint64_t); - //==---------------------------------------------------------------------==// // Generic Data Map methods. //==---------------------------------------------------------------------==// @@ -620,16 +619,22 @@ inline const GRState *GRState::bindLoc(SVal LV, SVal V) const { return !isa<Loc>(LV) ? this : bindLoc(cast<Loc>(LV), V); } -inline SVal GRState::getLValue(const VarDecl* VD, +inline const GRState *GRState::bindDefault(SVal loc, SVal V) const { + const MemRegion *R = cast<loc::MemRegionVal>(loc).getRegion(); + Store new_store = getStateManager().StoreMgr->BindDefault(St, R, V); + return makeWithStore(new_store); +} + +inline Loc GRState::getLValue(const VarDecl* VD, const LocationContext *LC) const { return getStateManager().StoreMgr->getLValueVar(VD, LC); } -inline SVal GRState::getLValue(const StringLiteral *literal) const { +inline Loc GRState::getLValue(const StringLiteral *literal) const { return getStateManager().StoreMgr->getLValueString(literal); } -inline SVal GRState::getLValue(const CompoundLiteralExpr *literal, +inline Loc GRState::getLValue(const CompoundLiteralExpr *literal, const LocationContext *LC) const { return getStateManager().StoreMgr->getLValueCompoundLiteral(literal, LC); } diff --git a/include/clang/Checker/PathSensitive/GRSubEngine.h b/include/clang/Checker/PathSensitive/GRSubEngine.h index d2e7457ea93d7..90a41d7c093f8 100644 --- a/include/clang/Checker/PathSensitive/GRSubEngine.h +++ b/include/clang/Checker/PathSensitive/GRSubEngine.h @@ -41,27 +41,27 @@ public: virtual GRStateManager& getStateManager() = 0; - /// ProcessStmt - Called by GRCoreEngine. Used to generate new successor - /// nodes by processing the 'effects' of a block-level statement. + /// Called by GRCoreEngine. Used to generate new successor + /// nodes by processing the 'effects' of a block-level statement. virtual void ProcessStmt(CFGElement E, GRStmtNodeBuilder& builder) = 0; - /// ProcessBlockEntrance - Called by GRCoreEngine when start processing - /// a CFGBlock. This method returns true if the analysis should continue - /// exploring the given path, and false otherwise. + /// Called by GRCoreEngine when start processing + /// a CFGBlock. This method returns true if the analysis should continue + /// exploring the given path, and false otherwise. virtual bool ProcessBlockEntrance(CFGBlock* B, const ExplodedNode *Pred, GRBlockCounter BC) = 0; - /// ProcessBranch - Called by GRCoreEngine. Used to generate successor + /// Called by GRCoreEngine. Used to generate successor /// nodes by processing the 'effects' of a branch condition. virtual void ProcessBranch(Stmt* Condition, Stmt* Term, GRBranchNodeBuilder& builder) = 0; - /// ProcessIndirectGoto - Called by GRCoreEngine. Used to generate successor - /// nodes by processing the 'effects' of a computed goto jump. + /// Called by GRCoreEngine. Used to generate successor + /// nodes by processing the 'effects' of a computed goto jump. virtual void ProcessIndirectGoto(GRIndirectGotoNodeBuilder& builder) = 0; - /// ProcessSwitch - Called by GRCoreEngine. Used to generate successor - /// nodes by processing the 'effects' of a switch statement. + /// Called by GRCoreEngine. Used to generate successor + /// nodes by processing the 'effects' of a switch statement. virtual void ProcessSwitch(GRSwitchNodeBuilder& builder) = 0; /// ProcessEndPath - Called by GRCoreEngine. Used to generate end-of-path @@ -74,10 +74,14 @@ public: // Generate the first post callsite node. virtual void ProcessCallExit(GRCallExitNodeBuilder &builder) = 0; - /// EvalAssume - Called by ConstraintManager. Used to call checker-specific - /// logic for handling assumptions on symbolic values. + /// Called by ConstraintManager. Used to call checker-specific + /// logic for handling assumptions on symbolic values. virtual const GRState* ProcessAssume(const GRState *state, SVal cond, bool assumption) = 0; + + /// Called by GRCoreEngine when the analysis worklist is either empty or the + // maximum number of analysis steps have been reached. + virtual void ProcessEndWorklist(bool hasWorkRemaining) = 0; }; } diff --git a/include/clang/Checker/PathSensitive/GRTransferFuncs.h b/include/clang/Checker/PathSensitive/GRTransferFuncs.h index 13325edea778d..374f99820bd0f 100644 --- a/include/clang/Checker/PathSensitive/GRTransferFuncs.h +++ b/include/clang/Checker/PathSensitive/GRTransferFuncs.h @@ -66,7 +66,7 @@ public: GRExprEngine& Engine, GRStmtNodeBuilder& Builder, ExplodedNode* Pred, - Stmt* S, const GRState* state, + const GRState* state, SymbolReaper& SymReaper) {} // Return statements. diff --git a/include/clang/Checker/PathSensitive/MemRegion.h b/include/clang/Checker/PathSensitive/MemRegion.h index 2ab3b420c3139..feb4b7218a7e9 100644 --- a/include/clang/Checker/PathSensitive/MemRegion.h +++ b/include/clang/Checker/PathSensitive/MemRegion.h @@ -34,7 +34,9 @@ class MemRegionManager; class MemSpaceRegion; class LocationContext; class StackFrameContext; +class ValueManager; class VarRegion; +class CodeTextRegion; //===----------------------------------------------------------------------===// // Base region classes. @@ -46,14 +48,17 @@ class MemRegion : public llvm::FoldingSetNode { public: enum Kind { // Memory spaces. - BEG_MEMSPACES, - GenericMemSpaceRegionKind = BEG_MEMSPACES, + GenericMemSpaceRegionKind, StackLocalsSpaceRegionKind, StackArgumentsSpaceRegionKind, HeapSpaceRegionKind, UnknownSpaceRegionKind, - GlobalsSpaceRegionKind, - END_MEMSPACES = GlobalsSpaceRegionKind, + NonStaticGlobalSpaceRegionKind, + StaticGlobalSpaceRegionKind, + BEG_GLOBAL_MEMSPACES = NonStaticGlobalSpaceRegionKind, + END_GLOBAL_MEMSPACES = StaticGlobalSpaceRegionKind, + BEG_MEMSPACES = GenericMemSpaceRegionKind, + END_MEMSPACES = StaticGlobalSpaceRegionKind, // Untyped regions. SymbolicRegionKind, AllocaRegionKind, @@ -146,13 +151,48 @@ public: }; class GlobalsSpaceRegion : public MemSpaceRegion { +protected: + GlobalsSpaceRegion(MemRegionManager *mgr, Kind k) + : MemSpaceRegion(mgr, k) {} +public: + static bool classof(const MemRegion *R) { + Kind k = R->getKind(); + return k >= BEG_GLOBAL_MEMSPACES && k <= END_GLOBAL_MEMSPACES; + } +}; + +class StaticGlobalSpaceRegion : public GlobalsSpaceRegion { friend class MemRegionManager; - GlobalsSpaceRegion(MemRegionManager *mgr) - : MemSpaceRegion(mgr, GlobalsSpaceRegionKind) {} + const CodeTextRegion *CR; + + StaticGlobalSpaceRegion(MemRegionManager *mgr, const CodeTextRegion *cr) + : GlobalsSpaceRegion(mgr, StaticGlobalSpaceRegionKind), CR(cr) {} + +public: + void Profile(llvm::FoldingSetNodeID &ID) const; + + void dumpToStream(llvm::raw_ostream& os) const; + + const CodeTextRegion *getCodeRegion() const { return CR; } + + static bool classof(const MemRegion *R) { + return R->getKind() == StaticGlobalSpaceRegionKind; + } +}; + +class NonStaticGlobalSpaceRegion : public GlobalsSpaceRegion { + friend class MemRegionManager; + + NonStaticGlobalSpaceRegion(MemRegionManager *mgr) + : GlobalsSpaceRegion(mgr, NonStaticGlobalSpaceRegionKind) {} + public: + + void dumpToStream(llvm::raw_ostream& os) const; + static bool classof(const MemRegion *R) { - return R->getKind() == GlobalsSpaceRegionKind; + return R->getKind() == NonStaticGlobalSpaceRegionKind; } }; @@ -232,6 +272,11 @@ public: return superRegion; } + /// getExtent - Returns the size of the region in bytes. + virtual DefinedOrUnknownSVal getExtent(ValueManager& ValMgr) const { + return UnknownVal(); + } + MemRegionManager* getMemRegionManager() const; bool isSubRegionOf(const MemRegion* R) const; @@ -288,6 +333,8 @@ public: bool isBoundable() const { return true; } + DefinedOrUnknownSVal getExtent(ValueManager& ValMgr) const; + void Profile(llvm::FoldingSetNodeID& ID) const; static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Expr* Ex, @@ -502,6 +549,8 @@ public: bool isBoundable() const { return true; } + DefinedOrUnknownSVal getExtent(ValueManager& ValMgr) const; + void Profile(llvm::FoldingSetNodeID& ID) const; static void ProfileRegion(llvm::FoldingSetNodeID& ID, @@ -536,6 +585,8 @@ public: return Str->getType(); } + DefinedOrUnknownSVal getExtent(ValueManager& ValMgr) const; + bool isBoundable() const { return false; } void Profile(llvm::FoldingSetNodeID& ID) const { @@ -595,6 +646,8 @@ public: const Decl* getDecl() const { return D; } void Profile(llvm::FoldingSetNodeID& ID) const; + DefinedOrUnknownSVal getExtent(ValueManager& ValMgr) const; + static bool classof(const MemRegion* R) { unsigned k = R->getKind(); return k >= BEG_DECL_REGIONS && k <= END_DECL_REGIONS; @@ -679,6 +732,8 @@ public: return C.getCanonicalType(getDecl()->getType()); } + DefinedOrUnknownSVal getExtent(ValueManager& ValMgr) const; + static void ProfileRegion(llvm::FoldingSetNodeID& ID, const FieldDecl* FD, const MemRegion* superRegion) { DeclRegion::ProfileRegion(ID, FD, superRegion, FieldRegionKind); @@ -793,12 +848,14 @@ class MemRegionManager { llvm::BumpPtrAllocator& A; llvm::FoldingSet<MemRegion> Regions; - GlobalsSpaceRegion *globals; + NonStaticGlobalSpaceRegion *globals; llvm::DenseMap<const StackFrameContext *, StackLocalsSpaceRegion *> StackLocalsSpaceRegions; llvm::DenseMap<const StackFrameContext *, StackArgumentsSpaceRegion *> StackArgumentsSpaceRegions; + llvm::DenseMap<const CodeTextRegion *, StaticGlobalSpaceRegion *> + StaticsGlobalSpaceRegions; HeapSpaceRegion *heap; UnknownSpaceRegion *unknown; @@ -825,8 +882,8 @@ public: getStackArgumentsRegion(const StackFrameContext *STC); /// getGlobalsRegion - Retrieve the memory region associated with - /// all global variables. - const GlobalsSpaceRegion *getGlobalsRegion(); + /// global variables. + const GlobalsSpaceRegion *getGlobalsRegion(const CodeTextRegion *R = 0); /// getHeapRegion - Retrieve the memory region associated with the /// generic "heap". diff --git a/include/clang/Checker/PathSensitive/SVals.h b/include/clang/Checker/PathSensitive/SVals.h index 040db831b8c0f..55fd3ea5c929c 100644 --- a/include/clang/Checker/PathSensitive/SVals.h +++ b/include/clang/Checker/PathSensitive/SVals.h @@ -98,6 +98,8 @@ public: bool isConstant() const; + bool isConstant(int I) const; + bool isZeroConstant() const; /// hasConjuredSymbol - If this SVal wraps a conjured symbol, return true; @@ -109,7 +111,7 @@ public: const FunctionDecl* getAsFunctionDecl() const; /// getAsLocSymbol - If this SVal is a location (subclasses Loc) and - /// wraps a symbol, return that SymbolRef. Otherwise return a SymbolData* + /// wraps a symbol, return that SymbolRef. Otherwise return NULL. SymbolRef getAsLocSymbol() const; /// Get the symbol in the SVal or its base region. diff --git a/include/clang/Checker/PathSensitive/SValuator.h b/include/clang/Checker/PathSensitive/SValuator.h index 9beb8cb08661b..9192ca7b86140 100644 --- a/include/clang/Checker/PathSensitive/SValuator.h +++ b/include/clang/Checker/PathSensitive/SValuator.h @@ -47,11 +47,15 @@ public: virtual SVal EvalBinOpNN(const GRState *state, BinaryOperator::Opcode Op, NonLoc lhs, NonLoc rhs, QualType resultTy) = 0; - virtual SVal EvalBinOpLL(BinaryOperator::Opcode Op, Loc lhs, Loc rhs, - QualType resultTy) = 0; + virtual SVal EvalBinOpLL(const GRState *state, BinaryOperator::Opcode Op, + Loc lhs, Loc rhs, QualType resultTy) = 0; virtual SVal EvalBinOpLN(const GRState *state, BinaryOperator::Opcode Op, Loc lhs, NonLoc rhs, QualType resultTy) = 0; + + /// getKnownValue - Evaluates a given SVal. If the SVal has only one possible + /// (integer) value, that value is returned. Otherwise, returns NULL. + virtual const llvm::APSInt *getKnownValue(const GRState *state, SVal V) = 0; SVal EvalBinOp(const GRState *ST, BinaryOperator::Opcode Op, SVal L, SVal R, QualType T); diff --git a/include/clang/Checker/PathSensitive/Store.h b/include/clang/Checker/PathSensitive/Store.h index f3155b9aacd48..7a60ebb0838e3 100644 --- a/include/clang/Checker/PathSensitive/Store.h +++ b/include/clang/Checker/PathSensitive/Store.h @@ -64,6 +64,10 @@ public: /// to the location given for \c loc. virtual Store Bind(Store store, Loc loc, SVal val) = 0; + virtual Store BindDefault(Store store, const MemRegion *R, SVal V) { + return store; + } + virtual Store Remove(Store St, Loc L) = 0; /// BindCompoundLiteral - Return the store that has the bindings currently @@ -87,16 +91,16 @@ public: // caller's responsibility to 'delete' the returned map. virtual SubRegionMap *getSubRegionMap(Store store) = 0; - virtual SVal getLValueVar(const VarDecl *VD, const LocationContext *LC) { + virtual Loc getLValueVar(const VarDecl *VD, const LocationContext *LC) { return ValMgr.makeLoc(MRMgr.getVarRegion(VD, LC)); } - virtual SVal getLValueString(const StringLiteral* S) { + virtual Loc getLValueString(const StringLiteral* S) { return ValMgr.makeLoc(MRMgr.getStringRegion(S)); } - SVal getLValueCompoundLiteral(const CompoundLiteralExpr* CL, - const LocationContext *LC) { + Loc getLValueCompoundLiteral(const CompoundLiteralExpr* CL, + const LocationContext *LC) { return loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL, LC)); } @@ -110,7 +114,8 @@ public: virtual SVal getLValueElement(QualType elementType, SVal offset, SVal Base); - // FIXME: Make out-of-line. + // FIXME: This should soon be eliminated altogether; clients should deal with + // region extents directly. virtual DefinedOrUnknownSVal getSizeInElements(const GRState *state, const MemRegion *region, QualType EleTy) { @@ -144,7 +149,7 @@ public: return UnknownVal(); } - virtual const GRState *RemoveDeadBindings(GRState &state, Stmt* Loc, + virtual const GRState *RemoveDeadBindings(GRState &state, const StackFrameContext *LCtx, SymbolReaper& SymReaper, llvm::SmallVectorImpl<const MemRegion*>& RegionRoots) = 0; @@ -164,18 +169,8 @@ public: const MemRegion * const *Begin, const MemRegion * const *End, const Expr *E, unsigned Count, - InvalidatedSymbols *IS); - - // FIXME: Make out-of-line. - virtual const GRState *setExtent(const GRState *state, - const MemRegion *region, SVal extent) { - return state; - } - - virtual llvm::Optional<SVal> getExtent(const GRState *state, - const MemRegion *R) { - return llvm::Optional<SVal>(); - } + InvalidatedSymbols *IS, + bool invalidateGlobals) = 0; /// EnterStackFrame - Let the StoreManager to do something when execution /// engine is about to execute into a callee. diff --git a/include/clang/Checker/PathSensitive/SymbolManager.h b/include/clang/Checker/PathSensitive/SymbolManager.h index dea877c0657f9..ffbd2892499ea 100644 --- a/include/clang/Checker/PathSensitive/SymbolManager.h +++ b/include/clang/Checker/PathSensitive/SymbolManager.h @@ -31,6 +31,7 @@ namespace clang { class ASTContext; class BasicValueFactory; class MemRegion; + class SubRegion; class TypedRegion; class VarRegion; class StackFrameContext; @@ -38,7 +39,7 @@ namespace clang { class SymExpr : public llvm::FoldingSetNode { public: enum Kind { BEGIN_SYMBOLS, - RegionValueKind, ConjuredKind, DerivedKind, + RegionValueKind, ConjuredKind, DerivedKind, ExtentKind, END_SYMBOLS, SymIntKind, SymSymKind }; private: @@ -189,6 +190,34 @@ public: } }; +class SymbolExtent : public SymbolData { + const SubRegion *R; + +public: + SymbolExtent(SymbolID sym, const SubRegion *r) + : SymbolData(ExtentKind, sym), R(r) {} + + const SubRegion *getRegion() const { return R; } + + QualType getType(ASTContext&) const; + + void dumpToStream(llvm::raw_ostream &os) const; + + static void Profile(llvm::FoldingSetNodeID& profile, const SubRegion *R) { + profile.AddInteger((unsigned) ExtentKind); + profile.AddPointer(R); + } + + virtual void Profile(llvm::FoldingSetNodeID& profile) { + Profile(profile, R); + } + + // Implement isa<T> support. + static inline bool classof(const SymExpr* SE) { + return SE->getKind() == ExtentKind; + } +}; + // SymIntExpr - Represents symbolic expression like 'x' + 3. class SymIntExpr : public SymExpr { const SymExpr *LHS; @@ -305,6 +334,8 @@ public: const SymbolDerived *getDerivedSymbol(SymbolRef parentSymbol, const TypedRegion *R); + const SymbolExtent *getExtentSymbol(const SubRegion *R); + const SymIntExpr *getSymIntExpr(const SymExpr *lhs, BinaryOperator::Opcode op, const llvm::APSInt& rhs, QualType t); @@ -330,21 +361,23 @@ class SymbolReaper { SetTy TheLiving; SetTy TheDead; const LocationContext *LCtx; + const Stmt *Loc; SymbolManager& SymMgr; public: - SymbolReaper(const LocationContext *ctx, SymbolManager& symmgr) - : LCtx(ctx), SymMgr(symmgr) {} + SymbolReaper(const LocationContext *ctx, const Stmt *s, SymbolManager& symmgr) + : LCtx(ctx), Loc(s), SymMgr(symmgr) {} ~SymbolReaper() {} const LocationContext *getLocationContext() const { return LCtx; } + const Stmt *getCurrentStatement() const { return Loc; } bool isLive(SymbolRef sym); - bool isLive(const Stmt* Loc, const Stmt* ExprVal) const; + bool isLive(const Stmt *ExprVal) const; - bool isLive(const Stmt* Loc, const VarRegion *VR) const; + bool isLive(const VarRegion *VR) const; void markLive(SymbolRef sym); bool maybeDead(SymbolRef sym); |