78 using namespace clang;
85 struct IteratorPosition {
89 const MemRegion *Cont;
97 IteratorPosition(
const MemRegion *C,
bool V,
SymbolRef Of)
98 : Cont(C), Valid(V), Offset(Of) {}
101 const MemRegion *getContainer()
const {
return Cont; }
102 bool isValid()
const {
return Valid; }
105 IteratorPosition invalidate()
const {
106 return IteratorPosition(Cont,
false, Offset);
109 static IteratorPosition getPosition(
const MemRegion *C,
SymbolRef Of) {
110 return IteratorPosition(C,
true, Of);
113 IteratorPosition setTo(
SymbolRef NewOf)
const {
114 return IteratorPosition(Cont, Valid, NewOf);
117 IteratorPosition reAssign(
const MemRegion *NewCont)
const {
118 return IteratorPosition(NewCont, Valid, Offset);
122 return Cont == X.Cont && Valid == X.Valid && Offset == X.Offset;
126 return Cont != X.Cont || Valid != X.Valid || Offset != X.Offset;
129 void Profile(llvm::FoldingSetNodeID &
ID)
const {
131 ID.AddInteger(Valid);
137 struct ContainerData {
144 static ContainerData fromBegin(
SymbolRef B) {
145 return ContainerData(B,
nullptr);
148 static ContainerData fromEnd(
SymbolRef E) {
149 return ContainerData(
nullptr, E);
155 ContainerData newBegin(
SymbolRef B)
const {
return ContainerData(B, End); }
157 ContainerData newEnd(
SymbolRef E)
const {
return ContainerData(Begin, E); }
160 return Begin == X.Begin && End == X.End;
164 return Begin != X.Begin || End != X.End;
167 void Profile(llvm::FoldingSetNodeID &ID)
const {
173 class IteratorChecker
174 :
public Checker<check::PreCall, check::PostCall,
175 check::PostStmt<MaterializeTemporaryExpr>, check::Bind,
176 check::LiveSymbols, check::DeadSymbols> {
178 std::unique_ptr<BugType> OutOfRangeBugType;
179 std::unique_ptr<BugType> MismatchedBugType;
180 std::unique_ptr<BugType> InvalidatedBugType;
182 void handleComparison(CheckerContext &C,
const Expr *CE,
const SVal &RetVal,
183 const SVal &LVal,
const SVal &RVal,
188 void verifyAccess(CheckerContext &C,
const SVal &Val)
const;
189 void verifyDereference(CheckerContext &C,
const SVal &Val)
const;
190 void handleIncrement(CheckerContext &C,
const SVal &RetVal,
const SVal &Iter,
192 void handleDecrement(CheckerContext &C,
const SVal &RetVal,
const SVal &Iter,
195 const SVal &RetVal,
const SVal &LHS,
196 const SVal &RHS)
const;
197 void handleBegin(CheckerContext &C,
const Expr *CE,
const SVal &RetVal,
198 const SVal &Cont)
const;
199 void handleEnd(CheckerContext &C,
const Expr *CE,
const SVal &RetVal,
200 const SVal &Cont)
const;
201 void assignToContainer(CheckerContext &C,
const Expr *CE,
const SVal &RetVal,
202 const MemRegion *Cont)
const;
203 void handleAssign(CheckerContext &C,
const SVal &Cont,
204 const Expr *CE =
nullptr,
205 const SVal &OldCont = UndefinedVal())
const;
206 void handleClear(CheckerContext &C,
const SVal &Cont)
const;
207 void handlePushBack(CheckerContext &C,
const SVal &Cont)
const;
208 void handlePopBack(CheckerContext &C,
const SVal &Cont)
const;
209 void handlePushFront(CheckerContext &C,
const SVal &Cont)
const;
210 void handlePopFront(CheckerContext &C,
const SVal &Cont)
const;
211 void handleInsert(CheckerContext &C,
const SVal &Iter)
const;
212 void handleErase(CheckerContext &C,
const SVal &Iter)
const;
213 void handleErase(CheckerContext &C,
const SVal &Iter1,
214 const SVal &Iter2)
const;
215 void handleEraseAfter(CheckerContext &C,
const SVal &Iter)
const;
216 void handleEraseAfter(CheckerContext &C,
const SVal &Iter1,
217 const SVal &Iter2)
const;
218 void verifyIncrement(CheckerContext &C,
const SVal &Iter)
const;
219 void verifyDecrement(CheckerContext &C,
const SVal &Iter)
const;
221 const SVal &LHS,
const SVal &RHS)
const;
222 void verifyMatch(CheckerContext &C,
const SVal &Iter,
223 const MemRegion *Cont)
const;
224 void verifyMatch(CheckerContext &C,
const SVal &Iter1,
225 const SVal &Iter2)
const;
227 const IteratorPosition &Pos,
228 const SVal &Distance)
const;
229 void reportOutOfRangeBug(
const StringRef &Message,
const SVal &Val,
230 CheckerContext &C, ExplodedNode *ErrNode)
const;
231 void reportMismatchedBug(
const StringRef &Message,
const SVal &Val1,
232 const SVal &Val2, CheckerContext &C,
233 ExplodedNode *ErrNode)
const;
234 void reportMismatchedBug(
const StringRef &Message,
const SVal &Val,
235 const MemRegion *Reg, CheckerContext &C,
236 ExplodedNode *ErrNode)
const;
237 void reportInvalidatedBug(
const StringRef &Message,
const SVal &Val,
238 CheckerContext &C, ExplodedNode *ErrNode)
const;
244 CK_IteratorRangeChecker,
245 CK_MismatchedIteratorChecker,
246 CK_InvalidatedIteratorChecker,
250 DefaultBool ChecksEnabled[CK_NumCheckKinds];
251 CheckName CheckNames[CK_NumCheckKinds];
253 void checkPreCall(
const CallEvent &Call, CheckerContext &C)
const;
254 void checkPostCall(
const CallEvent &Call, CheckerContext &C)
const;
255 void checkBind(SVal Loc, SVal Val,
const Stmt *S, CheckerContext &C)
const;
257 void checkPostStmt(
const DeclStmt *DS, CheckerContext &C)
const;
259 CheckerContext &C)
const;
261 void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C)
const;
303 const MemRegion *Cont,
const Expr *E,
305 unsigned BlockCount);
309 unsigned BlockCount);
313 const IteratorPosition &Pos);
318 const MemRegion *Cont);
332 const MemRegion *Cont,
333 const MemRegion *NewCont);
335 const MemRegion *Cont,
336 const MemRegion *NewCont,
345 const MemRegion *Cont);
347 const ContainerData &CData);
349 bool isBoundThroughLazyCompoundVal(
const Environment &Env,
350 const MemRegion *Reg);
352 bool isAheadOfRange(
ProgramStateRef State,
const IteratorPosition &Pos);
353 bool isBehindPastTheEnd(
ProgramStateRef State,
const IteratorPosition &Pos);
357 IteratorChecker::IteratorChecker() {
358 OutOfRangeBugType.reset(
359 new BugType(
this,
"Iterator out of range",
"Misuse of STL APIs",
361 MismatchedBugType.reset(
362 new BugType(
this,
"Iterator(s) mismatched",
"Misuse of STL APIs",
364 InvalidatedBugType.reset(
365 new BugType(
this,
"Iterator invalidated",
"Misuse of STL APIs",
369 void IteratorChecker::checkPreCall(
const CallEvent &Call,
370 CheckerContext &C)
const {
373 const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
377 if (Func->isOverloadedOperator()) {
378 if (ChecksEnabled[CK_InvalidatedIteratorChecker] &&
379 isAccessOperator(Func->getOverloadedOperator())) {
381 if (
const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
382 verifyAccess(C, InstCall->getCXXThisVal());
384 verifyAccess(C, Call.getArgSVal(0));
387 if (ChecksEnabled[CK_IteratorRangeChecker]) {
388 if (isIncrementOperator(Func->getOverloadedOperator())) {
390 if (
const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
391 verifyIncrement(C, InstCall->getCXXThisVal());
393 if (Call.getNumArgs() >= 1) {
394 verifyIncrement(C, Call.getArgSVal(0));
397 }
else if (isDecrementOperator(Func->getOverloadedOperator())) {
399 if (
const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
400 verifyDecrement(C, InstCall->getCXXThisVal());
402 if (Call.getNumArgs() >= 1) {
403 verifyDecrement(C, Call.getArgSVal(0));
406 }
else if (isRandomIncrOrDecrOperator(Func->getOverloadedOperator())) {
407 if (
const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
409 if (Call.getNumArgs() >= 1 &&
410 Call.getArgExpr(0)->getType()->isIntegralOrEnumerationType()) {
411 verifyRandomIncrOrDecr(C, Func->getOverloadedOperator(),
412 InstCall->getCXXThisVal(),
416 if (Call.getNumArgs() >= 2 &&
417 Call.getArgExpr(1)->getType()->isIntegralOrEnumerationType()) {
418 verifyRandomIncrOrDecr(C, Func->getOverloadedOperator(),
419 Call.getArgSVal(0), Call.getArgSVal(1));
422 }
else if (isDereferenceOperator(Func->getOverloadedOperator())) {
424 if (
const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
425 verifyDereference(C, InstCall->getCXXThisVal());
427 verifyDereference(C, Call.getArgSVal(0));
430 }
else if (ChecksEnabled[CK_MismatchedIteratorChecker] &&
431 isComparisonOperator(Func->getOverloadedOperator())) {
433 if (
const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
434 if (Call.getNumArgs() < 1)
437 if (!isIteratorType(InstCall->getCXXThisExpr()->getType()) ||
438 !isIteratorType(Call.getArgExpr(0)->getType()))
441 verifyMatch(C, InstCall->getCXXThisVal(), Call.getArgSVal(0));
443 if (Call.getNumArgs() < 2)
446 if (!isIteratorType(Call.getArgExpr(0)->getType()) ||
447 !isIteratorType(Call.getArgExpr(1)->getType()))
450 verifyMatch(C, Call.getArgSVal(0), Call.getArgSVal(1));
453 }
else if (
const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
454 if (!ChecksEnabled[CK_MismatchedIteratorChecker])
457 const auto *ContReg = InstCall->getCXXThisVal().getAsRegion();
461 if (isEraseCall(Func) || isEraseAfterCall(Func)) {
462 verifyMatch(C, Call.getArgSVal(0),
463 InstCall->getCXXThisVal().getAsRegion());
464 if (Call.getNumArgs() == 2) {
465 verifyMatch(C, Call.getArgSVal(1),
466 InstCall->getCXXThisVal().getAsRegion());
468 }
else if (isInsertCall(Func)) {
469 verifyMatch(C, Call.getArgSVal(0),
470 InstCall->getCXXThisVal().getAsRegion());
471 if (Call.getNumArgs() == 3 &&
472 isIteratorType(Call.getArgExpr(1)->getType()) &&
473 isIteratorType(Call.getArgExpr(2)->getType())) {
474 verifyMatch(C, Call.getArgSVal(1), Call.getArgSVal(2));
476 }
else if (isEmplaceCall(Func)) {
477 verifyMatch(C, Call.getArgSVal(0),
478 InstCall->getCXXThisVal().getAsRegion());
480 }
else if (isa<CXXConstructorCall>(&Call)) {
482 if (Call.getNumArgs() < 2)
485 const auto *Ctr = cast<CXXConstructorDecl>(Call.getDecl());
486 if (Ctr->getNumParams() < 2)
489 if (Ctr->getParamDecl(0)->getName() !=
"first" ||
490 Ctr->getParamDecl(1)->getName() !=
"last")
493 if (!isIteratorType(Call.getArgExpr(0)->getType()) ||
494 !isIteratorType(Call.getArgExpr(1)->getType()))
497 verifyMatch(C, Call.getArgSVal(0), Call.getArgSVal(1));
515 if (!ChecksEnabled[CK_MismatchedIteratorChecker])
518 const auto *Templ = Func->getPrimaryTemplate();
522 const auto *TParams = Templ->getTemplateParameters();
523 const auto *TArgs = Func->getTemplateSpecializationArgs();
526 for (
size_t I = 0; I < TParams->size(); ++I) {
531 if (TPDecl->isParameterPack())
534 const auto TAType = TArgs->get(I).getAsType();
535 if (!isIteratorType(TAType))
538 SVal LHS = UndefinedVal();
543 for (
auto J = 0U; J < Func->getNumParams(); ++J) {
544 const auto *Param = Func->getParamDecl(J);
545 const auto *ParamType =
548 ParamType->getReplacedParameter()->getDecl() != TPDecl)
551 LHS = Call.getArgSVal(J);
553 verifyMatch(C, LHS, Call.getArgSVal(J));
560 void IteratorChecker::checkPostCall(
const CallEvent &Call,
561 CheckerContext &C)
const {
563 const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
567 if (Func->isOverloadedOperator()) {
568 const auto Op = Func->getOverloadedOperator();
569 if (isAssignmentOperator(Op)) {
571 if (cast<CXXMethodDecl>(Func)->isMoveAssignmentOperator()) {
572 handleAssign(C, InstCall->getCXXThisVal(), Call.getOriginExpr(),
577 handleAssign(C, InstCall->getCXXThisVal());
579 }
else if (isSimpleComparisonOperator(Op)) {
580 const auto *OrigExpr = Call.getOriginExpr();
584 if (
const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
585 handleComparison(C, OrigExpr, Call.getReturnValue(),
586 InstCall->getCXXThisVal(), Call.getArgSVal(0), Op);
590 handleComparison(C, OrigExpr, Call.getReturnValue(), Call.getArgSVal(0),
591 Call.getArgSVal(1), Op);
593 }
else if (isRandomIncrOrDecrOperator(Func->getOverloadedOperator())) {
594 if (
const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
595 if (Call.getNumArgs() >= 1 &&
596 Call.getArgExpr(0)->getType()->isIntegralOrEnumerationType()) {
597 handleRandomIncrOrDecr(C, Func->getOverloadedOperator(),
598 Call.getReturnValue(),
599 InstCall->getCXXThisVal(), Call.getArgSVal(0));
603 if (Call.getNumArgs() >= 2 &&
604 Call.getArgExpr(1)->getType()->isIntegralOrEnumerationType()) {
605 handleRandomIncrOrDecr(C, Func->getOverloadedOperator(),
606 Call.getReturnValue(), Call.getArgSVal(0),
611 }
else if (isIncrementOperator(Func->getOverloadedOperator())) {
612 if (
const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
613 handleIncrement(C, Call.getReturnValue(), InstCall->getCXXThisVal(),
618 handleIncrement(C, Call.getReturnValue(), Call.getArgSVal(0),
621 }
else if (isDecrementOperator(Func->getOverloadedOperator())) {
622 if (
const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
623 handleDecrement(C, Call.getReturnValue(), InstCall->getCXXThisVal(),
628 handleDecrement(C, Call.getReturnValue(), Call.getArgSVal(0),
633 if (
const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
634 if (isAssignCall(Func)) {
635 handleAssign(C, InstCall->getCXXThisVal());
639 if (isClearCall(Func)) {
640 handleClear(C, InstCall->getCXXThisVal());
644 if (isPushBackCall(Func) || isEmplaceBackCall(Func)) {
645 handlePushBack(C, InstCall->getCXXThisVal());
649 if (isPopBackCall(Func)) {
650 handlePopBack(C, InstCall->getCXXThisVal());
654 if (isPushFrontCall(Func) || isEmplaceFrontCall(Func)) {
655 handlePushFront(C, InstCall->getCXXThisVal());
659 if (isPopFrontCall(Func)) {
660 handlePopFront(C, InstCall->getCXXThisVal());
664 if (isInsertCall(Func) || isEmplaceCall(Func)) {
665 handleInsert(C, Call.getArgSVal(0));
669 if (isEraseCall(Func)) {
670 if (Call.getNumArgs() == 1) {
671 handleErase(C, Call.getArgSVal(0));
675 if (Call.getNumArgs() == 2) {
676 handleErase(C, Call.getArgSVal(0), Call.getArgSVal(1));
681 if (isEraseAfterCall(Func)) {
682 if (Call.getNumArgs() == 1) {
683 handleEraseAfter(C, Call.getArgSVal(0));
687 if (Call.getNumArgs() == 2) {
688 handleEraseAfter(C, Call.getArgSVal(0), Call.getArgSVal(1));
694 const auto *OrigExpr = Call.getOriginExpr();
698 if (!isIteratorType(Call.getResultType()))
701 auto State = C.getState();
703 if (
const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
704 if (isBeginCall(Func)) {
705 handleBegin(C, OrigExpr, Call.getReturnValue(),
706 InstCall->getCXXThisVal());
710 if (isEndCall(Func)) {
711 handleEnd(C, OrigExpr, Call.getReturnValue(),
712 InstCall->getCXXThisVal());
718 if (getIteratorPosition(
State, Call.getReturnValue()))
722 if (isa<CXXConstructorCall>(&Call) && Call.getNumArgs() == 1) {
723 if (
const auto *Pos = getIteratorPosition(
State, Call.getArgSVal(0))) {
724 State = setIteratorPosition(
State, Call.getReturnValue(), *Pos);
725 if (cast<CXXConstructorDecl>(Func)->isMoveConstructor()) {
726 State = removeIteratorPosition(
State, Call.getArgSVal(0));
728 C.addTransition(
State);
738 for (
unsigned i = 0;
i < Call.getNumArgs(); ++
i) {
739 if (isIteratorType(Call.getArgExpr(
i)->getType())) {
740 if (
const auto *Pos = getIteratorPosition(
State, Call.getArgSVal(
i))) {
741 assignToContainer(C, OrigExpr, Call.getReturnValue(),
742 Pos->getContainer());
750 void IteratorChecker::checkBind(SVal Loc, SVal Val,
const Stmt *S,
751 CheckerContext &C)
const {
752 auto State = C.getState();
753 const auto *Pos = getIteratorPosition(
State, Val);
755 State = setIteratorPosition(
State, Loc, *Pos);
756 C.addTransition(
State);
758 const auto *OldPos = getIteratorPosition(
State, Loc);
761 C.addTransition(
State);
767 CheckerContext &C)
const {
769 auto State = C.getState();
774 State = setIteratorPosition(
State, C.getSVal(MTE), *Pos);
775 C.addTransition(
State);
779 SymbolReaper &SR)
const {
782 auto RegionMap = State->get<IteratorRegionMap>();
783 for (
const auto Reg : RegionMap) {
784 const auto Offset = Reg.second.getOffset();
785 for (
auto i = Offset->symbol_begin();
i != Offset->symbol_end(); ++
i)
786 if (isa<SymbolData>(*
i))
790 auto SymbolMap = State->get<IteratorSymbolMap>();
791 for (
const auto Sym : SymbolMap) {
792 const auto Offset = Sym.second.getOffset();
793 for (
auto i = Offset->symbol_begin();
i != Offset->symbol_end(); ++
i)
794 if (isa<SymbolData>(*
i))
798 auto ContMap = State->get<ContainerMap>();
799 for (
const auto Cont : ContMap) {
800 const auto CData = Cont.second;
801 if (CData.getBegin()) {
802 SR.markLive(CData.getBegin());
803 if(
const auto *SIE = dyn_cast<SymIntExpr>(CData.getBegin()))
804 SR.markLive(SIE->getLHS());
806 if (CData.getEnd()) {
807 SR.markLive(CData.getEnd());
808 if(
const auto *SIE = dyn_cast<SymIntExpr>(CData.getEnd()))
809 SR.markLive(SIE->getLHS());
814 void IteratorChecker::checkDeadSymbols(SymbolReaper &SR,
815 CheckerContext &C)
const {
817 auto State = C.getState();
819 auto RegionMap = State->get<IteratorRegionMap>();
820 for (
const auto Reg : RegionMap) {
821 if (!SR.isLiveRegion(Reg.first)) {
825 if (!isBoundThroughLazyCompoundVal(State->getEnvironment(), Reg.first)) {
826 State = State->remove<IteratorRegionMap>(Reg.first);
831 auto SymbolMap = State->get<IteratorSymbolMap>();
832 for (
const auto Sym : SymbolMap) {
833 if (!SR.isLive(Sym.first)) {
834 State = State->remove<IteratorSymbolMap>(Sym.first);
838 auto ContMap = State->get<ContainerMap>();
839 for (
const auto Cont : ContMap) {
840 if (!SR.isLiveRegion(Cont.first)) {
843 if (!hasLiveIterators(State, Cont.first)) {
844 State = State->remove<ContainerMap>(Cont.first);
849 C.addTransition(State);
852 void IteratorChecker::handleComparison(CheckerContext &C,
const Expr *CE,
853 const SVal &RetVal,
const SVal &LVal,
860 auto State = C.getState();
861 const auto *LPos = getIteratorPosition(State, LVal);
862 const auto *RPos = getIteratorPosition(State, RVal);
863 const MemRegion *Cont =
nullptr;
865 Cont = LPos->getContainer();
867 Cont = RPos->getContainer();
875 if (!LPos || !RPos) {
876 auto &SymMgr = C.getSymbolManager();
877 Sym = SymMgr.conjureSymbol(CE, C.getLocationContext(),
878 C.getASTContext().LongTy, C.blockCount());
879 State = assumeNoOverflow(State, Sym, 4);
883 State = setIteratorPosition(State, LVal,
884 IteratorPosition::getPosition(Cont, Sym));
885 LPos = getIteratorPosition(State, LVal);
887 State = setIteratorPosition(State, RVal,
888 IteratorPosition::getPosition(Cont, Sym));
889 RPos = getIteratorPosition(State, RVal);
892 processComparison(C, State, LPos->getOffset(), RPos->getOffset(), RetVal, Op);
895 void IteratorChecker::processComparison(CheckerContext &C,
899 if (
const auto TruthVal = RetVal.getAs<nonloc::ConcreteInt>()) {
900 if ((State = relateSymbols(State, Sym1, Sym2,
901 (Op == OO_EqualEqual) ==
902 (TruthVal->getValue() != 0)))) {
903 C.addTransition(State);
905 C.generateSink(State, C.getPredecessor());
910 const auto ConditionVal = RetVal.getAs<DefinedSVal>();
914 if (
auto StateTrue = relateSymbols(State, Sym1, Sym2, Op == OO_EqualEqual)) {
915 StateTrue = StateTrue->assume(*ConditionVal,
true);
916 C.addTransition(StateTrue);
919 if (
auto StateFalse = relateSymbols(State, Sym1, Sym2, Op != OO_EqualEqual)) {
920 StateFalse = StateFalse->assume(*ConditionVal,
false);
921 C.addTransition(StateFalse);
925 void IteratorChecker::verifyDereference(CheckerContext &C,
926 const SVal &Val)
const {
927 auto State = C.getState();
928 const auto *Pos = getIteratorPosition(State, Val);
929 if (Pos && isPastTheEnd(State, *Pos)) {
930 auto *N = C.generateNonFatalErrorNode(State);
933 reportOutOfRangeBug(
"Past-the-end iterator dereferenced.", Val, C, N);
938 void IteratorChecker::verifyAccess(CheckerContext &C,
const SVal &Val)
const {
939 auto State = C.getState();
940 const auto *Pos = getIteratorPosition(State, Val);
941 if (Pos && !Pos->isValid()) {
942 auto *N = C.generateNonFatalErrorNode(State);
946 reportInvalidatedBug(
"Invalidated iterator accessed.", Val, C, N);
950 void IteratorChecker::handleIncrement(CheckerContext &C,
const SVal &RetVal,
951 const SVal &Iter,
bool Postfix)
const {
954 auto State = C.getState();
955 const auto *Pos = getIteratorPosition(State, Iter);
957 auto &SymMgr = C.getSymbolManager();
958 auto &BVF = SymMgr.getBasicVals();
960 advancePosition(C, OO_Plus, *Pos,
961 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
962 State = setIteratorPosition(State, Iter, NewPos);
963 State = setIteratorPosition(State, RetVal, Postfix ? *Pos : NewPos);
964 C.addTransition(State);
968 void IteratorChecker::handleDecrement(CheckerContext &C,
const SVal &RetVal,
969 const SVal &Iter,
bool Postfix)
const {
972 auto State = C.getState();
973 const auto *Pos = getIteratorPosition(State, Iter);
975 auto &SymMgr = C.getSymbolManager();
976 auto &BVF = SymMgr.getBasicVals();
978 advancePosition(C, OO_Minus, *Pos,
979 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
980 State = setIteratorPosition(State, Iter, NewPos);
981 State = setIteratorPosition(State, RetVal, Postfix ? *Pos : NewPos);
982 C.addTransition(State);
986 void IteratorChecker::handleRandomIncrOrDecr(CheckerContext &C,
990 const SVal &RHS)
const {
993 auto State = C.getState();
994 const auto *Pos = getIteratorPosition(State, LHS);
998 const auto *value = &RHS;
999 if (
auto loc = RHS.getAs<Loc>()) {
1000 const auto val = State->getRawSVal(*loc);
1004 auto &TgtVal = (Op == OO_PlusEqual || Op == OO_MinusEqual) ? LHS : RetVal;
1006 setIteratorPosition(State, TgtVal, advancePosition(C, Op, *Pos, *value));
1007 C.addTransition(State);
1010 void IteratorChecker::verifyIncrement(CheckerContext &C,
1011 const SVal &Iter)
const {
1012 auto &BVF = C.getSValBuilder().getBasicValueFactory();
1013 verifyRandomIncrOrDecr(C, OO_Plus, Iter,
1014 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
1017 void IteratorChecker::verifyDecrement(CheckerContext &C,
1018 const SVal &Iter)
const {
1019 auto &BVF = C.getSValBuilder().getBasicValueFactory();
1020 verifyRandomIncrOrDecr(C, OO_Minus, Iter,
1021 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
1024 void IteratorChecker::verifyRandomIncrOrDecr(CheckerContext &C,
1027 const SVal &RHS)
const {
1028 auto State = C.getState();
1031 const auto *Pos = getIteratorPosition(State, LHS);
1036 if (
auto ValAsLoc = RHS.getAs<Loc>()) {
1037 Value = State->getRawSVal(*ValAsLoc);
1040 if (
Value.isUnknown())
1044 if (isZero(State,
Value.castAs<NonLoc>()))
1049 if (isAheadOfRange(State, advancePosition(C, Op, *Pos,
Value))) {
1050 auto *N = C.generateNonFatalErrorNode(State);
1053 reportOutOfRangeBug(
"Iterator decremented ahead of its valid range.", LHS,
1056 if (isBehindPastTheEnd(State, advancePosition(C, Op, *Pos,
Value))) {
1057 auto *N = C.generateNonFatalErrorNode(State);
1060 reportOutOfRangeBug(
"Iterator incremented behind the past-the-end " 1061 "iterator.", LHS, C, N);
1065 void IteratorChecker::verifyMatch(CheckerContext &C,
const SVal &Iter,
1066 const MemRegion *Cont)
const {
1068 Cont = Cont->getMostDerivedObjectRegion();
1070 if (
const auto *ContSym = Cont->getSymbolicBase()) {
1071 if (isa<SymbolConjured>(ContSym->getSymbol()))
1075 auto State = C.getState();
1076 const auto *Pos = getIteratorPosition(State, Iter);
1080 const auto *IterCont = Pos->getContainer();
1086 if (
const auto *ContSym = IterCont->getSymbolicBase()) {
1087 if (isa<SymbolConjured>(ContSym->getSymbol()))
1091 if (IterCont != Cont) {
1092 auto *N = C.generateNonFatalErrorNode(State);
1096 reportMismatchedBug(
"Container accessed using foreign iterator argument.",
1101 void IteratorChecker::verifyMatch(CheckerContext &C,
const SVal &Iter1,
1102 const SVal &Iter2)
const {
1104 auto State = C.getState();
1105 const auto *Pos1 = getIteratorPosition(State, Iter1);
1109 const auto *IterCont1 = Pos1->getContainer();
1115 if (
const auto *ContSym = IterCont1->getSymbolicBase()) {
1116 if (isa<SymbolConjured>(ContSym->getSymbol()))
1120 const auto *Pos2 = getIteratorPosition(State, Iter2);
1124 const auto *IterCont2 = Pos2->getContainer();
1125 if (
const auto *ContSym = IterCont2->getSymbolicBase()) {
1126 if (isa<SymbolConjured>(ContSym->getSymbol()))
1130 if (IterCont1 != IterCont2) {
1131 auto *N = C.generateNonFatalErrorNode(State);
1134 reportMismatchedBug(
"Iterators of different containers used where the " 1135 "same container is expected.", Iter1, Iter2, C, N);
1139 void IteratorChecker::handleBegin(CheckerContext &C,
const Expr *CE,
1140 const SVal &RetVal,
const SVal &Cont)
const {
1141 const auto *ContReg = Cont.getAsRegion();
1145 ContReg = ContReg->getMostDerivedObjectRegion();
1149 auto State = C.getState();
1150 auto BeginSym = getContainerBegin(State, ContReg);
1152 State = createContainerBegin(State, ContReg, CE, C.getASTContext().LongTy,
1153 C.getLocationContext(), C.blockCount());
1154 BeginSym = getContainerBegin(State, ContReg);
1156 State = setIteratorPosition(State, RetVal,
1157 IteratorPosition::getPosition(ContReg, BeginSym));
1158 C.addTransition(State);
1161 void IteratorChecker::handleEnd(CheckerContext &C,
const Expr *CE,
1162 const SVal &RetVal,
const SVal &Cont)
const {
1163 const auto *ContReg = Cont.getAsRegion();
1167 ContReg = ContReg->getMostDerivedObjectRegion();
1171 auto State = C.getState();
1172 auto EndSym = getContainerEnd(State, ContReg);
1174 State = createContainerEnd(State, ContReg, CE, C.getASTContext().LongTy,
1175 C.getLocationContext(), C.blockCount());
1176 EndSym = getContainerEnd(State, ContReg);
1178 State = setIteratorPosition(State, RetVal,
1179 IteratorPosition::getPosition(ContReg, EndSym));
1180 C.addTransition(State);
1183 void IteratorChecker::assignToContainer(CheckerContext &C,
const Expr *CE,
1185 const MemRegion *Cont)
const {
1186 Cont = Cont->getMostDerivedObjectRegion();
1188 auto State = C.getState();
1189 auto &SymMgr = C.getSymbolManager();
1190 auto Sym = SymMgr.conjureSymbol(CE, C.getLocationContext(),
1191 C.getASTContext().LongTy, C.blockCount());
1192 State = assumeNoOverflow(State, Sym, 4);
1193 State = setIteratorPosition(State, RetVal,
1194 IteratorPosition::getPosition(Cont, Sym));
1195 C.addTransition(State);
1198 void IteratorChecker::handleAssign(CheckerContext &C,
const SVal &Cont,
1199 const Expr *CE,
const SVal &OldCont)
const {
1200 const auto *ContReg = Cont.getAsRegion();
1204 ContReg = ContReg->getMostDerivedObjectRegion();
1208 auto State = C.getState();
1209 const auto CData = getContainerData(State, ContReg);
1211 State = invalidateAllIteratorPositions(State, ContReg);
1216 if (!OldCont.isUndef()) {
1217 const auto *OldContReg = OldCont.getAsRegion();
1219 OldContReg = OldContReg->getMostDerivedObjectRegion();
1220 const auto OldCData = getContainerData(State, OldContReg);
1222 if (
const auto OldEndSym = OldCData->getEnd()) {
1227 State = reassignAllIteratorPositionsUnless(State, OldContReg, ContReg,
1229 auto &SymMgr = C.getSymbolManager();
1230 auto &SVB = C.getSValBuilder();
1233 SymMgr.conjureSymbol(CE, C.getLocationContext(),
1234 C.getASTContext().LongTy, C.blockCount());
1235 State = assumeNoOverflow(State, NewEndSym, 4);
1237 State = setContainerData(State, ContReg, CData->newEnd(NewEndSym));
1239 State = setContainerData(State, ContReg,
1240 ContainerData::fromEnd(NewEndSym));
1244 State = rebaseSymbolInIteratorPositionsIf(
1245 State, SVB, OldEndSym, NewEndSym, OldEndSym, BO_LT);
1249 State = reassignAllIteratorPositions(State, OldContReg, ContReg);
1251 if (
const auto OldBeginSym = OldCData->getBegin()) {
1256 setContainerData(State, ContReg, CData->newBegin(OldBeginSym));
1258 State = setContainerData(State, ContReg,
1259 ContainerData::fromBegin(OldBeginSym));
1262 setContainerData(State, OldContReg, OldCData->newEnd(
nullptr));
1267 State = reassignAllIteratorPositions(State, OldContReg, ContReg);
1271 C.addTransition(State);
1274 void IteratorChecker::handleClear(CheckerContext &C,
const SVal &Cont)
const {
1275 const auto *ContReg = Cont.getAsRegion();
1279 ContReg = ContReg->getMostDerivedObjectRegion();
1283 auto State = C.getState();
1284 if (!hasSubscriptOperator(State, ContReg) ||
1285 !backModifiable(State, ContReg)) {
1286 const auto CData = getContainerData(State, ContReg);
1288 if (
const auto EndSym = CData->getEnd()) {
1290 invalidateAllIteratorPositionsExcept(State, ContReg, EndSym, BO_GE);
1291 C.addTransition(State);
1296 State = invalidateAllIteratorPositions(State, ContReg);
1297 C.addTransition(State);
1300 void IteratorChecker::handlePushBack(CheckerContext &C,
1301 const SVal &Cont)
const {
1302 const auto *ContReg = Cont.getAsRegion();
1306 ContReg = ContReg->getMostDerivedObjectRegion();
1309 auto State = C.getState();
1310 if (hasSubscriptOperator(State, ContReg) && frontModifiable(State, ContReg)) {
1311 State = invalidateAllIteratorPositions(State, ContReg);
1312 C.addTransition(State);
1316 const auto CData = getContainerData(State, ContReg);
1321 if (
const auto EndSym = CData->getEnd()) {
1322 if (hasSubscriptOperator(State, ContReg)) {
1323 State = invalidateIteratorPositions(State, EndSym, BO_GE);
1325 auto &SymMgr = C.getSymbolManager();
1326 auto &BVF = SymMgr.getBasicVals();
1327 auto &SVB = C.getSValBuilder();
1328 const auto newEndSym =
1329 SVB.evalBinOp(State, BO_Add,
1330 nonloc::SymbolVal(EndSym),
1331 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
1332 SymMgr.getType(EndSym)).getAsSymbol();
1333 State = setContainerData(State, ContReg, CData->newEnd(newEndSym));
1335 C.addTransition(State);
1338 void IteratorChecker::handlePopBack(CheckerContext &C,
const SVal &Cont)
const {
1339 const auto *ContReg = Cont.getAsRegion();
1343 ContReg = ContReg->getMostDerivedObjectRegion();
1345 auto State = C.getState();
1346 const auto CData = getContainerData(State, ContReg);
1350 if (
const auto EndSym = CData->getEnd()) {
1351 auto &SymMgr = C.getSymbolManager();
1352 auto &BVF = SymMgr.getBasicVals();
1353 auto &SVB = C.getSValBuilder();
1354 const auto BackSym =
1355 SVB.evalBinOp(State, BO_Sub,
1356 nonloc::SymbolVal(EndSym),
1357 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
1358 SymMgr.getType(EndSym)).getAsSymbol();
1362 if (hasSubscriptOperator(State, ContReg) &&
1363 backModifiable(State, ContReg)) {
1364 State = invalidateIteratorPositions(State, BackSym, BO_GE);
1365 State = setContainerData(State, ContReg, CData->newEnd(
nullptr));
1367 State = invalidateIteratorPositions(State, BackSym, BO_EQ);
1369 auto newEndSym = BackSym;
1370 State = setContainerData(State, ContReg, CData->newEnd(newEndSym));
1371 C.addTransition(State);
1375 void IteratorChecker::handlePushFront(CheckerContext &C,
1376 const SVal &Cont)
const {
1377 const auto *ContReg = Cont.getAsRegion();
1381 ContReg = ContReg->getMostDerivedObjectRegion();
1384 auto State = C.getState();
1385 if (hasSubscriptOperator(State, ContReg)) {
1386 State = invalidateAllIteratorPositions(State, ContReg);
1387 C.addTransition(State);
1389 const auto CData = getContainerData(State, ContReg);
1393 if (
const auto BeginSym = CData->getBegin()) {
1394 auto &SymMgr = C.getSymbolManager();
1395 auto &BVF = SymMgr.getBasicVals();
1396 auto &SVB = C.getSValBuilder();
1397 const auto newBeginSym =
1398 SVB.evalBinOp(State, BO_Sub,
1399 nonloc::SymbolVal(BeginSym),
1400 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
1401 SymMgr.getType(BeginSym)).getAsSymbol();
1402 State = setContainerData(State, ContReg, CData->newBegin(newBeginSym));
1403 C.addTransition(State);
1408 void IteratorChecker::handlePopFront(CheckerContext &C,
1409 const SVal &Cont)
const {
1410 const auto *ContReg = Cont.getAsRegion();
1414 ContReg = ContReg->getMostDerivedObjectRegion();
1416 auto State = C.getState();
1417 const auto CData = getContainerData(State, ContReg);
1423 if (
const auto BeginSym = CData->getBegin()) {
1424 if (hasSubscriptOperator(State, ContReg)) {
1425 State = invalidateIteratorPositions(State, BeginSym, BO_LE);
1427 State = invalidateIteratorPositions(State, BeginSym, BO_EQ);
1429 auto &SymMgr = C.getSymbolManager();
1430 auto &BVF = SymMgr.getBasicVals();
1431 auto &SVB = C.getSValBuilder();
1432 const auto newBeginSym =
1433 SVB.evalBinOp(State, BO_Add,
1434 nonloc::SymbolVal(BeginSym),
1435 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
1436 SymMgr.getType(BeginSym)).getAsSymbol();
1437 State = setContainerData(State, ContReg, CData->newBegin(newBeginSym));
1438 C.addTransition(State);
1442 void IteratorChecker::handleInsert(CheckerContext &C,
const SVal &Iter)
const {
1443 auto State = C.getState();
1444 const auto *Pos = getIteratorPosition(State, Iter);
1450 const auto *Cont = Pos->getContainer();
1451 if (hasSubscriptOperator(State, Cont) && backModifiable(State, Cont)) {
1452 if (frontModifiable(State, Cont)) {
1453 State = invalidateAllIteratorPositions(State, Cont);
1455 State = invalidateIteratorPositions(State, Pos->getOffset(), BO_GE);
1457 if (
const auto *CData = getContainerData(State, Cont)) {
1458 if (
const auto EndSym = CData->getEnd()) {
1459 State = invalidateIteratorPositions(State, EndSym, BO_GE);
1460 State = setContainerData(State, Cont, CData->newEnd(
nullptr));
1463 C.addTransition(State);
1467 void IteratorChecker::handleErase(CheckerContext &C,
const SVal &Iter)
const {
1468 auto State = C.getState();
1469 const auto *Pos = getIteratorPosition(State, Iter);
1476 const auto *Cont = Pos->getContainer();
1477 if (hasSubscriptOperator(State, Cont) && backModifiable(State, Cont)) {
1478 if (frontModifiable(State, Cont)) {
1479 State = invalidateAllIteratorPositions(State, Cont);
1481 State = invalidateIteratorPositions(State, Pos->getOffset(), BO_GE);
1483 if (
const auto *CData = getContainerData(State, Cont)) {
1484 if (
const auto EndSym = CData->getEnd()) {
1485 State = invalidateIteratorPositions(State, EndSym, BO_GE);
1486 State = setContainerData(State, Cont, CData->newEnd(
nullptr));
1490 State = invalidateIteratorPositions(State, Pos->getOffset(), BO_EQ);
1492 C.addTransition(State);
1495 void IteratorChecker::handleErase(CheckerContext &C,
const SVal &Iter1,
1496 const SVal &Iter2)
const {
1497 auto State = C.getState();
1498 const auto *Pos1 = getIteratorPosition(State, Iter1);
1499 const auto *Pos2 = getIteratorPosition(State, Iter2);
1507 const auto *Cont = Pos1->getContainer();
1508 if (hasSubscriptOperator(State, Cont) && backModifiable(State, Cont)) {
1509 if (frontModifiable(State, Cont)) {
1510 State = invalidateAllIteratorPositions(State, Cont);
1512 State = invalidateIteratorPositions(State, Pos1->getOffset(), BO_GE);
1514 if (
const auto *CData = getContainerData(State, Cont)) {
1515 if (
const auto EndSym = CData->getEnd()) {
1516 State = invalidateIteratorPositions(State, EndSym, BO_GE);
1517 State = setContainerData(State, Cont, CData->newEnd(
nullptr));
1521 State = invalidateIteratorPositions(State, Pos1->getOffset(), BO_GE,
1522 Pos2->getOffset(), BO_LT);
1524 C.addTransition(State);
1527 void IteratorChecker::handleEraseAfter(CheckerContext &C,
1528 const SVal &Iter)
const {
1529 auto State = C.getState();
1530 const auto *Pos = getIteratorPosition(State, Iter);
1536 auto &SymMgr = C.getSymbolManager();
1537 auto &BVF = SymMgr.getBasicVals();
1538 auto &SVB = C.getSValBuilder();
1539 const auto NextSym =
1540 SVB.evalBinOp(State, BO_Add,
1541 nonloc::SymbolVal(Pos->getOffset()),
1542 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
1543 SymMgr.getType(Pos->getOffset())).getAsSymbol();
1544 State = invalidateIteratorPositions(State, NextSym, BO_EQ);
1545 C.addTransition(State);
1548 void IteratorChecker::handleEraseAfter(CheckerContext &C,
const SVal &Iter1,
1549 const SVal &Iter2)
const {
1550 auto State = C.getState();
1551 const auto *Pos1 = getIteratorPosition(State, Iter1);
1552 const auto *Pos2 = getIteratorPosition(State, Iter2);
1557 State = invalidateIteratorPositions(State, Pos1->getOffset(), BO_GT,
1558 Pos2->getOffset(), BO_LT);
1559 C.addTransition(State);
1562 IteratorPosition IteratorChecker::advancePosition(CheckerContext &C,
1564 const IteratorPosition &Pos,
1565 const SVal &Distance)
const {
1566 auto State = C.getState();
1567 auto &SymMgr = C.getSymbolManager();
1568 auto &SVB = C.getSValBuilder();
1570 assert ((Op == OO_Plus || Op == OO_PlusEqual ||
1571 Op == OO_Minus || Op == OO_MinusEqual) &&
1572 "Advance operator must be one of +, -, += and -=.");
1573 auto BinOp = (Op == OO_Plus || Op == OO_PlusEqual) ? BO_Add : BO_Sub;
1574 if (
const auto IntDist = Distance.getAs<nonloc::ConcreteInt>()) {
1576 return Pos.setTo(SVB.evalBinOp(State, BinOp,
1577 nonloc::SymbolVal(Pos.getOffset()), *IntDist,
1578 SymMgr.getType(Pos.getOffset()))
1582 const auto &LCtx = C.getLocationContext();
1583 const auto NewPosSym = SymMgr.conjureSymbol(
nullptr, LCtx,
1584 SymMgr.getType(Pos.getOffset()),
1586 State = assumeNoOverflow(State, NewPosSym, 4);
1587 return Pos.setTo(NewPosSym);
1591 void IteratorChecker::reportOutOfRangeBug(
const StringRef &Message,
1592 const SVal &Val, CheckerContext &C,
1593 ExplodedNode *ErrNode)
const {
1594 auto R = llvm::make_unique<BugReport>(*OutOfRangeBugType, Message, ErrNode);
1595 R->markInteresting(Val);
1596 C.emitReport(std::move(R));
1599 void IteratorChecker::reportMismatchedBug(
const StringRef &Message,
1600 const SVal &Val1,
const SVal &Val2,
1602 ExplodedNode *ErrNode)
const {
1603 auto R = llvm::make_unique<BugReport>(*MismatchedBugType, Message, ErrNode);
1604 R->markInteresting(Val1);
1605 R->markInteresting(Val2);
1606 C.emitReport(std::move(R));
1609 void IteratorChecker::reportMismatchedBug(
const StringRef &Message,
1610 const SVal &Val,
const MemRegion *Reg,
1612 ExplodedNode *ErrNode)
const {
1613 auto R = llvm::make_unique<BugReport>(*MismatchedBugType, Message, ErrNode);
1614 R->markInteresting(Val);
1615 R->markInteresting(Reg);
1616 C.emitReport(std::move(R));
1619 void IteratorChecker::reportInvalidatedBug(
const StringRef &Message,
1620 const SVal &Val, CheckerContext &C,
1621 ExplodedNode *ErrNode)
const {
1622 auto R = llvm::make_unique<BugReport>(*InvalidatedBugType, Message, ErrNode);
1623 R->markInteresting(Val);
1624 C.emitReport(std::move(R));
1637 const MemRegion *Reg);
1646 return isIterator(CRD);
1653 const auto Name = CRD->
getName();
1654 if (!(Name.endswith_lower(
"iterator") || Name.endswith_lower(
"iter") ||
1655 Name.endswith_lower(
"it")))
1658 bool HasCopyCtor =
false, HasCopyAssign =
true, HasDtor =
false,
1659 HasPreIncrOp =
false, HasPostIncrOp =
false, HasDerefOp =
false;
1660 for (
const auto *Method : CRD->
methods()) {
1661 if (
const auto *Ctor = dyn_cast<CXXConstructorDecl>(Method)) {
1662 if (Ctor->isCopyConstructor()) {
1663 HasCopyCtor = !Ctor->isDeleted() && Ctor->getAccess() ==
AS_public;
1667 if (
const auto *Dtor = dyn_cast<CXXDestructorDecl>(Method)) {
1668 HasDtor = !Dtor->isDeleted() && Dtor->getAccess() ==
AS_public;
1671 if (Method->isCopyAssignmentOperator()) {
1672 HasCopyAssign = !Method->isDeleted() && Method->getAccess() ==
AS_public;
1675 if (!Method->isOverloadedOperator())
1677 const auto OPK = Method->getOverloadedOperator();
1678 if (OPK == OO_PlusPlus) {
1679 HasPreIncrOp = HasPreIncrOp || (Method->getNumParams() == 0);
1680 HasPostIncrOp = HasPostIncrOp || (Method->getNumParams() == 1);
1683 if (OPK == OO_Star) {
1684 HasDerefOp = (Method->getNumParams() == 0);
1689 return HasCopyCtor && HasCopyAssign && HasDtor && HasPreIncrOp &&
1690 HasPostIncrOp && HasDerefOp;
1694 return OK == OO_EqualEqual || OK == OO_ExclaimEqual || OK == OO_Less ||
1695 OK == OO_LessEqual || OK == OO_Greater || OK == OO_GreaterEqual;
1702 return IdInfo->
getName().endswith_lower(
"begin");
1709 return IdInfo->
getName().endswith_lower(
"end");
1718 return IdInfo->
getName() ==
"assign";
1727 return IdInfo->
getName() ==
"clear";
1736 return IdInfo->
getName() ==
"push_back";
1745 return IdInfo->
getName() ==
"emplace_back";
1754 return IdInfo->
getName() ==
"pop_back";
1763 return IdInfo->
getName() ==
"push_front";
1772 return IdInfo->
getName() ==
"emplace_front";
1781 return IdInfo->
getName() ==
"pop_front";
1792 return IdInfo->
getName() ==
"insert";
1803 return IdInfo->
getName() ==
"emplace";
1817 return IdInfo->
getName() ==
"erase";
1831 return IdInfo->
getName() ==
"erase_after";
1837 return OK == OO_EqualEqual || OK == OO_ExclaimEqual;
1841 return isDereferenceOperator(OK) || isIncrementOperator(OK) ||
1842 isDecrementOperator(OK) || isRandomIncrOrDecrOperator(OK);
1846 return OK == OO_Star || OK == OO_Arrow || OK == OO_ArrowStar ||
1851 return OK == OO_PlusPlus;
1855 return OK == OO_MinusMinus;
1859 return OK == OO_Plus || OK == OO_PlusEqual || OK == OO_Minus ||
1860 OK == OO_MinusEqual;
1863 bool hasSubscriptOperator(
ProgramStateRef State,
const MemRegion *Reg) {
1864 const auto *CRD = getCXXRecordDecl(State, Reg);
1868 for (
const auto *Method : CRD->
methods()) {
1869 if (!Method->isOverloadedOperator())
1871 const auto OPK = Method->getOverloadedOperator();
1872 if (OPK == OO_Subscript) {
1880 const auto *CRD = getCXXRecordDecl(State, Reg);
1884 for (
const auto *Method : CRD->
methods()) {
1885 if (!Method->getDeclName().isIdentifier())
1887 if (Method->getName() ==
"push_front" || Method->getName() ==
"pop_front") {
1895 const auto *CRD = getCXXRecordDecl(State, Reg);
1899 for (
const auto *Method : CRD->
methods()) {
1900 if (!Method->getDeclName().isIdentifier())
1902 if (Method->getName() ==
"push_back" || Method->getName() ==
"pop_back") {
1910 const MemRegion *Reg) {
1915 auto Type = TI.getType();
1924 const auto *CDataPtr = getContainerData(State, Cont);
1928 return CDataPtr->getBegin();
1932 const auto *CDataPtr = getContainerData(State, Cont);
1936 return CDataPtr->getEnd();
1940 const MemRegion *Cont,
const Expr *E,
1942 unsigned BlockCount) {
1944 const auto *CDataPtr = getContainerData(State, Cont);
1945 if (CDataPtr && CDataPtr->getBegin())
1948 auto &SymMgr = State->getSymbolManager();
1949 const SymbolConjured *Sym = SymMgr.conjureSymbol(E, LCtx, T, BlockCount,
1951 State = assumeNoOverflow(State, Sym, 4);
1954 const auto CData = CDataPtr->newBegin(Sym);
1955 return setContainerData(State, Cont, CData);
1958 const auto CData = ContainerData::fromBegin(Sym);
1959 return setContainerData(State, Cont, CData);
1965 unsigned BlockCount) {
1967 const auto *CDataPtr = getContainerData(State, Cont);
1968 if (CDataPtr && CDataPtr->getEnd())
1971 auto &SymMgr = State->getSymbolManager();
1972 const SymbolConjured *Sym = SymMgr.conjureSymbol(E, LCtx, T, BlockCount,
1974 State = assumeNoOverflow(State, Sym, 4);
1977 const auto CData = CDataPtr->newEnd(Sym);
1978 return setContainerData(State, Cont, CData);
1981 const auto CData = ContainerData::fromEnd(Sym);
1982 return setContainerData(State, Cont, CData);
1986 const MemRegion *Cont) {
1987 return State->get<ContainerMap>(Cont);
1991 const ContainerData &CData) {
1992 return State->set<ContainerMap>(Cont, CData);
1997 if (
auto Reg = Val.getAsRegion()) {
1998 Reg = Reg->getMostDerivedObjectRegion();
1999 return State->get<IteratorRegionMap>(Reg);
2000 }
else if (
const auto Sym = Val.getAsSymbol()) {
2001 return State->get<IteratorSymbolMap>(Sym);
2002 }
else if (
const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
2003 return State->get<IteratorRegionMap>(LCVal->getRegion());
2009 const IteratorPosition &Pos) {
2010 if (
auto Reg = Val.getAsRegion()) {
2011 Reg = Reg->getMostDerivedObjectRegion();
2012 return State->set<IteratorRegionMap>(Reg, Pos);
2013 }
else if (
const auto Sym = Val.getAsSymbol()) {
2014 return State->set<IteratorSymbolMap>(Sym, Pos);
2015 }
else if (
const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
2016 return State->set<IteratorRegionMap>(LCVal->getRegion(), Pos);
2022 if (
auto Reg = Val.getAsRegion()) {
2023 Reg = Reg->getMostDerivedObjectRegion();
2024 return State->remove<IteratorRegionMap>(Reg);
2025 }
else if (
const auto Sym = Val.getAsSymbol()) {
2026 return State->remove<IteratorSymbolMap>(Sym);
2027 }
else if (
const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
2028 return State->remove<IteratorRegionMap>(LCVal->getRegion());
2035 auto &SVB = State->getStateManager().getSValBuilder();
2042 const auto comparison =
2043 SVB.evalBinOp(State, BO_EQ, nonloc::SymbolVal(Sym1),
2044 nonloc::SymbolVal(Sym2), SVB.getConditionType());
2046 assert(comparison.getAs<DefinedSVal>() &&
2047 "Symbol comparison must be a `DefinedSVal`");
2049 auto NewState = State->assume(comparison.castAs<DefinedSVal>(), Equal);
2053 if (
const auto CompSym = comparison.getAsSymbol()) {
2054 assert(isa<SymIntExpr>(CompSym) &&
2055 "Symbol comparison must be a `SymIntExpr`");
2057 cast<SymIntExpr>(CompSym)->getOpcode()) &&
2058 "Symbol comparison must be a comparison");
2059 return assumeNoOverflow(NewState, cast<SymIntExpr>(CompSym)->getLHS(), 2);
2066 auto RegionMap = State->get<IteratorRegionMap>();
2067 for (
const auto Reg : RegionMap) {
2068 if (Reg.second.getContainer() == Cont)
2072 auto SymbolMap = State->get<IteratorSymbolMap>();
2073 for (
const auto Sym : SymbolMap) {
2074 if (Sym.second.getContainer() == Cont)
2081 bool isBoundThroughLazyCompoundVal(
const Environment &Env,
2082 const MemRegion *Reg) {
2083 for (
const auto Binding: Env) {
2084 if (
const auto LCVal = Binding.second.getAs<nonloc::LazyCompoundVal>()) {
2085 if (LCVal->getRegion() == Reg)
2102 SValBuilder &SVB = State->getStateManager().getSValBuilder();
2103 BasicValueFactory &BV = SVB.getBasicValueFactory();
2107 APSIntType AT = BV.getAPSIntType(T);
2111 llvm::APSInt Max = AT.getMaxValue() / AT.getValue(Scale);
2112 SVal IsCappedFromAbove =
2113 SVB.evalBinOpNN(State, BO_LE, nonloc::SymbolVal(Sym),
2114 nonloc::ConcreteInt(Max), SVB.getConditionType());
2115 if (
auto DV = IsCappedFromAbove.getAs<DefinedSVal>()) {
2116 NewState = NewState->assume(*DV,
true);
2121 llvm::APSInt Min = -Max;
2122 SVal IsCappedFromBelow =
2123 SVB.evalBinOpNN(State, BO_GE, nonloc::SymbolVal(Sym),
2124 nonloc::ConcreteInt(Min), SVB.getConditionType());
2125 if (
auto DV = IsCappedFromBelow.getAs<DefinedSVal>()) {
2126 NewState = NewState->assume(*DV,
true);
2134 template <
typename Condition,
typename Process>
2137 auto &RegionMapFactory = State->get_context<IteratorRegionMap>();
2138 auto RegionMap = State->get<IteratorRegionMap>();
2139 bool Changed =
false;
2140 for (
const auto Reg : RegionMap) {
2141 if (Cond(Reg.second)) {
2142 RegionMap = RegionMapFactory.add(RegionMap, Reg.first, Proc(Reg.second));
2148 State = State->set<IteratorRegionMap>(RegionMap);
2150 auto &SymbolMapFactory = State->get_context<IteratorSymbolMap>();
2151 auto SymbolMap = State->get<IteratorSymbolMap>();
2153 for (
const auto Sym : SymbolMap) {
2154 if (Cond(Sym.second)) {
2155 SymbolMap = SymbolMapFactory.add(SymbolMap, Sym.first, Proc(Sym.second));
2161 State = State->set<IteratorSymbolMap>(SymbolMap);
2167 const MemRegion *Cont) {
2168 auto MatchCont = [&](
const IteratorPosition &Pos) {
2169 return Pos.getContainer() == Cont;
2171 auto Invalidate = [&](
const IteratorPosition &Pos) {
2172 return Pos.invalidate();
2174 return processIteratorPositions(State, MatchCont, Invalidate);
2179 const MemRegion *Cont,
SymbolRef Offset,
2181 auto MatchContAndCompare = [&](
const IteratorPosition &Pos) {
2182 return Pos.getContainer() == Cont &&
2185 auto Invalidate = [&](
const IteratorPosition &Pos) {
2186 return Pos.invalidate();
2188 return processIteratorPositions(State, MatchContAndCompare, Invalidate);
2194 auto Compare = [&](
const IteratorPosition &Pos) {
2197 auto Invalidate = [&](
const IteratorPosition &Pos) {
2198 return Pos.invalidate();
2200 return processIteratorPositions(State, Compare, Invalidate);
2208 auto Compare = [&](
const IteratorPosition &Pos) {
2209 return compare(State, Pos.getOffset(), Offset1, Opc1) &&
2210 compare(State, Pos.getOffset(), Offset2, Opc2);
2212 auto Invalidate = [&](
const IteratorPosition &Pos) {
2213 return Pos.invalidate();
2215 return processIteratorPositions(State, Compare, Invalidate);
2219 const MemRegion *Cont,
2220 const MemRegion *NewCont) {
2221 auto MatchCont = [&](
const IteratorPosition &Pos) {
2222 return Pos.getContainer() == Cont;
2224 auto ReAssign = [&](
const IteratorPosition &Pos) {
2225 return Pos.reAssign(NewCont);
2227 return processIteratorPositions(State, MatchCont, ReAssign);
2231 const MemRegion *Cont,
2232 const MemRegion *NewCont,
2235 auto MatchContAndCompare = [&](
const IteratorPosition &Pos) {
2236 return Pos.getContainer() == Cont &&
2239 auto ReAssign = [&](
const IteratorPosition &Pos) {
2240 return Pos.reAssign(NewCont);
2242 return processIteratorPositions(State, MatchContAndCompare, ReAssign);
2251 auto LessThanEnd = [&](
const IteratorPosition &Pos) {
2252 return compare(State, Pos.getOffset(), CondSym, Opc);
2254 auto RebaseSymbol = [&](
const IteratorPosition &Pos) {
2255 return Pos.setTo(rebaseSymbol(State, SVB, Pos.getOffset(), OldSym,
2258 return processIteratorPositions(State, LessThanEnd, RebaseSymbol);
2267 auto &SymMgr = SVB.getSymbolManager();
2268 auto Diff = SVB.evalBinOpNN(State, BO_Sub, nonloc::SymbolVal(OrigExpr),
2269 nonloc::SymbolVal(OldExpr),
2270 SymMgr.getType(OrigExpr));
2272 const auto DiffInt = Diff.getAs<nonloc::ConcreteInt>();
2276 return SVB.evalBinOpNN(State, BO_Add, *DiffInt, nonloc::SymbolVal(NewSym),
2277 SymMgr.getType(OrigExpr)).getAsSymbol();
2281 auto &BVF = State->getBasicVals();
2283 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))),
2287 bool isPastTheEnd(
ProgramStateRef State,
const IteratorPosition &Pos) {
2288 const auto *Cont = Pos.getContainer();
2289 const auto *CData = getContainerData(State, Cont);
2293 const auto End = CData->getEnd();
2295 if (isEqual(State, Pos.getOffset(),
End)) {
2303 bool isAheadOfRange(
ProgramStateRef State,
const IteratorPosition &Pos) {
2304 const auto *Cont = Pos.getContainer();
2305 const auto *CData = getContainerData(State, Cont);
2309 const auto Beg = CData->getBegin();
2311 if (isLess(State, Pos.getOffset(), Beg)) {
2319 bool isBehindPastTheEnd(
ProgramStateRef State,
const IteratorPosition &Pos) {
2320 const auto *Cont = Pos.getContainer();
2321 const auto *CData = getContainerData(State, Cont);
2325 const auto End = CData->getEnd();
2327 if (isGreater(State, Pos.getOffset(),
End)) {
2336 return compare(State, Sym1, Sym2, BO_LT);
2340 return compare(State, Sym1, Sym2, BO_GT);
2344 return compare(State, Sym1, Sym2, BO_EQ);
2349 return compare(State, nonloc::SymbolVal(Sym1), nonloc::SymbolVal(Sym2), Opc);
2354 auto &SVB = State->getStateManager().getSValBuilder();
2356 const auto comparison =
2357 SVB.evalBinOp(State, Opc, NL1, NL2, SVB.getConditionType());
2359 assert(comparison.getAs<DefinedSVal>() &&
2360 "Symbol comparison must be a `DefinedSVal`");
2362 return !State->assume(comparison.castAs<DefinedSVal>(),
false);
2367 void ento::registerIteratorModeling(CheckerManager &mgr) {
2368 mgr.registerChecker<IteratorChecker>();
2371 bool ento::shouldRegisterIteratorModeling(
const LangOptions &LO) {
2375 #define REGISTER_CHECKER(name) \ 2376 void ento::register##name(CheckerManager &Mgr) { \ 2377 auto *checker = Mgr.getChecker<IteratorChecker>(); \ 2378 checker->ChecksEnabled[IteratorChecker::CK_##name] = true; \ 2379 checker->CheckNames[IteratorChecker::CK_##name] = \ 2380 Mgr.getCurrentCheckName(); \ 2383 bool ento::shouldRegister##name(const LangOptions &LO) { \
Represents a function declaration or definition.
A (possibly-)qualified type.
bool operator==(CanQual< T > x, CanQual< U > y)
const SymExpr * SymbolRef
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.
REGISTER_MAP_WITH_PROGRAMSTATE(IteratorRegionMap, const MemRegion *, IteratorPosition) namespace
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>'.
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.
Expr * GetTemporaryExpr() const
Retrieve the temporary-generating subexpression whose value will be materialized into a glvalue...
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
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.
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.
This represents one expression.
static bool compare(const PathDiagnostic &X, const PathDiagnostic &Y)
Declaration of a template type parameter.
bool isComparisonOp() const
DeclStmt - Adaptor class for mixing declarations with statements and expressions. ...
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...
StringRef getName() const
Return the actual identifier string.
Dataflow Directional Tag Classes.
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)
Base for LValueReferenceType and RValueReferenceType.
X
Add a minimal nested name specifier fixit hint to allow lookup of a tag name from an outer enclosing ...
Represents a C++ struct/union/class.
bool operator!=(CanQual< T > x, CanQual< U > y)
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
bool isPointerType() const
unsigned getNumParams() const
Return the number of parameters this function must have based on its FunctionType.
method_range methods() const