summaryrefslogtreecommitdiff
path: root/include/clang/Checker/PathSensitive
diff options
context:
space:
mode:
authorRoman Divacky <rdivacky@FreeBSD.org>2010-07-13 17:21:42 +0000
committerRoman Divacky <rdivacky@FreeBSD.org>2010-07-13 17:21:42 +0000
commit4ba675006b5a8edfc48b6a9bd3dcf54a70cc08f2 (patch)
tree48b44512b5db8ced345df4a1a56b5065cf2a14d9 /include/clang/Checker/PathSensitive
parentd7279c4c177bca357ef96ff1379fd9bc420bfe83 (diff)
Notes
Diffstat (limited to 'include/clang/Checker/PathSensitive')
-rw-r--r--include/clang/Checker/PathSensitive/Checker.h30
-rw-r--r--include/clang/Checker/PathSensitive/CheckerVisitor.h9
-rw-r--r--include/clang/Checker/PathSensitive/Environment.h2
-rw-r--r--include/clang/Checker/PathSensitive/ExplodedGraph.h10
-rw-r--r--include/clang/Checker/PathSensitive/GRCoreEngine.h18
-rw-r--r--include/clang/Checker/PathSensitive/GRExprEngine.h31
-rw-r--r--include/clang/Checker/PathSensitive/GRState.h27
-rw-r--r--include/clang/Checker/PathSensitive/GRSubEngine.h28
-rw-r--r--include/clang/Checker/PathSensitive/GRTransferFuncs.h2
-rw-r--r--include/clang/Checker/PathSensitive/MemRegion.h77
-rw-r--r--include/clang/Checker/PathSensitive/SVals.h4
-rw-r--r--include/clang/Checker/PathSensitive/SValuator.h8
-rw-r--r--include/clang/Checker/PathSensitive/Store.h31
-rw-r--r--include/clang/Checker/PathSensitive/SymbolManager.h43
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);