forked from OSchip/llvm-project
Rework ExprEngine::processCFGBlockEntrance()
to use a node builder. This paves the way for Checkers to interpose (via a "visit" method) at the entrance to blocks. llvm-svn: 123217
This commit is contained in:
parent
f82068a994
commit
a00bccc0c5
|
|
@ -37,6 +37,7 @@ namespace ento {
|
|||
/// any transfer function logic and the sub-expression level (if any).
|
||||
class CoreEngine {
|
||||
friend class StmtNodeBuilder;
|
||||
friend class GenericNodeBuilderImpl;
|
||||
friend class BranchNodeBuilder;
|
||||
friend class IndirectGotoNodeBuilder;
|
||||
friend class SwitchNodeBuilder;
|
||||
|
|
@ -397,6 +398,50 @@ public:
|
|||
const GRState* getState() const { return Pred->State; }
|
||||
};
|
||||
|
||||
class GenericNodeBuilderImpl {
|
||||
protected:
|
||||
CoreEngine &engine;
|
||||
ExplodedNode *pred;
|
||||
bool HasGeneratedNode;
|
||||
ProgramPoint pp;
|
||||
llvm::SmallVector<ExplodedNode*, 2> sinksGenerated;
|
||||
|
||||
ExplodedNode *generateNodeImpl(const GRState *state, ExplodedNode *pred,
|
||||
ProgramPoint programPoint, bool asSink);
|
||||
|
||||
GenericNodeBuilderImpl(CoreEngine &eng, ExplodedNode *pr, ProgramPoint p)
|
||||
: engine(eng), pred(pr), HasGeneratedNode(false), pp(p) {}
|
||||
|
||||
public:
|
||||
bool hasGeneratedNode() const { return HasGeneratedNode; }
|
||||
|
||||
WorkList &getWorkList() { return *engine.WList; }
|
||||
|
||||
ExplodedNode* getPredecessor() const { return pred; }
|
||||
|
||||
BlockCounter getBlockCounter() const {
|
||||
return engine.WList->getBlockCounter();
|
||||
}
|
||||
|
||||
const llvm::SmallVectorImpl<ExplodedNode*> &sinks() const {
|
||||
return sinksGenerated;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename PP>
|
||||
class GenericNodeBuilder : public GenericNodeBuilderImpl {
|
||||
public:
|
||||
GenericNodeBuilder(CoreEngine &eng, ExplodedNode *pr, const PP &p)
|
||||
: GenericNodeBuilderImpl(eng, pr, p) {}
|
||||
|
||||
ExplodedNode *generateNode(const GRState *state, ExplodedNode *pred,
|
||||
PP programPoint, bool asSink) {
|
||||
return generateNodeImpl(state, pred, programPoint, asSink);
|
||||
}
|
||||
|
||||
const PP &getProgramPoint() const { return cast<PP>(pp); }
|
||||
};
|
||||
|
||||
class EndOfFunctionNodeBuilder {
|
||||
CoreEngine &Eng;
|
||||
const CFGBlock& B;
|
||||
|
|
|
|||
|
|
@ -193,12 +193,10 @@ public:
|
|||
void ProcessTemporaryDtor(const CFGTemporaryDtor D,
|
||||
StmtNodeBuilder &builder);
|
||||
|
||||
/// processCFGBlockEntrance - Called by CoreEngine when start processing
|
||||
/// a CFGBlock. This method returns true if the analysis should continue
|
||||
/// exploring the given path, and false otherwise.
|
||||
bool processCFGBlockEntrance(const CFGBlock* B, const ExplodedNode *Pred,
|
||||
BlockCounter BC);
|
||||
|
||||
/// Called by CoreEngine when processing the entrance of a CFGBlock.
|
||||
virtual void processCFGBlockEntrance(ExplodedNodeSet &dstNodes,
|
||||
GenericNodeBuilder<BlockEntrance> &nodeBuilder);
|
||||
|
||||
/// ProcessBranch - Called by CoreEngine. Used to generate successor
|
||||
/// nodes by processing the 'effects' of a branch condition.
|
||||
void processBranch(const Stmt* Condition, const Stmt* Term,
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
#ifndef LLVM_CLANG_GR_SUBENGINE_H
|
||||
#define LLVM_CLANG_GR_SUBENGINE_H
|
||||
|
||||
#include "clang/Analysis/ProgramPoint.h"
|
||||
#include "clang/StaticAnalyzer/PathSensitive/SVals.h"
|
||||
|
||||
namespace clang {
|
||||
|
|
@ -23,8 +24,10 @@ class LocationContext;
|
|||
class Stmt;
|
||||
|
||||
namespace ento {
|
||||
|
||||
|
||||
template <typename PP> class GenericNodeBuilder;
|
||||
class AnalysisManager;
|
||||
class ExplodedNodeSet;
|
||||
class ExplodedNode;
|
||||
class GRState;
|
||||
class GRStateManager;
|
||||
|
|
@ -52,12 +55,11 @@ public:
|
|||
/// nodes by processing the 'effects' of a block-level statement.
|
||||
virtual void processCFGElement(const CFGElement E, StmtNodeBuilder& builder)=0;
|
||||
|
||||
/// Called by CoreEngine when start processing
|
||||
/// a CFGBlock. This method returns true if the analysis should continue
|
||||
/// exploring the given path, and false otherwise.
|
||||
virtual bool processCFGBlockEntrance(const CFGBlock* B,
|
||||
const ExplodedNode *Pred,
|
||||
BlockCounter BC) = 0;
|
||||
/// Called by CoreEngine when it starts processing a CFGBlock. The
|
||||
/// SubEngine is expected to populate dstNodes with new nodes representing
|
||||
/// updated analysis state, or generate no nodes at all if it doesn't.
|
||||
virtual void processCFGBlockEntrance(ExplodedNodeSet &dstNodes,
|
||||
GenericNodeBuilder<BlockEntrance> &nodeBuilder) = 0;
|
||||
|
||||
/// Called by CoreEngine. Used to generate successor
|
||||
/// nodes by processing the 'effects' of a branch condition.
|
||||
|
|
|
|||
|
|
@ -1077,11 +1077,22 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred,
|
|||
// Block entrance. (Update counters).
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
bool ExprEngine::processCFGBlockEntrance(const CFGBlock* B,
|
||||
const ExplodedNode *Pred,
|
||||
BlockCounter BC) {
|
||||
return BC.getNumVisited(Pred->getLocationContext()->getCurrentStackFrame(),
|
||||
B->getBlockID()) < AMgr.getMaxVisit();
|
||||
void ExprEngine::processCFGBlockEntrance(ExplodedNodeSet &dstNodes,
|
||||
GenericNodeBuilder<BlockEntrance> &nodeBuilder){
|
||||
|
||||
// FIXME: Refactor this into a checker.
|
||||
const CFGBlock *block = nodeBuilder.getProgramPoint().getBlock();
|
||||
ExplodedNode *pred = nodeBuilder.getPredecessor();
|
||||
|
||||
if (nodeBuilder.getBlockCounter().getNumVisited(
|
||||
pred->getLocationContext()->getCurrentStackFrame(),
|
||||
block->getBlockID()) >= AMgr.getMaxVisit()) {
|
||||
|
||||
static int tag = 0;
|
||||
const BlockEntrance &BE = nodeBuilder.getProgramPoint();
|
||||
BlockEntrance BE_tagged(BE.getBlock(), BE.getLocationContext(), &tag);
|
||||
nodeBuilder.generateNode(pred->getState(), pred, BE_tagged, true);
|
||||
}
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
|||
|
|
@ -288,13 +288,29 @@ void CoreEngine::HandleBlockEdge(const BlockEdge& L, ExplodedNode* Pred) {
|
|||
return;
|
||||
}
|
||||
|
||||
// FIXME: Should we allow processCFGBlockEntrance to also manipulate state?
|
||||
// Call into the subengine to process entering the CFGBlock.
|
||||
ExplodedNodeSet dstNodes;
|
||||
BlockEntrance BE(Blk, Pred->getLocationContext());
|
||||
GenericNodeBuilder<BlockEntrance> nodeBuilder(*this, Pred, BE);
|
||||
SubEng.processCFGBlockEntrance(dstNodes, nodeBuilder);
|
||||
|
||||
if (SubEng.processCFGBlockEntrance(Blk, Pred, WList->getBlockCounter()))
|
||||
generateNode(BlockEntrance(Blk, Pred->getLocationContext()),
|
||||
Pred->State, Pred);
|
||||
if (dstNodes.empty()) {
|
||||
if (!nodeBuilder.hasGeneratedNode()) {
|
||||
// Auto-generate a node and enqueue it to the worklist.
|
||||
generateNode(BE, Pred->State, Pred);
|
||||
}
|
||||
}
|
||||
else {
|
||||
blocksAborted.push_back(std::make_pair(L, Pred));
|
||||
for (ExplodedNodeSet::iterator I = dstNodes.begin(), E = dstNodes.end();
|
||||
I != E; ++I) {
|
||||
WList->enqueue(*I);
|
||||
}
|
||||
}
|
||||
|
||||
for (llvm::SmallVectorImpl<ExplodedNode*>::const_iterator
|
||||
I = nodeBuilder.sinks().begin(), E = nodeBuilder.sinks().end();
|
||||
I != E; ++I) {
|
||||
blocksAborted.push_back(std::make_pair(L, *I));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -446,6 +462,27 @@ void CoreEngine::generateNode(const ProgramPoint& Loc,
|
|||
if (IsNew) WList->enqueue(Node);
|
||||
}
|
||||
|
||||
ExplodedNode *
|
||||
GenericNodeBuilderImpl::generateNodeImpl(const GRState *state,
|
||||
ExplodedNode *pred,
|
||||
ProgramPoint programPoint,
|
||||
bool asSink) {
|
||||
|
||||
HasGeneratedNode = true;
|
||||
bool isNew;
|
||||
ExplodedNode *node = engine.getGraph().getNode(programPoint, state, &isNew);
|
||||
if (pred)
|
||||
node->addPredecessor(pred, engine.getGraph());
|
||||
if (isNew) {
|
||||
if (asSink) {
|
||||
node->markAsSink();
|
||||
sinksGenerated.push_back(node);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
StmtNodeBuilder::StmtNodeBuilder(const CFGBlock* b, unsigned idx,
|
||||
ExplodedNode* N, CoreEngine* e,
|
||||
GRStateManager &mgr)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=region -verify %s
|
||||
// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=region -analyzer-max-loop 6 -verify %s
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// The following code is reduced using delta-debugging from
|
||||
|
|
|
|||
Loading…
Reference in New Issue