PathDiagnosticLocation PathDiagnosticLocation::create(const ProgramPoint& P, const SourceManager &SMng) { const Stmt* S = 0; if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) { const CFGBlock *BSrc = BE->getSrc(); S = BSrc->getTerminatorCondition(); } else if (const StmtPoint *SP = dyn_cast<StmtPoint>(&P)) { S = SP->getStmt(); if (isa<PostStmtPurgeDeadSymbols>(P)) return PathDiagnosticLocation::createEnd(S, SMng, P.getLocationContext()); } else if (const PostImplicitCall *PIE = dyn_cast<PostImplicitCall>(&P)) { return PathDiagnosticLocation(PIE->getLocation(), SMng); } else if (const CallEnter *CE = dyn_cast<CallEnter>(&P)) { return getLocationForCaller(CE->getCalleeContext(), CE->getLocationContext(), SMng); } else if (const CallExitEnd *CEE = dyn_cast<CallExitEnd>(&P)) { return getLocationForCaller(CEE->getCalleeContext(), CEE->getLocationContext(), SMng); } else { llvm_unreachable("Unexpected ProgramPoint"); } return PathDiagnosticLocation(S, SMng, P.getLocationContext()); }
PathDiagnosticLocation PathDiagnosticLocation::create(const ProgramPoint& P, const SourceManager &SMng) { const Stmt* S = 0; if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) { const CFGBlock *BSrc = BE->getSrc(); S = BSrc->getTerminatorCondition(); } else if (Optional<StmtPoint> SP = P.getAs<StmtPoint>()) { S = SP->getStmt(); if (P.getAs<PostStmtPurgeDeadSymbols>()) return PathDiagnosticLocation::createEnd(S, SMng, P.getLocationContext()); } else if (Optional<PostInitializer> PIP = P.getAs<PostInitializer>()) { return PathDiagnosticLocation(PIP->getInitializer()->getSourceLocation(), SMng); } else if (Optional<PostImplicitCall> PIE = P.getAs<PostImplicitCall>()) { return PathDiagnosticLocation(PIE->getLocation(), SMng); } else if (Optional<CallEnter> CE = P.getAs<CallEnter>()) { return getLocationForCaller(CE->getCalleeContext(), CE->getLocationContext(), SMng); } else if (Optional<CallExitEnd> CEE = P.getAs<CallExitEnd>()) { return getLocationForCaller(CEE->getCalleeContext(), CEE->getLocationContext(), SMng); } else { llvm_unreachable("Unexpected ProgramPoint"); } return PathDiagnosticLocation(S, SMng, P.getLocationContext()); }
PathDiagnosticLocation PathDiagnosticLocation::create(const ProgramPoint& P, const SourceManager &SMng) { const Stmt* S = 0; if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) { const CFGBlock *BSrc = BE->getSrc(); S = BSrc->getTerminatorCondition(); } else if (const PostStmt *PS = dyn_cast<PostStmt>(&P)) { S = PS->getStmt(); } else if (const PostImplicitCall *PIE = dyn_cast<PostImplicitCall>(&P)) { return PathDiagnosticLocation(PIE->getLocation(), SMng); } else if (const CallEnter *CE = dyn_cast<CallEnter>(&P)) { return getLocationForCaller(CE->getCalleeContext(), CE->getLocationContext(), SMng); } else if (const CallExitEnd *CEE = dyn_cast<CallExitEnd>(&P)) { return getLocationForCaller(CEE->getCalleeContext(), CEE->getLocationContext(), SMng); } return PathDiagnosticLocation(S, SMng, P.getLocationContext()); }
PathDiagnosticLocation PathDiagnosticLocation::create(const ProgramPoint& P, const SourceManager &SMng) { const Stmt* S = nullptr; if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) { const CFGBlock *BSrc = BE->getSrc(); S = BSrc->getTerminatorCondition(); } else if (Optional<StmtPoint> SP = P.getAs<StmtPoint>()) { S = SP->getStmt(); if (P.getAs<PostStmtPurgeDeadSymbols>()) return PathDiagnosticLocation::createEnd(S, SMng, P.getLocationContext()); } else if (Optional<PostInitializer> PIP = P.getAs<PostInitializer>()) { return PathDiagnosticLocation(PIP->getInitializer()->getSourceLocation(), SMng); } else if (Optional<PreImplicitCall> PIC = P.getAs<PreImplicitCall>()) { return PathDiagnosticLocation(PIC->getLocation(), SMng); } else if (Optional<PostImplicitCall> PIE = P.getAs<PostImplicitCall>()) { return PathDiagnosticLocation(PIE->getLocation(), SMng); } else if (Optional<CallEnter> CE = P.getAs<CallEnter>()) { return getLocationForCaller(CE->getCalleeContext(), CE->getLocationContext(), SMng); } else if (Optional<CallExitEnd> CEE = P.getAs<CallExitEnd>()) { return getLocationForCaller(CEE->getCalleeContext(), CEE->getLocationContext(), SMng); } else if (auto CEB = P.getAs<CallExitBegin>()) { if (const ReturnStmt *RS = CEB->getReturnStmt()) return PathDiagnosticLocation::createBegin(RS, SMng, CEB->getLocationContext()); return PathDiagnosticLocation( CEB->getLocationContext()->getDecl()->getSourceRange().getEnd(), SMng); } else if (Optional<BlockEntrance> BE = P.getAs<BlockEntrance>()) { CFGElement BlockFront = BE->getBlock()->front(); if (auto StmtElt = BlockFront.getAs<CFGStmt>()) { return PathDiagnosticLocation(StmtElt->getStmt()->getBeginLoc(), SMng); } else if (auto NewAllocElt = BlockFront.getAs<CFGNewAllocator>()) { return PathDiagnosticLocation( NewAllocElt->getAllocatorExpr()->getBeginLoc(), SMng); } llvm_unreachable("Unexpected CFG element at front of block"); } else { llvm_unreachable("Unexpected ProgramPoint"); } return PathDiagnosticLocation(S, SMng, P.getLocationContext()); }
PathDiagnosticLocation PathDiagnosticLocation::create(const ProgramPoint& P, const SourceManager &SMng) { const Stmt* S = 0; if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) { const CFGBlock *BSrc = BE->getSrc(); S = BSrc->getTerminatorCondition(); } else if (const PostStmt *PS = dyn_cast<PostStmt>(&P)) { S = PS->getStmt(); } return PathDiagnosticLocation(S, SMng, P.getLocationContext()); }
PathDiagnosticLocation PathDiagnosticLocation::createEndOfPath(const ExplodedNode* N, const SourceManager &SM) { assert(N && "Cannot create a location with a null node."); const ExplodedNode *NI = N; while (NI) { ProgramPoint P = NI->getLocation(); const LocationContext *LC = P.getLocationContext(); if (const StmtPoint *PS = dyn_cast<StmtPoint>(&P)) return PathDiagnosticLocation(PS->getStmt(), SM, LC); else if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) { const Stmt *Term = BE->getSrc()->getTerminator(); assert(Term); return PathDiagnosticLocation(Term, SM, LC); } NI = NI->succ_empty() ? 0 : *(NI->succ_begin()); } return createDeclEnd(N->getLocationContext(), SM); }
bool ExplodedGraph::shouldCollect(const ExplodedNode *node) { // Reclaim 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 isn't for a non-consumed Stmt or Expr. // (9) The successor is not a CallExpr StmtPoint (so that we would be able to // find it when retrying a call with no inlining). // FIXME: It may be safe to reclaim PreCall and PostCall nodes as well. // Conditions 1 and 2. if (node->pred_size() != 1 || node->succ_size() != 1) return false; const ExplodedNode *pred = *(node->pred_begin()); if (pred->succ_size() != 1) return false; const ExplodedNode *succ = *(node->succ_begin()); if (succ->pred_size() != 1) return false; // Condition 3. ProgramPoint progPoint = node->getLocation(); if (!isa<PostStmt>(progPoint)) return false; // Condition 4. PostStmt ps = cast<PostStmt>(progPoint); if (ps.getTag()) return false; // Conditions 5, 6, and 7. ProgramStateRef state = node->getState(); ProgramStateRef pred_state = pred->getState(); if (state->store != pred_state->store || state->GDM != pred_state->GDM || progPoint.getLocationContext() != pred->getLocationContext()) return false; // Condition 8. // Do not collect nodes for non-consumed Stmt or Expr to ensure precise // diagnostic generation; specifically, so that we could anchor arrows // pointing to the beginning of statements (as written in code). if (!isa<Expr>(ps.getStmt())) return false; if (const Expr *Ex = dyn_cast<Expr>(ps.getStmt())) { ParentMap &PM = progPoint.getLocationContext()->getParentMap(); if (!PM.isConsumedExpr(Ex)) return false; } // Condition 9. const ProgramPoint SuccLoc = succ->getLocation(); if (const StmtPoint *SP = dyn_cast<StmtPoint>(&SuccLoc)) if (CallEvent::isCallStmt(SP->getStmt())) return false; return true; }
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(); }
PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ, const ExplodedNode *Pred, BugReporterContext &BRC, BugReport &BR) { if (Satisfied) return NULL; const ExplodedNode *StoreSite = 0; const Expr *InitE = 0; bool IsParam = false; // First see if we reached the declaration of the region. if (const VarRegion *VR = dyn_cast<VarRegion>(R)) { if (Optional<PostStmt> P = Pred->getLocationAs<PostStmt>()) { if (const DeclStmt *DS = P->getStmtAs<DeclStmt>()) { if (DS->getSingleDecl() == VR->getDecl()) { StoreSite = Pred; InitE = VR->getDecl()->getInit(); } } } } // Otherwise, see if this is the store site: // (1) Succ has this binding and Pred does not, i.e. this is // where the binding first occurred. // (2) Succ has this binding and is a PostStore node for this region, i.e. // the same binding was re-assigned here. if (!StoreSite) { if (Succ->getState()->getSVal(R) != V) return NULL; if (Pred->getState()->getSVal(R) == V) { Optional<PostStore> PS = Succ->getLocationAs<PostStore>(); if (!PS || PS->getLocationValue() != R) return NULL; } StoreSite = Succ; // If this is an assignment expression, we can track the value // being assigned. if (Optional<PostStmt> P = Succ->getLocationAs<PostStmt>()) if (const BinaryOperator *BO = P->getStmtAs<BinaryOperator>()) if (BO->isAssignmentOp()) InitE = BO->getRHS(); // If this is a call entry, the variable should be a parameter. // FIXME: Handle CXXThisRegion as well. (This is not a priority because // 'this' should never be NULL, but this visitor isn't just for NULL and // UndefinedVal.) if (Optional<CallEnter> CE = Succ->getLocationAs<CallEnter>()) { if (const VarRegion *VR = dyn_cast<VarRegion>(R)) { const ParmVarDecl *Param = cast<ParmVarDecl>(VR->getDecl()); ProgramStateManager &StateMgr = BRC.getStateManager(); CallEventManager &CallMgr = StateMgr.getCallEventManager(); CallEventRef<> Call = CallMgr.getCaller(CE->getCalleeContext(), Succ->getState()); InitE = Call->getArgExpr(Param->getFunctionScopeIndex()); IsParam = true; } } } if (!StoreSite) return NULL; Satisfied = true; // If we have an expression that provided the value, try to track where it // came from. if (InitE) { if (V.isUndef() || V.getAs<loc::ConcreteInt>()) { if (!IsParam) InitE = InitE->IgnoreParenCasts(); bugreporter::trackNullOrUndefValue(StoreSite, InitE, BR, IsParam); } else { ReturnVisitor::addVisitorIfNecessary(StoreSite, InitE->IgnoreParenCasts(), BR); } } if (!R->canPrintPretty()) return 0; // Okay, we've found the binding. Emit an appropriate message. SmallString<256> sbuf; llvm::raw_svector_ostream os(sbuf); if (Optional<PostStmt> PS = StoreSite->getLocationAs<PostStmt>()) { const Stmt *S = PS->getStmt(); const char *action = 0; const DeclStmt *DS = dyn_cast<DeclStmt>(S); const VarRegion *VR = dyn_cast<VarRegion>(R); if (DS) { action = "initialized to "; } else if (isa<BlockExpr>(S)) { action = "captured by block as "; if (VR) { // See if we can get the BlockVarRegion. ProgramStateRef State = StoreSite->getState(); SVal V = State->getSVal(S, PS->getLocationContext()); if (const BlockDataRegion *BDR = dyn_cast_or_null<BlockDataRegion>(V.getAsRegion())) { if (const VarRegion *OriginalR = BDR->getOriginalRegion(VR)) { if (Optional<KnownSVal> KV = State->getSVal(OriginalR).getAs<KnownSVal>()) BR.addVisitor(new FindLastStoreBRVisitor(*KV, OriginalR)); } } } } if (action) { if (!R) return 0; os << '\''; R->printPretty(os); os << "' "; if (V.getAs<loc::ConcreteInt>()) { bool b = false; if (R->isBoundable()) { if (const TypedValueRegion *TR = dyn_cast<TypedValueRegion>(R)) { if (TR->getValueType()->isObjCObjectPointerType()) { os << action << "nil"; b = true; } } } if (!b) os << action << "a null pointer value"; } else if (Optional<nonloc::ConcreteInt> CVal = V.getAs<nonloc::ConcreteInt>()) { os << action << CVal->getValue(); } else if (DS) { if (V.isUndef()) { if (isa<VarRegion>(R)) { const VarDecl *VD = cast<VarDecl>(DS->getSingleDecl()); if (VD->getInit()) os << "initialized to a garbage value"; else os << "declared without an initial value"; } } else { os << "initialized here"; } } } } else if (StoreSite->getLocation().getAs<CallEnter>()) { if (const VarRegion *VR = dyn_cast<VarRegion>(R)) { const ParmVarDecl *Param = cast<ParmVarDecl>(VR->getDecl()); os << "Passing "; if (V.getAs<loc::ConcreteInt>()) { if (Param->getType()->isObjCObjectPointerType()) os << "nil object reference"; else os << "null pointer value"; } else if (V.isUndef()) { os << "uninitialized value"; } else if (Optional<nonloc::ConcreteInt> CI = V.getAs<nonloc::ConcreteInt>()) { os << "the value " << CI->getValue(); } else { os << "value"; } // Printed parameter indexes are 1-based, not 0-based. unsigned Idx = Param->getFunctionScopeIndex() + 1; os << " via " << Idx << llvm::getOrdinalSuffix(Idx) << " parameter '"; R->printPretty(os); os << '\''; } } if (os.str().empty()) { if (V.getAs<loc::ConcreteInt>()) { bool b = false; if (R->isBoundable()) { if (const TypedValueRegion *TR = dyn_cast<TypedValueRegion>(R)) { if (TR->getValueType()->isObjCObjectPointerType()) { os << "nil object reference stored to "; b = true; } } } if (!b) os << "Null pointer value stored to "; } else if (V.isUndef()) { os << "Uninitialized value stored to "; } else if (Optional<nonloc::ConcreteInt> CV = V.getAs<nonloc::ConcreteInt>()) { os << "The value " << CV->getValue() << " is assigned to "; } else os << "Value assigned to "; os << '\''; R->printPretty(os); os << '\''; } // Construct a new PathDiagnosticPiece. ProgramPoint P = StoreSite->getLocation(); PathDiagnosticLocation L; if (P.getAs<CallEnter>() && InitE) L = PathDiagnosticLocation(InitE, BRC.getSourceManager(), P.getLocationContext()); else L = PathDiagnosticLocation::create(P, BRC.getSourceManager()); if (!L.isValid()) return NULL; return new PathDiagnosticEventPiece(L, os.str()); }
bool ExplodedGraph::shouldCollect(const ExplodedNode *node) { // First, we only consider nodes for reclamation of the following // conditions apply: // // (1) 1 predecessor (that has one successor) // (2) 1 successor (that has one predecessor) // // If a node has no successor it is on the "frontier", while a node // with no predecessor is a root. // // After these prerequisites, we discard all "filler" nodes that // are used only for intermediate processing, and are not essential // for analyzer history: // // (a) PreStmtPurgeDeadSymbols // // We then discard all other nodes where *all* of the following conditions // apply: // // (3) The ProgramPoint is for a PostStmt, but not a PostStore. // (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) Expressions that are *not* lvalue expressions. // (9) The PostStmt isn't for a non-consumed Stmt or Expr. // (10) The successor is neither a CallExpr StmtPoint nor a CallEnter or // PreImplicitCall (so that we would be able to find it when retrying a // call with no inlining). // FIXME: It may be safe to reclaim PreCall and PostCall nodes as well. // Conditions 1 and 2. if (node->pred_size() != 1 || node->succ_size() != 1) return false; const ExplodedNode *pred = *(node->pred_begin()); if (pred->succ_size() != 1) return false; const ExplodedNode *succ = *(node->succ_begin()); if (succ->pred_size() != 1) return false; // Now reclaim any nodes that are (by definition) not essential to // analysis history and are not consulted by any client code. ProgramPoint progPoint = node->getLocation(); if (progPoint.getAs<PreStmtPurgeDeadSymbols>()) return !progPoint.getTag(); // Condition 3. if (!progPoint.getAs<PostStmt>() || progPoint.getAs<PostStore>()) return false; // Condition 4. if (progPoint.getTag()) return false; // Conditions 5, 6, and 7. ProgramStateRef state = node->getState(); ProgramStateRef pred_state = pred->getState(); if (state->store != pred_state->store || state->GDM != pred_state->GDM || progPoint.getLocationContext() != pred->getLocationContext()) return false; // All further checks require expressions. As per #3, we know that we have // a PostStmt. const Expr *Ex = dyn_cast<Expr>(progPoint.castAs<PostStmt>().getStmt()); if (!Ex) return false; // Condition 8. // Do not collect nodes for "interesting" lvalue expressions since they are // used extensively for generating path diagnostics. if (isInterestingLValueExpr(Ex)) return false; // Condition 9. // Do not collect nodes for non-consumed Stmt or Expr to ensure precise // diagnostic generation; specifically, so that we could anchor arrows // pointing to the beginning of statements (as written in code). ParentMap &PM = progPoint.getLocationContext()->getParentMap(); if (!PM.isConsumedExpr(Ex)) return false; // Condition 10. const ProgramPoint SuccLoc = succ->getLocation(); if (Optional<StmtPoint> SP = SuccLoc.getAs<StmtPoint>()) if (CallEvent::isCallStmt(SP->getStmt())) return false; // Condition 10, continuation. if (SuccLoc.getAs<CallEnter>() || SuccLoc.getAs<PreImplicitCall>()) return false; return true; }