本文整理汇总了C++中ExplodedNode类的典型用法代码示例。如果您正苦于以下问题:C++ ExplodedNode类的具体用法?C++ ExplodedNode怎么用?C++ ExplodedNode使用的例子?那么, 这里精选的类代码示例或许可以为您提供帮助。
在下文中一共展示了ExplodedNode类的15个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的C++代码示例。
示例1:
ExplodedNode*
IndirectGotoNodeBuilder::generateNode(const iterator &I,
const ProgramState *St,
bool isSink) {
bool IsNew;
ExplodedNode *Succ = Eng.G->getNode(BlockEdge(Src, I.getBlock(),
Pred->getLocationContext()), St, &IsNew);
Succ->addPredecessor(Pred, *Eng.G);
if (IsNew) {
if (isSink)
Succ->markAsSink();
else
Eng.WList->enqueue(Succ);
return Succ;
}
return NULL;
}
示例2: assert
ExplodedNode*
GRSwitchNodeBuilder::generateDefaultCaseNode(const GRState* St, bool isSink) {
// Get the block for the default case.
assert (Src->succ_rbegin() != Src->succ_rend());
CFGBlock* DefaultBlock = *Src->succ_rbegin();
bool IsNew;
ExplodedNode* Succ = Eng.G->getNode(BlockEdge(Src, DefaultBlock,
Pred->getLocationContext()), St, &IsNew);
Succ->addPredecessor(Pred, *Eng.G);
if (IsNew) {
if (isSink)
Succ->markAsSink();
else
Eng.WList->Enqueue(Succ);
return Succ;
}
return NULL;
}
示例3: BuiltinBug
void UndefBranchChecker::checkBranchCondition(const Stmt *Condition,
CheckerContext &Ctx) const {
SVal X = Ctx.getState()->getSVal(Condition, Ctx.getLocationContext());
if (X.isUndef()) {
// Generate a sink node, which implicitly marks both outgoing branches as
// infeasible.
ExplodedNode *N = Ctx.generateSink();
if (N) {
if (!BT)
BT.reset(new BuiltinBug(
this, "Branch condition evaluates to a garbage value"));
// What's going on here: we want to highlight the subexpression of the
// condition that is the most likely source of the "uninitialized
// branch condition." We do a recursive walk of the condition's
// subexpressions and roughly look for the most nested subexpression
// that binds to Undefined. We then highlight that expression's range.
// Get the predecessor node and check if is a PostStmt with the Stmt
// being the terminator condition. We want to inspect the state
// of that node instead because it will contain main information about
// the subexpressions.
// Note: any predecessor will do. They should have identical state,
// since all the BlockEdge did was act as an error sink since the value
// had to already be undefined.
assert (!N->pred_empty());
const Expr *Ex = cast<Expr>(Condition);
ExplodedNode *PrevN = *N->pred_begin();
ProgramPoint P = PrevN->getLocation();
ProgramStateRef St = N->getState();
if (Optional<PostStmt> PS = P.getAs<PostStmt>())
if (PS->getStmt() == Ex)
St = PrevN->getState();
FindUndefExpr FindIt(St, Ctx.getLocationContext());
Ex = FindIt.FindExpr(Ex);
// Emit the bug report.
BugReport *R = new BugReport(*BT, BT->getDescription(), N);
bugreporter::trackNullOrUndefValue(N, Ex, *R);
R->addRange(Ex->getSourceRange());
Ctx.emitReport(R);
}
}
}
示例4: assert
/// \brief Run checkers for evaluating a call.
/// Only one checker will evaluate the call.
void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst,
const ExplodedNodeSet &Src,
const CallExpr *CE,
ExprEngine &Eng,
GraphExpander *defaultEval) {
if (EvalCallCheckers.empty() &&
InlineCallCheckers.empty() &&
defaultEval == 0) {
Dst.insert(Src);
return;
}
for (ExplodedNodeSet::iterator
NI = Src.begin(), NE = Src.end(); NI != NE; ++NI) {
ExplodedNode *Pred = *NI;
bool anyEvaluated = false;
// First, check if any of the InlineCall callbacks can evaluate the call.
assert(InlineCallCheckers.size() <= 1 &&
"InlineCall is a special hacky callback to allow intrusive"
"evaluation of the call (which simulates inlining). It is "
"currently only used by OSAtomicChecker and should go away "
"at some point.");
for (std::vector<InlineCallFunc>::iterator
EI = InlineCallCheckers.begin(), EE = InlineCallCheckers.end();
EI != EE; ++EI) {
ExplodedNodeSet checkDst;
bool evaluated = (*EI)(CE, Eng, Pred, checkDst);
assert(!(evaluated && anyEvaluated)
&& "There are more than one checkers evaluating the call");
if (evaluated) {
anyEvaluated = true;
Dst.insert(checkDst);
#ifdef NDEBUG
break; // on release don't check that no other checker also evals.
#endif
}
}
#ifdef NDEBUG // on release don't check that no other checker also evals.
if (anyEvaluated) {
break;
}
#endif
// Next, check if any of the EvalCall callbacks can evaluate the call.
for (std::vector<EvalCallFunc>::iterator
EI = EvalCallCheckers.begin(), EE = EvalCallCheckers.end();
EI != EE; ++EI) {
ExplodedNodeSet checkDst;
ProgramPoint::Kind K = ProgramPoint::PostStmtKind;
const ProgramPoint &L = ProgramPoint::getProgramPoint(CE, K,
Pred->getLocationContext(), EI->Checker);
bool evaluated = false;
{ // CheckerContext generates transitions(populates checkDest) on
// destruction, so introduce the scope to make sure it gets properly
// populated.
CheckerContext C(checkDst, Eng.getBuilder(), Eng, Pred, L, 0);
evaluated = (*EI)(CE, C);
}
assert(!(evaluated && anyEvaluated)
&& "There are more than one checkers evaluating the call");
if (evaluated) {
anyEvaluated = true;
Dst.insert(checkDst);
#ifdef NDEBUG
break; // on release don't check that no other checker also evals.
#endif
}
}
// If none of the checkers evaluated the call, ask ExprEngine to handle it.
if (!anyEvaluated) {
if (defaultEval)
defaultEval->expandGraph(Dst, Pred);
else
Dst.insert(Pred);
}
}
}
示例5: assert
/// ExecuteWorkList - Run the worklist algorithm for a maximum number of steps.
bool CoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps,
const ProgramState *InitState) {
if (G->num_roots() == 0) { // Initialize the analysis by constructing
// the root if none exists.
const CFGBlock *Entry = &(L->getCFG()->getEntry());
assert (Entry->empty() &&
"Entry block must be empty.");
assert (Entry->succ_size() == 1 &&
"Entry block must have 1 successor.");
// Get the solitary successor.
const CFGBlock *Succ = *(Entry->succ_begin());
// Construct an edge representing the
// starting location in the function.
BlockEdge StartLoc(Entry, Succ, L);
// Set the current block counter to being empty.
WList->setBlockCounter(BCounterFactory.GetEmptyCounter());
if (!InitState)
// Generate the root.
generateNode(StartLoc, SubEng.getInitialState(L), 0);
else
generateNode(StartLoc, InitState, 0);
}
// Check if we have a steps limit
bool UnlimitedSteps = Steps == 0;
while (WList->hasWork()) {
if (!UnlimitedSteps) {
if (Steps == 0)
break;
--Steps;
}
const WorkListUnit& WU = WList->dequeue();
// Set the current block counter.
WList->setBlockCounter(WU.getBlockCounter());
// Retrieve the node.
ExplodedNode *Node = WU.getNode();
// Dispatch on the location type.
switch (Node->getLocation().getKind()) {
case ProgramPoint::BlockEdgeKind:
HandleBlockEdge(cast<BlockEdge>(Node->getLocation()), Node);
break;
case ProgramPoint::BlockEntranceKind:
HandleBlockEntrance(cast<BlockEntrance>(Node->getLocation()), Node);
break;
case ProgramPoint::BlockExitKind:
assert (false && "BlockExit location never occur in forward analysis.");
break;
case ProgramPoint::CallEnterKind:
HandleCallEnter(cast<CallEnter>(Node->getLocation()), WU.getBlock(),
WU.getIndex(), Node);
break;
case ProgramPoint::CallExitKind:
HandleCallExit(cast<CallExit>(Node->getLocation()), Node);
break;
default:
assert(isa<PostStmt>(Node->getLocation()) ||
isa<PostInitializer>(Node->getLocation()));
HandlePostStmt(WU.getBlock(), WU.getIndex(), Node);
break;
}
}
SubEng.processEndWorklist(hasWorkRemaining());
return WList->hasWork();
}
示例6: NodeList
void ExplodedGraph::reclaimRecentlyAllocatedNodes() {
if (!recentlyAllocatedNodes)
return;
NodeList &nl = *getNodeList(recentlyAllocatedNodes);
// Reclaimn all nodes that match *all* the following criteria:
//
// (1) 1 predecessor (that has one successor)
// (2) 1 successor (that has one predecessor)
// (3) The ProgramPoint is for a PostStmt.
// (4) There is no 'tag' for the ProgramPoint.
// (5) The 'store' is the same as the predecessor.
// (6) The 'GDM' is the same as the predecessor.
// (7) The LocationContext is the same as the predecessor.
// (8) The PostStmt is for a non-CFGElement expression.
for (NodeList::iterator i = nl.begin(), e = nl.end() ; i != e; ++i) {
ExplodedNode *node = *i;
// Conditions 1 and 2.
if (node->pred_size() != 1 || node->succ_size() != 1)
continue;
ExplodedNode *pred = *(node->pred_begin());
if (pred->succ_size() != 1)
continue;
ExplodedNode *succ = *(node->succ_begin());
if (succ->pred_size() != 1)
continue;
// Condition 3.
ProgramPoint progPoint = node->getLocation();
if (!isa<PostStmt>(progPoint))
continue;
// Condition 4.
PostStmt ps = cast<PostStmt>(progPoint);
if (ps.getTag())
continue;
if (isa<BinaryOperator>(ps.getStmt()))
continue;
// Conditions 5, 6, and 7.
const ProgramState *state = node->getState();
const ProgramState *pred_state = pred->getState();
if (state->store != pred_state->store || state->GDM != pred_state->GDM ||
progPoint.getLocationContext() != pred->getLocationContext())
continue;
// Condition 8.
if (node->getCFG().isBlkExpr(ps.getStmt()))
continue;
// If we reach here, we can remove the node. This means:
// (a) changing the predecessors successor to the successor of this node
// (b) changing the successors predecessor to the predecessor of this node
// (c) Putting 'node' onto freeNodes.
pred->replaceSuccessor(succ);
succ->replacePredecessor(pred);
if (!freeNodes)
freeNodes = new NodeList();
getNodeList(freeNodes)->push_back(node);
Nodes.RemoveNode(node);
--NumNodes;
node->~ExplodedNode();
}
nl.clear();
}
示例7: getCheckerManager
void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
ExplodedNode *Pred, ExplodedNodeSet &Dst) {
ExplodedNodeSet dstPreStmt;
getCheckerManager().runCheckersForPreStmt(dstPreStmt, Pred, CastE, *this);
if (CastE->getCastKind() == CK_LValueToRValue) {
for (ExplodedNodeSet::iterator I = dstPreStmt.begin(), E = dstPreStmt.end();
I!=E; ++I) {
ExplodedNode *subExprNode = *I;
const ProgramState *state = subExprNode->getState();
const LocationContext *LCtx = subExprNode->getLocationContext();
evalLoad(Dst, CastE, subExprNode, state, state->getSVal(Ex, LCtx));
}
return;
}
// All other casts.
QualType T = CastE->getType();
QualType ExTy = Ex->getType();
if (const ExplicitCastExpr *ExCast=dyn_cast_or_null<ExplicitCastExpr>(CastE))
T = ExCast->getTypeAsWritten();
StmtNodeBuilder Bldr(dstPreStmt, Dst, *currentBuilderContext);
for (ExplodedNodeSet::iterator I = dstPreStmt.begin(), E = dstPreStmt.end();
I != E; ++I) {
Pred = *I;
switch (CastE->getCastKind()) {
case CK_LValueToRValue:
llvm_unreachable("LValueToRValue casts handled earlier.");
case CK_ToVoid:
continue;
// The analyzer doesn't do anything special with these casts,
// since it understands retain/release semantics already.
case CK_ARCProduceObject:
case CK_ARCConsumeObject:
case CK_ARCReclaimReturnedObject:
case CK_ARCExtendBlockObject: // Fall-through.
// The analyser can ignore atomic casts for now, although some future
// checkers may want to make certain that you're not modifying the same
// value through atomic and nonatomic pointers.
case CK_AtomicToNonAtomic:
case CK_NonAtomicToAtomic:
// True no-ops.
case CK_NoOp:
case CK_FunctionToPointerDecay: {
// Copy the SVal of Ex to CastE.
const ProgramState *state = Pred->getState();
const LocationContext *LCtx = Pred->getLocationContext();
SVal V = state->getSVal(Ex, LCtx);
state = state->BindExpr(CastE, LCtx, V);
Bldr.generateNode(CastE, Pred, state);
continue;
}
case CK_Dependent:
case CK_ArrayToPointerDecay:
case CK_BitCast:
case CK_LValueBitCast:
case CK_IntegralCast:
case CK_NullToPointer:
case CK_IntegralToPointer:
case CK_PointerToIntegral:
case CK_PointerToBoolean:
case CK_IntegralToBoolean:
case CK_IntegralToFloating:
case CK_FloatingToIntegral:
case CK_FloatingToBoolean:
case CK_FloatingCast:
case CK_FloatingRealToComplex:
case CK_FloatingComplexToReal:
case CK_FloatingComplexToBoolean:
case CK_FloatingComplexCast:
case CK_FloatingComplexToIntegralComplex:
case CK_IntegralRealToComplex:
case CK_IntegralComplexToReal:
case CK_IntegralComplexToBoolean:
case CK_IntegralComplexCast:
case CK_IntegralComplexToFloatingComplex:
case CK_CPointerToObjCPointerCast:
case CK_BlockPointerToObjCPointerCast:
case CK_AnyPointerToBlockPointerCast:
case CK_ObjCObjectLValueCast: {
// Delegate to SValBuilder to process.
const ProgramState *state = Pred->getState();
const LocationContext *LCtx = Pred->getLocationContext();
SVal V = state->getSVal(Ex, LCtx);
V = svalBuilder.evalCast(V, T, ExTy);
state = state->BindExpr(CastE, LCtx, V);
Bldr.generateNode(CastE, Pred, state);
continue;
}
case CK_DerivedToBase:
case CK_UncheckedDerivedToBase: {
// For DerivedToBase cast, delegate to the store manager.
const ProgramState *state = Pred->getState();
const LocationContext *LCtx = Pred->getLocationContext();
SVal val = state->getSVal(Ex, LCtx);
//.........这里部分代码省略.........
示例8: CrashInfo
/// The call exit is simulated with a sequence of nodes, which occur between
/// CallExitBegin and CallExitEnd. The following operations occur between the
/// two program points:
/// 1. CallExitBegin (triggers the start of call exit sequence)
/// 2. Bind the return value
/// 3. Run Remove dead bindings to clean up the dead symbols from the callee.
/// 4. CallExitEnd (switch to the caller context)
/// 5. PostStmt<CallExpr>
void ExprEngine::processCallExit(ExplodedNode *CEBNode) {
// Step 1 CEBNode was generated before the call.
PrettyStackTraceLocationContext CrashInfo(CEBNode->getLocationContext());
const StackFrameContext *calleeCtx =
CEBNode->getLocationContext()->getCurrentStackFrame();
// The parent context might not be a stack frame, so make sure we
// look up the first enclosing stack frame.
const StackFrameContext *callerCtx =
calleeCtx->getParent()->getCurrentStackFrame();
const Stmt *CE = calleeCtx->getCallSite();
ProgramStateRef state = CEBNode->getState();
// Find the last statement in the function and the corresponding basic block.
const Stmt *LastSt = nullptr;
const CFGBlock *Blk = nullptr;
std::tie(LastSt, Blk) = getLastStmt(CEBNode);
// Generate a CallEvent /before/ cleaning the state, so that we can get the
// correct value for 'this' (if necessary).
CallEventManager &CEMgr = getStateManager().getCallEventManager();
CallEventRef<> Call = CEMgr.getCaller(calleeCtx, state);
// Step 2: generate node with bound return value: CEBNode -> BindedRetNode.
// If the callee returns an expression, bind its value to CallExpr.
if (CE) {
if (const ReturnStmt *RS = dyn_cast_or_null<ReturnStmt>(LastSt)) {
const LocationContext *LCtx = CEBNode->getLocationContext();
SVal V = state->getSVal(RS, LCtx);
// Ensure that the return type matches the type of the returned Expr.
if (wasDifferentDeclUsedForInlining(Call, calleeCtx)) {
QualType ReturnedTy =
CallEvent::getDeclaredResultType(calleeCtx->getDecl());
if (!ReturnedTy.isNull()) {
if (const Expr *Ex = dyn_cast<Expr>(CE)) {
V = adjustReturnValue(V, Ex->getType(), ReturnedTy,
getStoreManager());
}
}
}
state = state->BindExpr(CE, callerCtx, V);
}
// Bind the constructed object value to CXXConstructExpr.
if (const CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(CE)) {
loc::MemRegionVal This =
svalBuilder.getCXXThis(CCE->getConstructor()->getParent(), calleeCtx);
SVal ThisV = state->getSVal(This);
// If the constructed object is a temporary prvalue, get its bindings.
if (isTemporaryPRValue(CCE, ThisV))
ThisV = state->getSVal(ThisV.castAs<Loc>());
state = state->BindExpr(CCE, callerCtx, ThisV);
}
}
// Step 3: BindedRetNode -> CleanedNodes
// If we can find a statement and a block in the inlined function, run remove
// dead bindings before returning from the call. This is important to ensure
// that we report the issues such as leaks in the stack contexts in which
// they occurred.
ExplodedNodeSet CleanedNodes;
if (LastSt && Blk && AMgr.options.AnalysisPurgeOpt != PurgeNone) {
static SimpleProgramPointTag retValBind("ExprEngine", "Bind Return Value");
PostStmt Loc(LastSt, calleeCtx, &retValBind);
bool isNew;
ExplodedNode *BindedRetNode = G.getNode(Loc, state, false, &isNew);
BindedRetNode->addPredecessor(CEBNode, G);
if (!isNew)
return;
NodeBuilderContext Ctx(getCoreEngine(), Blk, BindedRetNode);
currBldrCtx = &Ctx;
// Here, we call the Symbol Reaper with 0 statement and callee location
// context, telling it to clean up everything in the callee's context
// (and its children). We use the callee's function body as a diagnostic
// statement, with which the program point will be associated.
removeDead(BindedRetNode, CleanedNodes, nullptr, calleeCtx,
calleeCtx->getAnalysisDeclContext()->getBody(),
ProgramPoint::PostStmtPurgeDeadSymbolsKind);
currBldrCtx = nullptr;
} else {
CleanedNodes.Add(CEBNode);
}
for (ExplodedNodeSet::iterator I = CleanedNodes.begin(),
E = CleanedNodes.end(); I != E; ++I) {
//.........这里部分代码省略.........
示例9: AMgr
void CallEnterNodeBuilder::generateNode(const ProgramState *state) {
// Check if the callee is in the same translation unit.
if (CalleeCtx->getTranslationUnit() !=
Pred->getLocationContext()->getTranslationUnit()) {
// Create a new engine. We must be careful that the new engine should not
// reference data structures owned by the old engine.
AnalysisManager &OldMgr = Eng.SubEng.getAnalysisManager();
// Get the callee's translation unit.
idx::TranslationUnit *TU = CalleeCtx->getTranslationUnit();
// Create a new AnalysisManager with components of the callee's
// TranslationUnit.
// The Diagnostic is actually shared when we create ASTUnits from AST files.
AnalysisManager AMgr(TU->getASTContext(), TU->getDiagnostic(),
OldMgr.getLangOptions(),
OldMgr.getPathDiagnosticClient(),
OldMgr.getStoreManagerCreator(),
OldMgr.getConstraintManagerCreator(),
OldMgr.getCheckerManager(),
OldMgr.getIndexer(),
OldMgr.getMaxNodes(), OldMgr.getMaxVisit(),
OldMgr.shouldVisualizeGraphviz(),
OldMgr.shouldVisualizeUbigraph(),
OldMgr.shouldPurgeDead(),
OldMgr.shouldEagerlyAssume(),
OldMgr.shouldTrimGraph(),
OldMgr.shouldInlineCall(),
OldMgr.getAnalysisContextManager().getUseUnoptimizedCFG(),
OldMgr.getAnalysisContextManager().
getCFGBuildOptions().AddImplicitDtors,
OldMgr.getAnalysisContextManager().
getCFGBuildOptions().AddInitializers,
OldMgr.shouldEagerlyTrimExplodedGraph());
// Create the new engine.
// FIXME: This cast isn't really safe.
bool GCEnabled = static_cast<ExprEngine&>(Eng.SubEng).isObjCGCEnabled();
ExprEngine NewEng(AMgr, GCEnabled);
// Create the new LocationContext.
AnalysisContext *NewAnaCtx = AMgr.getAnalysisContext(CalleeCtx->getDecl(),
CalleeCtx->getTranslationUnit());
const StackFrameContext *OldLocCtx = CalleeCtx;
const StackFrameContext *NewLocCtx = AMgr.getStackFrame(NewAnaCtx,
OldLocCtx->getParent(),
OldLocCtx->getCallSite(),
OldLocCtx->getCallSiteBlock(),
OldLocCtx->getIndex());
// Now create an initial state for the new engine.
const ProgramState *NewState =
NewEng.getStateManager().MarshalState(state, NewLocCtx);
ExplodedNodeSet ReturnNodes;
NewEng.ExecuteWorkListWithInitialState(NewLocCtx, AMgr.getMaxNodes(),
NewState, ReturnNodes);
return;
}
// Get the callee entry block.
const CFGBlock *Entry = &(CalleeCtx->getCFG()->getEntry());
assert(Entry->empty());
assert(Entry->succ_size() == 1);
// Get the solitary successor.
const CFGBlock *SuccB = *(Entry->succ_begin());
// Construct an edge representing the starting location in the callee.
BlockEdge Loc(Entry, SuccB, CalleeCtx);
bool isNew;
ExplodedNode *Node = Eng.G->getNode(Loc, state, &isNew);
Node->addPredecessor(const_cast<ExplodedNode*>(Pred), *Eng.G);
if (isNew)
Eng.WList->enqueue(Node);
}
示例10: assert
/// ExecuteWorkList - Run the worklist algorithm for a maximum number of steps.
bool CoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps,
ProgramStateRef InitState) {
if (G->num_roots() == 0) { // Initialize the analysis by constructing
// the root if none exists.
const CFGBlock *Entry = &(L->getCFG()->getEntry());
assert (Entry->empty() &&
"Entry block must be empty.");
assert (Entry->succ_size() == 1 &&
"Entry block must have 1 successor.");
// Mark the entry block as visited.
FunctionSummaries->markVisitedBasicBlock(Entry->getBlockID(),
L->getDecl(),
L->getCFG()->getNumBlockIDs());
// Get the solitary successor.
const CFGBlock *Succ = *(Entry->succ_begin());
// Construct an edge representing the
// starting location in the function.
BlockEdge StartLoc(Entry, Succ, L);
// Set the current block counter to being empty.
WList->setBlockCounter(BCounterFactory.GetEmptyCounter());
if (!InitState)
// Generate the root.
generateNode(StartLoc, SubEng.getInitialState(L), 0);
else
generateNode(StartLoc, InitState, 0);
}
// Check if we have a steps limit
bool UnlimitedSteps = Steps == 0;
while (WList->hasWork()) {
if (!UnlimitedSteps) {
if (Steps == 0) {
NumReachedMaxSteps++;
break;
}
--Steps;
}
NumSteps++;
const WorkListUnit& WU = WList->dequeue();
// Set the current block counter.
WList->setBlockCounter(WU.getBlockCounter());
// Retrieve the node.
ExplodedNode *Node = WU.getNode();
dispatchWorkItem(Node, Node->getLocation(), WU);
}
SubEng.processEndWorklist(hasWorkRemaining());
return WList->hasWork();
}
示例11: assert
void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E,
const MemRegion *Dest,
ExplodedNode *Pred,
ExplodedNodeSet &destNodes) {
const CXXConstructorDecl *CD = E->getConstructor();
assert(CD);
#if 0
if (!(CD->doesThisDeclarationHaveABody() && AMgr.shouldInlineCall()))
// FIXME: invalidate the object.
return;
#endif
// Evaluate other arguments.
ExplodedNodeSet argsEvaluated;
const FunctionProtoType *FnType = CD->getType()->getAs<FunctionProtoType>();
evalArguments(E->arg_begin(), E->arg_end(), FnType, Pred, argsEvaluated);
#if 0
// Is the constructor elidable?
if (E->isElidable()) {
VisitAggExpr(E->getArg(0), destNodes, Pred, Dst);
// FIXME: this is here to force propagation if VisitAggExpr doesn't
if (destNodes.empty())
destNodes.Add(Pred);
return;
}
#endif
// Perform the previsit of the constructor.
ExplodedNodeSet destPreVisit;
getCheckerManager().runCheckersForPreStmt(destPreVisit, argsEvaluated, E,
*this);
// Evaluate the constructor. Currently we don't now allow checker-specific
// implementations of specific constructors (as we do with ordinary
// function calls. We can re-evaluate this in the future.
#if 0
// Inlining currently isn't fully implemented.
if (AMgr.shouldInlineCall()) {
if (!Dest)
Dest =
svalBuilder.getRegionManager().getCXXTempObjectRegion(E,
Pred->getLocationContext());
// The callee stack frame context used to create the 'this'
// parameter region.
const StackFrameContext *SFC =
AMgr.getStackFrame(CD, Pred->getLocationContext(),
E, currentBuilderContext->getBlock(),
currentStmtIdx);
// Create the 'this' region.
const CXXThisRegion *ThisR =
getCXXThisRegion(E->getConstructor()->getParent(), SFC);
CallEnter Loc(E, SFC, Pred->getLocationContext());
StmtNodeBuilder 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));
Bldr.generateNode(Loc, *NI, state);
}
}
#endif
// Default semantics: invalidate all regions passed as arguments.
ExplodedNodeSet destCall;
{
StmtNodeBuilder Bldr(destPreVisit, destCall, *currentBuilderContext);
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), LC);
Bldr.generateNode(E, Pred, state);
}
}
// Do the post visit.
getCheckerManager().runCheckersForPostStmt(destNodes, destCall, E, *this);
}
示例12: getLastStmt
/// The call exit is simulated with a sequence of nodes, which occur between
/// CallExitBegin and CallExitEnd. The following operations occur between the
/// two program points:
/// 1. CallExitBegin (triggers the start of call exit sequence)
/// 2. Bind the return value
/// 3. Run Remove dead bindings to clean up the dead symbols from the callee.
/// 4. CallExitEnd (switch to the caller context)
/// 5. PostStmt<CallExpr>
void ExprEngine::processCallExit(ExplodedNode *CEBNode) {
// Step 1 CEBNode was generated before the call.
const StackFrameContext *calleeCtx =
CEBNode->getLocationContext()->getCurrentStackFrame();
const LocationContext *callerCtx = calleeCtx->getParent();
const Stmt *CE = calleeCtx->getCallSite();
ProgramStateRef state = CEBNode->getState();
// Find the last statement in the function and the corresponding basic block.
const Stmt *LastSt = 0;
const CFGBlock *Blk = 0;
llvm::tie(LastSt, Blk) = getLastStmt(CEBNode);
// Step 2: generate node with binded return value: CEBNode -> BindedRetNode.
// If the callee returns an expression, bind its value to CallExpr.
if (const ReturnStmt *RS = dyn_cast_or_null<ReturnStmt>(LastSt)) {
const LocationContext *LCtx = CEBNode->getLocationContext();
SVal V = state->getSVal(RS, LCtx);
state = state->BindExpr(CE, callerCtx, V);
}
// Bind the constructed object value to CXXConstructExpr.
if (const CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(CE)) {
const CXXThisRegion *ThisR =
getCXXThisRegion(CCE->getConstructor()->getParent(), calleeCtx);
SVal ThisV = state->getSVal(ThisR);
// Always bind the region to the CXXConstructExpr.
state = state->BindExpr(CCE, CEBNode->getLocationContext(), ThisV);
}
static SimpleProgramPointTag retValBindTag("ExprEngine : Bind Return Value");
PostStmt Loc(LastSt, calleeCtx, &retValBindTag);
bool isNew;
ExplodedNode *BindedRetNode = G.getNode(Loc, state, false, &isNew);
BindedRetNode->addPredecessor(CEBNode, G);
if (!isNew)
return;
// Step 3: BindedRetNode -> CleanedNodes
// If we can find a statement and a block in the inlined function, run remove
// dead bindings before returning from the call. This is important to ensure
// that we report the issues such as leaks in the stack contexts in which
// they occurred.
ExplodedNodeSet CleanedNodes;
if (LastSt && Blk) {
NodeBuilderContext Ctx(getCoreEngine(), Blk, BindedRetNode);
currentBuilderContext = &Ctx;
// Here, we call the Symbol Reaper with 0 statement and caller location
// context, telling it to clean up everything in the callee's context
// (and it's children). We use LastStmt as a diagnostic statement, which
// which the PreStmtPurge Dead point will be associated.
removeDead(BindedRetNode, CleanedNodes, 0, callerCtx, LastSt,
ProgramPoint::PostStmtPurgeDeadSymbolsKind);
currentBuilderContext = 0;
}
for (ExplodedNodeSet::iterator I = CleanedNodes.begin(),
E = CleanedNodes.end(); I != E; ++I) {
// Step 4: Generate the CallExit and leave the callee's context.
// CleanedNodes -> CEENode
CallExitEnd Loc(CE, callerCtx);
bool isNew;
ExplodedNode *CEENode = G.getNode(Loc, (*I)->getState(), false, &isNew);
CEENode->addPredecessor(*I, G);
if (!isNew)
return;
// Step 5: Perform the post-condition check of the CallExpr and enqueue the
// result onto the work list.
// CEENode -> Dst -> WorkList
ExplodedNodeSet Dst;
NodeBuilderContext Ctx(Engine, calleeCtx->getCallSiteBlock(), CEENode);
SaveAndRestore<const NodeBuilderContext*> NBCSave(currentBuilderContext,
&Ctx);
SaveAndRestore<unsigned> CBISave(currentStmtIdx, calleeCtx->getIndex());
getCheckerManager().runCheckersForPostStmt(Dst, CEENode, CE, *this, true);
// Enqueue the next element in the block.
for (ExplodedNodeSet::iterator PSI = Dst.begin(), PSE = Dst.end();
PSI != PSE; ++PSI) {
Engine.getWorkList()->enqueue(*PSI, calleeCtx->getCallSiteBlock(),
calleeCtx->getIndex()+1);
}
}
}
示例13: getStateManager
void ExprEngine::VisitObjCMessage(const ObjCMessageExpr *ME,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
CallEventManager &CEMgr = getStateManager().getCallEventManager();
CallEventRef<ObjCMethodCall> Msg =
CEMgr.getObjCMethodCall(ME, Pred->getState(), Pred->getLocationContext());
// Handle the previsits checks.
ExplodedNodeSet dstPrevisit;
getCheckerManager().runCheckersForPreObjCMessage(dstPrevisit, Pred,
*Msg, *this);
ExplodedNodeSet dstGenericPrevisit;
getCheckerManager().runCheckersForPreCall(dstGenericPrevisit, dstPrevisit,
*Msg, *this);
// Proceed with evaluate the message expression.
ExplodedNodeSet dstEval;
StmtNodeBuilder Bldr(dstGenericPrevisit, dstEval, *currentBuilderContext);
for (ExplodedNodeSet::iterator DI = dstGenericPrevisit.begin(),
DE = dstGenericPrevisit.end(); DI != DE; ++DI) {
ExplodedNode *Pred = *DI;
ProgramStateRef State = Pred->getState();
CallEventRef<ObjCMethodCall> UpdatedMsg = Msg.cloneWithState(State);
if (UpdatedMsg->isInstanceMessage()) {
SVal recVal = UpdatedMsg->getReceiverSVal();
if (!recVal.isUndef()) {
// Bifurcate the state into nil and non-nil ones.
DefinedOrUnknownSVal receiverVal = cast<DefinedOrUnknownSVal>(recVal);
ProgramStateRef notNilState, nilState;
llvm::tie(notNilState, nilState) = State->assume(receiverVal);
// 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.
// FIXME: This ignores many potential bugs (<rdar://problem/11733396>).
// Revisit once we have lazier constraints.
if (nilState && !notNilState) {
continue;
}
// Check if the "raise" message was sent.
assert(notNilState);
if (Msg->getSelector() == RaiseSel) {
// If we raise an exception, for now treat it as a sink.
// Eventually we will want to handle exceptions properly.
Bldr.generateNode(currentStmt, Pred, State, true);
continue;
}
// Generate a transition to non-Nil state.
if (notNilState != State)
Pred = Bldr.generateNode(currentStmt, Pred, notNilState);
}
} else {
// Check for special class methods.
if (const ObjCInterfaceDecl *Iface = Msg->getReceiverInterface()) {
if (!NSExceptionII) {
ASTContext &Ctx = getContext();
NSExceptionII = &Ctx.Idents.get("NSException");
}
if (isSubclass(Iface, NSExceptionII)) {
enum { NUM_RAISE_SELECTORS = 2 };
// Lazily create a cache of the selectors.
if (!NSExceptionInstanceRaiseSelectors) {
ASTContext &Ctx = getContext();
NSExceptionInstanceRaiseSelectors =
new Selector[NUM_RAISE_SELECTORS];
SmallVector<IdentifierInfo*, NUM_RAISE_SELECTORS> II;
unsigned idx = 0;
// raise:format:
II.push_back(&Ctx.Idents.get("raise"));
II.push_back(&Ctx.Idents.get("format"));
NSExceptionInstanceRaiseSelectors[idx++] =
Ctx.Selectors.getSelector(II.size(), &II[0]);
// raise:format:arguments:
II.push_back(&Ctx.Idents.get("arguments"));
NSExceptionInstanceRaiseSelectors[idx++] =
Ctx.Selectors.getSelector(II.size(), &II[0]);
}
Selector S = Msg->getSelector();
bool RaisesException = false;
for (unsigned i = 0; i < NUM_RAISE_SELECTORS; ++i) {
if (S == NSExceptionInstanceRaiseSelectors[i]) {
RaisesException = true;
break;
}
}
if (RaisesException) {
// If we raise an exception, for now treat it as a sink.
// Eventually we will want to handle exceptions properly.
Bldr.generateNode(currentStmt, Pred, Pred->getState(), true);
continue;
}
//.........这里部分代码省略.........
示例14: getStateManager
void ExprEngine::VisitObjCMessage(const ObjCMessageExpr *ME,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
CallEventManager &CEMgr = getStateManager().getCallEventManager();
CallEventRef<ObjCMethodCall> Msg =
CEMgr.getObjCMethodCall(ME, Pred->getState(), Pred->getLocationContext());
// Handle the previsits checks.
ExplodedNodeSet dstPrevisit;
getCheckerManager().runCheckersForPreObjCMessage(dstPrevisit, Pred,
*Msg, *this);
ExplodedNodeSet dstGenericPrevisit;
getCheckerManager().runCheckersForPreCall(dstGenericPrevisit, dstPrevisit,
*Msg, *this);
// Proceed with evaluate the message expression.
ExplodedNodeSet dstEval;
StmtNodeBuilder Bldr(dstGenericPrevisit, dstEval, *currBldrCtx);
for (ExplodedNodeSet::iterator DI = dstGenericPrevisit.begin(),
DE = dstGenericPrevisit.end(); DI != DE; ++DI) {
ExplodedNode *Pred = *DI;
ProgramStateRef State = Pred->getState();
CallEventRef<ObjCMethodCall> UpdatedMsg = Msg.cloneWithState(State);
if (UpdatedMsg->isInstanceMessage()) {
SVal recVal = UpdatedMsg->getReceiverSVal();
if (!recVal.isUndef()) {
// Bifurcate the state into nil and non-nil ones.
DefinedOrUnknownSVal receiverVal =
recVal.castAs<DefinedOrUnknownSVal>();
ProgramStateRef notNilState, nilState;
std::tie(notNilState, nilState) = State->assume(receiverVal);
// 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.
// FIXME: This ignores many potential bugs (<rdar://problem/11733396>).
// Revisit once we have lazier constraints.
if (nilState && !notNilState) {
continue;
}
// Check if the "raise" message was sent.
assert(notNilState);
if (ObjCNoRet.isImplicitNoReturn(ME)) {
// If we raise an exception, for now treat it as a sink.
// Eventually we will want to handle exceptions properly.
Bldr.generateSink(ME, Pred, State);
continue;
}
// Generate a transition to non-Nil state.
if (notNilState != State) {
Pred = Bldr.generateNode(ME, Pred, notNilState);
assert(Pred && "Should have cached out already!");
}
}
} else {
// Check for special class methods that are known to not return
// and that we should treat as a sink.
if (ObjCNoRet.isImplicitNoReturn(ME)) {
// If we raise an exception, for now treat it as a sink.
// Eventually we will want to handle exceptions properly.
Bldr.generateSink(ME, Pred, Pred->getState());
continue;
}
}
defaultEvalCall(Bldr, Pred, *UpdatedMsg);
}
ExplodedNodeSet dstPostvisit;
getCheckerManager().runCheckersForPostCall(dstPostvisit, dstEval,
*Msg, *this);
// Finally, perform the post-condition check of the ObjCMessageExpr and store
// the created nodes in 'Dst'.
getCheckerManager().runCheckersForPostObjCMessage(Dst, dstPostvisit,
*Msg, *this);
}
示例15: while
std::unique_ptr<ExplodedGraph>
ExplodedGraph::trim(ArrayRef<const NodeTy *> Sinks,
InterExplodedGraphMap *ForwardMap,
InterExplodedGraphMap *InverseMap) const {
if (Nodes.empty())
return nullptr;
typedef llvm::DenseSet<const ExplodedNode*> Pass1Ty;
Pass1Ty Pass1;
typedef InterExplodedGraphMap Pass2Ty;
InterExplodedGraphMap Pass2Scratch;
Pass2Ty &Pass2 = ForwardMap ? *ForwardMap : Pass2Scratch;
SmallVector<const ExplodedNode*, 10> WL1, WL2;
// ===- Pass 1 (reverse DFS) -===
for (ArrayRef<const NodeTy *>::iterator I = Sinks.begin(), E = Sinks.end();
I != E; ++I) {
if (*I)
WL1.push_back(*I);
}
// Process the first worklist until it is empty.
while (!WL1.empty()) {
const ExplodedNode *N = WL1.pop_back_val();
// Have we already visited this node? If so, continue to the next one.
if (!Pass1.insert(N).second)
continue;
// If this is a root enqueue it to the second worklist.
if (N->Preds.empty()) {
WL2.push_back(N);
continue;
}
// Visit our predecessors and enqueue them.
WL1.append(N->Preds.begin(), N->Preds.end());
}
// We didn't hit a root? Return with a null pointer for the new graph.
if (WL2.empty())
return nullptr;
// Create an empty graph.
std::unique_ptr<ExplodedGraph> G = MakeEmptyGraph();
// ===- Pass 2 (forward DFS to construct the new graph) -===
while (!WL2.empty()) {
const ExplodedNode *N = WL2.pop_back_val();
// Skip this node if we have already processed it.
if (Pass2.find(N) != Pass2.end())
continue;
// Create the corresponding node in the new graph and record the mapping
// from the old node to the new node.
ExplodedNode *NewN = G->createUncachedNode(N->getLocation(), N->State, N->isSink());
Pass2[N] = NewN;
// Also record the reverse mapping from the new node to the old node.
if (InverseMap) (*InverseMap)[NewN] = N;
// If this node is a root, designate it as such in the graph.
if (N->Preds.empty())
G->addRoot(NewN);
// In the case that some of the intended predecessors of NewN have already
// been created, we should hook them up as predecessors.
// Walk through the predecessors of 'N' and hook up their corresponding
// nodes in the new graph (if any) to the freshly created node.
for (ExplodedNode::pred_iterator I = N->Preds.begin(), E = N->Preds.end();
I != E; ++I) {
Pass2Ty::iterator PI = Pass2.find(*I);
if (PI == Pass2.end())
continue;
NewN->addPredecessor(const_cast<ExplodedNode *>(PI->second), *G);
}
// In the case that some of the intended successors of NewN have already
// been created, we should hook them up as successors. Otherwise, enqueue
// the new nodes from the original graph that should have nodes created
// in the new graph.
for (ExplodedNode::succ_iterator I = N->Succs.begin(), E = N->Succs.end();
I != E; ++I) {
Pass2Ty::iterator PI = Pass2.find(*I);
if (PI != Pass2.end()) {
const_cast<ExplodedNode *>(PI->second)->addPredecessor(NewN, *G);
continue;
}
// Enqueue nodes to the worklist that were marked during pass 1.
if (Pass1.count(*I))
WL2.push_back(*I);
}
}
//.........这里部分代码省略.........