80 using namespace clang;
86 class IteratorModeling
87 :
public Checker<check::PostCall, check::PostStmt<MaterializeTemporaryExpr>,
88 check::Bind, check::LiveSymbols, check::DeadSymbols> {
90 void handleComparison(CheckerContext &C,
const Expr *CE, SVal RetVal,
91 const SVal &LVal,
const SVal &RVal,
96 void handleIncrement(CheckerContext &C,
const SVal &RetVal,
const SVal &Iter,
98 void handleDecrement(CheckerContext &C,
const SVal &RetVal,
const SVal &Iter,
100 void handleRandomIncrOrDecr(CheckerContext &C,
const Expr *CE,
102 const SVal &LHS,
const SVal &RHS)
const;
103 void handleBegin(CheckerContext &C,
const Expr *CE,
const SVal &RetVal,
104 const SVal &Cont)
const;
105 void handleEnd(CheckerContext &C,
const Expr *CE,
const SVal &RetVal,
106 const SVal &Cont)
const;
107 void assignToContainer(CheckerContext &C,
const Expr *CE,
const SVal &RetVal,
108 const MemRegion *Cont)
const;
109 void handleAssign(CheckerContext &C,
const SVal &Cont,
110 const Expr *CE =
nullptr,
111 const SVal &OldCont = UndefinedVal())
const;
112 void handleClear(CheckerContext &C,
const SVal &Cont)
const;
113 void handlePushBack(CheckerContext &C,
const SVal &Cont)
const;
114 void handlePopBack(CheckerContext &C,
const SVal &Cont)
const;
115 void handlePushFront(CheckerContext &C,
const SVal &Cont)
const;
116 void handlePopFront(CheckerContext &C,
const SVal &Cont)
const;
117 void handleInsert(CheckerContext &C,
const SVal &Iter)
const;
118 void handleErase(CheckerContext &C,
const SVal &Iter)
const;
119 void handleErase(CheckerContext &C,
const SVal &Iter1,
120 const SVal &Iter2)
const;
121 void handleEraseAfter(CheckerContext &C,
const SVal &Iter)
const;
122 void handleEraseAfter(CheckerContext &C,
const SVal &Iter1,
123 const SVal &Iter2)
const;
125 const char *Sep)
const override;
128 IteratorModeling() {}
130 void checkPostCall(
const CallEvent &Call, CheckerContext &C)
const;
131 void checkBind(SVal Loc, SVal Val,
const Stmt *S, CheckerContext &C)
const;
133 void checkPostStmt(
const DeclStmt *DS, CheckerContext &C)
const;
135 CheckerContext &C)
const;
137 void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C)
const;
158 const MemRegion *Cont,
const Expr *E,
160 unsigned BlockCount);
164 unsigned BlockCount);
166 const ContainerData &CData);
171 const MemRegion *Cont);
185 const MemRegion *Cont,
186 const MemRegion *NewCont);
188 const MemRegion *Cont,
189 const MemRegion *NewCont,
200 bool isBoundThroughLazyCompoundVal(
const Environment &Env,
201 const MemRegion *Reg);
205 void IteratorModeling::checkPostCall(
const CallEvent &Call,
206 CheckerContext &C)
const {
208 const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
212 if (Func->isOverloadedOperator()) {
213 const auto Op = Func->getOverloadedOperator();
214 if (isAssignmentOperator(Op)) {
216 const auto *InstCall = cast<CXXInstanceCall>(&Call);
217 if (cast<CXXMethodDecl>(Func)->isMoveAssignmentOperator()) {
218 handleAssign(C, InstCall->getCXXThisVal(), Call.getOriginExpr(),
223 handleAssign(C, InstCall->getCXXThisVal());
225 }
else if (isSimpleComparisonOperator(Op)) {
226 const auto *OrigExpr = Call.getOriginExpr();
230 if (
const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
231 handleComparison(C, OrigExpr, Call.getReturnValue(),
232 InstCall->getCXXThisVal(), Call.getArgSVal(0), Op);
236 handleComparison(C, OrigExpr, Call.getReturnValue(), Call.getArgSVal(0),
237 Call.getArgSVal(1), Op);
240 const auto *OrigExpr = Call.getOriginExpr();
244 if (
const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
245 if (Call.getNumArgs() >= 1 &&
246 Call.getArgExpr(0)->getType()->isIntegralOrEnumerationType()) {
247 handleRandomIncrOrDecr(C, OrigExpr, Func->getOverloadedOperator(),
248 Call.getReturnValue(),
249 InstCall->getCXXThisVal(), Call.getArgSVal(0));
253 if (Call.getNumArgs() >= 2 &&
254 Call.getArgExpr(1)->getType()->isIntegralOrEnumerationType()) {
255 handleRandomIncrOrDecr(C, OrigExpr, Func->getOverloadedOperator(),
256 Call.getReturnValue(), Call.getArgSVal(0),
262 if (
const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
263 handleIncrement(C, Call.getReturnValue(), InstCall->getCXXThisVal(),
268 handleIncrement(C, Call.getReturnValue(), Call.getArgSVal(0),
272 if (
const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
273 handleDecrement(C, Call.getReturnValue(), InstCall->getCXXThisVal(),
278 handleDecrement(C, Call.getReturnValue(), Call.getArgSVal(0),
283 if (
const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
284 if (isAssignCall(Func)) {
285 handleAssign(C, InstCall->getCXXThisVal());
289 if (isClearCall(Func)) {
290 handleClear(C, InstCall->getCXXThisVal());
294 if (isPushBackCall(Func) || isEmplaceBackCall(Func)) {
295 handlePushBack(C, InstCall->getCXXThisVal());
299 if (isPopBackCall(Func)) {
300 handlePopBack(C, InstCall->getCXXThisVal());
304 if (isPushFrontCall(Func) || isEmplaceFrontCall(Func)) {
305 handlePushFront(C, InstCall->getCXXThisVal());
309 if (isPopFrontCall(Func)) {
310 handlePopFront(C, InstCall->getCXXThisVal());
315 handleInsert(C, Call.getArgSVal(0));
320 if (Call.getNumArgs() == 1) {
321 handleErase(C, Call.getArgSVal(0));
325 if (Call.getNumArgs() == 2) {
326 handleErase(C, Call.getArgSVal(0), Call.getArgSVal(1));
332 if (Call.getNumArgs() == 1) {
333 handleEraseAfter(C, Call.getArgSVal(0));
337 if (Call.getNumArgs() == 2) {
338 handleEraseAfter(C, Call.getArgSVal(0), Call.getArgSVal(1));
344 const auto *OrigExpr = Call.getOriginExpr();
351 auto State = C.getState();
353 if (
const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
354 if (isBeginCall(Func)) {
355 handleBegin(C, OrigExpr, Call.getReturnValue(),
356 InstCall->getCXXThisVal());
360 if (isEndCall(Func)) {
361 handleEnd(C, OrigExpr, Call.getReturnValue(),
362 InstCall->getCXXThisVal());
372 if (isa<CXXConstructorCall>(&Call) && Call.getNumArgs() == 1) {
375 if (cast<CXXConstructorDecl>(Func)->isMoveConstructor()) {
376 State = removeIteratorPosition(
State, Call.getArgSVal(0));
378 C.addTransition(
State);
388 for (
unsigned i = 0; i < Call.getNumArgs(); ++i) {
391 assignToContainer(C, OrigExpr, Call.getReturnValue(),
392 Pos->getContainer());
400 void IteratorModeling::checkBind(SVal Loc, SVal Val,
const Stmt *S,
401 CheckerContext &C)
const {
402 auto State = C.getState();
406 C.addTransition(
State);
411 C.addTransition(
State);
417 CheckerContext &C)
const {
419 auto State = C.getState();
424 C.addTransition(
State);
428 SymbolReaper &SR)
const {
431 auto RegionMap = State->get<IteratorRegionMap>();
432 for (
const auto &Reg : RegionMap) {
433 const auto Offset = Reg.second.getOffset();
434 for (
auto i =
Offset->symbol_begin(); i !=
Offset->symbol_end(); ++i)
435 if (isa<SymbolData>(*i))
439 auto SymbolMap = State->get<IteratorSymbolMap>();
440 for (
const auto &Sym : SymbolMap) {
441 const auto Offset = Sym.second.getOffset();
442 for (
auto i =
Offset->symbol_begin(); i !=
Offset->symbol_end(); ++i)
443 if (isa<SymbolData>(*i))
447 auto ContMap = State->get<ContainerMap>();
448 for (
const auto &Cont : ContMap) {
449 const auto CData = Cont.second;
450 if (CData.getBegin()) {
451 SR.markLive(CData.getBegin());
452 if(
const auto *SIE = dyn_cast<SymIntExpr>(CData.getBegin()))
453 SR.markLive(SIE->getLHS());
455 if (CData.getEnd()) {
456 SR.markLive(CData.getEnd());
457 if(
const auto *SIE = dyn_cast<SymIntExpr>(CData.getEnd()))
458 SR.markLive(SIE->getLHS());
463 void IteratorModeling::checkDeadSymbols(SymbolReaper &SR,
464 CheckerContext &C)
const {
466 auto State = C.getState();
468 auto RegionMap = State->get<IteratorRegionMap>();
469 for (
const auto &Reg : RegionMap) {
470 if (!SR.isLiveRegion(Reg.first)) {
474 if (!isBoundThroughLazyCompoundVal(State->getEnvironment(), Reg.first)) {
475 State = State->remove<IteratorRegionMap>(Reg.first);
480 auto SymbolMap = State->get<IteratorSymbolMap>();
481 for (
const auto &Sym : SymbolMap) {
482 if (!SR.isLive(Sym.first)) {
483 State = State->remove<IteratorSymbolMap>(Sym.first);
487 auto ContMap = State->get<ContainerMap>();
488 for (
const auto &Cont : ContMap) {
489 if (!SR.isLiveRegion(Cont.first)) {
492 if (!hasLiveIterators(State, Cont.first)) {
493 State = State->remove<ContainerMap>(Cont.first);
498 C.addTransition(State);
501 void IteratorModeling::handleComparison(CheckerContext &C,
const Expr *CE,
502 SVal RetVal,
const SVal &LVal,
509 auto State = C.getState();
512 const MemRegion *Cont =
nullptr;
514 Cont = LPos->getContainer();
516 Cont = RPos->getContainer();
524 if (!LPos || !RPos) {
525 auto &SymMgr = C.getSymbolManager();
526 Sym = SymMgr.conjureSymbol(CE, C.getLocationContext(),
527 C.getASTContext().LongTy, C.blockCount());
528 State = assumeNoOverflow(State, Sym, 4);
543 if (RetVal.isUnknown()) {
544 auto &SymMgr = C.getSymbolManager();
545 auto *LCtx = C.getLocationContext();
546 RetVal = nonloc::SymbolVal(SymMgr.conjureSymbol(
547 CE, LCtx, C.getASTContext().BoolTy, C.blockCount()));
548 State = State->BindExpr(CE, LCtx, RetVal);
551 processComparison(C, State, LPos->getOffset(), RPos->getOffset(), RetVal, Op);
554 void IteratorModeling::processComparison(CheckerContext &C,
558 if (
const auto TruthVal = RetVal.getAs<nonloc::ConcreteInt>()) {
559 if ((State = relateSymbols(State, Sym1, Sym2,
560 (Op == OO_EqualEqual) ==
561 (TruthVal->getValue() != 0)))) {
562 C.addTransition(State);
564 C.generateSink(State, C.getPredecessor());
569 const auto ConditionVal = RetVal.getAs<DefinedSVal>();
573 if (
auto StateTrue = relateSymbols(State, Sym1, Sym2, Op == OO_EqualEqual)) {
574 StateTrue = StateTrue->assume(*ConditionVal,
true);
575 C.addTransition(StateTrue);
578 if (
auto StateFalse = relateSymbols(State, Sym1, Sym2, Op != OO_EqualEqual)) {
579 StateFalse = StateFalse->assume(*ConditionVal,
false);
580 C.addTransition(StateFalse);
584 void IteratorModeling::handleIncrement(CheckerContext &C,
const SVal &RetVal,
585 const SVal &Iter,
bool Postfix)
const {
588 auto State = C.getState();
589 auto &BVF = C.getSymbolManager().getBasicVals();
597 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
599 "Advancing position by concrete int should always be successful");
603 "Iterator should have position after successful advancement");
607 C.addTransition(State);
610 void IteratorModeling::handleDecrement(CheckerContext &C,
const SVal &RetVal,
611 const SVal &Iter,
bool Postfix)
const {
614 auto State = C.getState();
615 auto &BVF = C.getSymbolManager().getBasicVals();
623 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
625 "Advancing position by concrete int should always be successful");
629 "Iterator should have position after successful advancement");
633 C.addTransition(State);
636 void IteratorModeling::handleRandomIncrOrDecr(CheckerContext &C,
641 const SVal &RHS)
const {
644 auto State = C.getState();
650 const auto *value = &RHS;
651 if (
auto loc = RHS.getAs<Loc>()) {
652 const auto val = State->getRawSVal(*loc);
656 auto &TgtVal = (Op == OO_PlusEqual || Op == OO_MinusEqual) ? LHS : RetVal;
663 "Iterator should have position after successful advancement");
666 C.addTransition(State);
668 assignToContainer(C, CE, TgtVal, Pos->getContainer());
672 void IteratorModeling::handleBegin(CheckerContext &C,
const Expr *CE,
673 const SVal &RetVal,
const SVal &Cont)
const {
674 const auto *ContReg = Cont.getAsRegion();
678 ContReg = ContReg->getMostDerivedObjectRegion();
682 auto State = C.getState();
683 auto BeginSym = getContainerBegin(State, ContReg);
685 State = createContainerBegin(State, ContReg, CE, C.getASTContext().LongTy,
686 C.getLocationContext(), C.blockCount());
687 BeginSym = getContainerBegin(State, ContReg);
691 C.addTransition(State);
694 void IteratorModeling::handleEnd(CheckerContext &C,
const Expr *CE,
695 const SVal &RetVal,
const SVal &Cont)
const {
696 const auto *ContReg = Cont.getAsRegion();
700 ContReg = ContReg->getMostDerivedObjectRegion();
704 auto State = C.getState();
705 auto EndSym = getContainerEnd(State, ContReg);
707 State = createContainerEnd(State, ContReg, CE, C.getASTContext().LongTy,
708 C.getLocationContext(), C.blockCount());
709 EndSym = getContainerEnd(State, ContReg);
713 C.addTransition(State);
716 void IteratorModeling::assignToContainer(CheckerContext &C,
const Expr *CE,
718 const MemRegion *Cont)
const {
719 Cont = Cont->getMostDerivedObjectRegion();
721 auto State = C.getState();
722 auto &SymMgr = C.getSymbolManager();
723 auto Sym = SymMgr.conjureSymbol(CE, C.getLocationContext(),
724 C.getASTContext().LongTy, C.blockCount());
725 State = assumeNoOverflow(State, Sym, 4);
728 C.addTransition(State);
731 void IteratorModeling::handleAssign(CheckerContext &C,
const SVal &Cont,
732 const Expr *CE,
const SVal &OldCont)
const {
733 const auto *ContReg = Cont.getAsRegion();
737 ContReg = ContReg->getMostDerivedObjectRegion();
741 auto State = C.getState();
744 State = invalidateAllIteratorPositions(State, ContReg);
749 if (!OldCont.isUndef()) {
750 const auto *OldContReg = OldCont.getAsRegion();
752 OldContReg = OldContReg->getMostDerivedObjectRegion();
755 if (
const auto OldEndSym = OldCData->getEnd()) {
760 State = reassignAllIteratorPositionsUnless(State, OldContReg, ContReg,
762 auto &SymMgr = C.getSymbolManager();
763 auto &SVB = C.getSValBuilder();
766 SymMgr.conjureSymbol(CE, C.getLocationContext(),
767 C.getASTContext().LongTy, C.blockCount());
768 State = assumeNoOverflow(State, NewEndSym, 4);
770 State = setContainerData(State, ContReg, CData->newEnd(NewEndSym));
772 State = setContainerData(State, ContReg,
777 State = rebaseSymbolInIteratorPositionsIf(
778 State, SVB, OldEndSym, NewEndSym, OldEndSym, BO_LT);
782 State = reassignAllIteratorPositions(State, OldContReg, ContReg);
784 if (
const auto OldBeginSym = OldCData->getBegin()) {
789 setContainerData(State, ContReg, CData->newBegin(OldBeginSym));
791 State = setContainerData(State, ContReg,
795 setContainerData(State, OldContReg, OldCData->newEnd(
nullptr));
800 State = reassignAllIteratorPositions(State, OldContReg, ContReg);
804 C.addTransition(State);
807 void IteratorModeling::handleClear(CheckerContext &C,
const SVal &Cont)
const {
808 const auto *ContReg = Cont.getAsRegion();
812 ContReg = ContReg->getMostDerivedObjectRegion();
816 auto State = C.getState();
817 if (!hasSubscriptOperator(State, ContReg) ||
818 !backModifiable(State, ContReg)) {
821 if (
const auto EndSym = CData->getEnd()) {
823 invalidateAllIteratorPositionsExcept(State, ContReg, EndSym, BO_GE);
824 C.addTransition(State);
829 State = invalidateAllIteratorPositions(State, ContReg);
830 C.addTransition(State);
833 void IteratorModeling::handlePushBack(CheckerContext &C,
834 const SVal &Cont)
const {
835 const auto *ContReg = Cont.getAsRegion();
839 ContReg = ContReg->getMostDerivedObjectRegion();
842 auto State = C.getState();
843 if (hasSubscriptOperator(State, ContReg) && frontModifiable(State, ContReg)) {
844 State = invalidateAllIteratorPositions(State, ContReg);
845 C.addTransition(State);
854 if (
const auto EndSym = CData->getEnd()) {
855 if (hasSubscriptOperator(State, ContReg)) {
856 State = invalidateIteratorPositions(State, EndSym, BO_GE);
858 auto &SymMgr = C.getSymbolManager();
859 auto &BVF = SymMgr.getBasicVals();
860 auto &SVB = C.getSValBuilder();
861 const auto newEndSym =
862 SVB.evalBinOp(State, BO_Add,
863 nonloc::SymbolVal(EndSym),
864 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
865 SymMgr.getType(EndSym)).getAsSymbol();
866 State = setContainerData(State, ContReg, CData->newEnd(newEndSym));
868 C.addTransition(State);
871 void IteratorModeling::handlePopBack(CheckerContext &C,
872 const SVal &Cont)
const {
873 const auto *ContReg = Cont.getAsRegion();
877 ContReg = ContReg->getMostDerivedObjectRegion();
879 auto State = C.getState();
884 if (
const auto EndSym = CData->getEnd()) {
885 auto &SymMgr = C.getSymbolManager();
886 auto &BVF = SymMgr.getBasicVals();
887 auto &SVB = C.getSValBuilder();
889 SVB.evalBinOp(State, BO_Sub,
890 nonloc::SymbolVal(EndSym),
891 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
892 SymMgr.getType(EndSym)).getAsSymbol();
896 if (hasSubscriptOperator(State, ContReg) &&
897 backModifiable(State, ContReg)) {
898 State = invalidateIteratorPositions(State, BackSym, BO_GE);
899 State = setContainerData(State, ContReg, CData->newEnd(
nullptr));
901 State = invalidateIteratorPositions(State, BackSym, BO_EQ);
903 auto newEndSym = BackSym;
904 State = setContainerData(State, ContReg, CData->newEnd(newEndSym));
905 C.addTransition(State);
909 void IteratorModeling::handlePushFront(CheckerContext &C,
910 const SVal &Cont)
const {
911 const auto *ContReg = Cont.getAsRegion();
915 ContReg = ContReg->getMostDerivedObjectRegion();
918 auto State = C.getState();
919 if (hasSubscriptOperator(State, ContReg)) {
920 State = invalidateAllIteratorPositions(State, ContReg);
921 C.addTransition(State);
927 if (
const auto BeginSym = CData->getBegin()) {
928 auto &SymMgr = C.getSymbolManager();
929 auto &BVF = SymMgr.getBasicVals();
930 auto &SVB = C.getSValBuilder();
931 const auto newBeginSym =
932 SVB.evalBinOp(State, BO_Sub,
933 nonloc::SymbolVal(BeginSym),
934 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
935 SymMgr.getType(BeginSym)).getAsSymbol();
936 State = setContainerData(State, ContReg, CData->newBegin(newBeginSym));
937 C.addTransition(State);
942 void IteratorModeling::handlePopFront(CheckerContext &C,
943 const SVal &Cont)
const {
944 const auto *ContReg = Cont.getAsRegion();
948 ContReg = ContReg->getMostDerivedObjectRegion();
950 auto State = C.getState();
957 if (
const auto BeginSym = CData->getBegin()) {
958 if (hasSubscriptOperator(State, ContReg)) {
959 State = invalidateIteratorPositions(State, BeginSym, BO_LE);
961 State = invalidateIteratorPositions(State, BeginSym, BO_EQ);
963 auto &SymMgr = C.getSymbolManager();
964 auto &BVF = SymMgr.getBasicVals();
965 auto &SVB = C.getSValBuilder();
966 const auto newBeginSym =
967 SVB.evalBinOp(State, BO_Add,
968 nonloc::SymbolVal(BeginSym),
969 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
970 SymMgr.getType(BeginSym)).getAsSymbol();
971 State = setContainerData(State, ContReg, CData->newBegin(newBeginSym));
972 C.addTransition(State);
976 void IteratorModeling::handleInsert(CheckerContext &C,
const SVal &Iter)
const {
977 auto State = C.getState();
984 const auto *Cont = Pos->getContainer();
985 if (hasSubscriptOperator(State, Cont) && backModifiable(State, Cont)) {
986 if (frontModifiable(State, Cont)) {
987 State = invalidateAllIteratorPositions(State, Cont);
989 State = invalidateIteratorPositions(State, Pos->getOffset(), BO_GE);
992 if (
const auto EndSym = CData->getEnd()) {
993 State = invalidateIteratorPositions(State, EndSym, BO_GE);
994 State = setContainerData(State, Cont, CData->newEnd(
nullptr));
997 C.addTransition(State);
1001 void IteratorModeling::handleErase(CheckerContext &C,
const SVal &Iter)
const {
1002 auto State = C.getState();
1010 const auto *Cont = Pos->getContainer();
1011 if (hasSubscriptOperator(State, Cont) && backModifiable(State, Cont)) {
1012 if (frontModifiable(State, Cont)) {
1013 State = invalidateAllIteratorPositions(State, Cont);
1015 State = invalidateIteratorPositions(State, Pos->getOffset(), BO_GE);
1018 if (
const auto EndSym = CData->getEnd()) {
1019 State = invalidateIteratorPositions(State, EndSym, BO_GE);
1020 State = setContainerData(State, Cont, CData->newEnd(
nullptr));
1024 State = invalidateIteratorPositions(State, Pos->getOffset(), BO_EQ);
1026 C.addTransition(State);
1029 void IteratorModeling::handleErase(CheckerContext &C,
const SVal &Iter1,
1030 const SVal &Iter2)
const {
1031 auto State = C.getState();
1041 const auto *Cont = Pos1->getContainer();
1042 if (hasSubscriptOperator(State, Cont) && backModifiable(State, Cont)) {
1043 if (frontModifiable(State, Cont)) {
1044 State = invalidateAllIteratorPositions(State, Cont);
1046 State = invalidateIteratorPositions(State, Pos1->getOffset(), BO_GE);
1049 if (
const auto EndSym = CData->getEnd()) {
1050 State = invalidateIteratorPositions(State, EndSym, BO_GE);
1051 State = setContainerData(State, Cont, CData->newEnd(
nullptr));
1055 State = invalidateIteratorPositions(State, Pos1->getOffset(), BO_GE,
1056 Pos2->getOffset(), BO_LT);
1058 C.addTransition(State);
1061 void IteratorModeling::handleEraseAfter(CheckerContext &C,
1062 const SVal &Iter)
const {
1063 auto State = C.getState();
1070 auto &SymMgr = C.getSymbolManager();
1071 auto &BVF = SymMgr.getBasicVals();
1072 auto &SVB = C.getSValBuilder();
1073 const auto NextSym =
1074 SVB.evalBinOp(State, BO_Add,
1075 nonloc::SymbolVal(Pos->getOffset()),
1076 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
1077 SymMgr.getType(Pos->getOffset())).getAsSymbol();
1078 State = invalidateIteratorPositions(State, NextSym, BO_EQ);
1079 C.addTransition(State);
1082 void IteratorModeling::handleEraseAfter(CheckerContext &C,
const SVal &Iter1,
1083 const SVal &Iter2)
const {
1084 auto State = C.getState();
1091 State = invalidateIteratorPositions(State, Pos1->getOffset(), BO_GT,
1092 Pos2->getOffset(), BO_LT);
1093 C.addTransition(State);
1096 void IteratorModeling::printState(raw_ostream &Out,
ProgramStateRef State,
1097 const char *NL,
const char *Sep)
const {
1099 auto ContMap = State->get<ContainerMap>();
1101 if (!ContMap.isEmpty()) {
1102 Out << Sep <<
"Container Data :" << NL;
1103 for (
const auto &Cont : ContMap) {
1104 Cont.first->dumpToStream(Out);
1106 const auto CData = Cont.second;
1107 if (CData.getBegin())
1108 CData.getBegin()->dumpToStream(Out);
1113 CData.getEnd()->dumpToStream(Out);
1120 auto SymbolMap = State->get<IteratorSymbolMap>();
1121 auto RegionMap = State->get<IteratorRegionMap>();
1123 if (!SymbolMap.isEmpty() || !RegionMap.isEmpty()) {
1124 Out << Sep <<
"Iterator Positions :" << NL;
1125 for (
const auto &Sym : SymbolMap) {
1126 Sym.first->dumpToStream(Out);
1128 const auto Pos = Sym.second;
1129 Out << (Pos.isValid() ?
"Valid" :
"Invalid") <<
" ; Container == ";
1130 Pos.getContainer()->dumpToStream(Out);
1131 Out<<
" ; Offset == ";
1132 Pos.getOffset()->dumpToStream(Out);
1135 for (
const auto &Reg : RegionMap) {
1136 Reg.first->dumpToStream(Out);
1138 const auto Pos = Reg.second;
1139 Out << (Pos.isValid() ?
"Valid" :
"Invalid") <<
" ; Container == ";
1140 Pos.getContainer()->dumpToStream(Out);
1141 Out<<
" ; Offset == ";
1142 Pos.getOffset()->dumpToStream(Out);
1151 const MemRegion *Reg);
1157 return IdInfo->
getName().endswith_lower(
"begin");
1164 return IdInfo->
getName().endswith_lower(
"end");
1173 return IdInfo->
getName() ==
"assign";
1182 return IdInfo->
getName() ==
"clear";
1191 return IdInfo->
getName() ==
"push_back";
1200 return IdInfo->
getName() ==
"emplace_back";
1209 return IdInfo->
getName() ==
"pop_back";
1218 return IdInfo->
getName() ==
"push_front";
1227 return IdInfo->
getName() ==
"emplace_front";
1236 return IdInfo->
getName() ==
"pop_front";
1242 return OK == OO_EqualEqual || OK == OO_ExclaimEqual;
1245 bool hasSubscriptOperator(
ProgramStateRef State,
const MemRegion *Reg) {
1246 const auto *CRD = getCXXRecordDecl(State, Reg);
1250 for (
const auto *Method : CRD->methods()) {
1251 if (!Method->isOverloadedOperator())
1253 const auto OPK = Method->getOverloadedOperator();
1254 if (OPK == OO_Subscript) {
1262 const auto *CRD = getCXXRecordDecl(State, Reg);
1266 for (
const auto *Method : CRD->methods()) {
1267 if (!Method->getDeclName().isIdentifier())
1269 if (Method->getName() ==
"push_front" || Method->getName() ==
"pop_front") {
1277 const auto *CRD = getCXXRecordDecl(State, Reg);
1281 for (
const auto *Method : CRD->methods()) {
1282 if (!Method->getDeclName().isIdentifier())
1284 if (Method->getName() ==
"push_back" || Method->getName() ==
"pop_back") {
1292 const MemRegion *Reg) {
1297 auto Type = TI.getType();
1310 return CDataPtr->getBegin();
1318 return CDataPtr->getEnd();
1322 const MemRegion *Cont,
const Expr *E,
1324 unsigned BlockCount) {
1327 if (CDataPtr && CDataPtr->getBegin())
1330 auto &SymMgr = State->getSymbolManager();
1331 const SymbolConjured *Sym = SymMgr.conjureSymbol(E, LCtx, T, BlockCount,
1333 State = assumeNoOverflow(State, Sym, 4);
1336 const auto CData = CDataPtr->newBegin(Sym);
1337 return setContainerData(State, Cont, CData);
1341 return setContainerData(State, Cont, CData);
1347 unsigned BlockCount) {
1350 if (CDataPtr && CDataPtr->getEnd())
1353 auto &SymMgr = State->getSymbolManager();
1354 const SymbolConjured *Sym = SymMgr.conjureSymbol(E, LCtx, T, BlockCount,
1356 State = assumeNoOverflow(State, Sym, 4);
1359 const auto CData = CDataPtr->newEnd(Sym);
1360 return setContainerData(State, Cont, CData);
1364 return setContainerData(State, Cont, CData);
1368 const ContainerData &CData) {
1369 return State->set<ContainerMap>(Cont, CData);
1373 if (
auto Reg = Val.getAsRegion()) {
1374 Reg = Reg->getMostDerivedObjectRegion();
1375 return State->remove<IteratorRegionMap>(Reg);
1376 }
else if (
const auto Sym = Val.getAsSymbol()) {
1377 return State->remove<IteratorSymbolMap>(Sym);
1378 }
else if (
const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
1379 return State->remove<IteratorRegionMap>(LCVal->getRegion());
1393 SValBuilder &SVB = State->getStateManager().getSValBuilder();
1394 BasicValueFactory &BV = SVB.getBasicValueFactory();
1398 APSIntType AT = BV.getAPSIntType(T);
1402 llvm::APSInt Max = AT.getMaxValue() / AT.getValue(Scale);
1403 SVal IsCappedFromAbove =
1404 SVB.evalBinOpNN(State, BO_LE, nonloc::SymbolVal(Sym),
1405 nonloc::ConcreteInt(Max), SVB.getConditionType());
1406 if (
auto DV = IsCappedFromAbove.getAs<DefinedSVal>()) {
1407 NewState = NewState->assume(*DV,
true);
1413 SVal IsCappedFromBelow =
1414 SVB.evalBinOpNN(State, BO_GE, nonloc::SymbolVal(Sym),
1415 nonloc::ConcreteInt(Min), SVB.getConditionType());
1416 if (
auto DV = IsCappedFromBelow.getAs<DefinedSVal>()) {
1417 NewState = NewState->assume(*DV,
true);
1427 auto &SVB = State->getStateManager().getSValBuilder();
1434 const auto comparison =
1435 SVB.evalBinOp(State, BO_EQ, nonloc::SymbolVal(Sym1),
1436 nonloc::SymbolVal(Sym2), SVB.getConditionType());
1438 assert(comparison.getAs<DefinedSVal>() &&
1439 "Symbol comparison must be a `DefinedSVal`");
1441 auto NewState = State->assume(comparison.castAs<DefinedSVal>(), Equal);
1445 if (
const auto CompSym = comparison.getAsSymbol()) {
1446 assert(isa<SymIntExpr>(CompSym) &&
1447 "Symbol comparison must be a `SymIntExpr`");
1449 cast<SymIntExpr>(CompSym)->getOpcode()) &&
1450 "Symbol comparison must be a comparison");
1451 return assumeNoOverflow(NewState, cast<SymIntExpr>(CompSym)->getLHS(), 2);
1458 auto RegionMap = State->get<IteratorRegionMap>();
1459 for (
const auto &Reg : RegionMap) {
1460 if (Reg.second.getContainer() == Cont)
1464 auto SymbolMap = State->get<IteratorSymbolMap>();
1465 for (
const auto &Sym : SymbolMap) {
1466 if (Sym.second.getContainer() == Cont)
1473 bool isBoundThroughLazyCompoundVal(
const Environment &Env,
1474 const MemRegion *Reg) {
1475 for (
const auto &Binding : Env) {
1476 if (
const auto LCVal = Binding.second.getAs<nonloc::LazyCompoundVal>()) {
1477 if (LCVal->getRegion() == Reg)
1485 template <
typename Condition,
typename Process>
1488 auto &RegionMapFactory = State->get_context<IteratorRegionMap>();
1489 auto RegionMap = State->get<IteratorRegionMap>();
1490 bool Changed =
false;
1491 for (
const auto &Reg : RegionMap) {
1492 if (Cond(Reg.second)) {
1493 RegionMap = RegionMapFactory.add(RegionMap, Reg.first, Proc(Reg.second));
1499 State = State->set<IteratorRegionMap>(RegionMap);
1501 auto &SymbolMapFactory = State->get_context<IteratorSymbolMap>();
1502 auto SymbolMap = State->get<IteratorSymbolMap>();
1504 for (
const auto &Sym : SymbolMap) {
1505 if (Cond(Sym.second)) {
1506 SymbolMap = SymbolMapFactory.add(SymbolMap, Sym.first, Proc(Sym.second));
1512 State = State->set<IteratorSymbolMap>(SymbolMap);
1518 const MemRegion *Cont) {
1519 auto MatchCont = [&](
const IteratorPosition &Pos) {
1520 return Pos.getContainer() == Cont;
1522 auto Invalidate = [&](
const IteratorPosition &Pos) {
1523 return Pos.invalidate();
1525 return processIteratorPositions(State, MatchCont, Invalidate);
1532 auto MatchContAndCompare = [&](
const IteratorPosition &Pos) {
1533 return Pos.getContainer() == Cont &&
1536 auto Invalidate = [&](
const IteratorPosition &Pos) {
1537 return Pos.invalidate();
1539 return processIteratorPositions(State, MatchContAndCompare, Invalidate);
1545 auto Compare = [&](
const IteratorPosition &Pos) {
1548 auto Invalidate = [&](
const IteratorPosition &Pos) {
1549 return Pos.invalidate();
1551 return processIteratorPositions(State,
Compare, Invalidate);
1559 auto Compare = [&](
const IteratorPosition &Pos) {
1560 return compare(State, Pos.getOffset(), Offset1, Opc1) &&
1561 compare(State, Pos.getOffset(), Offset2, Opc2);
1563 auto Invalidate = [&](
const IteratorPosition &Pos) {
1564 return Pos.invalidate();
1566 return processIteratorPositions(State,
Compare, Invalidate);
1570 const MemRegion *Cont,
1571 const MemRegion *NewCont) {
1572 auto MatchCont = [&](
const IteratorPosition &Pos) {
1573 return Pos.getContainer() == Cont;
1575 auto ReAssign = [&](
const IteratorPosition &Pos) {
1576 return Pos.reAssign(NewCont);
1578 return processIteratorPositions(State, MatchCont, ReAssign);
1582 const MemRegion *Cont,
1583 const MemRegion *NewCont,
1586 auto MatchContAndCompare = [&](
const IteratorPosition &Pos) {
1587 return Pos.getContainer() == Cont &&
1590 auto ReAssign = [&](
const IteratorPosition &Pos) {
1591 return Pos.reAssign(NewCont);
1593 return processIteratorPositions(State, MatchContAndCompare, ReAssign);
1602 auto LessThanEnd = [&](
const IteratorPosition &Pos) {
1603 return compare(State, Pos.getOffset(), CondSym, Opc);
1605 auto RebaseSymbol = [&](
const IteratorPosition &Pos) {
1606 return Pos.setTo(rebaseSymbol(State, SVB, Pos.getOffset(), OldSym,
1609 return processIteratorPositions(State, LessThanEnd, RebaseSymbol);
1618 auto &SymMgr = SVB.getSymbolManager();
1619 auto Diff = SVB.evalBinOpNN(State, BO_Sub, nonloc::SymbolVal(OrigExpr),
1620 nonloc::SymbolVal(OldExpr),
1621 SymMgr.getType(OrigExpr));
1623 const auto DiffInt = Diff.getAs<nonloc::ConcreteInt>();
1627 return SVB.evalBinOpNN(State, BO_Add, *DiffInt, nonloc::SymbolVal(NewSym),
1628 SymMgr.getType(OrigExpr)).getAsSymbol();
1633 void ento::registerIteratorModeling(CheckerManager &mgr) {
1634 mgr.registerChecker<IteratorModeling>();
1637 bool ento::shouldRegisterIteratorModeling(
const LangOptions &LO) {
bool isDecrementOperator(OverloadedOperatorKind OK)
Represents a function declaration or definition.
A (possibly-)qualified type.
Stmt - This represents one statement.
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee...
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
Defines the C++ template declaration subclasses.
The base class of the type hierarchy.
Represents a call to a C++ constructor.
Represents a prvalue temporary that is written into memory so that a reference can bind to it...
const T * getAs() const
Member-template getAs<specific type>'.
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
const SymExpr * SymbolRef
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
bool isIteratorType(const QualType &Type)
const Type * getUnqualifiedDesugaredType() const
Return the specified type with any "sugar" removed from the type, removing any typedefs, typeofs, etc., as well as any qualifiers.
bool isIncrementOperator(OverloadedOperatorKind OK)
const IteratorPosition * getIteratorPosition(ProgramStateRef State, const SVal &Val)
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
const ContainerData * getContainerData(ProgramStateRef State, const MemRegion *Cont)
This represents one expression.
static ContainerData fromEnd(SymbolRef E)
bool isEraseCall(const FunctionDecl *Func)
bool isComparisonOp() const
DeclStmt - Adaptor class for mixing declarations with statements and expressions. ...
bool isSignedIntegerOrEnumerationType() const
Determines whether this is an integer type that is signed or an enumeration types whose underlying ty...
static IteratorPosition getPosition(const MemRegion *C, SymbolRef Of)
StringRef getName() const
Return the actual identifier string.
ComparisonCategoryResult Compare(const T &X, const T &Y)
Helper to compare two comparable types.
bool isEraseAfterCall(const FunctionDecl *Func)
Dataflow Directional Tag Classes.
OverloadedOperatorKind
Enumeration specifying the different kinds of C++ overloaded operators.
static ContainerData fromBegin(SymbolRef B)
bool isRandomIncrOrDecrOperator(OverloadedOperatorKind OK)
bool isInsertCall(const FunctionDecl *Func)
DynamicTypeInfo getDynamicTypeInfo(ProgramStateRef State, const MemRegion *MR)
Get dynamic type information for the region MR.
Base for LValueReferenceType and RValueReferenceType.
ProgramStateRef advancePosition(ProgramStateRef State, const SVal &Iter, OverloadedOperatorKind Op, const SVal &Distance)
Represents a C++ struct/union/class.
bool isEmplaceCall(const FunctionDecl *Func)
ProgramStateRef setIteratorPosition(ProgramStateRef State, const SVal &Val, const IteratorPosition &Pos)
bool compare(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2, BinaryOperator::Opcode Opc)
unsigned getNumParams() const
Return the number of parameters this function must have based on its FunctionType.
Expr * getSubExpr() const
Retrieve the temporary-generating subexpression whose value will be materialized into a glvalue...