1*e038c9c4Sjoerg //===-- IteratorRangeChecker.cpp ----------------------------------*- C++ -*--//
2*e038c9c4Sjoerg //
3*e038c9c4Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*e038c9c4Sjoerg // See https://llvm.org/LICENSE.txt for license information.
5*e038c9c4Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*e038c9c4Sjoerg //
7*e038c9c4Sjoerg //===----------------------------------------------------------------------===//
8*e038c9c4Sjoerg //
9*e038c9c4Sjoerg // Defines a checker for dereference of the past-the-end iterator and
10*e038c9c4Sjoerg // out-of-range increments and decrements.
11*e038c9c4Sjoerg //
12*e038c9c4Sjoerg //===----------------------------------------------------------------------===//
13*e038c9c4Sjoerg
14*e038c9c4Sjoerg #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
15*e038c9c4Sjoerg #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
16*e038c9c4Sjoerg #include "clang/StaticAnalyzer/Core/Checker.h"
17*e038c9c4Sjoerg #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
18*e038c9c4Sjoerg #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
19*e038c9c4Sjoerg
20*e038c9c4Sjoerg
21*e038c9c4Sjoerg #include "Iterator.h"
22*e038c9c4Sjoerg
23*e038c9c4Sjoerg using namespace clang;
24*e038c9c4Sjoerg using namespace ento;
25*e038c9c4Sjoerg using namespace iterator;
26*e038c9c4Sjoerg
27*e038c9c4Sjoerg namespace {
28*e038c9c4Sjoerg
29*e038c9c4Sjoerg class IteratorRangeChecker
30*e038c9c4Sjoerg : public Checker<check::PreCall, check::PreStmt<UnaryOperator>,
31*e038c9c4Sjoerg check::PreStmt<BinaryOperator>,
32*e038c9c4Sjoerg check::PreStmt<ArraySubscriptExpr>,
33*e038c9c4Sjoerg check::PreStmt<MemberExpr>> {
34*e038c9c4Sjoerg
35*e038c9c4Sjoerg std::unique_ptr<BugType> OutOfRangeBugType;
36*e038c9c4Sjoerg
37*e038c9c4Sjoerg void verifyDereference(CheckerContext &C, SVal Val) const;
38*e038c9c4Sjoerg void verifyIncrement(CheckerContext &C, SVal Iter) const;
39*e038c9c4Sjoerg void verifyDecrement(CheckerContext &C, SVal Iter) const;
40*e038c9c4Sjoerg void verifyRandomIncrOrDecr(CheckerContext &C, OverloadedOperatorKind Op,
41*e038c9c4Sjoerg SVal LHS, SVal RHS) const;
42*e038c9c4Sjoerg void verifyAdvance(CheckerContext &C, SVal LHS, SVal RHS) const;
43*e038c9c4Sjoerg void verifyPrev(CheckerContext &C, SVal LHS, SVal RHS) const;
44*e038c9c4Sjoerg void verifyNext(CheckerContext &C, SVal LHS, SVal RHS) const;
45*e038c9c4Sjoerg void reportBug(const StringRef &Message, SVal Val, CheckerContext &C,
46*e038c9c4Sjoerg ExplodedNode *ErrNode) const;
47*e038c9c4Sjoerg
48*e038c9c4Sjoerg public:
49*e038c9c4Sjoerg IteratorRangeChecker();
50*e038c9c4Sjoerg
51*e038c9c4Sjoerg void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
52*e038c9c4Sjoerg void checkPreStmt(const UnaryOperator *UO, CheckerContext &C) const;
53*e038c9c4Sjoerg void checkPreStmt(const BinaryOperator *BO, CheckerContext &C) const;
54*e038c9c4Sjoerg void checkPreStmt(const ArraySubscriptExpr *ASE, CheckerContext &C) const;
55*e038c9c4Sjoerg void checkPreStmt(const MemberExpr *ME, CheckerContext &C) const;
56*e038c9c4Sjoerg
57*e038c9c4Sjoerg using AdvanceFn = void (IteratorRangeChecker::*)(CheckerContext &, SVal,
58*e038c9c4Sjoerg SVal) const;
59*e038c9c4Sjoerg
60*e038c9c4Sjoerg CallDescriptionMap<AdvanceFn> AdvanceFunctions = {
61*e038c9c4Sjoerg {{{"std", "advance"}, 2}, &IteratorRangeChecker::verifyAdvance},
62*e038c9c4Sjoerg {{{"std", "prev"}, 2}, &IteratorRangeChecker::verifyPrev},
63*e038c9c4Sjoerg {{{"std", "next"}, 2}, &IteratorRangeChecker::verifyNext},
64*e038c9c4Sjoerg };
65*e038c9c4Sjoerg };
66*e038c9c4Sjoerg
67*e038c9c4Sjoerg bool isPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos);
68*e038c9c4Sjoerg bool isAheadOfRange(ProgramStateRef State, const IteratorPosition &Pos);
69*e038c9c4Sjoerg bool isBehindPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos);
70*e038c9c4Sjoerg bool isZero(ProgramStateRef State, const NonLoc &Val);
71*e038c9c4Sjoerg
72*e038c9c4Sjoerg } //namespace
73*e038c9c4Sjoerg
IteratorRangeChecker()74*e038c9c4Sjoerg IteratorRangeChecker::IteratorRangeChecker() {
75*e038c9c4Sjoerg OutOfRangeBugType.reset(
76*e038c9c4Sjoerg new BugType(this, "Iterator out of range", "Misuse of STL APIs"));
77*e038c9c4Sjoerg }
78*e038c9c4Sjoerg
checkPreCall(const CallEvent & Call,CheckerContext & C) const79*e038c9c4Sjoerg void IteratorRangeChecker::checkPreCall(const CallEvent &Call,
80*e038c9c4Sjoerg CheckerContext &C) const {
81*e038c9c4Sjoerg // Check for out of range access
82*e038c9c4Sjoerg const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
83*e038c9c4Sjoerg if (!Func)
84*e038c9c4Sjoerg return;
85*e038c9c4Sjoerg
86*e038c9c4Sjoerg if (Func->isOverloadedOperator()) {
87*e038c9c4Sjoerg if (isIncrementOperator(Func->getOverloadedOperator())) {
88*e038c9c4Sjoerg // Check for out-of-range incrementions
89*e038c9c4Sjoerg if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
90*e038c9c4Sjoerg verifyIncrement(C, InstCall->getCXXThisVal());
91*e038c9c4Sjoerg } else {
92*e038c9c4Sjoerg if (Call.getNumArgs() >= 1) {
93*e038c9c4Sjoerg verifyIncrement(C, Call.getArgSVal(0));
94*e038c9c4Sjoerg }
95*e038c9c4Sjoerg }
96*e038c9c4Sjoerg } else if (isDecrementOperator(Func->getOverloadedOperator())) {
97*e038c9c4Sjoerg // Check for out-of-range decrementions
98*e038c9c4Sjoerg if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
99*e038c9c4Sjoerg verifyDecrement(C, InstCall->getCXXThisVal());
100*e038c9c4Sjoerg } else {
101*e038c9c4Sjoerg if (Call.getNumArgs() >= 1) {
102*e038c9c4Sjoerg verifyDecrement(C, Call.getArgSVal(0));
103*e038c9c4Sjoerg }
104*e038c9c4Sjoerg }
105*e038c9c4Sjoerg } else if (isRandomIncrOrDecrOperator(Func->getOverloadedOperator())) {
106*e038c9c4Sjoerg if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
107*e038c9c4Sjoerg // Check for out-of-range incrementions and decrementions
108*e038c9c4Sjoerg if (Call.getNumArgs() >= 1 &&
109*e038c9c4Sjoerg Call.getArgExpr(0)->getType()->isIntegralOrEnumerationType()) {
110*e038c9c4Sjoerg verifyRandomIncrOrDecr(C, Func->getOverloadedOperator(),
111*e038c9c4Sjoerg InstCall->getCXXThisVal(),
112*e038c9c4Sjoerg Call.getArgSVal(0));
113*e038c9c4Sjoerg }
114*e038c9c4Sjoerg } else {
115*e038c9c4Sjoerg if (Call.getNumArgs() >= 2 &&
116*e038c9c4Sjoerg Call.getArgExpr(1)->getType()->isIntegralOrEnumerationType()) {
117*e038c9c4Sjoerg verifyRandomIncrOrDecr(C, Func->getOverloadedOperator(),
118*e038c9c4Sjoerg Call.getArgSVal(0), Call.getArgSVal(1));
119*e038c9c4Sjoerg }
120*e038c9c4Sjoerg }
121*e038c9c4Sjoerg } else if (isDereferenceOperator(Func->getOverloadedOperator())) {
122*e038c9c4Sjoerg // Check for dereference of out-of-range iterators
123*e038c9c4Sjoerg if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
124*e038c9c4Sjoerg verifyDereference(C, InstCall->getCXXThisVal());
125*e038c9c4Sjoerg } else {
126*e038c9c4Sjoerg verifyDereference(C, Call.getArgSVal(0));
127*e038c9c4Sjoerg }
128*e038c9c4Sjoerg }
129*e038c9c4Sjoerg } else {
130*e038c9c4Sjoerg const AdvanceFn *Verifier = AdvanceFunctions.lookup(Call);
131*e038c9c4Sjoerg if (Verifier) {
132*e038c9c4Sjoerg if (Call.getNumArgs() > 1) {
133*e038c9c4Sjoerg (this->**Verifier)(C, Call.getArgSVal(0), Call.getArgSVal(1));
134*e038c9c4Sjoerg } else {
135*e038c9c4Sjoerg auto &BVF = C.getSValBuilder().getBasicValueFactory();
136*e038c9c4Sjoerg (this->**Verifier)(
137*e038c9c4Sjoerg C, Call.getArgSVal(0),
138*e038c9c4Sjoerg nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
139*e038c9c4Sjoerg }
140*e038c9c4Sjoerg }
141*e038c9c4Sjoerg }
142*e038c9c4Sjoerg }
143*e038c9c4Sjoerg
checkPreStmt(const UnaryOperator * UO,CheckerContext & C) const144*e038c9c4Sjoerg void IteratorRangeChecker::checkPreStmt(const UnaryOperator *UO,
145*e038c9c4Sjoerg CheckerContext &C) const {
146*e038c9c4Sjoerg if (isa<CXXThisExpr>(UO->getSubExpr()))
147*e038c9c4Sjoerg return;
148*e038c9c4Sjoerg
149*e038c9c4Sjoerg ProgramStateRef State = C.getState();
150*e038c9c4Sjoerg UnaryOperatorKind OK = UO->getOpcode();
151*e038c9c4Sjoerg SVal SubVal = State->getSVal(UO->getSubExpr(), C.getLocationContext());
152*e038c9c4Sjoerg
153*e038c9c4Sjoerg if (isDereferenceOperator(OK)) {
154*e038c9c4Sjoerg verifyDereference(C, SubVal);
155*e038c9c4Sjoerg } else if (isIncrementOperator(OK)) {
156*e038c9c4Sjoerg verifyIncrement(C, SubVal);
157*e038c9c4Sjoerg } else if (isDecrementOperator(OK)) {
158*e038c9c4Sjoerg verifyDecrement(C, SubVal);
159*e038c9c4Sjoerg }
160*e038c9c4Sjoerg }
161*e038c9c4Sjoerg
checkPreStmt(const BinaryOperator * BO,CheckerContext & C) const162*e038c9c4Sjoerg void IteratorRangeChecker::checkPreStmt(const BinaryOperator *BO,
163*e038c9c4Sjoerg CheckerContext &C) const {
164*e038c9c4Sjoerg ProgramStateRef State = C.getState();
165*e038c9c4Sjoerg BinaryOperatorKind OK = BO->getOpcode();
166*e038c9c4Sjoerg SVal LVal = State->getSVal(BO->getLHS(), C.getLocationContext());
167*e038c9c4Sjoerg
168*e038c9c4Sjoerg if (isDereferenceOperator(OK)) {
169*e038c9c4Sjoerg verifyDereference(C, LVal);
170*e038c9c4Sjoerg } else if (isRandomIncrOrDecrOperator(OK)) {
171*e038c9c4Sjoerg SVal RVal = State->getSVal(BO->getRHS(), C.getLocationContext());
172*e038c9c4Sjoerg if (!BO->getRHS()->getType()->isIntegralOrEnumerationType())
173*e038c9c4Sjoerg return;
174*e038c9c4Sjoerg verifyRandomIncrOrDecr(C, BinaryOperator::getOverloadedOperator(OK), LVal,
175*e038c9c4Sjoerg RVal);
176*e038c9c4Sjoerg }
177*e038c9c4Sjoerg }
178*e038c9c4Sjoerg
checkPreStmt(const ArraySubscriptExpr * ASE,CheckerContext & C) const179*e038c9c4Sjoerg void IteratorRangeChecker::checkPreStmt(const ArraySubscriptExpr *ASE,
180*e038c9c4Sjoerg CheckerContext &C) const {
181*e038c9c4Sjoerg ProgramStateRef State = C.getState();
182*e038c9c4Sjoerg SVal LVal = State->getSVal(ASE->getLHS(), C.getLocationContext());
183*e038c9c4Sjoerg verifyDereference(C, LVal);
184*e038c9c4Sjoerg }
185*e038c9c4Sjoerg
checkPreStmt(const MemberExpr * ME,CheckerContext & C) const186*e038c9c4Sjoerg void IteratorRangeChecker::checkPreStmt(const MemberExpr *ME,
187*e038c9c4Sjoerg CheckerContext &C) const {
188*e038c9c4Sjoerg if (!ME->isArrow() || ME->isImplicitAccess())
189*e038c9c4Sjoerg return;
190*e038c9c4Sjoerg
191*e038c9c4Sjoerg ProgramStateRef State = C.getState();
192*e038c9c4Sjoerg SVal BaseVal = State->getSVal(ME->getBase(), C.getLocationContext());
193*e038c9c4Sjoerg verifyDereference(C, BaseVal);
194*e038c9c4Sjoerg }
195*e038c9c4Sjoerg
verifyDereference(CheckerContext & C,SVal Val) const196*e038c9c4Sjoerg void IteratorRangeChecker::verifyDereference(CheckerContext &C,
197*e038c9c4Sjoerg SVal Val) const {
198*e038c9c4Sjoerg auto State = C.getState();
199*e038c9c4Sjoerg const auto *Pos = getIteratorPosition(State, Val);
200*e038c9c4Sjoerg if (Pos && isPastTheEnd(State, *Pos)) {
201*e038c9c4Sjoerg auto *N = C.generateErrorNode(State);
202*e038c9c4Sjoerg if (!N)
203*e038c9c4Sjoerg return;
204*e038c9c4Sjoerg reportBug("Past-the-end iterator dereferenced.", Val, C, N);
205*e038c9c4Sjoerg return;
206*e038c9c4Sjoerg }
207*e038c9c4Sjoerg }
208*e038c9c4Sjoerg
verifyIncrement(CheckerContext & C,SVal Iter) const209*e038c9c4Sjoerg void IteratorRangeChecker::verifyIncrement(CheckerContext &C, SVal Iter) const {
210*e038c9c4Sjoerg auto &BVF = C.getSValBuilder().getBasicValueFactory();
211*e038c9c4Sjoerg verifyRandomIncrOrDecr(C, OO_Plus, Iter,
212*e038c9c4Sjoerg nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
213*e038c9c4Sjoerg }
214*e038c9c4Sjoerg
verifyDecrement(CheckerContext & C,SVal Iter) const215*e038c9c4Sjoerg void IteratorRangeChecker::verifyDecrement(CheckerContext &C, SVal Iter) const {
216*e038c9c4Sjoerg auto &BVF = C.getSValBuilder().getBasicValueFactory();
217*e038c9c4Sjoerg verifyRandomIncrOrDecr(C, OO_Minus, Iter,
218*e038c9c4Sjoerg nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
219*e038c9c4Sjoerg }
220*e038c9c4Sjoerg
verifyRandomIncrOrDecr(CheckerContext & C,OverloadedOperatorKind Op,SVal LHS,SVal RHS) const221*e038c9c4Sjoerg void IteratorRangeChecker::verifyRandomIncrOrDecr(CheckerContext &C,
222*e038c9c4Sjoerg OverloadedOperatorKind Op,
223*e038c9c4Sjoerg SVal LHS, SVal RHS) const {
224*e038c9c4Sjoerg auto State = C.getState();
225*e038c9c4Sjoerg
226*e038c9c4Sjoerg auto Value = RHS;
227*e038c9c4Sjoerg if (auto ValAsLoc = RHS.getAs<Loc>()) {
228*e038c9c4Sjoerg Value = State->getRawSVal(*ValAsLoc);
229*e038c9c4Sjoerg }
230*e038c9c4Sjoerg
231*e038c9c4Sjoerg if (Value.isUnknownOrUndef())
232*e038c9c4Sjoerg return;
233*e038c9c4Sjoerg
234*e038c9c4Sjoerg // Incremention or decremention by 0 is never a bug.
235*e038c9c4Sjoerg if (isZero(State, Value.castAs<NonLoc>()))
236*e038c9c4Sjoerg return;
237*e038c9c4Sjoerg
238*e038c9c4Sjoerg // The result may be the past-end iterator of the container, but any other
239*e038c9c4Sjoerg // out of range position is undefined behaviour
240*e038c9c4Sjoerg auto StateAfter = advancePosition(State, LHS, Op, Value);
241*e038c9c4Sjoerg if (!StateAfter)
242*e038c9c4Sjoerg return;
243*e038c9c4Sjoerg
244*e038c9c4Sjoerg const auto *PosAfter = getIteratorPosition(StateAfter, LHS);
245*e038c9c4Sjoerg assert(PosAfter &&
246*e038c9c4Sjoerg "Iterator should have position after successful advancement");
247*e038c9c4Sjoerg if (isAheadOfRange(State, *PosAfter)) {
248*e038c9c4Sjoerg auto *N = C.generateErrorNode(State);
249*e038c9c4Sjoerg if (!N)
250*e038c9c4Sjoerg return;
251*e038c9c4Sjoerg reportBug("Iterator decremented ahead of its valid range.", LHS,
252*e038c9c4Sjoerg C, N);
253*e038c9c4Sjoerg }
254*e038c9c4Sjoerg if (isBehindPastTheEnd(State, *PosAfter)) {
255*e038c9c4Sjoerg auto *N = C.generateErrorNode(State);
256*e038c9c4Sjoerg if (!N)
257*e038c9c4Sjoerg return;
258*e038c9c4Sjoerg reportBug("Iterator incremented behind the past-the-end "
259*e038c9c4Sjoerg "iterator.", LHS, C, N);
260*e038c9c4Sjoerg }
261*e038c9c4Sjoerg }
262*e038c9c4Sjoerg
verifyAdvance(CheckerContext & C,SVal LHS,SVal RHS) const263*e038c9c4Sjoerg void IteratorRangeChecker::verifyAdvance(CheckerContext &C, SVal LHS,
264*e038c9c4Sjoerg SVal RHS) const {
265*e038c9c4Sjoerg verifyRandomIncrOrDecr(C, OO_PlusEqual, LHS, RHS);
266*e038c9c4Sjoerg }
267*e038c9c4Sjoerg
verifyPrev(CheckerContext & C,SVal LHS,SVal RHS) const268*e038c9c4Sjoerg void IteratorRangeChecker::verifyPrev(CheckerContext &C, SVal LHS,
269*e038c9c4Sjoerg SVal RHS) const {
270*e038c9c4Sjoerg verifyRandomIncrOrDecr(C, OO_Minus, LHS, RHS);
271*e038c9c4Sjoerg }
272*e038c9c4Sjoerg
verifyNext(CheckerContext & C,SVal LHS,SVal RHS) const273*e038c9c4Sjoerg void IteratorRangeChecker::verifyNext(CheckerContext &C, SVal LHS,
274*e038c9c4Sjoerg SVal RHS) const {
275*e038c9c4Sjoerg verifyRandomIncrOrDecr(C, OO_Plus, LHS, RHS);
276*e038c9c4Sjoerg }
277*e038c9c4Sjoerg
reportBug(const StringRef & Message,SVal Val,CheckerContext & C,ExplodedNode * ErrNode) const278*e038c9c4Sjoerg void IteratorRangeChecker::reportBug(const StringRef &Message, SVal Val,
279*e038c9c4Sjoerg CheckerContext &C,
280*e038c9c4Sjoerg ExplodedNode *ErrNode) const {
281*e038c9c4Sjoerg auto R = std::make_unique<PathSensitiveBugReport>(*OutOfRangeBugType, Message,
282*e038c9c4Sjoerg ErrNode);
283*e038c9c4Sjoerg
284*e038c9c4Sjoerg const auto *Pos = getIteratorPosition(C.getState(), Val);
285*e038c9c4Sjoerg assert(Pos && "Iterator without known position cannot be out-of-range.");
286*e038c9c4Sjoerg
287*e038c9c4Sjoerg R->markInteresting(Val);
288*e038c9c4Sjoerg R->markInteresting(Pos->getContainer());
289*e038c9c4Sjoerg C.emitReport(std::move(R));
290*e038c9c4Sjoerg }
291*e038c9c4Sjoerg
292*e038c9c4Sjoerg namespace {
293*e038c9c4Sjoerg
294*e038c9c4Sjoerg bool isLess(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2);
295*e038c9c4Sjoerg bool isGreater(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2);
296*e038c9c4Sjoerg bool isEqual(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2);
297*e038c9c4Sjoerg
isZero(ProgramStateRef State,const NonLoc & Val)298*e038c9c4Sjoerg bool isZero(ProgramStateRef State, const NonLoc &Val) {
299*e038c9c4Sjoerg auto &BVF = State->getBasicVals();
300*e038c9c4Sjoerg return compare(State, Val,
301*e038c9c4Sjoerg nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))),
302*e038c9c4Sjoerg BO_EQ);
303*e038c9c4Sjoerg }
304*e038c9c4Sjoerg
isPastTheEnd(ProgramStateRef State,const IteratorPosition & Pos)305*e038c9c4Sjoerg bool isPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos) {
306*e038c9c4Sjoerg const auto *Cont = Pos.getContainer();
307*e038c9c4Sjoerg const auto *CData = getContainerData(State, Cont);
308*e038c9c4Sjoerg if (!CData)
309*e038c9c4Sjoerg return false;
310*e038c9c4Sjoerg
311*e038c9c4Sjoerg const auto End = CData->getEnd();
312*e038c9c4Sjoerg if (End) {
313*e038c9c4Sjoerg if (isEqual(State, Pos.getOffset(), End)) {
314*e038c9c4Sjoerg return true;
315*e038c9c4Sjoerg }
316*e038c9c4Sjoerg }
317*e038c9c4Sjoerg
318*e038c9c4Sjoerg return false;
319*e038c9c4Sjoerg }
320*e038c9c4Sjoerg
isAheadOfRange(ProgramStateRef State,const IteratorPosition & Pos)321*e038c9c4Sjoerg bool isAheadOfRange(ProgramStateRef State, const IteratorPosition &Pos) {
322*e038c9c4Sjoerg const auto *Cont = Pos.getContainer();
323*e038c9c4Sjoerg const auto *CData = getContainerData(State, Cont);
324*e038c9c4Sjoerg if (!CData)
325*e038c9c4Sjoerg return false;
326*e038c9c4Sjoerg
327*e038c9c4Sjoerg const auto Beg = CData->getBegin();
328*e038c9c4Sjoerg if (Beg) {
329*e038c9c4Sjoerg if (isLess(State, Pos.getOffset(), Beg)) {
330*e038c9c4Sjoerg return true;
331*e038c9c4Sjoerg }
332*e038c9c4Sjoerg }
333*e038c9c4Sjoerg
334*e038c9c4Sjoerg return false;
335*e038c9c4Sjoerg }
336*e038c9c4Sjoerg
isBehindPastTheEnd(ProgramStateRef State,const IteratorPosition & Pos)337*e038c9c4Sjoerg bool isBehindPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos) {
338*e038c9c4Sjoerg const auto *Cont = Pos.getContainer();
339*e038c9c4Sjoerg const auto *CData = getContainerData(State, Cont);
340*e038c9c4Sjoerg if (!CData)
341*e038c9c4Sjoerg return false;
342*e038c9c4Sjoerg
343*e038c9c4Sjoerg const auto End = CData->getEnd();
344*e038c9c4Sjoerg if (End) {
345*e038c9c4Sjoerg if (isGreater(State, Pos.getOffset(), End)) {
346*e038c9c4Sjoerg return true;
347*e038c9c4Sjoerg }
348*e038c9c4Sjoerg }
349*e038c9c4Sjoerg
350*e038c9c4Sjoerg return false;
351*e038c9c4Sjoerg }
352*e038c9c4Sjoerg
isLess(ProgramStateRef State,SymbolRef Sym1,SymbolRef Sym2)353*e038c9c4Sjoerg bool isLess(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) {
354*e038c9c4Sjoerg return compare(State, Sym1, Sym2, BO_LT);
355*e038c9c4Sjoerg }
356*e038c9c4Sjoerg
isGreater(ProgramStateRef State,SymbolRef Sym1,SymbolRef Sym2)357*e038c9c4Sjoerg bool isGreater(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) {
358*e038c9c4Sjoerg return compare(State, Sym1, Sym2, BO_GT);
359*e038c9c4Sjoerg }
360*e038c9c4Sjoerg
isEqual(ProgramStateRef State,SymbolRef Sym1,SymbolRef Sym2)361*e038c9c4Sjoerg bool isEqual(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) {
362*e038c9c4Sjoerg return compare(State, Sym1, Sym2, BO_EQ);
363*e038c9c4Sjoerg }
364*e038c9c4Sjoerg
365*e038c9c4Sjoerg } // namespace
366*e038c9c4Sjoerg
registerIteratorRangeChecker(CheckerManager & mgr)367*e038c9c4Sjoerg void ento::registerIteratorRangeChecker(CheckerManager &mgr) {
368*e038c9c4Sjoerg mgr.registerChecker<IteratorRangeChecker>();
369*e038c9c4Sjoerg }
370*e038c9c4Sjoerg
shouldRegisterIteratorRangeChecker(const CheckerManager & mgr)371*e038c9c4Sjoerg bool ento::shouldRegisterIteratorRangeChecker(const CheckerManager &mgr) {
372*e038c9c4Sjoerg return true;
373*e038c9c4Sjoerg }
374