79 using namespace clang;
86 struct IteratorPosition {
90 const MemRegion *Cont;
98 IteratorPosition(
const MemRegion *C,
bool V,
SymbolRef Of)
99 : Cont(C), Valid(V), Offset(Of) {}
102 const MemRegion *getContainer()
const {
return Cont; }
103 bool isValid()
const {
return Valid; }
106 IteratorPosition invalidate()
const {
107 return IteratorPosition(Cont,
false, Offset);
110 static IteratorPosition getPosition(
const MemRegion *C,
SymbolRef Of) {
111 return IteratorPosition(C,
true, Of);
114 IteratorPosition setTo(
SymbolRef NewOf)
const {
115 return IteratorPosition(Cont, Valid, NewOf);
118 IteratorPosition reAssign(
const MemRegion *NewCont)
const {
119 return IteratorPosition(NewCont, Valid, Offset);
123 return Cont == X.Cont && Valid == X.Valid && Offset == X.Offset;
127 return Cont != X.Cont || Valid != X.Valid || Offset != X.Offset;
130 void Profile(llvm::FoldingSetNodeID &
ID)
const {
132 ID.AddInteger(Valid);
137 typedef llvm::PointerUnion<const MemRegion *, SymbolRef> RegionOrSymbol;
140 struct ContainerData {
147 static ContainerData fromBegin(
SymbolRef B) {
148 return ContainerData(B,
nullptr);
151 static ContainerData fromEnd(
SymbolRef E) {
152 return ContainerData(
nullptr, E);
158 ContainerData newBegin(
SymbolRef B)
const {
return ContainerData(B, End); }
160 ContainerData newEnd(
SymbolRef E)
const {
return ContainerData(Begin, E); }
163 return Begin == X.Begin && End == X.End;
167 return Begin != X.Begin || End != X.End;
170 void Profile(llvm::FoldingSetNodeID &ID)
const {
180 RegionOrSymbol Left, Right;
185 : Left(L), Right(R), Equality(Eq) {}
187 RegionOrSymbol getLeft()
const {
return Left; }
188 RegionOrSymbol getRight()
const {
return Right; }
189 bool isEquality()
const {
return Equality; }
191 return Left == X.Left && Right == X.Right && Equality == X.Equality;
194 return Left != X.Left || Right != X.Right || Equality != X.Equality;
196 void Profile(llvm::FoldingSetNodeID &ID)
const { ID.AddInteger(Equality); }
199 class IteratorChecker
200 :
public Checker<check::PreCall, check::PostCall,
201 check::PostStmt<MaterializeTemporaryExpr>, check::Bind,
202 check::LiveSymbols, check::DeadSymbols,
205 std::unique_ptr<BugType> OutOfRangeBugType;
206 std::unique_ptr<BugType> MismatchedBugType;
207 std::unique_ptr<BugType> InvalidatedBugType;
209 void handleComparison(CheckerContext &C,
const SVal &RetVal,
const SVal &LVal,
211 void verifyAccess(CheckerContext &C,
const SVal &Val)
const;
212 void verifyDereference(CheckerContext &C,
const SVal &Val)
const;
213 void handleIncrement(CheckerContext &C,
const SVal &RetVal,
const SVal &Iter,
215 void handleDecrement(CheckerContext &C,
const SVal &RetVal,
const SVal &Iter,
218 const SVal &RetVal,
const SVal &LHS,
219 const SVal &RHS)
const;
220 void handleBegin(CheckerContext &C,
const Expr *CE,
const SVal &RetVal,
221 const SVal &Cont)
const;
222 void handleEnd(CheckerContext &C,
const Expr *CE,
const SVal &RetVal,
223 const SVal &Cont)
const;
224 void assignToContainer(CheckerContext &C,
const Expr *CE,
const SVal &RetVal,
225 const MemRegion *Cont)
const;
226 void handleAssign(CheckerContext &C,
const SVal &Cont,
227 const Expr *CE =
nullptr,
228 const SVal &OldCont = UndefinedVal())
const;
229 void handleClear(CheckerContext &C,
const SVal &Cont)
const;
230 void handlePushBack(CheckerContext &C,
const SVal &Cont)
const;
231 void handlePopBack(CheckerContext &C,
const SVal &Cont)
const;
232 void handlePushFront(CheckerContext &C,
const SVal &Cont)
const;
233 void handlePopFront(CheckerContext &C,
const SVal &Cont)
const;
234 void handleInsert(CheckerContext &C,
const SVal &Iter)
const;
235 void handleErase(CheckerContext &C,
const SVal &Iter)
const;
236 void handleErase(CheckerContext &C,
const SVal &Iter1,
237 const SVal &Iter2)
const;
238 void handleEraseAfter(CheckerContext &C,
const SVal &Iter)
const;
239 void handleEraseAfter(CheckerContext &C,
const SVal &Iter1,
240 const SVal &Iter2)
const;
241 void verifyIncrement(CheckerContext &C,
const SVal &Iter)
const;
242 void verifyDecrement(CheckerContext &C,
const SVal &Iter)
const;
244 const SVal &LHS,
const SVal &RHS)
const;
245 void verifyMatch(CheckerContext &C,
const SVal &Iter,
246 const MemRegion *Cont)
const;
247 void verifyMatch(CheckerContext &C,
const SVal &Iter1,
248 const SVal &Iter2)
const;
250 const IteratorPosition &Pos,
251 const SVal &Distance)
const;
252 void reportOutOfRangeBug(
const StringRef &Message,
const SVal &Val,
253 CheckerContext &C, ExplodedNode *ErrNode)
const;
254 void reportMismatchedBug(
const StringRef &Message,
const SVal &Val1,
255 const SVal &Val2, CheckerContext &C,
256 ExplodedNode *ErrNode)
const;
257 void reportMismatchedBug(
const StringRef &Message,
const SVal &Val,
258 const MemRegion *Reg, CheckerContext &C,
259 ExplodedNode *ErrNode)
const;
260 void reportInvalidatedBug(
const StringRef &Message,
const SVal &Val,
261 CheckerContext &C, ExplodedNode *ErrNode)
const;
267 CK_IteratorRangeChecker,
268 CK_MismatchedIteratorChecker,
269 CK_InvalidatedIteratorChecker,
273 DefaultBool ChecksEnabled[CK_NumCheckKinds];
274 CheckName CheckNames[CK_NumCheckKinds];
276 void checkPreCall(
const CallEvent &Call, CheckerContext &C)
const;
277 void checkPostCall(
const CallEvent &Call, CheckerContext &C)
const;
278 void checkBind(SVal Loc, SVal Val,
const Stmt *S, CheckerContext &C)
const;
280 void checkPostStmt(
const DeclStmt *DS, CheckerContext &C)
const;
282 CheckerContext &C)
const;
284 void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C)
const;
286 bool Assumption)
const;
332 RegionOrSymbol RVal,
bool Equal);
334 const SymExpr *Condition,
const SVal &LVal,
335 const SVal &RVal,
bool Eq);
337 const SymExpr *Condition);
341 const MemRegion *Cont,
348 RegionOrSymbol RegOrSym);
350 const IteratorPosition &Pos);
352 RegionOrSymbol RegOrSym,
353 const IteratorPosition &Pos);
356 RegionOrSymbol RegOrSym,
357 const IteratorPosition &Pos,
bool Equal);
359 const IteratorPosition &Pos1,
360 const IteratorPosition &Pos2,
363 const MemRegion *Cont);
377 const MemRegion *Cont,
378 const MemRegion *NewCont);
380 const MemRegion *Cont,
381 const MemRegion *NewCont,
388 const MemRegion *Cont);
390 const ContainerData &CData);
393 const MemRegion *Reg);
400 IteratorChecker::IteratorChecker() {
401 OutOfRangeBugType.reset(
402 new BugType(
this,
"Iterator out of range",
"Misuse of STL APIs"));
403 OutOfRangeBugType->setSuppressOnSink(
true);
404 MismatchedBugType.reset(
405 new BugType(
this,
"Iterator(s) mismatched",
"Misuse of STL APIs"));
406 MismatchedBugType->setSuppressOnSink(
true);
407 InvalidatedBugType.reset(
408 new BugType(
this,
"Iterator invalidated",
"Misuse of STL APIs"));
409 InvalidatedBugType->setSuppressOnSink(
true);
412 void IteratorChecker::checkPreCall(
const CallEvent &Call,
413 CheckerContext &C)
const {
416 const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
420 if (Func->isOverloadedOperator()) {
421 if (ChecksEnabled[CK_InvalidatedIteratorChecker] &&
424 if (
const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
425 verifyAccess(C, InstCall->getCXXThisVal());
427 verifyAccess(C, Call.getArgSVal(0));
430 if (ChecksEnabled[CK_IteratorRangeChecker]) {
433 if (
const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
434 verifyIncrement(C, InstCall->getCXXThisVal());
436 if (Call.getNumArgs() >= 1) {
437 verifyIncrement(C, Call.getArgSVal(0));
442 if (
const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
443 verifyDecrement(C, InstCall->getCXXThisVal());
445 if (Call.getNumArgs() >= 1) {
446 verifyDecrement(C, Call.getArgSVal(0));
450 if (
const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
452 if (Call.getNumArgs() >= 1) {
453 verifyRandomIncrOrDecr(C, Func->getOverloadedOperator(),
454 InstCall->getCXXThisVal(),
458 if (Call.getNumArgs() >= 2) {
459 verifyRandomIncrOrDecr(C, Func->getOverloadedOperator(),
460 Call.getArgSVal(0), Call.getArgSVal(1));
465 if (
const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
466 verifyDereference(C, InstCall->getCXXThisVal());
468 verifyDereference(C, Call.getArgSVal(0));
471 }
else if (ChecksEnabled[CK_MismatchedIteratorChecker] &&
474 if (
const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
475 if (Call.getNumArgs() < 1)
482 verifyMatch(C, InstCall->getCXXThisVal(), Call.getArgSVal(0));
484 if (Call.getNumArgs() < 2)
491 verifyMatch(C, Call.getArgSVal(0), Call.getArgSVal(1));
494 }
else if (
const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
495 if (!ChecksEnabled[CK_MismatchedIteratorChecker])
498 const auto *ContReg = InstCall->getCXXThisVal().getAsRegion();
503 verifyMatch(C, Call.getArgSVal(0),
504 InstCall->getCXXThisVal().getAsRegion());
505 if (Call.getNumArgs() == 2) {
506 verifyMatch(C, Call.getArgSVal(1),
507 InstCall->getCXXThisVal().getAsRegion());
510 verifyMatch(C, Call.getArgSVal(0),
511 InstCall->getCXXThisVal().getAsRegion());
512 if (Call.getNumArgs() == 3 &&
515 verifyMatch(C, Call.getArgSVal(1), Call.getArgSVal(2));
518 verifyMatch(C, Call.getArgSVal(0),
519 InstCall->getCXXThisVal().getAsRegion());
521 }
else if (isa<CXXConstructorCall>(&Call)) {
523 if (Call.getNumArgs() < 2)
526 const auto *Ctr = cast<CXXConstructorDecl>(Call.getDecl());
527 if (Ctr->getNumParams() < 2)
530 if (Ctr->getParamDecl(0)->getName() !=
"first" ||
531 Ctr->getParamDecl(1)->getName() !=
"last")
538 verifyMatch(C, Call.getArgSVal(0), Call.getArgSVal(1));
556 if (!ChecksEnabled[CK_MismatchedIteratorChecker])
559 const auto *Templ = Func->getPrimaryTemplate();
563 const auto *TParams = Templ->getTemplateParameters();
564 const auto *TArgs = Func->getTemplateSpecializationArgs();
567 for (
size_t I = 0; I < TParams->size(); ++I) {
572 if (TPDecl->isParameterPack())
575 const auto TAType = TArgs->get(I).getAsType();
579 SVal LHS = UndefinedVal();
584 for (
auto J = 0U; J < Func->getNumParams(); ++J) {
585 const auto *Param = Func->getParamDecl(J);
586 const auto *ParamType =
589 ParamType->getReplacedParameter()->getDecl() != TPDecl)
592 LHS = Call.getArgSVal(J);
594 verifyMatch(C, LHS, Call.getArgSVal(J));
601 void IteratorChecker::checkPostCall(
const CallEvent &Call,
602 CheckerContext &C)
const {
604 const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
608 if (Func->isOverloadedOperator()) {
609 const auto Op = Func->getOverloadedOperator();
612 if (Func->getParamDecl(0)->getType()->isRValueReferenceType()) {
613 handleAssign(C, InstCall->getCXXThisVal(), Call.getOriginExpr(),
616 handleAssign(C, InstCall->getCXXThisVal());
619 if (
const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
620 handleComparison(C, Call.getReturnValue(), InstCall->getCXXThisVal(),
621 Call.getArgSVal(0), Op);
623 handleComparison(C, Call.getReturnValue(), Call.getArgSVal(0),
624 Call.getArgSVal(1), Op);
627 if (
const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
628 if (Call.getNumArgs() >= 1) {
629 handleRandomIncrOrDecr(C, Func->getOverloadedOperator(),
630 Call.getReturnValue(),
631 InstCall->getCXXThisVal(), Call.getArgSVal(0));
634 if (Call.getNumArgs() >= 2) {
635 handleRandomIncrOrDecr(C, Func->getOverloadedOperator(),
636 Call.getReturnValue(), Call.getArgSVal(0),
641 if (
const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
642 handleIncrement(C, Call.getReturnValue(), InstCall->getCXXThisVal(),
645 handleIncrement(C, Call.getReturnValue(), Call.getArgSVal(0),
649 if (
const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
650 handleDecrement(C, Call.getReturnValue(), InstCall->getCXXThisVal(),
653 handleDecrement(C, Call.getReturnValue(), Call.getArgSVal(0),
658 if (
const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
660 handleAssign(C, InstCall->getCXXThisVal());
662 handleClear(C, InstCall->getCXXThisVal());
664 handlePushBack(C, InstCall->getCXXThisVal());
666 handlePopBack(C, InstCall->getCXXThisVal());
668 handlePushFront(C, InstCall->getCXXThisVal());
670 handlePopFront(C, InstCall->getCXXThisVal());
672 handleInsert(C, Call.getArgSVal(0));
674 if (Call.getNumArgs() == 1) {
675 handleErase(C, Call.getArgSVal(0));
676 }
else if (Call.getNumArgs() == 2) {
677 handleErase(C, Call.getArgSVal(0), Call.getArgSVal(1));
680 if (Call.getNumArgs() == 1) {
681 handleEraseAfter(C, Call.getArgSVal(0));
682 }
else if (Call.getNumArgs() == 2) {
683 handleEraseAfter(C, Call.getArgSVal(0), Call.getArgSVal(1));
688 const auto *OrigExpr = Call.getOriginExpr();
695 auto State = C.getState();
697 if (
const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
699 handleBegin(C, OrigExpr, Call.getReturnValue(),
700 InstCall->getCXXThisVal());
704 handleEnd(C, OrigExpr, Call.getReturnValue(),
705 InstCall->getCXXThisVal());
715 if (isa<CXXConstructorCall>(&Call) && Call.getNumArgs() == 1) {
718 if (cast<CXXConstructorDecl>(Func)->isMoveConstructor()) {
721 C.addTransition(
State);
731 for (
unsigned i = 0; i < Call.getNumArgs(); ++i) {
734 assignToContainer(C, OrigExpr, Call.getReturnValue(),
735 Pos->getContainer());
743 void IteratorChecker::checkBind(SVal Loc, SVal Val,
const Stmt *S,
744 CheckerContext &C)
const {
745 auto State = C.getState();
749 C.addTransition(
State);
754 C.addTransition(
State);
760 CheckerContext &C)
const {
762 auto State = C.getState();
768 C.addTransition(
State);
772 SymbolReaper &SR)
const {
775 auto RegionMap = State->get<IteratorRegionMap>();
776 for (
const auto Reg : RegionMap) {
777 const auto Offset = Reg.second.getOffset();
778 for (
auto i = Offset->symbol_begin(); i != Offset->symbol_end(); ++i)
779 if (isa<SymbolData>(*i))
783 auto SymbolMap = State->get<IteratorSymbolMap>();
784 for (
const auto Sym : SymbolMap) {
785 const auto Offset = Sym.second.getOffset();
786 for (
auto i = Offset->symbol_begin(); i != Offset->symbol_end(); ++i)
787 if (isa<SymbolData>(*i))
791 auto ContMap = State->get<ContainerMap>();
792 for (
const auto Cont : ContMap) {
793 const auto CData = Cont.second;
794 if (CData.getBegin()) {
795 SR.markLive(CData.getBegin());
796 if(
const auto *SIE = dyn_cast<SymIntExpr>(CData.getBegin()))
797 SR.markLive(SIE->getLHS());
799 if (CData.getEnd()) {
800 SR.markLive(CData.getEnd());
801 if(
const auto *SIE = dyn_cast<SymIntExpr>(CData.getEnd()))
802 SR.markLive(SIE->getLHS());
807 void IteratorChecker::checkDeadSymbols(SymbolReaper &SR,
808 CheckerContext &C)
const {
810 auto State = C.getState();
812 auto RegionMap = State->get<IteratorRegionMap>();
813 for (
const auto Reg : RegionMap) {
814 if (!SR.isLiveRegion(Reg.first)) {
819 State = State->remove<IteratorRegionMap>(Reg.first);
824 auto SymbolMap = State->get<IteratorSymbolMap>();
825 for (
const auto Sym : SymbolMap) {
826 if (!SR.isLive(Sym.first)) {
827 State = State->remove<IteratorSymbolMap>(Sym.first);
831 auto ContMap = State->get<ContainerMap>();
832 for (
const auto Cont : ContMap) {
833 if (!SR.isLiveRegion(Cont.first)) {
837 State = State->remove<ContainerMap>(Cont.first);
842 auto ComparisonMap = State->get<IteratorComparisonMap>();
843 for (
const auto Comp : ComparisonMap) {
844 if (!SR.isLive(Comp.first)) {
845 State = State->remove<IteratorComparisonMap>(Comp.first);
849 C.addTransition(State);
853 bool Assumption)
const {
856 const auto *SE = Cond.getAsSymExpr();
861 if (Opc != BO_EQ && Opc != BO_NE)
864 bool Negated =
false;
868 const auto *SIE = dyn_cast<SymIntExpr>(SE);
872 if (SIE->getRHS() != 0)
876 Negated = SIE->getOpcode() == BO_EQ;
878 if (Opc != BO_EQ && Opc != BO_NE)
887 (Comp->isEquality() == Assumption) != Negated);
890 void IteratorChecker::handleComparison(CheckerContext &C,
const SVal &RetVal,
891 const SVal &LVal,
const SVal &RVal,
897 auto State = C.getState();
898 if (
const auto *Condition = RetVal.getAsSymbolicExpression()) {
903 State =
saveComparison(State, Condition, LVal, RVal, Op == OO_EqualEqual);
904 C.addTransition(State);
905 }
else if (
const auto TruthVal = RetVal.getAs<nonloc::ConcreteInt>()) {
908 (Op == OO_EqualEqual) == (TruthVal->getValue() != 0)))) {
909 C.addTransition(State);
911 C.generateSink(State, C.getPredecessor());
916 void IteratorChecker::verifyDereference(CheckerContext &C,
917 const SVal &Val)
const {
918 auto State = C.getState();
921 auto *N = C.generateNonFatalErrorNode(State);
924 reportOutOfRangeBug(
"Past-the-end iterator dereferenced.", Val, C, N);
929 void IteratorChecker::verifyAccess(CheckerContext &C,
const SVal &Val)
const {
930 auto State = C.getState();
932 if (Pos && !Pos->isValid()) {
933 auto *N = C.generateNonFatalErrorNode(State);
937 reportInvalidatedBug(
"Invalidated iterator accessed.", Val, C, N);
941 void IteratorChecker::handleIncrement(CheckerContext &C,
const SVal &RetVal,
942 const SVal &Iter,
bool Postfix)
const {
945 auto State = C.getState();
948 auto &SymMgr = C.getSymbolManager();
949 auto &BVF = SymMgr.getBasicVals();
951 advancePosition(C, OO_Plus, *Pos,
952 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
955 C.addTransition(State);
959 void IteratorChecker::handleDecrement(CheckerContext &C,
const SVal &RetVal,
960 const SVal &Iter,
bool Postfix)
const {
963 auto State = C.getState();
966 auto &SymMgr = C.getSymbolManager();
967 auto &BVF = SymMgr.getBasicVals();
969 advancePosition(C, OO_Minus, *Pos,
970 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
973 C.addTransition(State);
986 SValBuilder &SVB = State->getStateManager().getSValBuilder();
987 BasicValueFactory &BV = SVB.getBasicValueFactory();
991 APSIntType AT = BV.getAPSIntType(T);
995 llvm::APSInt Max = AT.getMaxValue() / AT.getValue(Scale);
996 SVal IsCappedFromAbove =
997 SVB.evalBinOpNN(State, BO_LE, nonloc::SymbolVal(Sym),
998 nonloc::ConcreteInt(Max), SVB.getConditionType());
999 if (
auto DV = IsCappedFromAbove.getAs<DefinedSVal>()) {
1000 NewState = NewState->assume(*DV,
true);
1005 llvm::APSInt Min = -Max;
1006 SVal IsCappedFromBelow =
1007 SVB.evalBinOpNN(State, BO_GE, nonloc::SymbolVal(Sym),
1008 nonloc::ConcreteInt(Min), SVB.getConditionType());
1009 if (
auto DV = IsCappedFromBelow.getAs<DefinedSVal>()) {
1010 NewState = NewState->assume(*DV,
true);
1018 void IteratorChecker::handleRandomIncrOrDecr(CheckerContext &C,
1022 const SVal &RHS)
const {
1025 auto State = C.getState();
1030 const auto *value = &RHS;
1031 if (
auto loc = RHS.getAs<Loc>()) {
1032 const auto val = State->getRawSVal(*loc);
1036 auto &TgtVal = (Op == OO_PlusEqual || Op == OO_MinusEqual) ? LHS : RetVal;
1039 C.addTransition(State);
1042 void IteratorChecker::verifyIncrement(CheckerContext &C,
1043 const SVal &Iter)
const {
1044 auto &BVF = C.getSValBuilder().getBasicValueFactory();
1045 verifyRandomIncrOrDecr(C, OO_Plus, Iter,
1046 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
1049 void IteratorChecker::verifyDecrement(CheckerContext &C,
1050 const SVal &Iter)
const {
1051 auto &BVF = C.getSValBuilder().getBasicValueFactory();
1052 verifyRandomIncrOrDecr(C, OO_Minus, Iter,
1053 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
1056 void IteratorChecker::verifyRandomIncrOrDecr(CheckerContext &C,
1059 const SVal &RHS)
const {
1060 auto State = C.getState();
1068 if (
auto ValAsLoc = RHS.getAs<Loc>()) {
1069 Value = State->getRawSVal(*ValAsLoc);
1072 if (
Value.isUnknown())
1082 auto *N = C.generateNonFatalErrorNode(State);
1085 reportOutOfRangeBug(
"Iterator decremented ahead of its valid range.", LHS,
1089 auto *N = C.generateNonFatalErrorNode(State);
1092 reportOutOfRangeBug(
"Iterator incremented behind the past-the-end " 1093 "iterator.", LHS, C, N);
1097 void IteratorChecker::verifyMatch(CheckerContext &C,
const SVal &Iter,
1098 const MemRegion *Cont)
const {
1100 Cont = Cont->getMostDerivedObjectRegion();
1102 auto State = C.getState();
1104 if (Pos && Pos->getContainer() != Cont) {
1105 auto *N = C.generateNonFatalErrorNode(State);
1109 reportMismatchedBug(
"Container accessed using foreign iterator argument.", Iter, Cont, C, N);
1113 void IteratorChecker::verifyMatch(CheckerContext &C,
const SVal &Iter1,
1114 const SVal &Iter2)
const {
1116 auto State = C.getState();
1119 if (Pos1 && Pos2 && Pos1->getContainer() != Pos2->getContainer()) {
1120 auto *N = C.generateNonFatalErrorNode(State);
1123 reportMismatchedBug(
"Iterators of different containers used where the " 1124 "same container is expected.", Iter1, Iter2, C, N);
1128 void IteratorChecker::handleBegin(CheckerContext &C,
const Expr *CE,
1129 const SVal &RetVal,
const SVal &Cont)
const {
1130 const auto *ContReg = Cont.getAsRegion();
1134 ContReg = ContReg->getMostDerivedObjectRegion();
1138 auto State = C.getState();
1141 auto &SymMgr = C.getSymbolManager();
1142 BeginSym = SymMgr.conjureSymbol(CE, C.getLocationContext(),
1143 C.getASTContext().LongTy, C.blockCount());
1148 IteratorPosition::getPosition(ContReg, BeginSym));
1149 C.addTransition(State);
1152 void IteratorChecker::handleEnd(CheckerContext &C,
const Expr *CE,
1153 const SVal &RetVal,
const SVal &Cont)
const {
1154 const auto *ContReg = Cont.getAsRegion();
1158 ContReg = ContReg->getMostDerivedObjectRegion();
1162 auto State = C.getState();
1165 auto &SymMgr = C.getSymbolManager();
1166 EndSym = SymMgr.conjureSymbol(CE, C.getLocationContext(),
1167 C.getASTContext().LongTy, C.blockCount());
1172 IteratorPosition::getPosition(ContReg, EndSym));
1173 C.addTransition(State);
1176 void IteratorChecker::assignToContainer(CheckerContext &C,
const Expr *CE,
1178 const MemRegion *Cont)
const {
1179 Cont = Cont->getMostDerivedObjectRegion();
1181 auto State = C.getState();
1182 auto &SymMgr = C.getSymbolManager();
1183 auto Sym = SymMgr.conjureSymbol(CE, C.getLocationContext(),
1184 C.getASTContext().LongTy, C.blockCount());
1187 IteratorPosition::getPosition(Cont, Sym));
1188 C.addTransition(State);
1191 void IteratorChecker::handleAssign(CheckerContext &C,
const SVal &Cont,
1192 const Expr *CE,
const SVal &OldCont)
const {
1193 const auto *ContReg = Cont.getAsRegion();
1197 ContReg = ContReg->getMostDerivedObjectRegion();
1201 auto State = C.getState();
1209 if (!OldCont.isUndef()) {
1210 const auto *OldContReg = OldCont.getAsRegion();
1212 OldContReg = OldContReg->getMostDerivedObjectRegion();
1215 if (
const auto OldEndSym = OldCData->getEnd()) {
1222 auto &SymMgr = C.getSymbolManager();
1223 auto &SVB = C.getSValBuilder();
1226 SymMgr.conjureSymbol(CE, C.getLocationContext(),
1227 C.getASTContext().LongTy, C.blockCount());
1233 ContainerData::fromEnd(NewEndSym));
1238 State, SVB, OldEndSym, NewEndSym, OldEndSym, BO_LT);
1244 if (
const auto OldBeginSym = OldCData->getBegin()) {
1252 ContainerData::fromBegin(OldBeginSym));
1264 C.addTransition(State);
1267 void IteratorChecker::handleClear(CheckerContext &C,
const SVal &Cont)
const {
1268 const auto *ContReg = Cont.getAsRegion();
1272 ContReg = ContReg->getMostDerivedObjectRegion();
1276 auto State = C.getState();
1281 if (
const auto EndSym = CData->getEnd()) {
1284 C.addTransition(State);
1290 C.addTransition(State);
1293 void IteratorChecker::handlePushBack(CheckerContext &C,
1294 const SVal &Cont)
const {
1295 const auto *ContReg = Cont.getAsRegion();
1299 ContReg = ContReg->getMostDerivedObjectRegion();
1302 auto State = C.getState();
1305 C.addTransition(State);
1314 if (
const auto EndSym = CData->getEnd()) {
1318 auto &SymMgr = C.getSymbolManager();
1319 auto &BVF = SymMgr.getBasicVals();
1320 auto &SVB = C.getSValBuilder();
1321 const auto newEndSym =
1322 SVB.evalBinOp(State, BO_Add,
1323 nonloc::SymbolVal(EndSym),
1324 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
1325 SymMgr.getType(EndSym)).getAsSymbol();
1328 C.addTransition(State);
1331 void IteratorChecker::handlePopBack(CheckerContext &C,
const SVal &Cont)
const {
1332 const auto *ContReg = Cont.getAsRegion();
1336 ContReg = ContReg->getMostDerivedObjectRegion();
1338 auto State = C.getState();
1343 if (
const auto EndSym = CData->getEnd()) {
1344 auto &SymMgr = C.getSymbolManager();
1345 auto &BVF = SymMgr.getBasicVals();
1346 auto &SVB = C.getSValBuilder();
1347 const auto BackSym =
1348 SVB.evalBinOp(State, BO_Sub,
1349 nonloc::SymbolVal(EndSym),
1350 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
1351 SymMgr.getType(EndSym)).getAsSymbol();
1362 auto newEndSym = BackSym;
1364 C.addTransition(State);
1368 void IteratorChecker::handlePushFront(CheckerContext &C,
1369 const SVal &Cont)
const {
1370 const auto *ContReg = Cont.getAsRegion();
1374 ContReg = ContReg->getMostDerivedObjectRegion();
1377 auto State = C.getState();
1380 C.addTransition(State);
1386 if (
const auto BeginSym = CData->getBegin()) {
1387 auto &SymMgr = C.getSymbolManager();
1388 auto &BVF = SymMgr.getBasicVals();
1389 auto &SVB = C.getSValBuilder();
1390 const auto newBeginSym =
1391 SVB.evalBinOp(State, BO_Sub,
1392 nonloc::SymbolVal(BeginSym),
1393 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
1394 SymMgr.getType(BeginSym)).getAsSymbol();
1396 C.addTransition(State);
1401 void IteratorChecker::handlePopFront(CheckerContext &C,
1402 const SVal &Cont)
const {
1403 const auto *ContReg = Cont.getAsRegion();
1407 ContReg = ContReg->getMostDerivedObjectRegion();
1409 auto State = C.getState();
1416 if (
const auto BeginSym = CData->getBegin()) {
1422 auto &SymMgr = C.getSymbolManager();
1423 auto &BVF = SymMgr.getBasicVals();
1424 auto &SVB = C.getSValBuilder();
1425 const auto newBeginSym =
1426 SVB.evalBinOp(State, BO_Add,
1427 nonloc::SymbolVal(BeginSym),
1428 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
1429 SymMgr.getType(BeginSym)).getAsSymbol();
1431 C.addTransition(State);
1435 void IteratorChecker::handleInsert(CheckerContext &C,
const SVal &Iter)
const {
1436 auto State = C.getState();
1443 const auto *Cont = Pos->getContainer();
1451 if (
const auto EndSym = CData->getEnd()) {
1456 C.addTransition(State);
1460 void IteratorChecker::handleErase(CheckerContext &C,
const SVal &Iter)
const {
1461 auto State = C.getState();
1469 const auto *Cont = Pos->getContainer();
1477 if (
const auto EndSym = CData->getEnd()) {
1485 C.addTransition(State);
1488 void IteratorChecker::handleErase(CheckerContext &C,
const SVal &Iter1,
1489 const SVal &Iter2)
const {
1490 auto State = C.getState();
1500 const auto *Cont = Pos1->getContainer();
1508 if (
const auto EndSym = CData->getEnd()) {
1515 Pos2->getOffset(), BO_LT);
1517 C.addTransition(State);
1520 void IteratorChecker::handleEraseAfter(CheckerContext &C,
1521 const SVal &Iter)
const {
1522 auto State = C.getState();
1529 auto &SymMgr = C.getSymbolManager();
1530 auto &BVF = SymMgr.getBasicVals();
1531 auto &SVB = C.getSValBuilder();
1532 const auto NextSym =
1533 SVB.evalBinOp(State, BO_Add,
1534 nonloc::SymbolVal(Pos->getOffset()),
1535 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
1536 SymMgr.getType(Pos->getOffset())).getAsSymbol();
1538 C.addTransition(State);
1541 void IteratorChecker::handleEraseAfter(CheckerContext &C,
const SVal &Iter1,
1542 const SVal &Iter2)
const {
1543 auto State = C.getState();
1551 Pos2->getOffset(), BO_LT);
1552 C.addTransition(State);
1555 IteratorPosition IteratorChecker::advancePosition(CheckerContext &C,
1557 const IteratorPosition &Pos,
1558 const SVal &Distance)
const {
1559 auto State = C.getState();
1560 auto &SymMgr = C.getSymbolManager();
1561 auto &SVB = C.getSValBuilder();
1563 assert ((Op == OO_Plus || Op == OO_PlusEqual ||
1564 Op == OO_Minus || Op == OO_MinusEqual) &&
1565 "Advance operator must be one of +, -, += and -=.");
1566 auto BinOp = (Op == OO_Plus || Op == OO_PlusEqual) ? BO_Add : BO_Sub;
1567 if (
const auto IntDist = Distance.getAs<nonloc::ConcreteInt>()) {
1569 return Pos.setTo(SVB.evalBinOp(State, BinOp,
1570 nonloc::SymbolVal(Pos.getOffset()), *IntDist,
1571 SymMgr.getType(Pos.getOffset()))
1575 const auto &LCtx = C.getLocationContext();
1576 const auto NewPosSym = SymMgr.conjureSymbol(
nullptr, LCtx,
1577 SymMgr.getType(Pos.getOffset()),
1580 return Pos.setTo(NewPosSym);
1584 void IteratorChecker::reportOutOfRangeBug(
const StringRef &Message,
1585 const SVal &Val, CheckerContext &C,
1586 ExplodedNode *ErrNode)
const {
1587 auto R = llvm::make_unique<BugReport>(*OutOfRangeBugType, Message, ErrNode);
1588 R->markInteresting(Val);
1589 C.emitReport(std::move(R));
1592 void IteratorChecker::reportMismatchedBug(
const StringRef &Message,
1593 const SVal &Val1,
const SVal &Val2,
1595 ExplodedNode *ErrNode)
const {
1596 auto R = llvm::make_unique<BugReport>(*MismatchedBugType, Message, ErrNode);
1597 R->markInteresting(Val1);
1598 R->markInteresting(Val2);
1599 C.emitReport(std::move(R));
1602 void IteratorChecker::reportMismatchedBug(
const StringRef &Message,
1603 const SVal &Val,
const MemRegion *Reg,
1605 ExplodedNode *ErrNode)
const {
1606 auto R = llvm::make_unique<BugReport>(*MismatchedBugType, Message, ErrNode);
1607 R->markInteresting(Val);
1608 R->markInteresting(Reg);
1609 C.emitReport(std::move(R));
1612 void IteratorChecker::reportInvalidatedBug(
const StringRef &Message,
1613 const SVal &Val, CheckerContext &C,
1614 ExplodedNode *ErrNode)
const {
1615 auto R = llvm::make_unique<BugReport>(*InvalidatedBugType, Message, ErrNode);
1616 R->markInteresting(Val);
1617 C.emitReport(std::move(R));
1630 const MemRegion *Reg);
1646 const auto Name = CRD->
getName();
1647 if (!(Name.endswith_lower(
"iterator") || Name.endswith_lower(
"iter") ||
1648 Name.endswith_lower(
"it")))
1651 bool HasCopyCtor =
false, HasCopyAssign =
true, HasDtor =
false,
1652 HasPreIncrOp =
false, HasPostIncrOp =
false, HasDerefOp =
false;
1653 for (
const auto *Method : CRD->
methods()) {
1654 if (
const auto *Ctor = dyn_cast<CXXConstructorDecl>(Method)) {
1655 if (Ctor->isCopyConstructor()) {
1656 HasCopyCtor = !Ctor->isDeleted() && Ctor->getAccess() ==
AS_public;
1660 if (
const auto *Dtor = dyn_cast<CXXDestructorDecl>(Method)) {
1661 HasDtor = !Dtor->isDeleted() && Dtor->getAccess() ==
AS_public;
1664 if (Method->isCopyAssignmentOperator()) {
1665 HasCopyAssign = !Method->isDeleted() && Method->getAccess() ==
AS_public;
1668 if (!Method->isOverloadedOperator())
1670 const auto OPK = Method->getOverloadedOperator();
1671 if (OPK == OO_PlusPlus) {
1672 HasPreIncrOp = HasPreIncrOp || (Method->getNumParams() == 0);
1673 HasPostIncrOp = HasPostIncrOp || (Method->getNumParams() == 1);
1676 if (OPK == OO_Star) {
1677 HasDerefOp = (Method->getNumParams() == 0);
1682 return HasCopyCtor && HasCopyAssign && HasDtor && HasPreIncrOp &&
1683 HasPostIncrOp && HasDerefOp;
1687 return OK == OO_EqualEqual || OK == OO_ExclaimEqual || OK == OO_Less ||
1688 OK == OO_LessEqual || OK == OO_Greater || OK == OO_GreaterEqual;
1695 return IdInfo->
getName().endswith_lower(
"begin");
1702 return IdInfo->
getName().endswith_lower(
"end");
1711 return IdInfo->
getName() ==
"assign";
1720 return IdInfo->
getName() ==
"clear";
1729 return IdInfo->
getName() ==
"push_back";
1738 return IdInfo->
getName() ==
"emplace_back";
1747 return IdInfo->
getName() ==
"pop_back";
1756 return IdInfo->
getName() ==
"push_front";
1765 return IdInfo->
getName() ==
"emplace_front";
1774 return IdInfo->
getName() ==
"pop_front";
1785 return IdInfo->
getName() ==
"insert";
1796 return IdInfo->
getName() ==
"emplace";
1810 return IdInfo->
getName() ==
"erase";
1824 return IdInfo->
getName() ==
"erase_after";
1830 return OK == OO_EqualEqual || OK == OO_ExclaimEqual;
1839 return OK == OO_Star || OK == OO_Arrow || OK == OO_ArrowStar ||
1844 return OK == OO_PlusPlus;
1848 return OK == OO_MinusMinus;
1852 return OK == OO_Plus || OK == OO_PlusEqual || OK == OO_Minus ||
1853 OK == OO_MinusEqual;
1857 if (
const auto *BSE = dyn_cast<BinarySymExpr>(SE)) {
1858 return BSE->getOpcode();
1859 }
else if (
const auto *SC = dyn_cast<SymbolConjured>(SE)) {
1860 const auto *COE = dyn_cast_or_null<CXXOperatorCallExpr>(SC->getStmt());
1863 if (COE->getOperator() == OO_EqualEqual) {
1865 }
else if (COE->getOperator() == OO_ExclaimEqual) {
1874 const auto *CRD = getCXXRecordDecl(State, Reg);
1878 for (
const auto *Method : CRD->
methods()) {
1879 if (!Method->isOverloadedOperator())
1881 const auto OPK = Method->getOverloadedOperator();
1882 if (OPK == OO_Subscript) {
1890 const auto *CRD = getCXXRecordDecl(State, Reg);
1894 for (
const auto *Method : CRD->
methods()) {
1895 if (!Method->getDeclName().isIdentifier())
1897 if (Method->getName() ==
"push_front" || Method->getName() ==
"pop_front") {
1905 const auto *CRD = getCXXRecordDecl(State, Reg);
1909 for (
const auto *Method : CRD->
methods()) {
1910 if (!Method->getDeclName().isIdentifier())
1912 if (Method->getName() ==
"push_back" || Method->getName() ==
"pop_back") {
1920 const MemRegion *Reg) {
1925 auto Type = TI.getType();
1934 if (
const auto Reg = Val.getAsRegion()) {
1936 }
else if (
const auto Sym = Val.getAsSymbol()) {
1938 }
else if (
const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
1939 return LCVal->getRegion();
1941 return RegionOrSymbol();
1945 RegionOrSymbol LVal,
1946 RegionOrSymbol RVal,
bool Equal) {
1949 if (LPos && !RPos) {
1951 }
else if (!LPos && RPos) {
1953 }
else if (LPos && RPos) {
1960 const SymExpr *Condition,
const SVal &LVal,
1961 const SVal &RVal,
bool Eq) {
1964 if (!Left || !Right)
1966 return State->set<IteratorComparisonMap>(Condition,
1971 const SymExpr *Condition) {
1972 return State->get<IteratorComparisonMap>(Condition);
1980 return CDataPtr->getBegin();
1988 return CDataPtr->getEnd();
1992 const MemRegion *Cont,
1997 if (CDataPtr->getBegin()) {
2000 const auto CData = CDataPtr->newBegin(Sym);
2003 const auto CData = ContainerData::fromBegin(Sym);
2012 if (CDataPtr->getEnd()) {
2015 const auto CData = CDataPtr->newEnd(Sym);
2018 const auto CData = ContainerData::fromEnd(Sym);
2023 const MemRegion *Cont) {
2024 return State->get<ContainerMap>(Cont);
2028 const ContainerData &CData) {
2029 return State->set<ContainerMap>(Cont, CData);
2034 if (
auto Reg = Val.getAsRegion()) {
2035 Reg = Reg->getMostDerivedObjectRegion();
2036 return State->get<IteratorRegionMap>(Reg);
2037 }
else if (
const auto Sym = Val.getAsSymbol()) {
2038 return State->get<IteratorSymbolMap>(Sym);
2039 }
else if (
const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
2040 return State->get<IteratorRegionMap>(LCVal->getRegion());
2046 RegionOrSymbol RegOrSym) {
2047 if (RegOrSym.is<
const MemRegion *>()) {
2048 auto Reg = RegOrSym.get<
const MemRegion *>()->getMostDerivedObjectRegion();
2049 return State->get<IteratorRegionMap>(Reg);
2051 return State->get<IteratorSymbolMap>(RegOrSym.get<
SymbolRef>());
2057 const IteratorPosition &Pos) {
2058 if (
auto Reg = Val.getAsRegion()) {
2059 Reg = Reg->getMostDerivedObjectRegion();
2060 return State->set<IteratorRegionMap>(Reg, Pos);
2061 }
else if (
const auto Sym = Val.getAsSymbol()) {
2062 return State->set<IteratorSymbolMap>(Sym, Pos);
2063 }
else if (
const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
2064 return State->set<IteratorRegionMap>(LCVal->getRegion(), Pos);
2070 RegionOrSymbol RegOrSym,
2071 const IteratorPosition &Pos) {
2072 if (RegOrSym.is<
const MemRegion *>()) {
2073 auto Reg = RegOrSym.get<
const MemRegion *>()->getMostDerivedObjectRegion();
2074 return State->set<IteratorRegionMap>(Reg, Pos);
2076 return State->set<IteratorSymbolMap>(RegOrSym.get<
SymbolRef>(), Pos);
2082 if (
auto Reg = Val.getAsRegion()) {
2083 Reg = Reg->getMostDerivedObjectRegion();
2084 return State->remove<IteratorRegionMap>(Reg);
2085 }
else if (
const auto Sym = Val.getAsSymbol()) {
2086 return State->remove<IteratorSymbolMap>(Sym);
2087 }
else if (
const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
2088 return State->remove<IteratorRegionMap>(LCVal->getRegion());
2094 RegionOrSymbol RegOrSym,
2095 const IteratorPosition &Pos,
2105 const IteratorPosition &Pos1,
2106 const IteratorPosition &Pos2,
2108 auto &SVB = State->getStateManager().getSValBuilder();
2115 const auto comparison =
2116 SVB.evalBinOp(State, BO_EQ, nonloc::SymbolVal(Pos1.getOffset()),
2117 nonloc::SymbolVal(Pos2.getOffset()),
2118 SVB.getConditionType());
2120 assert(comparison.getAs<DefinedSVal>() &&
2121 "Symbol comparison must be a `DefinedSVal`");
2123 auto NewState = State->assume(comparison.castAs<DefinedSVal>(), Equal);
2124 if (
const auto CompSym = comparison.getAsSymbol()) {
2125 assert(isa<SymIntExpr>(CompSym) &&
2126 "Symbol comparison must be a `SymIntExpr`");
2128 cast<SymIntExpr>(CompSym)->
getOpcode()) &&
2129 "Symbol comparison must be a comparison");
2137 auto RegionMap = State->get<IteratorRegionMap>();
2138 for (
const auto Reg : RegionMap) {
2139 if (Reg.second.getContainer() == Cont)
2143 auto SymbolMap = State->get<IteratorSymbolMap>();
2144 for (
const auto Sym : SymbolMap) {
2145 if (Sym.second.getContainer() == Cont)
2153 const MemRegion *Reg) {
2154 for (
const auto Binding: Env) {
2155 if (
const auto LCVal = Binding.second.getAs<nonloc::LazyCompoundVal>()) {
2156 if (LCVal->getRegion() == Reg)
2164 template <
typename Condition,
typename Process>
2167 auto &RegionMapFactory = State->get_context<IteratorRegionMap>();
2168 auto RegionMap = State->get<IteratorRegionMap>();
2169 bool Changed =
false;
2170 for (
const auto Reg : RegionMap) {
2171 if (Cond(Reg.second)) {
2172 RegionMap = RegionMapFactory.add(RegionMap, Reg.first, Proc(Reg.second));
2178 State = State->set<IteratorRegionMap>(RegionMap);
2180 auto &SymbolMapFactory = State->get_context<IteratorSymbolMap>();
2181 auto SymbolMap = State->get<IteratorSymbolMap>();
2183 for (
const auto Sym : SymbolMap) {
2184 if (Cond(Sym.second)) {
2185 SymbolMap = SymbolMapFactory.add(SymbolMap, Sym.first, Proc(Sym.second));
2191 State = State->set<IteratorSymbolMap>(SymbolMap);
2197 const MemRegion *Cont) {
2198 auto MatchCont = [&](
const IteratorPosition &Pos) {
2199 return Pos.getContainer() == Cont;
2201 auto Invalidate = [&](
const IteratorPosition &Pos) {
2202 return Pos.invalidate();
2204 return processIteratorPositions(State, MatchCont, Invalidate);
2209 const MemRegion *Cont,
SymbolRef Offset,
2211 auto MatchContAndCompare = [&](
const IteratorPosition &Pos) {
2212 return Pos.getContainer() == Cont &&
2215 auto Invalidate = [&](
const IteratorPosition &Pos) {
2216 return Pos.invalidate();
2218 return processIteratorPositions(State, MatchContAndCompare, Invalidate);
2224 auto Compare = [&](
const IteratorPosition &Pos) {
2227 auto Invalidate = [&](
const IteratorPosition &Pos) {
2228 return Pos.invalidate();
2230 return processIteratorPositions(State, Compare, Invalidate);
2238 auto Compare = [&](
const IteratorPosition &Pos) {
2239 return compare(State, Pos.getOffset(), Offset1, Opc1) &&
2240 compare(State, Pos.getOffset(), Offset2, Opc2);
2242 auto Invalidate = [&](
const IteratorPosition &Pos) {
2243 return Pos.invalidate();
2245 return processIteratorPositions(State, Compare, Invalidate);
2249 const MemRegion *Cont,
2250 const MemRegion *NewCont) {
2251 auto MatchCont = [&](
const IteratorPosition &Pos) {
2252 return Pos.getContainer() == Cont;
2254 auto ReAssign = [&](
const IteratorPosition &Pos) {
2255 return Pos.reAssign(NewCont);
2257 return processIteratorPositions(State, MatchCont, ReAssign);
2261 const MemRegion *Cont,
2262 const MemRegion *NewCont,
2265 auto MatchContAndCompare = [&](
const IteratorPosition &Pos) {
2266 return Pos.getContainer() == Cont &&
2269 auto ReAssign = [&](
const IteratorPosition &Pos) {
2270 return Pos.reAssign(NewCont);
2272 return processIteratorPositions(State, MatchContAndCompare, ReAssign);
2281 auto LessThanEnd = [&](
const IteratorPosition &Pos) {
2282 return compare(State, Pos.getOffset(), CondSym, Opc);
2284 auto RebaseSymbol = [&](
const IteratorPosition &Pos) {
2285 return Pos.setTo(rebaseSymbol(State, SVB, Pos.getOffset(), OldSym,
2288 return processIteratorPositions(State, LessThanEnd, RebaseSymbol);
2297 auto &SymMgr = SVB.getSymbolManager();
2298 auto Diff = SVB.evalBinOpNN(State, BO_Sub, nonloc::SymbolVal(OrigExpr),
2299 nonloc::SymbolVal(OldExpr),
2300 SymMgr.getType(OrigExpr));
2302 const auto DiffInt = Diff.getAs<nonloc::ConcreteInt>();
2306 return SVB.evalBinOpNN(State, BO_Add, *DiffInt, nonloc::SymbolVal(NewSym),
2307 SymMgr.getType(OrigExpr)).getAsSymbol();
2311 auto &BVF = State->getBasicVals();
2313 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))),
2318 const auto *Cont = Pos.getContainer();
2323 const auto End = CData->getEnd();
2325 if (isEqual(State, Pos.getOffset(),
End)) {
2334 const auto *Cont = Pos.getContainer();
2339 const auto Beg = CData->getBegin();
2341 if (isLess(State, Pos.getOffset(), Beg)) {
2350 const auto *Cont = Pos.getContainer();
2355 const auto End = CData->getEnd();
2357 if (isGreater(State, Pos.getOffset(),
End)) {
2366 return compare(State, Sym1, Sym2, BO_LT);
2370 return compare(State, Sym1, Sym2, BO_GT);
2374 return compare(State, Sym1, Sym2, BO_EQ);
2379 return compare(State, nonloc::SymbolVal(Sym1), nonloc::SymbolVal(Sym2), Opc);
2385 auto &SVB = State->getStateManager().getSValBuilder();
2387 const auto comparison =
2388 SVB.evalBinOp(State, Opc, NL1, NL2, SVB.getConditionType());
2390 assert(comparison.getAs<DefinedSVal>() &&
2391 "Symbol comparison must be a `DefinedSVal`");
2393 return !State->assume(comparison.castAs<DefinedSVal>(),
false);
2398 #define REGISTER_CHECKER(name) \ 2399 void ento::register##name(CheckerManager &Mgr) { \ 2400 auto *checker = Mgr.registerChecker<IteratorChecker>(); \ 2401 checker->ChecksEnabled[IteratorChecker::CK_##name] = true; \ 2402 checker->CheckNames[IteratorChecker::CK_##name] = \ 2403 Mgr.getCurrentCheckName(); \
const ProgramStateRef processComparison(ProgramStateRef State, RegionOrSymbol LVal, RegionOrSymbol RVal, bool Equal)
Represents a function declaration or definition.
bool isInsertCall(const FunctionDecl *Func)
A (possibly-)qualified type.
SymbolRef getContainerEnd(ProgramStateRef State, const MemRegion *Cont)
ProgramStateRef rebaseSymbolInIteratorPositionsIf(ProgramStateRef State, SValBuilder &SVB, SymbolRef OldSym, SymbolRef NewSym, SymbolRef CondSym, BinaryOperator::Opcode Opc)
bool isBehindPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos)
bool isSimpleComparisonOperator(OverloadedOperatorKind OK)
bool operator==(CanQual< T > x, CanQual< U > y)
const SymExpr * SymbolRef
REGISTER_MAP_WITH_PROGRAMSTATE(IteratorRegionMap, const MemRegion *, IteratorPosition) REGISTER_MAP_WITH_PROGRAMSTATE(IteratorComparisonMap
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.
bool isAssignmentOperator(OverloadedOperatorKind OK)
The base class of the type hierarchy.
Represents a call to a C++ constructor.
bool isZero(ProgramStateRef State, const NonLoc &Val)
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>'.
Represents the result of substituting a type for a template type parameter.
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
bool isAccessOperator(OverloadedOperatorKind OK)
Expr * GetTemporaryExpr() const
Retrieve the temporary-generating subexpression whose value will be materialized into a glvalue...
ProgramStateRef reassignAllIteratorPositions(ProgramStateRef State, const MemRegion *Cont, const MemRegion *NewCont)
bool isEraseAfterCall(const FunctionDecl *Func)
ProgramStateRef adjustIteratorPosition(ProgramStateRef State, RegionOrSymbol RegOrSym, const IteratorPosition &Pos, bool Equal)
bool isPopFrontCall(const FunctionDecl *Func)
bool isAssignCall(const FunctionDecl *Func)
ProgramStateRef reassignAllIteratorPositionsUnless(ProgramStateRef State, const MemRegion *Cont, const MemRegion *NewCont, SymbolRef Offset, BinaryOperator::Opcode Opc)
bool isEndCall(const FunctionDecl *Func)
bool hasSubscriptOperator(ProgramStateRef State, const MemRegion *Reg)
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 isAheadOfRange(ProgramStateRef State, const IteratorPosition &Pos)
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
Represents a non-static C++ member function call, no matter how it is written.
const IteratorPosition * getIteratorPosition(ProgramStateRef State, RegionOrSymbol RegOrSym)
bool isPushBackCall(const FunctionDecl *Func)
bool frontModifiable(ProgramStateRef State, const MemRegion *Reg)
This represents one expression.
static bool compare(const PathDiagnostic &X, const PathDiagnostic &Y)
Declaration of a template type parameter.
bool isComparisonOperator(OverloadedOperatorKind OK)
bool isDereferenceOperator(OverloadedOperatorKind OK)
ProgramStateRef createContainerEnd(ProgramStateRef State, const MemRegion *Cont, const SymbolRef Sym)
ProgramStateRef invalidateIteratorPositions(ProgramStateRef State, SymbolRef Offset1, BinaryOperator::Opcode Opc1, SymbolRef Offset2, BinaryOperator::Opcode Opc2)
const ContainerData * getContainerData(ProgramStateRef State, const MemRegion *Cont)
bool isComparisonOp() const
ProgramStateRef invalidateAllIteratorPositionsExcept(ProgramStateRef State, const MemRegion *Cont, SymbolRef Offset, BinaryOperator::Opcode Opc)
ProgramStateRef setIteratorPosition(ProgramStateRef State, RegionOrSymbol RegOrSym, const IteratorPosition &Pos)
bool isPopBackCall(const FunctionDecl *Func)
DeclStmt - Adaptor class for mixing declarations with statements and expressions. ...
ProgramStateRef invalidateAllIteratorPositions(ProgramStateRef State, const MemRegion *Cont)
const ParmVarDecl * getParamDecl(unsigned i) const
bool isSignedIntegerOrEnumerationType() const
Determines whether this is an integer type that is signed or an enumeration types whose underlying ty...
SymbolRef getContainerBegin(ProgramStateRef State, const MemRegion *Cont)
bool isDecrementOperator(OverloadedOperatorKind OK)
ProgramStateRef relateIteratorPositions(ProgramStateRef State, const IteratorPosition &Pos1, const IteratorPosition &Pos2, bool Equal)
const IteratorComparison * loadComparison(ProgramStateRef State, const SymExpr *Condition)
StringRef getName() const
Return the actual identifier string.
bool isPushFrontCall(const FunctionDecl *Func)
Dataflow Directional Tag Classes.
bool isClearCall(const FunctionDecl *Func)
OverloadedOperatorKind
Enumeration specifying the different kinds of C++ overloaded operators.
DynamicTypeInfo getDynamicTypeInfo(ProgramStateRef State, const MemRegion *Reg)
Get dynamic type information for a region.
#define REGISTER_CHECKER(name)
BinaryOperator::Opcode getOpcode(const SymExpr *SE)
bool isIteratorType(const QualType &Type)
ProgramStateRef removeIteratorPosition(ProgramStateRef State, const SVal &Val)
bool backModifiable(ProgramStateRef State, const MemRegion *Reg)
ProgramStateRef setContainerData(ProgramStateRef State, const MemRegion *Cont, const ContainerData &CData)
bool isBoundThroughLazyCompoundVal(const Environment &Env, const MemRegion *Reg)
bool isEmplaceCall(const FunctionDecl *Func)
Base for LValueReferenceType and RValueReferenceType.
bool isEmplaceBackCall(const FunctionDecl *Func)
const ProgramStateRef saveComparison(ProgramStateRef State, const SymExpr *Condition, const SVal &LVal, const SVal &RVal, bool Eq)
bool isEmplaceFrontCall(const FunctionDecl *Func)
X
Add a minimal nested name specifier fixit hint to allow lookup of a tag name from an outer enclosing ...
bool hasLiveIterators(ProgramStateRef State, const MemRegion *Cont)
Represents a C++ struct/union/class.
bool isPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos)
bool isBeginCall(const FunctionDecl *Func)
const RegionOrSymbol getRegionOrSymbol(const SVal &Val)
bool operator!=(CanQual< T > x, CanQual< U > y)
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
bool isEraseCall(const FunctionDecl *Func)
ProgramStateRef createContainerBegin(ProgramStateRef State, const MemRegion *Cont, const SymbolRef Sym)
bool isPointerType() const
bool isIncrementOperator(OverloadedOperatorKind OK)
unsigned getNumParams() const
Return the number of parameters this function must have based on its FunctionType.
bool isIterator(const CXXRecordDecl *CRD)
static ProgramStateRef assumeNoOverflow(ProgramStateRef State, SymbolRef Sym, long Scale)
bool isRandomIncrOrDecrOperator(OverloadedOperatorKind OK)
method_range methods() const