void CoreEngine::HandleBlockEdge(const BlockEdge &L, ExplodedNode *Pred) { const CFGBlock *Blk = L.getDst(); NodeBuilderContext BuilderCtx(*this, Blk, Pred); // Mark this block as visited. const LocationContext *LC = Pred->getLocationContext(); FunctionSummaries->markVisitedBasicBlock(Blk->getBlockID(), LC->getDecl(), LC->getCFG()->getNumBlockIDs()); // Check if we are entering the EXIT block. if (Blk == &(L.getLocationContext()->getCFG()->getExit())) { assert(L.getLocationContext()->getCFG()->getExit().empty() && "EXIT block cannot contain Stmts."); // Get return statement.. const ReturnStmt *RS = nullptr; if (!L.getSrc()->empty()) { CFGElement LastElement = L.getSrc()->back(); if (Optional<CFGStmt> LastStmt = LastElement.getAs<CFGStmt>()) { RS = dyn_cast<ReturnStmt>(LastStmt->getStmt()); } else if (Optional<CFGAutomaticObjDtor> AutoDtor = LastElement.getAs<CFGAutomaticObjDtor>()) { RS = dyn_cast<ReturnStmt>(AutoDtor->getTriggerStmt()); } } // Process the final state transition. SubEng.processEndOfFunction(BuilderCtx, Pred, RS); // This path is done. Don't enqueue any more nodes. return; } // Call into the SubEngine to process entering the CFGBlock. ExplodedNodeSet dstNodes; BlockEntrance BE(Blk, Pred->getLocationContext()); NodeBuilderWithSinks nodeBuilder(Pred, dstNodes, BuilderCtx, BE); SubEng.processCFGBlockEntrance(L, nodeBuilder, Pred); // Auto-generate a node. if (!nodeBuilder.hasGeneratedNodes()) { nodeBuilder.generateNode(Pred->State, Pred); } // Enqueue nodes onto the worklist. enqueue(dstNodes); }
void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred, ExplodedNodeSet &Dst) { assert(B->getOpcode() == BO_LAnd || B->getOpcode() == BO_LOr); StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext); ProgramStateRef state = Pred->getState(); ExplodedNode *N = Pred; while (!isa<BlockEntrance>(N->getLocation())) { ProgramPoint P = N->getLocation(); assert(isa<PreStmt>(P)|| isa<PreStmtPurgeDeadSymbols>(P)); (void) P; assert(N->pred_size() == 1); N = *N->pred_begin(); } assert(N->pred_size() == 1); N = *N->pred_begin(); BlockEdge BE = cast<BlockEdge>(N->getLocation()); SVal X; // Determine the value of the expression by introspecting how we // got this location in the CFG. This requires looking at the previous // block we were in and what kind of control-flow transfer was involved. const CFGBlock *SrcBlock = BE.getSrc(); // The only terminator (if there is one) that makes sense is a logical op. CFGTerminator T = SrcBlock->getTerminator(); if (const BinaryOperator *Term = cast_or_null<BinaryOperator>(T.getStmt())) { (void) Term; assert(Term->isLogicalOp()); assert(SrcBlock->succ_size() == 2); // Did we take the true or false branch? unsigned constant = (*SrcBlock->succ_begin() == BE.getDst()) ? 1 : 0; X = svalBuilder.makeIntVal(constant, B->getType()); } else { // If there is no terminator, by construction the last statement // in SrcBlock is the value of the enclosing expression. assert(!SrcBlock->empty()); CFGStmt Elem = cast<CFGStmt>(*SrcBlock->rbegin()); const Stmt *S = Elem.getStmt(); X = N->getState()->getSVal(S, Pred->getLocationContext()); } Bldr.generateNode(B, Pred, state->BindExpr(B, Pred->getLocationContext(), X)); }
void CoreEngine::HandleBlockEdge(const BlockEdge &L, ExplodedNode *Pred) { const CFGBlock *Blk = L.getDst(); // Check if we are entering the EXIT block. if (Blk == &(L.getLocationContext()->getCFG()->getExit())) { assert (L.getLocationContext()->getCFG()->getExit().size() == 0 && "EXIT block cannot contain Stmts."); // Process the final state transition. EndOfFunctionNodeBuilder Builder(Blk, Pred, this); SubEng.processEndOfFunction(Builder); // This path is done. Don't enqueue any more nodes. return; } // Call into the subengine to process entering the CFGBlock. ExplodedNodeSet dstNodes; BlockEntrance BE(Blk, Pred->getLocationContext()); GenericNodeBuilder<BlockEntrance> nodeBuilder(*this, Pred, BE); SubEng.processCFGBlockEntrance(dstNodes, nodeBuilder); if (dstNodes.empty()) { if (!nodeBuilder.hasGeneratedNode) { // Auto-generate a node and enqueue it to the worklist. generateNode(BE, Pred->State, Pred); } } else { for (ExplodedNodeSet::iterator I = dstNodes.begin(), E = dstNodes.end(); I != E; ++I) { WList->enqueue(*I); } } for (SmallVectorImpl<ExplodedNode*>::const_iterator I = nodeBuilder.sinks().begin(), E = nodeBuilder.sinks().end(); I != E; ++I) { blocksExhausted.push_back(std::make_pair(L, *I)); } }
void CoreEngine::HandleBlockEdge(const BlockEdge &L, ExplodedNode *Pred) { const CFGBlock *Blk = L.getDst(); NodeBuilderContext BuilderCtx(*this, Blk, Pred); // Mark this block as visited. const LocationContext *LC = Pred->getLocationContext(); FunctionSummaries->markVisitedBasicBlock(Blk->getBlockID(), LC->getDecl(), LC->getCFG()->getNumBlockIDs()); // Check if we are entering the EXIT block. if (Blk == &(L.getLocationContext()->getCFG()->getExit())) { assert (L.getLocationContext()->getCFG()->getExit().size() == 0 && "EXIT block cannot contain Stmts."); // Process the final state transition. SubEng.processEndOfFunction(BuilderCtx); // This path is done. Don't enqueue any more nodes. return; } // Call into the SubEngine to process entering the CFGBlock. ExplodedNodeSet dstNodes; BlockEntrance BE(Blk, Pred->getLocationContext()); NodeBuilderWithSinks nodeBuilder(Pred, dstNodes, BuilderCtx, BE); SubEng.processCFGBlockEntrance(L, nodeBuilder); // Auto-generate a node. if (!nodeBuilder.hasGeneratedNodes()) { nodeBuilder.generateNode(Pred->State, Pred); } // Enqueue nodes onto the worklist. enqueue(dstNodes); }
void GRCoreEngine::HandleBlockEdge(const BlockEdge& L, ExplodedNode* Pred) { CFGBlock* Blk = L.getDst(); // Check if we are entering the EXIT block. if (Blk == &(L.getLocationContext()->getCFG()->getExit())) { assert (L.getLocationContext()->getCFG()->getExit().size() == 0 && "EXIT block cannot contain Stmts."); // Process the final state transition. GREndPathNodeBuilder Builder(Blk, Pred, this); ProcessEndPath(Builder); // This path is done. Don't enqueue any more nodes. return; } // FIXME: Should we allow ProcessBlockEntrance to also manipulate state? if (ProcessBlockEntrance(Blk, Pred->State, WList->getBlockCounter())) GenerateNode(BlockEntrance(Blk, Pred->getLocationContext()), Pred->State, Pred); }
void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred, ExplodedNodeSet &Dst) { assert(B->getOpcode() == BO_LAnd || B->getOpcode() == BO_LOr); StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx); ProgramStateRef state = Pred->getState(); ExplodedNode *N = Pred; while (!N->getLocation().getAs<BlockEntrance>()) { ProgramPoint P = N->getLocation(); assert(P.getAs<PreStmt>()|| P.getAs<PreStmtPurgeDeadSymbols>()); (void) P; assert(N->pred_size() == 1); N = *N->pred_begin(); } assert(N->pred_size() == 1); N = *N->pred_begin(); BlockEdge BE = N->getLocation().castAs<BlockEdge>(); SVal X; // Determine the value of the expression by introspecting how we // got this location in the CFG. This requires looking at the previous // block we were in and what kind of control-flow transfer was involved. const CFGBlock *SrcBlock = BE.getSrc(); // The only terminator (if there is one) that makes sense is a logical op. CFGTerminator T = SrcBlock->getTerminator(); if (const BinaryOperator *Term = cast_or_null<BinaryOperator>(T.getStmt())) { (void) Term; assert(Term->isLogicalOp()); assert(SrcBlock->succ_size() == 2); // Did we take the true or false branch? unsigned constant = (*SrcBlock->succ_begin() == BE.getDst()) ? 1 : 0; X = svalBuilder.makeIntVal(constant, B->getType()); } else { // If there is no terminator, by construction the last statement // in SrcBlock is the value of the enclosing expression. // However, we still need to constrain that value to be 0 or 1. assert(!SrcBlock->empty()); CFGStmt Elem = SrcBlock->rbegin()->castAs<CFGStmt>(); const Expr *RHS = cast<Expr>(Elem.getStmt()); SVal RHSVal = N->getState()->getSVal(RHS, Pred->getLocationContext()); if (RHSVal.isUndef()) { X = RHSVal; } else { DefinedOrUnknownSVal DefinedRHS = RHSVal.castAs<DefinedOrUnknownSVal>(); ProgramStateRef StTrue, StFalse; llvm::tie(StTrue, StFalse) = N->getState()->assume(DefinedRHS); if (StTrue) { if (StFalse) { // We can't constrain the value to 0 or 1. // The best we can do is a cast. X = getSValBuilder().evalCast(RHSVal, B->getType(), RHS->getType()); } else { // The value is known to be true. X = getSValBuilder().makeIntVal(1, B->getType()); } } else { // The value is known to be false. assert(StFalse && "Infeasible path!"); X = getSValBuilder().makeIntVal(0, B->getType()); } } } Bldr.generateNode(B, Pred, state->BindExpr(B, Pred->getLocationContext(), X)); }
void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred, ExplodedNodeSet &Dst) { assert(B->getOpcode() == BO_LAnd || B->getOpcode() == BO_LOr); StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx); ProgramStateRef state = Pred->getState(); if (B->getType()->isVectorType()) { // FIXME: We do not model vector arithmetic yet. When adding support for // that, note that the CFG-based reasoning below does not apply, because // logical operators on vectors are not short-circuit. Currently they are // modeled as short-circuit in Clang CFG but this is incorrect. // Do not set the value for the expression. It'd be UnknownVal by default. Bldr.generateNode(B, Pred, state); return; } ExplodedNode *N = Pred; while (!N->getLocation().getAs<BlockEntrance>()) { ProgramPoint P = N->getLocation(); assert(P.getAs<PreStmt>()|| P.getAs<PreStmtPurgeDeadSymbols>()); (void) P; assert(N->pred_size() == 1); N = *N->pred_begin(); } assert(N->pred_size() == 1); N = *N->pred_begin(); BlockEdge BE = N->getLocation().castAs<BlockEdge>(); SVal X; // Determine the value of the expression by introspecting how we // got this location in the CFG. This requires looking at the previous // block we were in and what kind of control-flow transfer was involved. const CFGBlock *SrcBlock = BE.getSrc(); // The only terminator (if there is one) that makes sense is a logical op. CFGTerminator T = SrcBlock->getTerminator(); if (const BinaryOperator *Term = cast_or_null<BinaryOperator>(T.getStmt())) { (void) Term; assert(Term->isLogicalOp()); assert(SrcBlock->succ_size() == 2); // Did we take the true or false branch? unsigned constant = (*SrcBlock->succ_begin() == BE.getDst()) ? 1 : 0; X = svalBuilder.makeIntVal(constant, B->getType()); } else { // If there is no terminator, by construction the last statement // in SrcBlock is the value of the enclosing expression. // However, we still need to constrain that value to be 0 or 1. assert(!SrcBlock->empty()); CFGStmt Elem = SrcBlock->rbegin()->castAs<CFGStmt>(); const Expr *RHS = cast<Expr>(Elem.getStmt()); SVal RHSVal = N->getState()->getSVal(RHS, Pred->getLocationContext()); if (RHSVal.isUndef()) { X = RHSVal; } else { // We evaluate "RHSVal != 0" expression which result in 0 if the value is // known to be false, 1 if the value is known to be true and a new symbol // when the assumption is unknown. nonloc::ConcreteInt Zero(getBasicVals().getValue(0, B->getType())); X = evalBinOp(N->getState(), BO_NE, svalBuilder.evalCast(RHSVal, B->getType(), RHS->getType()), Zero, B->getType()); } } Bldr.generateNode(B, Pred, state->BindExpr(B, Pred->getLocationContext(), X)); }