xref: /netbsd-src/external/apache2/llvm/dist/clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp (revision e038c9c4676b0f19b1b7dd08a940c6ed64a6d5ae)
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