#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h"
+#include "clang/Analysis/ProgramPoint.h"
#include <vector>
namespace clang {
void runCheckersForBind(ExplodedNodeSet &Dst,
const ExplodedNodeSet &Src,
SVal location, SVal val,
- const Stmt *S, ExprEngine &Eng);
+ const Stmt *S, ExprEngine &Eng,
+ ProgramPoint::Kind PointKind);
/// \brief Run checkers for end of analysis.
void runCheckersForEndAnalysis(ExplodedGraph &G, BugReporter &BR,
/// \brief Returns the number of times the current block has been visited
/// along the analyzed path.
- unsigned getCurrentBlockCount() {return NB.getCurrentBlockCount();}
+ unsigned getCurrentBlockCount() {
+ return NB.getContext().getCurrentBlockCount();
+ }
ASTContext &getASTContext() {
return Eng.getContext();
/// at the statement and block-level. The analyses themselves must implement
/// any transfer function logic and the sub-expression level (if any).
class CoreEngine {
- friend class CommonNodeBuilder;
+ friend struct NodeBuilderContext;
friend class NodeBuilder;
friend class StmtNodeBuilder;
+ friend class CommonNodeBuilder;
friend class GenericNodeBuilderImpl;
- friend class BranchNodeBuilder;
friend class IndirectGotoNodeBuilder;
friend class SwitchNodeBuilder;
friend class EndOfFunctionNodeBuilder;
friend class CallEnterNodeBuilder;
friend class CallExitNodeBuilder;
+ friend class ExprEngine;
public:
typedef std::vector<std::pair<BlockEdge, const ExplodedNode*> >
ExplodedNode *ContextPred;
NodeBuilderContext(CoreEngine &E, const CFGBlock *B, ExplodedNode *N)
: Eng(E), Block(B), ContextPred(N) { assert(B); assert(!N->isSink()); }
+
+ /// \brief Return the CFGBlock associated with this builder.
+ const CFGBlock *getBlock() const { return Block; }
+
+ /// \brief Returns the number of times the current basic block has been
+ /// visited on the exploded graph path.
+ unsigned getCurrentBlockCount() const {
+ return Eng.WList->getBlockCounter().getNumVisited(
+ ContextPred->getLocationContext()->getCurrentStackFrame(),
+ Block->getBlockID());
+ }
+
};
/// This is the simplest builder which generates nodes in the ExplodedGraph.
/// the builder dies.
ExplodedNodeSet &Frontier;
- BlockCounter getBlockCounter() const { return C.Eng.WList->getBlockCounter();}
-
/// Checkes if the results are ready.
virtual bool checkResults() {
if (!Finalized)
return Frontier.end();
}
- /// \brief Return the CFGBlock associated with this builder.
- const CFGBlock *getBlock() const { return C.Block; }
-
const NodeBuilderContext &getContext() { return C; }
- /// \brief Returns the number of times the current basic block has been
- /// visited on the exploded graph path.
- unsigned getCurrentBlockCount() const {
- return getBlockCounter().getNumVisited(
- C.ContextPred->getLocationContext()->getCurrentStackFrame(),
- C.Block->getBlockID());
- }
-
void takeNodes(const ExplodedNodeSet &S) {
for (ExplodedNodeSet::iterator I = S.begin(), E = S.end(); I != E; ++I )
Frontier.erase(*I);
class CommonNodeBuilder {
protected:
ExplodedNode *Pred;
- CoreEngine& Eng;
+ CoreEngine &Eng;
CommonNodeBuilder(CoreEngine* E, ExplodedNode *P) : Pred(P), Eng(*E) {}
BlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter(); }
class PureStmtNodeBuilder: public NodeBuilder {
+ NodeBuilder *EnclosingBldr;
public:
PureStmtNodeBuilder(ExplodedNode *SrcNode, ExplodedNodeSet &DstSet,
- const NodeBuilderContext &Ctx)
- : NodeBuilder(SrcNode, DstSet, Ctx) {}
+ const NodeBuilderContext &Ctx, NodeBuilder *Enclosing = 0)
+ : NodeBuilder(SrcNode, DstSet, Ctx), EnclosingBldr(Enclosing) {
+ if (EnclosingBldr)
+ EnclosingBldr->takeNodes(SrcNode);
+ }
PureStmtNodeBuilder(ExplodedNodeSet &SrcSet, ExplodedNodeSet &DstSet,
- const NodeBuilderContext &Ctx)
- : NodeBuilder(SrcSet, DstSet, Ctx) {}
+ const NodeBuilderContext &Ctx, NodeBuilder *Enclosing = 0)
+ : NodeBuilder(SrcSet, DstSet, Ctx), EnclosingBldr(Enclosing) {
+ if (EnclosingBldr)
+ for (ExplodedNodeSet::iterator I = SrcSet.begin(),
+ E = SrcSet.end(); I != E; ++I )
+ EnclosingBldr->takeNodes(*I);
+
+ }
+
+ virtual ~PureStmtNodeBuilder() {
+ if (EnclosingBldr)
+ for (ExplodedNodeSet::iterator I = Frontier.begin(),
+ E = Frontier.end(); I != E; ++I )
+ EnclosingBldr->addNodes(*I);
+ }
ExplodedNode *generateNode(const Stmt *S,
ExplodedNode *Pred,
const ProgramState *St,
- ProgramPoint::Kind K = ProgramPoint::PostStmtKind,
bool MarkAsSink = false,
const ProgramPointTag *tag = 0,
+ ProgramPoint::Kind K = ProgramPoint::PostStmtKind,
bool Purging = false) {
if (Purging) {
assert(K == ProgramPoint::PostStmtKind);
Pred->getLocationContext(), tag);
return generateNodeImpl(L, St, Pred, MarkAsSink);
}
+
+ ExplodedNode *generateNode(const ProgramPoint &PP,
+ ExplodedNode *Pred,
+ const ProgramState *State,
+ bool MarkAsSink = false) {
+ return generateNodeImpl(PP, State, Pred, MarkAsSink);
+ }
+
};
class StmtNodeBuilder : public NodeBuilder {
PurgingDeadSymbols(false), BuildSinks(false), hasGeneratedNode(false),
PointKind(ProgramPoint::PostStmtKind), Tag(0) {}
- virtual ~StmtNodeBuilder();
-
ExplodedNode *generateNode(const Stmt *S,
const ProgramState *St,
ExplodedNode *Pred,
StmtNodeBuilder &getBuilder() { assert(Builder); return *Builder; }
const NodeBuilderContext &getBuilderContext() {
- assert(Builder);
- return Builder->getContext();
+ assert(currentBuilderContext);
+ return *currentBuilderContext;
}
bool isObjCGCEnabled() { return ObjCGCEnabled; }
+ const Stmt *getStmt() const;
+
+ void GenerateAutoTransition(ExplodedNode *N);
+
/// ViewGraph - Visualize the ExplodedGraph created by executing the
/// simulation.
void ViewGraph(bool trim = false);
/// processCFGElement - Called by CoreEngine. Used to generate new successor
/// nodes by processing the 'effects' of a CFG element.
- void processCFGElement(const CFGElement E, StmtNodeBuilder& Bldr,
- ExplodedNode *Pred);
+ void processCFGElement(const CFGElement E, ExplodedNode *Pred,
+ unsigned StmtIdx, NodeBuilderContext *Ctx);
- void ProcessStmt(const CFGStmt S, StmtNodeBuilder &builder,
- ExplodedNode *Pred);
+ void ProcessStmt(const CFGStmt S, ExplodedNode *Pred);
- void ProcessInitializer(const CFGInitializer I, StmtNodeBuilder &Bldr,
- ExplodedNode *Pred);
+ void ProcessInitializer(const CFGInitializer I, ExplodedNode *Pred);
- void ProcessImplicitDtor(const CFGImplicitDtor D, StmtNodeBuilder &builder,
- ExplodedNode *Pred);
+ void ProcessImplicitDtor(const CFGImplicitDtor D, ExplodedNode *Pred);
void ProcessAutomaticObjDtor(const CFGAutomaticObjDtor D,
StmtNodeBuilder &builder, ExplodedNode *Pred);
}
protected:
- void evalObjCMessage(ExplodedNodeSet &Dst, const ObjCMessage &msg,
- ExplodedNode *Pred, const ProgramState *state);
+ void evalObjCMessage(PureStmtNodeBuilder &Bldr, const ObjCMessage &msg,
+ ExplodedNode *Pred, const ProgramState *state,
+ bool GenSink);
const ProgramState *invalidateArguments(const ProgramState *State,
const CallOrObjCMessage &Call,
/// evalBind - Handle the semantics of binding a value to a specific location.
/// This method is used by evalStore, VisitDeclStmt, and others.
void evalBind(ExplodedNodeSet &Dst, const Stmt *StoreE, ExplodedNode *Pred,
- SVal location, SVal Val, bool atDeclInit = false);
+ SVal location, SVal Val, bool atDeclInit = false,
+ ProgramPoint::Kind PP = ProgramPoint::PostStmtKind);
public:
// FIXME: 'tag' should be removed, and a LocationContext should be used
/// Called by CoreEngine. Used to generate new successor
/// nodes by processing the 'effects' of a block-level statement.
- virtual void processCFGElement(const CFGElement E, StmtNodeBuilder& builder,
- ExplodedNode* Pred)=0;
+ virtual void processCFGElement(const CFGElement E, ExplodedNode* Pred,
+ unsigned StmtIdx, NodeBuilderContext *Ctx)=0;
/// Called by CoreEngine when it starts processing a CFGBlock. The
/// SubEngine is expected to populate dstNodes with new nodes representing
}
/// \brief Run checkers for load/store of a location.
+
void CheckerManager::runCheckersForLocation(ExplodedNodeSet &Dst,
const ExplodedNodeSet &Src,
SVal location, bool isLoad,
SVal Val;
const Stmt *S;
ExprEngine &Eng;
+ ProgramPoint::Kind PointKind;
CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
CheckBindContext(const CheckersTy &checkers,
- SVal loc, SVal val, const Stmt *s, ExprEngine &eng)
- : Checkers(checkers), Loc(loc), Val(val), S(s), Eng(eng) { }
+ SVal loc, SVal val, const Stmt *s, ExprEngine &eng,
+ ProgramPoint::Kind PK)
+ : Checkers(checkers), Loc(loc), Val(val), S(s), Eng(eng), PointKind(PK) {}
void runChecker(CheckerManager::CheckBindFunc checkFn,
NodeBuilder &Bldr, ExplodedNode *Pred) {
- ProgramPoint::Kind K = ProgramPoint::PreStmtKind;
- const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K,
+ const ProgramPoint &L = ProgramPoint::getProgramPoint(S, PointKind,
Pred->getLocationContext(), checkFn.Checker);
CheckerContext C(Bldr, Eng, Pred, L, 0);
void CheckerManager::runCheckersForBind(ExplodedNodeSet &Dst,
const ExplodedNodeSet &Src,
SVal location, SVal val,
- const Stmt *S, ExprEngine &Eng) {
- CheckBindContext C(BindCheckers, location, val, S, Eng);
+ const Stmt *S, ExprEngine &Eng,
+ ProgramPoint::Kind PointKind) {
+ CheckBindContext C(BindCheckers, location, val, S, Eng, PointKind);
expandGraphWithCheckers(C, Dst, Src);
}
// Process the entrance of the block.
if (CFGElement E = L.getFirstElement()) {
NodeBuilderContext Ctx(*this, L.getBlock(), Pred);
- ExplodedNodeSet Dst;
- StmtNodeBuilder Builder(Pred, Dst, 0, Ctx);
- SubEng.processCFGElement(E, Builder, Pred);
+ SubEng.processCFGElement(E, Pred, 0, &Ctx);
}
else
HandleBlockExit(L.getBlock(), Pred);
HandleBlockExit(B, Pred);
else {
NodeBuilderContext Ctx(*this, B, Pred);
- ExplodedNodeSet Dst;
- StmtNodeBuilder Builder(Pred, Dst, StmtIdx, Ctx);
- SubEng.processCFGElement((*B)[StmtIdx], Builder, Pred);
+ SubEng.processCFGElement((*B)[StmtIdx], Pred, StmtIdx, &Ctx);
}
}
return (IsNew ? N : 0);
}
-StmtNodeBuilder::~StmtNodeBuilder() {
- for (iterator I=Frontier.begin(), E=Frontier.end(); I!=E; ++I)
- if (!(*I)->isSink())
- GenerateAutoTransition(*I);
-}
-
void StmtNodeBuilder::GenerateAutoTransition(ExplodedNode *N) {
assert (!N->isSink());
getCheckerManager().runCheckersForEndAnalysis(G, BR, *this);
}
-void ExprEngine::processCFGElement(const CFGElement E,
- StmtNodeBuilder& Bldr,
- ExplodedNode *Pred) {
+void ExprEngine::processCFGElement(const CFGElement E, ExplodedNode *Pred,
+ unsigned StmtIdx, NodeBuilderContext *Ctx) {
+ currentStmtIdx = StmtIdx;
+ currentBuilderContext = Ctx;
+
switch (E.getKind()) {
case CFGElement::Invalid:
llvm_unreachable("Unexpected CFGElement kind.");
case CFGElement::Statement:
- ProcessStmt(const_cast<Stmt*>(E.getAs<CFGStmt>()->getStmt()), Bldr, Pred);
+ ProcessStmt(const_cast<Stmt*>(E.getAs<CFGStmt>()->getStmt()), Pred);
return;
case CFGElement::Initializer:
- ProcessInitializer(E.getAs<CFGInitializer>()->getInitializer(),
- Bldr, Pred);
+ ProcessInitializer(E.getAs<CFGInitializer>()->getInitializer(), Pred);
return;
case CFGElement::AutomaticObjectDtor:
case CFGElement::BaseDtor:
case CFGElement::MemberDtor:
case CFGElement::TemporaryDtor:
- ProcessImplicitDtor(*E.getAs<CFGImplicitDtor>(), Bldr, Pred);
+ ProcessImplicitDtor(*E.getAs<CFGImplicitDtor>(), Pred);
return;
}
}
-void ExprEngine::ProcessStmt(const CFGStmt S, StmtNodeBuilder& builder,
+const Stmt *ExprEngine::getStmt() const {
+ const CFGStmt *CS = (*currentBuilderContext->getBlock())[currentStmtIdx].getAs<CFGStmt>();
+ return CS ? CS->getStmt() : 0;
+}
+
+// TODO: Adding nodes to the worklist shoudl be a function inside CoreEngine.
+void ExprEngine::GenerateAutoTransition(ExplodedNode *N) {
+ assert (!N->isSink());
+ const CFGBlock *Block = currentBuilderContext->getBlock();
+ unsigned Idx = currentStmtIdx;
+
+ // Check if this node entered a callee.
+ if (isa<CallEnter>(N->getLocation())) {
+ // Still use the index of the CallExpr. It's needed to create the callee
+ // StackFrameContext.
+ Engine.WList->enqueue(N, Block, Idx);
+ return;
+ }
+
+ // Do not create extra nodes. Move to the next CFG element.
+ if (isa<PostInitializer>(N->getLocation())) {
+ Engine.WList->enqueue(N, Block, Idx+1);
+ return;
+ }
+
+ PostStmt Loc(getStmt(), N->getLocationContext());
+
+ if (Loc == N->getLocation()) {
+ // Note: 'N' should be a fresh node because otherwise it shouldn't be
+ // a member of Deferred.
+ Engine.WList->enqueue(N, Block, Idx+1);
+ return;
+ }
+
+ bool IsNew;
+ ExplodedNode *Succ = Engine.G->getNode(Loc, N->getState(), &IsNew);
+ Succ->addPredecessor(N, *Engine.G);
+
+ if (IsNew)
+ Engine.WList->enqueue(Succ, Block, Idx+1);
+}
+
+
+void ExprEngine::ProcessStmt(const CFGStmt S,
ExplodedNode *Pred) {
+ ExplodedNodeSet TopDst;
+ StmtNodeBuilder builder(Pred, TopDst, currentStmtIdx, *currentBuilderContext);
+
// TODO: Use RAII to remove the unnecessary, tagged nodes.
//RegisterCreatedNodes registerCreatedNodes(getGraph());
StateMgr.recycleUnusedStates();
currentStmt = S.getStmt();
- currentStmtIdx = builder.getIndex();
- currentBuilderContext = &builder.getContext();
-
PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
currentStmt->getLocStart(),
"Error evaluating statement");
// up. Since no symbols are dead, we can optimize and not clean out
// the constraint manager.
CleanedNode =
- Builder->generateNode(currentStmt, CleanedState, EntryNode, &cleanupTag);
+ builder.generateNode(currentStmt, CleanedState, EntryNode, &cleanupTag);
Tmp.Add(CleanedNode);
} else {
- SaveAndRestore<bool> OldSink(Builder->BuildSinks);
- SaveOr OldHasGen(Builder->hasGeneratedNode);
+ SaveAndRestore<bool> OldSink(builder.BuildSinks);
+ SaveOr OldHasGen(builder.hasGeneratedNode);
- SaveAndRestore<bool> OldPurgeDeadSymbols(Builder->PurgingDeadSymbols);
- Builder->PurgingDeadSymbols = true;
+ SaveAndRestore<bool> OldPurgeDeadSymbols(builder.PurgingDeadSymbols);
+ builder.PurgingDeadSymbols = true;
// Call checkers with the non-cleaned state so that they could query the
// values of the soon to be dead symbols.
// generate a transition to that state.
const ProgramState *CleanedCheckerSt =
StateMgr.getPersistentStateWithGDM(CleanedState, CheckerState);
- ExplodedNode *CleanedNode = Builder->generateNode(currentStmt,
+ ExplodedNode *CleanedNode = builder.generateNode(currentStmt,
CleanedCheckerSt, *I,
&cleanupTag);
Tmp.Add(CleanedNode);
}
}
+ ExplodedNodeSet AllDst;
for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
- // TODO: Remove Dest set, it's no longer needed.
ExplodedNodeSet Dst;
// Visit the statement.
Visit(currentStmt, *I, Dst);
+ AllDst.insert(Dst);
+ }
+
+ for (ExplodedNodeSet::iterator I = AllDst.begin(),
+ E = AllDst.end(); I != E; ++I) {
+ assert(!(*I)->isSink());
+ GenerateAutoTransition(*I);
}
// NULL out these variables to cleanup.
}
void ExprEngine::ProcessInitializer(const CFGInitializer Init,
- StmtNodeBuilder &builder,
ExplodedNode *pred) {
+ ExplodedNodeSet Dst;
+ StmtNodeBuilder Bldr(pred, Dst, currentStmtIdx, *currentBuilderContext);
+
// We don't set EntryNode and currentStmt. And we don't clean up state.
const CXXCtorInitializer *BMI = Init.getInitializer();
const StackFrameContext *stackFrame = cast<StackFrameContext>(pred->getLocationContext());
PostInitializer PP(BMI, stackFrame);
// Builder automatically add the generated node to the deferred set,
// which are processed in the builder's dtor.
- builder.generateNode(PP, state, Pred);
+ Bldr.generateNode(PP, state, Pred);
}
return;
}
getStoreManager().evalDerivedToBase(thisVal, ctorExpr->getType());
const MemRegion *baseReg = baseVal.getAsRegion();
assert(baseReg);
- Builder = &builder;
+ Builder = &Bldr;
ExplodedNodeSet dst;
VisitCXXConstructExpr(ctorExpr, baseReg, pred, dst);
+ for (ExplodedNodeSet::iterator I = dst.begin(),
+ E = dst.end(); I != E; ++I) {
+ GenerateAutoTransition(*I);
+ }
}
void ExprEngine::ProcessImplicitDtor(const CFGImplicitDtor D,
- StmtNodeBuilder &builder,
- ExplodedNode *Pred) {
+ ExplodedNode *Pred) {
+ ExplodedNodeSet Dst;
+ StmtNodeBuilder builder(Pred, Dst, currentStmtIdx, *currentBuilderContext);
+
Builder = &builder;
switch (D.getKind()) {
default:
llvm_unreachable("Unexpected dtor kind.");
}
+
+ for (ExplodedNodeSet::iterator I = Dst.begin(),
+ E = Dst.end(); I != E; ++I) {
+ GenerateAutoTransition(*I);
+ }
}
void ExprEngine::ProcessAutomaticObjDtor(const CFGAutomaticObjDtor dtor,
PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
S->getLocStart(),
"Error evaluating statement");
+ PureStmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
// Expressions to ignore.
if (const Expr *Ex = dyn_cast<Expr>(S))
// this check when we KNOW that there is no block-level subexpression.
// The motivation is that this check requires a hashtable lookup.
- if (S != currentStmt && Pred->getLocationContext()->getCFG()->isBlkExpr(S)) {
- Dst.Add(Pred);
+ if (S != currentStmt && Pred->getLocationContext()->getCFG()->isBlkExpr(S))
return;
- }
switch (S->getStmtClass()) {
// C++ and ARC stuff we don't support yet.
case Stmt::SubstNonTypeTemplateParmPackExprClass:
case Stmt::SEHTryStmtClass:
case Stmt::SEHExceptStmtClass:
- case Stmt::SEHFinallyStmtClass:
- {
- SaveAndRestore<bool> OldSink(Builder->BuildSinks);
- Builder->BuildSinks = true;
- const ExplodedNode *node = MakeNode(Dst, S, Pred, Pred->getState());
- Engine.addAbortedBlock(node, Builder->getBlock());
+ case Stmt::SEHFinallyStmtClass: {
+ const ExplodedNode *node = Bldr.generateNode(S, Pred, Pred->getState());
+ Engine.addAbortedBlock(node, currentBuilderContext->getBlock());
break;
}
// We don't handle default arguments either yet, but we can fake it
// for now by just skipping them.
case Stmt::SubstNonTypeTemplateParmExprClass:
- case Stmt::CXXDefaultArgExprClass: {
- Dst.Add(Pred);
+ case Stmt::CXXDefaultArgExprClass:
break;
- }
case Stmt::ParenExprClass:
llvm_unreachable("ParenExprs already handled.");
// GNU __null is a pointer-width integer, not an actual pointer.
const ProgramState *state = Pred->getState();
state = state->BindExpr(S, svalBuilder.makeIntValWithPtrWidth(0, false));
- MakeNode(Dst, S, Pred, state);
+ Bldr.generateNode(S, Pred, state);
break;
}
case Stmt::ObjCAtSynchronizedStmtClass:
+ Bldr.takeNodes(Pred);
VisitObjCAtSynchronizedStmt(cast<ObjCAtSynchronizedStmt>(S), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
case Stmt::ObjCPropertyRefExprClass:
// Implicitly handled by Environment::getSVal().
- Dst.Add(Pred);
break;
case Stmt::ImplicitValueInitExprClass: {
const ProgramState *state = Pred->getState();
QualType ty = cast<ImplicitValueInitExpr>(S)->getType();
SVal val = svalBuilder.makeZeroVal(ty);
- MakeNode(Dst, S, Pred, state->BindExpr(S, val));
+ Bldr.generateNode(S, Pred, state->BindExpr(S, val));
break;
}
- case Stmt::ExprWithCleanupsClass: {
+ case Stmt::ExprWithCleanupsClass:
+ Bldr.takeNodes(Pred);
Visit(cast<ExprWithCleanups>(S)->getSubExpr(), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
- }
// Cases not handled yet; but will handle some day.
case Stmt::DesignatedInitExprClass:
case Stmt::FloatingLiteralClass:
case Stmt::SizeOfPackExprClass:
case Stmt::CXXNullPtrLiteralExprClass:
- Dst.Add(Pred); // No-op. Simply propagate the current state unchanged.
+ // No-op. Simply propagate the current state unchanged.
break;
case Stmt::ArraySubscriptExprClass:
+ Bldr.takeNodes(Pred);
VisitLvalArraySubscriptExpr(cast<ArraySubscriptExpr>(S), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
case Stmt::AsmStmtClass:
+ Bldr.takeNodes(Pred);
VisitAsmStmt(cast<AsmStmt>(S), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
case Stmt::BlockDeclRefExprClass: {
+ Bldr.takeNodes(Pred);
const BlockDeclRefExpr *BE = cast<BlockDeclRefExpr>(S);
VisitCommonDeclRefExpr(BE, BE->getDecl(), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
}
case Stmt::BlockExprClass:
+ Bldr.takeNodes(Pred);
VisitBlockExpr(cast<BlockExpr>(S), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
case Stmt::BinaryOperatorClass: {
const BinaryOperator* B = cast<BinaryOperator>(S);
if (B->isLogicalOp()) {
+ Bldr.takeNodes(Pred);
VisitLogicalExpr(B, Pred, Dst);
+ Bldr.addNodes(Dst);
break;
}
else if (B->getOpcode() == BO_Comma) {
const ProgramState *state = Pred->getState();
- MakeNode(Dst, B, Pred, state->BindExpr(B, state->getSVal(B->getRHS())));
+ Bldr.generateNode(B, Pred,
+ state->BindExpr(B, state->getSVal(B->getRHS())));
break;
}
+ Bldr.takeNodes(Pred);
+
if (AMgr.shouldEagerlyAssume() &&
(B->isRelationalOp() || B->isEqualityOp())) {
ExplodedNodeSet Tmp;
else
VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
}
case Stmt::CallExprClass:
case Stmt::CXXOperatorCallExprClass:
case Stmt::CXXMemberCallExprClass: {
+ Bldr.takeNodes(Pred);
VisitCallExpr(cast<CallExpr>(S), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
}
const CXXConstructExpr *C = cast<CXXConstructExpr>(S);
// For block-level CXXConstructExpr, we don't have a destination region.
// Let VisitCXXConstructExpr() create one.
+ Bldr.takeNodes(Pred);
VisitCXXConstructExpr(C, 0, Pred, Dst);
+ Bldr.addNodes(Dst);
break;
}
case Stmt::CXXNewExprClass: {
+ Bldr.takeNodes(Pred);
const CXXNewExpr *NE = cast<CXXNewExpr>(S);
VisitCXXNewExpr(NE, Pred, Dst);
+ Bldr.addNodes(Dst);
break;
}
case Stmt::CXXDeleteExprClass: {
+ Bldr.takeNodes(Pred);
const CXXDeleteExpr *CDE = cast<CXXDeleteExpr>(S);
VisitCXXDeleteExpr(CDE, Pred, Dst);
+ Bldr.addNodes(Dst);
break;
}
// FIXME: ChooseExpr is really a constant. We need to fix
// the CFG do not model them as explicit control-flow.
case Stmt::ChooseExprClass: { // __builtin_choose_expr
+ Bldr.takeNodes(Pred);
const ChooseExpr *C = cast<ChooseExpr>(S);
VisitGuardedExpr(C, C->getLHS(), C->getRHS(), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
}
case Stmt::CompoundAssignOperatorClass:
+ Bldr.takeNodes(Pred);
VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
case Stmt::CompoundLiteralExprClass:
+ Bldr.takeNodes(Pred);
VisitCompoundLiteralExpr(cast<CompoundLiteralExpr>(S), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
case Stmt::BinaryConditionalOperatorClass:
case Stmt::ConditionalOperatorClass: { // '?' operator
+ Bldr.takeNodes(Pred);
const AbstractConditionalOperator *C
= cast<AbstractConditionalOperator>(S);
VisitGuardedExpr(C, C->getTrueExpr(), C->getFalseExpr(), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
}
case Stmt::CXXThisExprClass:
+ Bldr.takeNodes(Pred);
VisitCXXThisExpr(cast<CXXThisExpr>(S), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
case Stmt::DeclRefExprClass: {
+ Bldr.takeNodes(Pred);
const DeclRefExpr *DE = cast<DeclRefExpr>(S);
VisitCommonDeclRefExpr(DE, DE->getDecl(), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
}
case Stmt::DeclStmtClass:
+ Bldr.takeNodes(Pred);
VisitDeclStmt(cast<DeclStmt>(S), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
case Stmt::ImplicitCastExprClass:
case Stmt::CXXConstCastExprClass:
case Stmt::CXXFunctionalCastExprClass:
case Stmt::ObjCBridgedCastExprClass: {
+ Bldr.takeNodes(Pred);
const CastExpr *C = cast<CastExpr>(S);
// Handle the previsit checks.
ExplodedNodeSet dstPrevisit;
// Handle the postvisit checks.
getCheckerManager().runCheckersForPostStmt(Dst, dstExpr, C, *this);
+ Bldr.addNodes(Dst);
break;
}
case Expr::MaterializeTemporaryExprClass: {
+ Bldr.takeNodes(Pred);
const MaterializeTemporaryExpr *Materialize
= cast<MaterializeTemporaryExpr>(S);
if (!Materialize->getType()->isRecordType())
CreateCXXTemporaryObject(Materialize, Pred, Dst);
else
Visit(Materialize->GetTemporaryExpr(), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
}
case Stmt::InitListExprClass:
+ Bldr.takeNodes(Pred);
VisitInitListExpr(cast<InitListExpr>(S), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
case Stmt::MemberExprClass:
+ Bldr.takeNodes(Pred);
VisitMemberExpr(cast<MemberExpr>(S), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
+
case Stmt::ObjCIvarRefExprClass:
+ Bldr.takeNodes(Pred);
VisitLvalObjCIvarRefExpr(cast<ObjCIvarRefExpr>(S), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
case Stmt::ObjCForCollectionStmtClass:
+ Bldr.takeNodes(Pred);
VisitObjCForCollectionStmt(cast<ObjCForCollectionStmt>(S), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
case Stmt::ObjCMessageExprClass:
+ Bldr.takeNodes(Pred);
VisitObjCMessage(cast<ObjCMessageExpr>(S), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
case Stmt::ObjCAtThrowStmtClass: {
// FIXME: This is not complete. We basically treat @throw as
// an abort.
- SaveAndRestore<bool> OldSink(Builder->BuildSinks);
- Builder->BuildSinks = true;
- MakeNode(Dst, S, Pred, Pred->getState());
+ Bldr.generateNode(S, Pred, Pred->getState());
break;
}
case Stmt::ReturnStmtClass:
+ Bldr.takeNodes(Pred);
VisitReturnStmt(cast<ReturnStmt>(S), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
case Stmt::OffsetOfExprClass:
+ Bldr.takeNodes(Pred);
VisitOffsetOfExpr(cast<OffsetOfExpr>(S), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
case Stmt::UnaryExprOrTypeTraitExprClass:
+ Bldr.takeNodes(Pred);
VisitUnaryExprOrTypeTraitExpr(cast<UnaryExprOrTypeTraitExpr>(S),
Pred, Dst);
+ Bldr.addNodes(Dst);
break;
case Stmt::StmtExprClass: {
// Empty statement expression.
assert(SE->getType() == getContext().VoidTy
&& "Empty statement expression must have void type.");
- Dst.Add(Pred);
break;
}
if (Expr *LastExpr = dyn_cast<Expr>(*SE->getSubStmt()->body_rbegin())) {
const ProgramState *state = Pred->getState();
- MakeNode(Dst, SE, Pred, state->BindExpr(SE, state->getSVal(LastExpr)));
+ Bldr.generateNode(SE, Pred,
+ state->BindExpr(SE, state->getSVal(LastExpr)));
}
- else
- Dst.Add(Pred);
-
break;
}
case Stmt::StringLiteralClass: {
const ProgramState *state = Pred->getState();
SVal V = state->getLValue(cast<StringLiteral>(S));
- MakeNode(Dst, S, Pred, state->BindExpr(S, V));
+ Bldr.generateNode(S, Pred, state->BindExpr(S, V));
return;
}
case Stmt::UnaryOperatorClass: {
+ Bldr.takeNodes(Pred);
const UnaryOperator *U = cast<UnaryOperator>(S);
- if (AMgr.shouldEagerlyAssume()&&(U->getOpcode() == UO_LNot)) {
+ if (AMgr.shouldEagerlyAssume() && (U->getOpcode() == UO_LNot)) {
ExplodedNodeSet Tmp;
VisitUnaryOperator(U, Pred, Tmp);
evalEagerlyAssume(Dst, Tmp, U);
}
else
VisitUnaryOperator(U, Pred, Dst);
+ Bldr.addNodes(Dst);
break;
}
}
void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
+ PureStmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext, Builder);
+
const ProgramState *state = Pred->getState();
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
V = UnknownVal();
}
- MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, V),
- ProgramPoint::PostLValueKind);
+ Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, V), false, 0,
+ ProgramPoint::PostLValueKind);
return;
}
if (const EnumConstantDecl *ED = dyn_cast<EnumConstantDecl>(D)) {
assert(!Ex->isLValue());
SVal V = svalBuilder.makeIntVal(ED->getInitVal());
- MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, V));
+ Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, V));
return;
}
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
SVal V = svalBuilder.getFunctionPointer(FD);
- MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, V),
- ProgramPoint::PostLValueKind);
+ Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, V), false, 0,
+ ProgramPoint::PostLValueKind);
return;
}
assert (false &&
ExplodedNodeSet checkerPreStmt;
getCheckerManager().runCheckersForPreStmt(checkerPreStmt, Pred, A, *this);
+ PureStmtNodeBuilder Bldr(checkerPreStmt, Dst, *currentBuilderContext, Builder);
+
for (ExplodedNodeSet::iterator it = checkerPreStmt.begin(),
ei = checkerPreStmt.end(); it != ei; ++it) {
const ProgramState *state = (*it)->getState();
SVal V = state->getLValue(A->getType(), state->getSVal(Idx),
state->getSVal(Base));
assert(A->isLValue());
- MakeNode(Dst, A, *it, state->BindExpr(A, V), ProgramPoint::PostLValueKind);
+ Bldr.generateNode(A, *it, state->BindExpr(A, V),
+ false, 0, ProgramPoint::PostLValueKind);
}
}
void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
+ PureStmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext, Builder);
Decl *member = M->getMemberDecl();
if (VarDecl *VD = dyn_cast<VarDecl>(member)) {
assert(M->isLValue());
+ Bldr.takeNodes(Pred);
VisitCommonDeclRefExpr(M, VD, Pred, Dst);
+ Bldr.addNodes(Dst);
return;
}
// temporary struct object, see test/Analysis/fields.c:
// (p = getit()).x
isa<nonloc::SymbolVal>(baseExprVal)) {
- MakeNode(Dst, M, Pred, state->BindExpr(M, UnknownVal()));
+ Bldr.generateNode(M, Pred, state->BindExpr(M, UnknownVal()));
return;
}
// For all other cases, compute an lvalue.
SVal L = state->getLValue(field, baseExprVal);
if (M->isLValue())
- MakeNode(Dst, M, Pred, state->BindExpr(M, L), ProgramPoint::PostLValueKind);
- else
+ Bldr.generateNode(M, Pred, state->BindExpr(M, L), false, 0,
+ ProgramPoint::PostLValueKind);
+ else {
+ Bldr.takeNodes(Pred);
evalLoad(Dst, M, Pred, state, L);
+ Bldr.addNodes(Dst);
+ }
}
/// evalBind - Handle the semantics of binding a value to a specific location.
/// This method is used by evalStore and (soon) VisitDeclStmt, and others.
void ExprEngine::evalBind(ExplodedNodeSet &Dst, const Stmt *StoreE,
ExplodedNode *Pred,
- SVal location, SVal Val, bool atDeclInit) {
+ SVal location, SVal Val, bool atDeclInit,
+ ProgramPoint::Kind PointKind) {
// Do a previsit of the bind.
ExplodedNodeSet CheckedSet;
getCheckerManager().runCheckersForBind(CheckedSet, Pred, location, Val,
- StoreE, *this);
+ StoreE, *this, PointKind);
// TODO:AZ Remove TmpDst after NB refactoring is done.
ExplodedNodeSet TmpDst;
- Builder->takeNodes(CheckedSet);
PureStmtNodeBuilder Bldr(CheckedSet, TmpDst, *currentBuilderContext);
for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end();
state = state->bindLoc(location, Val);
}
- Bldr.generateNode(StoreE, *I, state);
+ Bldr.generateNode(StoreE, *I, state, false, 0, PointKind);
}
- Builder->addNodes(TmpDst);
+
Dst.insert(TmpDst);
}
if (location.isUndef())
return;
- SaveAndRestore<ProgramPoint::Kind> OldSPointKind(Builder->PointKind,
- ProgramPoint::PostStoreKind);
-
for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI)
- evalBind(Dst, StoreE, *NI, location, Val);
+ evalBind(Dst, StoreE, *NI, location, Val, false,
+ ProgramPoint::PostStoreKind);
}
void ExprEngine::evalLoad(ExplodedNodeSet &Dst, const Expr *Ex,
// Evaluate the location (checks for bad dereferences).
ExplodedNodeSet Tmp;
evalLocation(Tmp, Ex, Pred, state, location, tag, true);
-
if (Tmp.empty())
return;
+ PureStmtNodeBuilder Bldr(Tmp, Dst, *currentBuilderContext, Builder);
if (location.isUndef())
return;
- SaveAndRestore<ProgramPoint::Kind> OldSPointKind(Builder->PointKind);
-
// Proceed with the load.
for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) {
state = (*NI)->getState();
if (location.isUnknown()) {
// This is important. We must nuke the old binding.
- MakeNode(Dst, Ex, *NI, state->BindExpr(Ex, UnknownVal()),
- ProgramPoint::PostLoadKind, tag);
+ Bldr.generateNode(Ex, *NI, state->BindExpr(Ex, UnknownVal()),
+ false, tag, ProgramPoint::PostLoadKind);
}
else {
if (LoadTy.isNull())
LoadTy = Ex->getType();
SVal V = state->getSVal(cast<Loc>(location), LoadTy);
- MakeNode(Dst, Ex, *NI, state->bindExprAndLocation(Ex, location, V),
- ProgramPoint::PostLoadKind, tag);
+ Bldr.generateNode(Ex, *NI, state->bindExprAndLocation(Ex, location, V),
+ false, tag, ProgramPoint::PostLoadKind);
}
}
}
ExplodedNode *Pred,
const ProgramState *state, SVal location,
const ProgramPointTag *tag, bool isLoad) {
+ PureStmtNodeBuilder BldrTop(Pred, Dst, *currentBuilderContext, Builder);
// Early checks for performance reason.
if (location.isUnknown()) {
- Dst.Add(Pred);
return;
}
ExplodedNodeSet Src;
- if (Pred->getState() == state) {
- Src.Add(Pred);
- } else {
+ BldrTop.takeNodes(Pred);
+ PureStmtNodeBuilder Bldr(Pred, Src, *currentBuilderContext);
+ if (Pred->getState() != state) {
// Associate this new state with an ExplodedNode.
// FIXME: If I pass null tag, the graph is incorrect, e.g for
// int *p;
// FIXME: why is 'tag' not used instead of etag?
static SimpleProgramPointTag etag("ExprEngine: Location");
- ExplodedNode *N = Builder->generateNode(S, state, Pred, &etag);
- Src.Add(N ? N : Pred);
+ Bldr.generateNode(S, Pred, state, false, &etag);
}
- getCheckerManager().runCheckersForLocation(Dst, Src, location, isLoad, S,
+ ExplodedNodeSet Tmp;
+ getCheckerManager().runCheckersForLocation(Tmp, Src, location, isLoad, S,
*this);
+ BldrTop.addNodes(Tmp);
}
bool ExprEngine::InlineCall(ExplodedNodeSet &Dst, const CallExpr *CE,
void ExprEngine::evalEagerlyAssume(ExplodedNodeSet &Dst, ExplodedNodeSet &Src,
const Expr *Ex) {
-
+ PureStmtNodeBuilder Bldr(Src, Dst, *currentBuilderContext, Builder);
for (ExplodedNodeSet::iterator I=Src.begin(), E=Src.end(); I!=E; ++I) {
ExplodedNode *Pred = *I;
-
// Test if the previous node was as the same expression. This can happen
// when the expression fails to evaluate to anything meaningful and
// (as an optimization) we don't generate a node.
ProgramPoint P = Pred->getLocation();
if (!isa<PostStmt>(P) || cast<PostStmt>(P).getStmt() != Ex) {
- Dst.Add(Pred);
continue;
}
if (const ProgramState *StateTrue = state->assume(*SEV, true)) {
SVal Val = svalBuilder.makeIntVal(1U, Ex->getType());
StateTrue = StateTrue->BindExpr(Ex, Val);
- Dst.Add(Builder->generateNode(Ex, StateTrue, Pred, tags.first));
+ Bldr.generateNode(Ex, Pred, StateTrue, false, tags.first);
}
// Next, assume that the condition is false.
if (const ProgramState *StateFalse = state->assume(*SEV, false)) {
SVal Val = svalBuilder.makeIntVal(0U, Ex->getType());
StateFalse = StateFalse->BindExpr(Ex, Val);
- Dst.Add(Builder->generateNode(Ex, StateFalse, Pred, tags.second));
+ Bldr.generateNode(Ex, Pred, StateFalse, false, tags.second);
}
}
- else
- Dst.Add(Pred);
}
}
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
if (I == E) {
-
+ PureStmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext, Builder);
// We have processed both the inputs and the outputs. All of the outputs
// should evaluate to Locs. Nuke all of their values.
state = state->bindLoc(cast<Loc>(X), UnknownVal());
}
- MakeNode(Dst, A, Pred, state);
+ Bldr.generateNode(A, Pred, state);
return;
}
// FIXME: Handle structs.
if (RightV.isUnknown() ||
!getConstraintManager().canReasonAbout(RightV)) {
- unsigned Count = Builder->getCurrentBlockCount();
+ unsigned Count = currentBuilderContext->getCurrentBlockCount();
RightV = svalBuilder.getConjuredSymbolVal(NULL, B->getRHS(), Count);
}
// Simulate the effects of a "store": bind the value of the RHS
}
if (!B->isAssignmentOp()) {
+ PureStmtNodeBuilder Bldr(*it, Tmp2, *currentBuilderContext, Builder);
// Process non-assignments except commas or short-circuited
// logical expressions (LAnd and LOr).
SVal Result = evalBinOp(state, Op, LeftV, RightV, B->getType());
if (Result.isUnknown()) {
- MakeNode(Tmp2, B, *it, state);
+ Bldr.generateNode(B, *it, state);
continue;
}
state = state->BindExpr(B, Result);
- MakeNode(Tmp2, B, *it, state);
+ Bldr.generateNode(B, *it, state);
continue;
}
if (Result.isUnknown() ||
!getConstraintManager().canReasonAbout(Result)) {
- unsigned Count = Builder->getCurrentBlockCount();
+ unsigned Count = currentBuilderContext->getCurrentBlockCount();
// The symbolic value is actually for the type of the left-hand side
// expression, not the computation type, as this is the value the
Pred->getLocationContext());
ExplodedNodeSet Tmp;
- MakeNode(Tmp, BE, Pred, Pred->getState()->BindExpr(BE, V),
- ProgramPoint::PostLValueKind);
+ PureStmtNodeBuilder Bldr(Pred, Tmp, *currentBuilderContext);
+ Bldr.generateNode(BE, Pred, Pred->getState()->BindExpr(BE, V), false, 0,
+ ProgramPoint::PostLValueKind);
// FIXME: Move all post/pre visits to ::Visit().
getCheckerManager().runCheckersForPostStmt(Dst, Tmp, BE, *this);
if (const ExplicitCastExpr *ExCast=dyn_cast_or_null<ExplicitCastExpr>(CastE))
T = ExCast->getTypeAsWritten();
+ PureStmtNodeBuilder Bldr(dstPreStmt, Dst, *currentBuilderContext, Builder);
for (ExplodedNodeSet::iterator I = dstPreStmt.begin(), E = dstPreStmt.end();
I != E; ++I) {
case CK_GetObjCProperty:
llvm_unreachable("GetObjCProperty casts handled earlier.");
case CK_ToVoid:
- Dst.Add(Pred);
continue;
// The analyzer doesn't do anything special with these casts,
// since it understands retain/release semantics already.
const ProgramState *state = Pred->getState();
SVal V = state->getSVal(Ex);
state = state->BindExpr(CastE, V);
- MakeNode(Dst, CastE, Pred, state);
+ Bldr.generateNode(CastE, Pred, state);
continue;
}
case CK_Dependent:
SVal V = state->getSVal(Ex);
V = svalBuilder.evalCast(V, T, ExTy);
state = state->BindExpr(CastE, V);
- MakeNode(Dst, CastE, Pred, state);
+ Bldr.generateNode(CastE, Pred, state);
continue;
}
case CK_DerivedToBase:
SVal val = state->getSVal(Ex);
val = getStoreManager().evalDerivedToBase(val, T);
state = state->BindExpr(CastE, val);
- MakeNode(Dst, CastE, Pred, state);
+ Bldr.generateNode(CastE, Pred, state);
continue;
}
// Various C++ casts that are not handled yet.
SVal result =
svalBuilder.getConjuredSymbolVal(NULL, CastE, resultType,
- Builder->getCurrentBlockCount());
+ currentBuilderContext->getCurrentBlockCount());
const ProgramState *state = Pred->getState()->BindExpr(CastE, result);
- MakeNode(Dst, CastE, Pred, state);
+ Bldr.generateNode(CastE, Pred, state);
continue;
}
}
void ExprEngine::VisitCompoundLiteralExpr(const CompoundLiteralExpr *CL,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
- PureStmtNodeBuilder B(Pred, Dst, *currentBuilderContext);
- Builder->takeNodes(Pred);
+ PureStmtNodeBuilder B(Pred, Dst, *currentBuilderContext, Builder);
const InitListExpr *ILE
= cast<InitListExpr>(CL->getInitializer()->IgnoreParens());
B.generateNode(CL, Pred, state->BindExpr(CL, state->getLValue(CL, LC)));
else
B.generateNode(CL, Pred, state->BindExpr(CL, ILV));
- Builder->addNodes(Dst);
}
void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred,
// Assumption: The CFG has one DeclStmt per Decl.
const Decl *D = *DS->decl_begin();
- if (!D || !isa<VarDecl>(D))
+ if (!D || !isa<VarDecl>(D)) {
+ //TODO:AZ: remove explicit insertion after refactoring is done.
+ Dst.insert(Pred);
return;
+ }
// FIXME: all pre/post visits should eventually be handled by ::Visit().
ExplodedNodeSet dstPreVisit;
getCheckerManager().runCheckersForPreStmt(dstPreVisit, Pred, DS, *this);
- PureStmtNodeBuilder B(dstPreVisit, Dst, *currentBuilderContext);
- Builder->takeNodes(dstPreVisit);
+ PureStmtNodeBuilder B(dstPreVisit, Dst, *currentBuilderContext, Builder);
const VarDecl *VD = dyn_cast<VarDecl>(D);
for (ExplodedNodeSet::iterator I = dstPreVisit.begin(), E = dstPreVisit.end();
I!=E; ++I) {
!getConstraintManager().canReasonAbout(InitVal)) &&
!VD->getType()->isReferenceType()) {
InitVal = svalBuilder.getConjuredSymbolVal(NULL, InitEx,
- Builder->getCurrentBlockCount());
+ currentBuilderContext->getCurrentBlockCount());
}
B.takeNodes(N);
evalBind(Dst, DS, N, state->getLValue(VD, LC), InitVal, true);
B.generateNode(DS, N,state->bindDeclWithNoInit(state->getRegion(VD, LC)));
}
}
- Builder->addNodes(Dst);
}
void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
- Builder->takeNodes(Pred);
- PureStmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
-
assert(B->getOpcode() == BO_LAnd ||
B->getOpcode() == BO_LOr);
-
+
+ PureStmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext, Builder);
const ProgramState *state = Pred->getState();
SVal X = state->getSVal(B);
assert(X.isUndef());
// Handle undefined values.
if (X.isUndef()) {
Bldr.generateNode(B, Pred, state->BindExpr(B, X));
- Builder->addNodes(Dst);
return;
}
B->getType());
Bldr.generateNode(B, Pred, state->BindExpr(B, X));
}
- Builder->addNodes(Dst);
}
void ExprEngine::VisitInitListExpr(const InitListExpr *IE,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
- Builder->takeNodes(Pred);
- PureStmtNodeBuilder B(Pred, Dst, *currentBuilderContext);
+ PureStmtNodeBuilder B(Pred, Dst, *currentBuilderContext, Builder);
const ProgramState *state = Pred->getState();
QualType T = getContext().getCanonicalType(IE->getType());
if (NumInitElements == 0) {
SVal V = svalBuilder.makeCompoundVal(T, vals);
B.generateNode(IE, Pred, state->BindExpr(IE, V));
- Builder->addNodes(Dst);
return;
}
B.generateNode(IE, Pred,
state->BindExpr(IE, svalBuilder.makeCompoundVal(T, vals)));
- Builder->addNodes(Dst);
return;
}
assert(IE->getNumInits() == 1);
const Expr *initEx = IE->getInit(0);
B.generateNode(IE, Pred, state->BindExpr(IE, state->getSVal(initEx)));
- Builder->addNodes(Dst);
return;
}
const Expr *R,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
- Builder->takeNodes(Pred);
- PureStmtNodeBuilder B(Pred, Dst, *currentBuilderContext);
+ PureStmtNodeBuilder B(Pred, Dst, *currentBuilderContext, Builder);
const ProgramState *state = Pred->getState();
SVal X = state->getSVal(Ex);
// Make sure that we invalidate the previous binding.
B.generateNode(Ex, Pred, state->BindExpr(Ex, X, true));
- Builder->addNodes(Dst);
}
void ExprEngine::
VisitOffsetOfExpr(const OffsetOfExpr *OOE,
ExplodedNode *Pred, ExplodedNodeSet &Dst) {
- Builder->takeNodes(Pred);
- PureStmtNodeBuilder B(Pred, Dst, *currentBuilderContext);
+ PureStmtNodeBuilder B(Pred, Dst, *currentBuilderContext, Builder);
Expr::EvalResult Res;
if (OOE->Evaluate(Res, getContext()) && Res.Val.isInt()) {
const APSInt &IV = Res.Val.getInt();
B.generateNode(OOE, Pred, Pred->getState()->BindExpr(OOE, X));
}
// FIXME: Handle the case where __builtin_offsetof is not a constant.
- Builder->addNodes(Dst);
}
VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Ex,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
+ PureStmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext, Builder);
QualType T = Ex->getTypeOfArgument();
// FIXME: Add support for VLA type arguments and VLA expressions.
// When that happens, we should probably refactor VLASizeChecker's code.
- Dst.Add(Pred);
return;
}
else if (T->getAs<ObjCObjectType>()) {
// Some code tries to take the sizeof an ObjCObjectType, relying that
// the compiler has laid out its representation. Just report Unknown
// for these.
- Dst.Add(Pred);
return;
}
}
const ProgramState *state = Pred->getState();
state = state->BindExpr(Ex, svalBuilder.makeIntVal(amt.getQuantity(),
Ex->getType()));
- MakeNode(Dst, Ex, Pred, state);
+ Bldr.generateNode(Ex, Pred, state);
}
void ExprEngine::VisitUnaryOperator(const UnaryOperator* U,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
- Builder->takeNodes(Pred);
PureStmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
bool IncDec = false;
switch (U->getOpcode()) {
- default:
- Builder->addNodes(Pred);
+ default: {
+ Bldr.takeNodes(Pred);
IncDec = true;
- VisitIncrementDecrementOperator(U, Pred, Dst);
+ ExplodedNodeSet Tmp;
+ VisitIncrementDecrementOperator(U, Pred, Tmp);
+ Bldr.addNodes(Tmp);
+ }
break;
case UO_Real: {
const Expr *Ex = U->getSubExpr()->IgnoreParens();
}
}
- if (!IncDec)
- Builder->addNodes(Dst);
}
void ExprEngine::VisitIncrementDecrementOperator(const UnaryOperator* U,
ExplodedNodeSet Tmp2;
evalLoad(Tmp2, Ex, *I, state, loc);
+ ExplodedNodeSet Dst2;
+ PureStmtNodeBuilder Bldr(Tmp2, Dst2, *currentBuilderContext, Builder);
for (ExplodedNodeSet::iterator I2=Tmp2.begin(), E2=Tmp2.end();I2!=E2;++I2) {
state = (*I2)->getState();
// Propagate unknown and undefined values.
if (V2_untested.isUnknownOrUndef()) {
- MakeNode(Dst, U, *I2, state->BindExpr(U, V2_untested));
+ Bldr.generateNode(U, *I2, state->BindExpr(U, V2_untested));
continue;
}
DefinedSVal V2 = cast<DefinedSVal>(V2_untested);
if (Result.isUnknown() || !getConstraintManager().canReasonAbout(Result)){
DefinedOrUnknownSVal SymVal =
svalBuilder.getConjuredSymbolVal(NULL, Ex,
- Builder->getCurrentBlockCount());
+ currentBuilderContext->getCurrentBlockCount());
Result = SymVal;
// If the value is a location, ++/-- should always preserve
state = state->BindExpr(U, U->isPostfix() ? V2 : Result);
// Perform the store.
- evalStore(Dst, NULL, U, *I2, state, loc, Result);
+ Bldr.takeNodes(*I2);
+ ExplodedNodeSet Dst4;
+ evalStore(Dst4, NULL, U, *I2, state, loc, Result);
+ Bldr.addNodes(Dst4);
}
+ Dst.insert(Dst2);
}
}
void ExprEngine::CreateCXXTemporaryObject(const MaterializeTemporaryExpr *ME,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
+ PureStmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext, Builder);
const Expr *tempExpr = ME->GetTemporaryExpr()->IgnoreParens();
const ProgramState *state = Pred->getState();
Pred->getLocationContext());
state = state->bindLoc(loc::MemRegionVal(R), V);
- MakeNode(Dst, ME, Pred, state->BindExpr(ME, loc::MemRegionVal(R)));
+ Bldr.generateNode(ME, Pred, state->BindExpr(ME, loc::MemRegionVal(R)));
}
void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E,
// parameter region.
const StackFrameContext *SFC =
AMgr.getStackFrame(CD, Pred->getLocationContext(),
- E, Builder->getBlock(), Builder->getIndex());
+ E, currentBuilderContext->getBlock(),
+ currentStmtIdx);
// Create the 'this' region.
const CXXThisRegion *ThisR =
CallEnter Loc(E, SFC, Pred->getLocationContext());
-
+ PureStmtNodeBuilder Bldr(argsEvaluated, destNodes, *currentBuilderContext);
for (ExplodedNodeSet::iterator NI = argsEvaluated.begin(),
NE = argsEvaluated.end(); NI != NE; ++NI) {
const ProgramState *state = (*NI)->getState();
// Setup 'this' region, so that the ctor is evaluated on the object pointed
// by 'Dest'.
state = state->bindLoc(loc::MemRegionVal(ThisR), loc::MemRegionVal(Dest));
- if (ExplodedNode *N = Builder->generateNode(Loc, state, *NI))
- destNodes.Add(N);
+ Bldr.generateNode(Loc, *NI, state);
}
}
#endif
// Default semantics: invalidate all regions passed as arguments.
ExplodedNodeSet destCall;
-
- for (ExplodedNodeSet::iterator
- i = destPreVisit.begin(), e = destPreVisit.end();
- i != e; ++i)
{
- ExplodedNode *Pred = *i;
- const LocationContext *LC = Pred->getLocationContext();
- const ProgramState *state = Pred->getState();
+ PureStmtNodeBuilder Bldr(destPreVisit, destCall,
+ *currentBuilderContext, Builder);
+ for (ExplodedNodeSet::iterator
+ i = destPreVisit.begin(), e = destPreVisit.end();
+ i != e; ++i)
+ {
+ ExplodedNode *Pred = *i;
+ const LocationContext *LC = Pred->getLocationContext();
+ const ProgramState *state = Pred->getState();
- state = invalidateArguments(state, CallOrObjCMessage(E, state), LC);
- Builder->MakeNode(destCall, E, Pred, state);
+ state = invalidateArguments(state, CallOrObjCMessage(E, state), LC);
+ Bldr.generateNode(E, Pred, state);
+ }
}
-
// Do the post visit.
getCheckerManager().runCheckersForPostStmt(destNodes, destCall, E, *this);
}
void ExprEngine::VisitCXXDestructor(const CXXDestructorDecl *DD,
- const MemRegion *Dest,
- const Stmt *S,
- ExplodedNode *Pred,
- ExplodedNodeSet &Dst) {
+ const MemRegion *Dest,
+ const Stmt *S,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
+ PureStmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext, Builder);
if (!(DD->doesThisDeclarationHaveABody() && AMgr.shouldInlineCall()))
return;
const StackFrameContext *SFC =
AnalysisDeclContexts.getContext(DD)->
getStackFrame(Pred->getLocationContext(), S,
- Builder->getBlock(), Builder->getIndex());
+ currentBuilderContext->getBlock(), currentStmtIdx);
const CXXThisRegion *ThisR = getCXXThisRegion(DD->getParent(), SFC);
const ProgramState *state = Pred->getState();
state = state->bindLoc(loc::MemRegionVal(ThisR), loc::MemRegionVal(Dest));
- ExplodedNode *N = Builder->generateNode(PP, state, Pred);
- if (N)
- Dst.Add(N);
+ Bldr.generateNode(PP, Pred, state);
}
void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
+ PureStmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext, Builder);
- unsigned blockCount = Builder->getCurrentBlockCount();
+ unsigned blockCount = currentBuilderContext->getCurrentBlockCount();
DefinedOrUnknownSVal symVal =
svalBuilder.getConjuredSymbolVal(NULL, CNE, CNE->getType(), blockCount);
const MemRegion *NewReg = cast<loc::MemRegionVal>(symVal).getRegion();
// For now, just return a symbolicated region.
const ProgramState *state = Pred->getState();
state = state->BindExpr(CNE, loc::MemRegionVal(EleReg));
- MakeNode(Dst, CNE, Pred, state);
+ Bldr.generateNode(CNE, Pred, state);
return;
}
if (CD)
FnType = CD->getType()->getAs<FunctionProtoType>();
ExplodedNodeSet argsEvaluated;
+ Bldr.takeNodes(Pred);
evalArguments(CNE->constructor_arg_begin(), CNE->constructor_arg_end(),
FnType, Pred, argsEvaluated);
+ Bldr.addNodes(argsEvaluated);
// Initialize the object region and bind the 'new' expression.
for (ExplodedNodeSet::iterator I = argsEvaluated.begin(),
}
}
state = state->BindExpr(CNE, loc::MemRegionVal(EleReg));
- MakeNode(Dst, CNE, *I, state);
+ Bldr.generateNode(CNE, *I, state);
}
}
void ExprEngine::VisitCXXDeleteExpr(const CXXDeleteExpr *CDE,
- ExplodedNode *Pred,ExplodedNodeSet &Dst) {
+ ExplodedNode *Pred, ExplodedNodeSet &Dst) {
// Should do more checking.
ExplodedNodeSet Argevaluated;
Visit(CDE->getArgument(), Pred, Argevaluated);
+ PureStmtNodeBuilder Bldr(Argevaluated, Dst, *currentBuilderContext, Builder);
for (ExplodedNodeSet::iterator I = Argevaluated.begin(),
E = Argevaluated.end(); I != E; ++I) {
const ProgramState *state = (*I)->getState();
- MakeNode(Dst, CDE, *I, state);
+ Bldr.generateNode(CDE, *I, state);
}
}
void ExprEngine::VisitCXXThisExpr(const CXXThisExpr *TE, ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
+ PureStmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext, Builder);
+
// Get the this object region from StoreManager.
const MemRegion *R =
svalBuilder.getRegionManager().getCXXThisRegion(
const ProgramState *state = Pred->getState();
SVal V = state->getSVal(loc::MemRegionVal(R));
- MakeNode(Dst, TE, Pred, state->BindExpr(TE, V));
+ Bldr.generateNode(TE, Pred, state->BindExpr(TE, V));
}
// expression (the context) and the expression itself. This should
// disambiguate conjured symbols.
assert(Builder && "Invalidating arguments outside of a statement context");
- unsigned Count = Builder->getCurrentBlockCount();
+ unsigned Count = currentBuilderContext->getCurrentBlockCount();
StoreManager::InvalidatedSymbols IS;
// NOTE: Even if RegionsToInvalidate is empty, we may still invalidate
}
// First handle the return value.
- StmtNodeBuilder &Builder = Eng.getBuilder();
- assert(&Builder && "StmtNodeBuilder must be defined.");
+ PureStmtNodeBuilder Bldr(Pred, Dst, *Eng.currentBuilderContext, Eng.Builder);
// Get the callee.
const Expr *Callee = CE->getCallee()->IgnoreParens();
// Conjure a symbol value to use as the result.
SValBuilder &SVB = Eng.getSValBuilder();
- unsigned Count = Builder.getCurrentBlockCount();
+ unsigned Count = Eng.currentBuilderContext->getCurrentBlockCount();
SVal RetVal = SVB.getConjuredSymbolVal(0, CE, ResultTy, Count);
// Generate a new state with the return value set.
state = Eng.invalidateArguments(state, CallOrObjCMessage(CE, state), LC);
// And make the result node.
- Eng.MakeNode(Dst, CE, Pred, state);
+ Bldr.generateNode(CE, Pred, state);
}
};
void ExprEngine::VisitReturnStmt(const ReturnStmt *RS, ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
ExplodedNodeSet Src;
- if (const Expr *RetE = RS->getRetValue()) {
- // Record the returned expression in the state. It will be used in
- // processCallExit to bind the return value to the call expr.
- {
- static SimpleProgramPointTag tag("ExprEngine: ReturnStmt");
- const ProgramState *state = Pred->getState();
- state = state->set<ReturnExpr>(RetE);
- Pred = Builder->generateNode(RetE, state, Pred, &tag);
+ {
+ PureStmtNodeBuilder Bldr(Pred, Src, *currentBuilderContext, Builder);
+ if (const Expr *RetE = RS->getRetValue()) {
+ // Record the returned expression in the state. It will be used in
+ // processCallExit to bind the return value to the call expr.
+ {
+ static SimpleProgramPointTag tag("ExprEngine: ReturnStmt");
+ const ProgramState *state = Pred->getState();
+ state = state->set<ReturnExpr>(RetE);
+ Pred = Bldr.generateNode(RetE, Pred, state, false, &tag);
+ }
+ // We may get a NULL Pred because we generated a cached node.
+ if (Pred) {
+ Bldr.takeNodes(Pred);
+ ExplodedNodeSet Tmp;
+ Visit(RetE, Pred, Tmp);
+ Bldr.addNodes(Tmp);
+ }
}
- // We may get a NULL Pred because we generated a cached node.
- if (Pred)
- Visit(RetE, Pred, Src);
- }
- else {
- Src.Add(Pred);
}
getCheckerManager().runCheckersForPreStmt(Dst, Src, RS, *this);
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"
-#include "clang/Analysis/Support/SaveAndRestore.h"
using namespace clang;
using namespace ento;
void ExprEngine::VisitLvalObjCIvarRefExpr(const ObjCIvarRefExpr *Ex,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
-
const ProgramState *state = Pred->getState();
SVal baseVal = state->getSVal(Ex->getBase());
SVal location = state->getLValue(Ex->getDecl(), baseVal);
ExplodedNodeSet dstIvar;
- MakeNode(dstIvar, Ex, Pred, state->BindExpr(Ex, location));
+ PureStmtNodeBuilder Bldr(Pred, dstIvar, *currentBuilderContext);
+ Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, location));
// Perform the post-condition check of the ObjCIvarRefExpr and store
// the created nodes in 'Dst'.
// For now: simulate (1) by assigning either a symbol or nil if the
// container is empty. Thus this transfer function will by default
// result in state splitting.
-
+
const Stmt *elem = S->getElement();
const ProgramState *state = Pred->getState();
SVal elementV;
+ PureStmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
if (const DeclStmt *DS = dyn_cast<DeclStmt>(elem)) {
const VarDecl *elemD = cast<VarDecl>(DS->getSingleDecl());
}
ExplodedNodeSet dstLocation;
+ Bldr.takeNodes(Pred);
evalLocation(dstLocation, elem, Pred, state, elementV, NULL, false);
-
- if (dstLocation.empty())
- return;
+ Bldr.addNodes(dstLocation);
for (ExplodedNodeSet::iterator NI = dstLocation.begin(),
NE = dstLocation.end(); NI!=NE; ++NI) {
// For now, just 'conjure' up a symbolic value.
QualType T = R->getValueType();
assert(Loc::isLocType(T));
- unsigned Count = Builder->getCurrentBlockCount();
+ unsigned Count = currentBuilderContext->getCurrentBlockCount();
SymbolRef Sym = SymMgr.getConjuredSymbol(elem, T, Count);
SVal V = svalBuilder.makeLoc(Sym);
hasElems = hasElems->bindLoc(elementV, V);
}
// Create the new nodes.
- MakeNode(Dst, S, Pred, hasElems);
- MakeNode(Dst, S, Pred, noElems);
+ Bldr.generateNode(S, Pred, hasElems);
+ Bldr.generateNode(S, Pred, noElems);
}
}
// Proceed with evaluate the message expression.
ExplodedNodeSet dstEval;
-
+ PureStmtNodeBuilder Bldr(dstPrevisit, dstEval, *currentBuilderContext);
+
for (ExplodedNodeSet::iterator DI = dstPrevisit.begin(),
DE = dstPrevisit.end(); DI != DE; ++DI) {
ExplodedNode *Pred = *DI;
bool RaisesException = false;
- SaveAndRestore<bool> OldSink(Builder->BuildSinks);
- SaveOr OldHasGen(Builder->hasGeneratedNode);
if (const Expr *Receiver = msg.getInstanceReceiver()) {
const ProgramState *state = Pred->getState();
// There are three cases: can be nil or non-nil, must be nil, must be
// non-nil. We ignore must be nil, and merge the rest two into non-nil.
if (nilState && !notNilState) {
- dstEval.insert(Pred);
continue;
}
if (msg.getSelector() == RaiseSel)
RaisesException = true;
- // Check if we raise an exception. For now treat these as sinks.
+ // If we raise an exception, for now treat it as a sink.
// Eventually we will want to handle exceptions properly.
- if (RaisesException)
- Builder->BuildSinks = true;
-
// Dispatch to plug-in transfer function.
- evalObjCMessage(dstEval, msg, Pred, notNilState);
+ evalObjCMessage(Bldr, msg, Pred, notNilState, RaisesException);
}
}
else if (const ObjCInterfaceDecl *Iface = msg.getReceiverInterface()) {
}
}
- // Check if we raise an exception. For now treat these as sinks.
+ // If we raise an exception, for now treat it as a sink.
// Eventually we will want to handle exceptions properly.
- if (RaisesException)
- Builder->BuildSinks = true;
-
// Dispatch to plug-in transfer function.
- evalObjCMessage(dstEval, msg, Pred, Pred->getState());
+ evalObjCMessage(Bldr, msg, Pred, Pred->getState(), RaisesException);
}
-
- assert(Builder->BuildSinks || Builder->hasGeneratedNodes());
}
// Finally, perform the post-condition check of the ObjCMessageExpr and store
getCheckerManager().runCheckersForPostObjCMessage(Dst, dstEval, msg, *this);
}
-void ExprEngine::evalObjCMessage(ExplodedNodeSet &Dst, const ObjCMessage &msg,
+void ExprEngine::evalObjCMessage(PureStmtNodeBuilder &Bldr,
+ const ObjCMessage &msg,
ExplodedNode *Pred,
- const ProgramState *state) {
- assert (Builder && "StmtNodeBuilder must be defined.");
-
+ const ProgramState *state,
+ bool GenSink) {
// First handle the return value.
SVal ReturnValue = UnknownVal();
if (ReturnValue.isUnknown()) {
SValBuilder &SVB = getSValBuilder();
QualType ResultTy = msg.getResultType(getContext());
- unsigned Count = Builder->getCurrentBlockCount();
+ unsigned Count = currentBuilderContext->getCurrentBlockCount();
const Expr *CurrentE = cast<Expr>(currentStmt);
ReturnValue = SVB.getConjuredSymbolVal(NULL, CurrentE, ResultTy, Count);
}
state = invalidateArguments(state, CallOrObjCMessage(msg, state), LC);
// And create the new node.
- MakeNode(Dst, msg.getOriginExpr(), Pred, state);
+ Bldr.generateNode(msg.getOriginExpr(), Pred, state, GenSink);
+ assert(Bldr.hasGeneratedNodes());
}