void CoreEngine::enqueueStmtNode(ExplodedNode *N, const CFGBlock *Block, unsigned Idx) { assert(Block); assert(!N->isSink()); // Check if this node entered a callee. if (N->getLocation().getAs<CallEnter>()) { // Still use the index of the CallExpr. It's needed to create the callee // StackFrameContext. WList->enqueue(N, Block, Idx); return; } // Do not create extra nodes. Move to the next CFG element. if (N->getLocation().getAs<PostInitializer>() || N->getLocation().getAs<PostImplicitCall>()|| N->getLocation().getAs<LoopExit>()) { WList->enqueue(N, Block, Idx+1); return; } if (N->getLocation().getAs<EpsilonPoint>()) { WList->enqueue(N, Block, Idx); return; } if ((*Block)[Idx].getKind() == CFGElement::NewAllocator) { WList->enqueue(N, Block, Idx+1); return; } // At this point, we know we're processing a normal statement. CFGStmt CS = (*Block)[Idx].castAs<CFGStmt>(); PostStmt Loc(CS.getStmt(), N->getLocationContext()); if (Loc == N->getLocation().withTag(nullptr)) { // Note: 'N' should be a fresh node because otherwise it shouldn't be // a member of Deferred. WList->enqueue(N, Block, Idx+1); return; } bool IsNew; ExplodedNode *Succ = G.getNode(Loc, N->getState(), false, &IsNew); Succ->addPredecessor(N, G); if (IsNew) WList->enqueue(Succ, Block, Idx+1); }
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 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)); }
/// CheckFallThrough - Check that we don't fall off the end of a /// Statement that should return a value. /// /// \returns AlwaysFallThrough iff we always fall off the end of the statement, /// MaybeFallThrough iff we might or might not fall off the end, /// NeverFallThroughOrReturn iff we never fall off the end of the statement or /// return. We assume NeverFallThrough iff we never fall off the end of the /// statement but we may return. We assume that functions not marked noreturn /// will return. static ControlFlowKind CheckFallThrough(AnalysisContext &AC) { CFG *cfg = AC.getCFG(); if (cfg == 0) return UnknownFallThrough; // The CFG leaves in dead things, and we don't want the dead code paths to // confuse us, so we mark all live things first. llvm::BitVector live(cfg->getNumBlockIDs()); unsigned count = reachable_code::ScanReachableFromBlock(cfg->getEntry(), live); bool AddEHEdges = AC.getAddEHEdges(); if (!AddEHEdges && count != cfg->getNumBlockIDs()) // When there are things remaining dead, and we didn't add EH edges // from CallExprs to the catch clauses, we have to go back and // mark them as live. for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) { CFGBlock &b = **I; if (!live[b.getBlockID()]) { if (b.pred_begin() == b.pred_end()) { if (b.getTerminator() && isa<CXXTryStmt>(b.getTerminator())) // When not adding EH edges from calls, catch clauses // can otherwise seem dead. Avoid noting them as dead. count += reachable_code::ScanReachableFromBlock(b, live); continue; } } } // Now we know what is live, we check the live precessors of the exit block // and look for fall through paths, being careful to ignore normal returns, // and exceptional paths. bool HasLiveReturn = false; bool HasFakeEdge = false; bool HasPlainEdge = false; bool HasAbnormalEdge = false; // Ignore default cases that aren't likely to be reachable because all // enums in a switch(X) have explicit case statements. CFGBlock::FilterOptions FO; FO.IgnoreDefaultsWithCoveredEnums = 1; for (CFGBlock::filtered_pred_iterator I = cfg->getExit().filtered_pred_start_end(FO); I.hasMore(); ++I) { const CFGBlock& B = **I; if (!live[B.getBlockID()]) continue; // Destructors can appear after the 'return' in the CFG. This is // normal. We need to look pass the destructors for the return // statement (if it exists). CFGBlock::const_reverse_iterator ri = B.rbegin(), re = B.rend(); bool hasNoReturnDtor = false; for ( ; ri != re ; ++ri) { CFGElement CE = *ri; // FIXME: The right solution is to just sever the edges in the // CFG itself. if (const CFGImplicitDtor *iDtor = ri->getAs<CFGImplicitDtor>()) if (iDtor->isNoReturn(AC.getASTContext())) { hasNoReturnDtor = true; HasFakeEdge = true; break; } if (isa<CFGStmt>(CE)) break; } if (hasNoReturnDtor) continue; // No more CFGElements in the block? if (ri == re) { if (B.getTerminator() && isa<CXXTryStmt>(B.getTerminator())) { HasAbnormalEdge = true; continue; } // A labeled empty statement, or the entry block... HasPlainEdge = true; continue; } CFGStmt CS = cast<CFGStmt>(*ri); Stmt *S = CS.getStmt(); if (isa<ReturnStmt>(S)) { HasLiveReturn = true; continue; } if (isa<ObjCAtThrowStmt>(S)) { HasFakeEdge = true; continue; } if (isa<CXXThrowExpr>(S)) { HasFakeEdge = true; continue; } if (const AsmStmt *AS = dyn_cast<AsmStmt>(S)) { if (AS->isMSAsm()) { HasFakeEdge = true; HasLiveReturn = true; continue; } } if (isa<CXXTryStmt>(S)) { HasAbnormalEdge = true; continue; } bool NoReturnEdge = false; if (CallExpr *C = dyn_cast<CallExpr>(S)) { if (std::find(B.succ_begin(), B.succ_end(), &cfg->getExit()) == B.succ_end()) { HasAbnormalEdge = true; continue; } Expr *CEE = C->getCallee()->IgnoreParenCasts(); QualType calleeType = CEE->getType(); if (calleeType == AC.getASTContext().BoundMemberTy) { calleeType = Expr::findBoundMemberType(CEE); assert(!calleeType.isNull() && "analyzing unresolved call?"); } if (getFunctionExtInfo(calleeType).getNoReturn()) { NoReturnEdge = true; HasFakeEdge = true; } else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE)) { ValueDecl *VD = DRE->getDecl(); if (VD->hasAttr<NoReturnAttr>()) { NoReturnEdge = true; HasFakeEdge = true; } } } // FIXME: Add noreturn message sends. if (NoReturnEdge == false) HasPlainEdge = true; } if (!HasPlainEdge) { if (HasLiveReturn) return NeverFallThrough; return NeverFallThroughOrReturn; } if (HasAbnormalEdge || HasFakeEdge || HasLiveReturn) return MaybeFallThrough; // This says AlwaysFallThrough for calls to functions that are not marked // noreturn, that don't return. If people would like this warning to be more // accurate, such functions should be marked as noreturn. return AlwaysFallThrough; }