void UndefBranchChecker::checkBranchCondition(const Stmt *Condition, BranchNodeBuilder &Builder, ExprEngine &Eng) const { const GRState *state = Builder.getState(); SVal X = state->getSVal(Condition); if (X.isUndef()) { ExplodedNode *N = Builder.generateNode(state, true); if (N) { N->markAsSink(); if (!BT) BT.reset( new BuiltinBug("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. BlockEdge B = cast<BlockEdge>(N->getLocation()); const Expr* Ex = cast<Expr>(B.getSrc()->getTerminatorCondition()); assert (Ex && "Block must have a terminator."); // 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. assert (!N->pred_empty()); // 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. ExplodedNode *PrevN = *N->pred_begin(); ProgramPoint P = PrevN->getLocation(); const GRState* St = N->getState(); if (PostStmt* PS = dyn_cast<PostStmt>(&P)) if (PS->getStmt() == Ex) St = PrevN->getState(); FindUndefExpr FindIt(Eng.getStateManager(), St); Ex = FindIt.FindExpr(Ex); // Emit the bug report. EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getDescription(),N); R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Ex); R->addRange(Ex->getSourceRange()); Eng.getBugReporter().EmitReport(R); } Builder.markInfeasible(true); Builder.markInfeasible(false); } }
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 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); } } }
void CoreEngine::dispatchWorkItem(ExplodedNode* Pred, ProgramPoint Loc, const WorkListUnit& WU) { // Dispatch on the location type. switch (Loc.getKind()) { case ProgramPoint::BlockEdgeKind: HandleBlockEdge(cast<BlockEdge>(Loc), Pred); break; case ProgramPoint::BlockEntranceKind: HandleBlockEntrance(cast<BlockEntrance>(Loc), Pred); break; case ProgramPoint::BlockExitKind: assert (false && "BlockExit location never occur in forward analysis."); break; case ProgramPoint::CallEnterKind: { CallEnter CEnter = cast<CallEnter>(Loc); if (AnalyzedCallees) if (const CallExpr* CE = dyn_cast_or_null<CallExpr>(CEnter.getCallExpr())) if (const Decl *CD = CE->getCalleeDecl()) AnalyzedCallees->insert(CD); SubEng.processCallEnter(CEnter, Pred); break; } case ProgramPoint::CallExitBeginKind: SubEng.processCallExit(Pred); break; case ProgramPoint::EpsilonKind: { assert(Pred->hasSinglePred() && "Assume epsilon has exactly one predecessor by construction"); ExplodedNode *PNode = Pred->getFirstPred(); dispatchWorkItem(Pred, PNode->getLocation(), WU); break; } default: assert(isa<PostStmt>(Loc) || isa<PostInitializer>(Loc) || isa<CallExitEnd>(Loc)); HandlePostStmt(WU.getBlock(), WU.getIndex(), Pred); break; } }
void CoreEngine::dispatchWorkItem(ExplodedNode* Pred, ProgramPoint Loc, const WorkListUnit& WU) { // Dispatch on the location type. switch (Loc.getKind()) { case ProgramPoint::BlockEdgeKind: HandleBlockEdge(Loc.castAs<BlockEdge>(), Pred); break; case ProgramPoint::BlockEntranceKind: HandleBlockEntrance(Loc.castAs<BlockEntrance>(), Pred); break; case ProgramPoint::BlockExitKind: assert (false && "BlockExit location never occur in forward analysis."); break; case ProgramPoint::CallEnterKind: { CallEnter CEnter = Loc.castAs<CallEnter>(); SubEng.processCallEnter(CEnter, Pred); break; } case ProgramPoint::CallExitBeginKind: SubEng.processCallExit(Pred); break; case ProgramPoint::EpsilonKind: { assert(Pred->hasSinglePred() && "Assume epsilon has exactly one predecessor by construction"); ExplodedNode *PNode = Pred->getFirstPred(); dispatchWorkItem(Pred, PNode->getLocation(), WU); break; } default: assert(Loc.getAs<PostStmt>() || Loc.getAs<PostInitializer>() || Loc.getAs<PostImplicitCall>() || Loc.getAs<CallExitEnd>()); HandlePostStmt(WU.getBlock(), WU.getIndex(), Pred); break; } }
/// ExecuteWorkList - Run the worklist algorithm for a maximum number of steps. bool GRCoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps) { if (G->num_roots() == 0) { // Initialize the analysis by constructing // the root if none exists. 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. 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()); // Generate the root. GenerateNode(StartLoc, getInitialState(L), 0); } while (Steps && WList->hasWork()) { --Steps; const GRWorkListUnit& 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; default: assert(isa<PostStmt>(Node->getLocation())); HandlePostStmt(cast<PostStmt>(Node->getLocation()), WU.getBlock(), WU.getIndex(), Node); break; } } return WList->hasWork(); }
/// 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(); }
/// 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(); }
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(); }
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)); }
/// 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) InitState = SubEng.getInitialState(L); bool IsNew; ExplodedNode *Node = G.getNode(StartLoc, InitState, false, &IsNew); assert(IsNew); G.addRoot(Node); NodeBuilderContext BuilderCtx(*this, StartLoc.getDst(), Node); ExplodedNodeSet DstBegin; SubEng.processBeginOfFunction(BuilderCtx, Node, DstBegin, StartLoc); enqueue(DstBegin); } // Check if we have a steps limit bool UnlimitedSteps = Steps == 0; // Cap our pre-reservation in the event that the user specifies // a very large number of maximum steps. const unsigned PreReservationCap = 4000000; if(!UnlimitedSteps) G.reserve(std::min(Steps,PreReservationCap)); 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(); }