Added a new ProgramPoint: PostPurgeDeadSymbols. This new program point distinguishes between the cases when we just evaluated the transfer function of a Stmt* (PostStmt) or performed a load (PostLoad). This solves a caching bug observed in a recent bug report.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@52443 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Ted Kremenek 2008-06-18 05:34:07 +00:00
Родитель 60c5e4263b
Коммит 331b0ac44b
5 изменённых файлов: 158 добавлений и 62 удалений

Просмотреть файл

@ -149,20 +149,25 @@ public:
unsigned getCurrentBlockCount() const {
return getBlockCounter().getNumVisited(B.getBlockID());
}
ExplodedNodeImpl* generateNodeImpl(Stmt* S, void* State,
ExplodedNodeImpl* Pred,
bool isLoad = false);
ExplodedNodeImpl*
generateNodeImpl(Stmt* S, void* State, ExplodedNodeImpl* Pred,
ProgramPoint::Kind K = ProgramPoint::PostStmtKind);
inline ExplodedNodeImpl* generateNodeImpl(Stmt* S, void* State,
bool isLoad = false) {
ExplodedNodeImpl*
generateNodeImpl(Stmt* S, void* State,
ProgramPoint::Kind K = ProgramPoint::PostStmtKind) {
ExplodedNodeImpl* N = getLastNode();
assert (N && "Predecessor of new node is infeasible.");
return generateNodeImpl(S, State, N, isLoad);
return generateNodeImpl(S, State, N, K);
}
/// getStmt - Return the current block-level expression associated with
/// this builder.
Stmt* getStmt() const { return B[Idx]; }
/// getBlock - Return the CFGBlock associated with the block-level expression
/// of this builder.
CFGBlock* getBlock() const { return &B; }
};
@ -182,6 +187,7 @@ public:
GRStmtNodeBuilder(GRStmtNodeBuilderImpl& nb) : NB(nb),
CallExprAuditBeg(0), CallExprAuditEnd(0),
ObjCMsgExprAuditBeg(0), ObjCMsgExprAuditEnd(0),
PurgingDeadSymbols(false),
BuildSinks(false), HasGeneratedNode(false) {
CleanedState = getLastNode()->getState();
@ -203,14 +209,22 @@ public:
return static_cast<NodeTy*>(NB.getLastNode());
}
NodeTy* generateNode(Stmt* S, StateTy* St, NodeTy* Pred, bool isLoad = false){
NodeTy*
generateNode(Stmt* S, StateTy* St, NodeTy* Pred,
ProgramPoint::Kind K = ProgramPoint::PostStmtKind) {
HasGeneratedNode = true;
return static_cast<NodeTy*>(NB.generateNodeImpl(S, St, Pred, isLoad));
if (PurgingDeadSymbols) K = ProgramPoint::PostPurgeDeadSymbolsKind;
return static_cast<NodeTy*>(NB.generateNodeImpl(S, St, Pred, K));
}
NodeTy* generateNode(Stmt* S, StateTy* St, bool isLoad = false) {
NodeTy*
generateNode(Stmt* S, StateTy* St,
ProgramPoint::Kind K = ProgramPoint::PostStmtKind) {
HasGeneratedNode = true;
return static_cast<NodeTy*>(NB.generateNodeImpl(S, St, isLoad));
if (PurgingDeadSymbols) K = ProgramPoint::PostPurgeDeadSymbolsKind;
return static_cast<NodeTy*>(NB.generateNodeImpl(S, St, K));
}
GRBlockCounter getBlockCounter() const {
@ -274,6 +288,7 @@ public:
return N;
}
bool PurgingDeadSymbols;
bool BuildSinks;
bool HasGeneratedNode;
};
@ -338,7 +353,7 @@ public:
return getPredecessor()->getState();
}
inline NodeTy* generateNode(StateTy* St, bool branch) {
NodeTy* generateNode(StateTy* St, bool branch) {
return static_cast<NodeTy*>(NB.generateNodeImpl(St, branch));
}
@ -350,7 +365,7 @@ public:
return NB.getTargetBlock(branch);
}
inline void markInfeasible(bool branch) {
void markInfeasible(bool branch) {
NB.markInfeasible(branch);
}
};
@ -393,8 +408,8 @@ public:
ExplodedNodeImpl* generateNodeImpl(const Iterator& I, void* State,
bool isSink);
inline Expr* getTarget() const { return E; }
inline void* getState() const { return Pred->State; }
Expr* getTarget() const { return E; }
void* getState() const { return Pred->State; }
};
template<typename STATE>
@ -410,16 +425,16 @@ public:
typedef GRIndirectGotoNodeBuilderImpl::Iterator iterator;
inline iterator begin() { return NB.begin(); }
inline iterator end() { return NB.end(); }
iterator begin() { return NB.begin(); }
iterator end() { return NB.end(); }
inline Expr* getTarget() const { return NB.getTarget(); }
Expr* getTarget() const { return NB.getTarget(); }
inline NodeTy* generateNode(const iterator& I, StateTy* St, bool isSink=false){
NodeTy* generateNode(const iterator& I, StateTy* St, bool isSink=false){
return static_cast<NodeTy*>(NB.generateNodeImpl(I, St, isSink));
}
inline StateTy* getState() const {
StateTy* getState() const {
return static_cast<StateTy*>(NB.getState());
}
};
@ -459,8 +474,8 @@ public:
ExplodedNodeImpl* generateCaseStmtNodeImpl(const Iterator& I, void* State);
ExplodedNodeImpl* generateDefaultCaseNodeImpl(void* State, bool isSink);
inline Expr* getCondition() const { return Condition; }
inline void* getState() const { return Pred->State; }
Expr* getCondition() const { return Condition; }
void* getState() const { return Pred->State; }
};
template<typename STATE>
@ -476,20 +491,20 @@ public:
typedef GRSwitchNodeBuilderImpl::Iterator iterator;
inline iterator begin() { return NB.begin(); }
inline iterator end() { return NB.end(); }
iterator begin() { return NB.begin(); }
iterator end() { return NB.end(); }
inline Expr* getCondition() const { return NB.getCondition(); }
Expr* getCondition() const { return NB.getCondition(); }
inline NodeTy* generateCaseStmtNode(const iterator& I, StateTy* St) {
NodeTy* generateCaseStmtNode(const iterator& I, StateTy* St) {
return static_cast<NodeTy*>(NB.generateCaseStmtNodeImpl(I, St));
}
inline NodeTy* generateDefaultCaseNode(StateTy* St, bool isSink = false) {
NodeTy* generateDefaultCaseNode(StateTy* St, bool isSink = false) {
return static_cast<NodeTy*>(NB.generateDefaultCaseNodeImpl(St, isSink));
}
inline StateTy* getState() const {
StateTy* getState() const {
return static_cast<StateTy*>(NB.getState());
}
};

Просмотреть файл

@ -25,9 +25,10 @@ namespace clang {
class ProgramPoint {
public:
enum Kind { BlockEntranceKind=0, PostStmtKind=1, PostLoadKind=2,
BlockExitKind=3, BlockEdgeSrcKind=4, BlockEdgeDstKind=5,
BlockEdgeAuxKind=6 };
enum Kind { BlockEntranceKind=0,
PostStmtKind=1, PostLoadKind=2, PostPurgeDeadSymbolsKind=3,
BlockExitKind=4, BlockEdgeSrcKind=5, BlockEdgeDstKind=6,
BlockEdgeAuxKind=7 };
protected:
uintptr_t Data;
@ -110,7 +111,7 @@ public:
static bool classof(const ProgramPoint* Location) {
unsigned k = Location->getKind();
return k == PostStmtKind || k == PostLoadKind;
return k >= PostStmtKind && k <= PostPurgeDeadSymbolsKind;
}
};
@ -123,6 +124,15 @@ public:
}
};
class PostPurgeDeadSymbols : public PostStmt {
public:
PostPurgeDeadSymbols(const Stmt* S) : PostStmt(S, PostPurgeDeadSymbolsKind) {}
static bool classof(const ProgramPoint* Location) {
return Location->getKind() == PostPurgeDeadSymbolsKind;
}
};
class BlockEdge : public ProgramPoint {
typedef std::pair<CFGBlock*,CFGBlock*> BPair;
public:

Просмотреть файл

@ -21,7 +21,7 @@
#include "clang/AST/Expr.h"
#include "clang/Analysis/ProgramPoint.h"
#include "clang/Analysis/PathDiagnostic.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/DenseMap.h"
#include <sstream>
using namespace clang;
@ -204,43 +204,86 @@ MakeReportGraph(ExplodedGraph<ValueState>* G, ExplodedNode<ValueState>* N) {
G = new ExplodedGraph<ValueState>(GTrim->getCFG(), GTrim->getCodeDecl(),
GTrim->getContext());
ExplodedNode<ValueState> *Last = 0, *First = 0;
// Sometimes TrimGraph can contain a cycle. Perform a reverse DFS
// to the root node, and then construct a new graph that contains only
// a single path.
llvm::DenseMap<void*,unsigned> Visited;
llvm::SmallVector<ExplodedNode<ValueState>*, 10> WS;
WS.push_back(N);
unsigned cnt = 0;
ExplodedNode<ValueState>* Root = 0;
// Sometimes TrimGraph can contain a cycle because there are multiple BFS
// paths with the same length. We mark the nodes we visit so that we
// don't get stuck in a cycle.
llvm::DenseSet<void*> Visited;
while (!WS.empty()) {
ExplodedNode<ValueState>* Node = WS.back();
WS.pop_back();
if (Visited.find(Node) != Visited.end())
continue;
Visited[Node] = cnt++;
if (Node->pred_empty()) {
Root = Node;
break;
}
for (ExplodedNode<ValueState>::pred_iterator I=Node->pred_begin(),
E=Node->pred_end(); I!=E; ++I)
WS.push_back(*I);
}
while (N) {
Visited.insert(N);
assert (Root);
// Now walk from the root down the DFS path, always taking the successor
// with the lowest number.
ExplodedNode<ValueState> *Last = 0, *First = 0;
for ( N = Root ;;) {
// Lookup the number associated with the current node.
llvm::DenseMap<void*,unsigned>::iterator I=Visited.find(N);
assert (I != Visited.end());
// Create the equivalent node in the new graph with the same state
// and location.
ExplodedNode<ValueState>* NewN =
G->getNode(N->getLocation(), N->getState());
if (!First) First = NewN;
if (Last) Last->addPredecessor(NewN);
G->getNode(N->getLocation(), N->getState());
// Link up the new node with the previous node.
if (Last)
NewN->addPredecessor(Last);
Last = NewN;
if (N->pred_empty())
// Are we at the final node?
if (I->second == 0) {
First = NewN;
break;
ExplodedNode<ValueState>::pred_iterator PI = N->pred_begin();
ExplodedNode<ValueState>::pred_iterator PE = N->pred_end();
}
// Find the next successor node. We choose the node that is marked
// with the lowest DFS number.
ExplodedNode<ValueState>::succ_iterator SI = N->succ_begin();
ExplodedNode<ValueState>::succ_iterator SE = N->succ_end();
N = 0;
// Look for the first predecessor that we have not already visited.
for (unsigned MinVal = 0; SI != SE; ++SI) {
for (; PI != PE; ++PI)
if (!Visited.count(*PI)) {
N = *PI;
break;
I = Visited.find(*SI);
if (I == Visited.end())
continue;
if (!N || I->second < MinVal) {
N = *SI;
MinVal = I->second;
}
assert (N && "All predecessors involved in a cycle!");
}
assert (N);
}
assert (First);
return std::make_pair(G, First);
}

Просмотреть файл

@ -317,12 +317,30 @@ void GRStmtNodeBuilderImpl::GenerateAutoTransition(ExplodedNodeImpl* N) {
Eng.WList->Enqueue(Succ, B, Idx+1);
}
static inline ProgramPoint GetPostLoc(Stmt* S, ProgramPoint::Kind K) {
switch (K) {
default:
assert(false && "Invalid PostXXXKind.");
case ProgramPoint::PostStmtKind:
return PostStmt(S);
case ProgramPoint::PostLoadKind:
return PostLoad(S);
case ProgramPoint::PostPurgeDeadSymbolsKind:
return PostPurgeDeadSymbols(S);
}
}
ExplodedNodeImpl*
GRStmtNodeBuilderImpl::generateNodeImpl(Stmt* S, void* State,
ExplodedNodeImpl* Pred, bool isLoad) {
ExplodedNodeImpl* Pred,
ProgramPoint::Kind K) {
bool IsNew;
ProgramPoint Loc = isLoad ? PostLoad(S) : PostStmt(S);
ProgramPoint Loc = GetPostLoc(S, K);
ExplodedNodeImpl* N = Eng.G->getNodeImpl(Loc, State, &IsNew);
N->addPredecessor(Pred);
Deferred.erase(Pred);

Просмотреть файл

@ -214,6 +214,9 @@ void GRExprEngine::ProcessStmt(Stmt* S, StmtNodeBuilder& builder) {
SaveAndRestore<bool> OldSink(Builder->BuildSinks);
SaveOr OldHasGen(Builder->HasGeneratedNode);
SaveAndRestore<bool> OldPurgeDeadSymbols(Builder->PurgingDeadSymbols);
Builder->PurgingDeadSymbols = true;
TF->EvalDeadSymbols(Tmp, *this, *Builder, EntryNode, S,
CleanedState, DeadSymbols);
@ -965,7 +968,10 @@ ValueState* GRExprEngine::EvalLocation(Expr* Ex, NodeTy* Pred,
// Check for loads/stores from/to undefined values.
if (location.isUndef()) {
if (NodeTy* Succ = Builder->generateNode(Ex, St, Pred, isLoad)) {
ProgramPoint::Kind K =
isLoad ? ProgramPoint::PostLoadKind : ProgramPoint::PostStmtKind;
if (NodeTy* Succ = Builder->generateNode(Ex, St, Pred, K)) {
Succ->markAsSink();
UndefDeref.insert(Succ);
}
@ -1000,7 +1006,10 @@ ValueState* GRExprEngine::EvalLocation(Expr* Ex, NodeTy* Pred,
// We don't use "MakeNode" here because the node will be a sink
// and we have no intention of processing it later.
NodeTy* NullNode = Builder->generateNode(Ex, StNull, Pred, isLoad);
ProgramPoint::Kind K =
isLoad ? ProgramPoint::PostLoadKind : ProgramPoint::PostStmtKind;
NodeTy* NullNode = Builder->generateNode(Ex, StNull, Pred, K);
if (NullNode) {
@ -2437,6 +2446,7 @@ struct VISIBILITY_HIDDEN DOTGraphTraits<GRExprEngine::NodeTy*> :
break;
case ProgramPoint::PostLoadKind:
case ProgramPoint::PostPurgeDeadSymbolsKind:
case ProgramPoint::PostStmtKind: {
const PostStmt& L = cast<PostStmt>(Loc);
Stmt* S = L.getStmt();