xref: /freebsd-src/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp (revision 5ffd83dbcc34f10e07f6d3e968ae6365869615f4)
1480093f4SDimitry Andric //===-- IteratorRangeChecker.cpp ----------------------------------*- C++ -*--//
2480093f4SDimitry Andric //
3480093f4SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4480093f4SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5480093f4SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6480093f4SDimitry Andric //
7480093f4SDimitry Andric //===----------------------------------------------------------------------===//
8480093f4SDimitry Andric //
9480093f4SDimitry Andric // Defines a checker for dereference of the past-the-end iterator and
10480093f4SDimitry Andric // out-of-range increments and decrements.
11480093f4SDimitry Andric //
12480093f4SDimitry Andric //===----------------------------------------------------------------------===//
13480093f4SDimitry Andric 
14480093f4SDimitry Andric #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
15480093f4SDimitry Andric #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
16480093f4SDimitry Andric #include "clang/StaticAnalyzer/Core/Checker.h"
17480093f4SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
18480093f4SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
19480093f4SDimitry Andric 
20480093f4SDimitry Andric 
21480093f4SDimitry Andric #include "Iterator.h"
22480093f4SDimitry Andric 
23480093f4SDimitry Andric using namespace clang;
24480093f4SDimitry Andric using namespace ento;
25480093f4SDimitry Andric using namespace iterator;
26480093f4SDimitry Andric 
27480093f4SDimitry Andric namespace {
28480093f4SDimitry Andric 
29480093f4SDimitry Andric class IteratorRangeChecker
30*5ffd83dbSDimitry Andric   : public Checker<check::PreCall, check::PreStmt<UnaryOperator>,
31*5ffd83dbSDimitry Andric                    check::PreStmt<BinaryOperator>,
32*5ffd83dbSDimitry Andric                    check::PreStmt<ArraySubscriptExpr>,
33*5ffd83dbSDimitry Andric                    check::PreStmt<MemberExpr>> {
34480093f4SDimitry Andric 
35480093f4SDimitry Andric   std::unique_ptr<BugType> OutOfRangeBugType;
36480093f4SDimitry Andric 
37*5ffd83dbSDimitry Andric   void verifyDereference(CheckerContext &C, SVal Val) const;
38*5ffd83dbSDimitry Andric   void verifyIncrement(CheckerContext &C, SVal Iter) const;
39*5ffd83dbSDimitry Andric   void verifyDecrement(CheckerContext &C, SVal Iter) const;
40480093f4SDimitry Andric   void verifyRandomIncrOrDecr(CheckerContext &C, OverloadedOperatorKind Op,
41*5ffd83dbSDimitry Andric                               SVal LHS, SVal RHS) const;
42*5ffd83dbSDimitry Andric   void verifyAdvance(CheckerContext &C, SVal LHS, SVal RHS) const;
43*5ffd83dbSDimitry Andric   void verifyPrev(CheckerContext &C, SVal LHS, SVal RHS) const;
44*5ffd83dbSDimitry Andric   void verifyNext(CheckerContext &C, SVal LHS, SVal RHS) const;
45*5ffd83dbSDimitry Andric   void reportBug(const StringRef &Message, SVal Val, CheckerContext &C,
46*5ffd83dbSDimitry Andric                  ExplodedNode *ErrNode) const;
47*5ffd83dbSDimitry Andric 
48480093f4SDimitry Andric public:
49480093f4SDimitry Andric   IteratorRangeChecker();
50480093f4SDimitry Andric 
51480093f4SDimitry Andric   void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
52*5ffd83dbSDimitry Andric   void checkPreStmt(const UnaryOperator *UO, CheckerContext &C) const;
53*5ffd83dbSDimitry Andric   void checkPreStmt(const BinaryOperator *BO, CheckerContext &C) const;
54*5ffd83dbSDimitry Andric   void checkPreStmt(const ArraySubscriptExpr *ASE, CheckerContext &C) const;
55*5ffd83dbSDimitry Andric   void checkPreStmt(const MemberExpr *ME, CheckerContext &C) const;
56480093f4SDimitry Andric 
57*5ffd83dbSDimitry Andric   using AdvanceFn = void (IteratorRangeChecker::*)(CheckerContext &, SVal,
58*5ffd83dbSDimitry Andric                                                    SVal) const;
59*5ffd83dbSDimitry Andric 
60*5ffd83dbSDimitry Andric   CallDescriptionMap<AdvanceFn> AdvanceFunctions = {
61*5ffd83dbSDimitry Andric       {{{"std", "advance"}, 2}, &IteratorRangeChecker::verifyAdvance},
62*5ffd83dbSDimitry Andric       {{{"std", "prev"}, 2}, &IteratorRangeChecker::verifyPrev},
63*5ffd83dbSDimitry Andric       {{{"std", "next"}, 2}, &IteratorRangeChecker::verifyNext},
64*5ffd83dbSDimitry Andric   };
65480093f4SDimitry Andric };
66480093f4SDimitry Andric 
67480093f4SDimitry Andric bool isPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos);
68480093f4SDimitry Andric bool isAheadOfRange(ProgramStateRef State, const IteratorPosition &Pos);
69480093f4SDimitry Andric bool isBehindPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos);
70480093f4SDimitry Andric bool isZero(ProgramStateRef State, const NonLoc &Val);
71480093f4SDimitry Andric 
72480093f4SDimitry Andric } //namespace
73480093f4SDimitry Andric 
74480093f4SDimitry Andric IteratorRangeChecker::IteratorRangeChecker() {
75480093f4SDimitry Andric   OutOfRangeBugType.reset(
76480093f4SDimitry Andric       new BugType(this, "Iterator out of range", "Misuse of STL APIs"));
77480093f4SDimitry Andric }
78480093f4SDimitry Andric 
79480093f4SDimitry Andric void IteratorRangeChecker::checkPreCall(const CallEvent &Call,
80480093f4SDimitry Andric                                         CheckerContext &C) const {
81480093f4SDimitry Andric   // Check for out of range access
82480093f4SDimitry Andric   const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
83480093f4SDimitry Andric   if (!Func)
84480093f4SDimitry Andric     return;
85480093f4SDimitry Andric 
86480093f4SDimitry Andric   if (Func->isOverloadedOperator()) {
87480093f4SDimitry Andric     if (isIncrementOperator(Func->getOverloadedOperator())) {
88480093f4SDimitry Andric       // Check for out-of-range incrementions
89480093f4SDimitry Andric       if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
90480093f4SDimitry Andric         verifyIncrement(C, InstCall->getCXXThisVal());
91480093f4SDimitry Andric       } else {
92480093f4SDimitry Andric         if (Call.getNumArgs() >= 1) {
93480093f4SDimitry Andric           verifyIncrement(C, Call.getArgSVal(0));
94480093f4SDimitry Andric         }
95480093f4SDimitry Andric       }
96480093f4SDimitry Andric     } else if (isDecrementOperator(Func->getOverloadedOperator())) {
97480093f4SDimitry Andric       // Check for out-of-range decrementions
98480093f4SDimitry Andric       if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
99480093f4SDimitry Andric         verifyDecrement(C, InstCall->getCXXThisVal());
100480093f4SDimitry Andric       } else {
101480093f4SDimitry Andric         if (Call.getNumArgs() >= 1) {
102480093f4SDimitry Andric           verifyDecrement(C, Call.getArgSVal(0));
103480093f4SDimitry Andric         }
104480093f4SDimitry Andric       }
105480093f4SDimitry Andric     } else if (isRandomIncrOrDecrOperator(Func->getOverloadedOperator())) {
106480093f4SDimitry Andric       if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
107480093f4SDimitry Andric         // Check for out-of-range incrementions and decrementions
108480093f4SDimitry Andric         if (Call.getNumArgs() >= 1 &&
109480093f4SDimitry Andric             Call.getArgExpr(0)->getType()->isIntegralOrEnumerationType()) {
110480093f4SDimitry Andric           verifyRandomIncrOrDecr(C, Func->getOverloadedOperator(),
111480093f4SDimitry Andric                                  InstCall->getCXXThisVal(),
112480093f4SDimitry Andric                                  Call.getArgSVal(0));
113480093f4SDimitry Andric         }
114480093f4SDimitry Andric       } else {
115480093f4SDimitry Andric         if (Call.getNumArgs() >= 2 &&
116480093f4SDimitry Andric             Call.getArgExpr(1)->getType()->isIntegralOrEnumerationType()) {
117480093f4SDimitry Andric           verifyRandomIncrOrDecr(C, Func->getOverloadedOperator(),
118480093f4SDimitry Andric                                  Call.getArgSVal(0), Call.getArgSVal(1));
119480093f4SDimitry Andric         }
120480093f4SDimitry Andric       }
121480093f4SDimitry Andric     } else if (isDereferenceOperator(Func->getOverloadedOperator())) {
122480093f4SDimitry Andric       // Check for dereference of out-of-range iterators
123480093f4SDimitry Andric       if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
124480093f4SDimitry Andric         verifyDereference(C, InstCall->getCXXThisVal());
125480093f4SDimitry Andric       } else {
126480093f4SDimitry Andric         verifyDereference(C, Call.getArgSVal(0));
127480093f4SDimitry Andric       }
128480093f4SDimitry Andric     }
129*5ffd83dbSDimitry Andric   } else {
130*5ffd83dbSDimitry Andric     const AdvanceFn *Verifier = AdvanceFunctions.lookup(Call);
131*5ffd83dbSDimitry Andric     if (Verifier) {
132*5ffd83dbSDimitry Andric       if (Call.getNumArgs() > 1) {
133*5ffd83dbSDimitry Andric         (this->**Verifier)(C, Call.getArgSVal(0), Call.getArgSVal(1));
134*5ffd83dbSDimitry Andric       } else {
135*5ffd83dbSDimitry Andric         auto &BVF = C.getSValBuilder().getBasicValueFactory();
136*5ffd83dbSDimitry Andric         (this->**Verifier)(
137*5ffd83dbSDimitry Andric             C, Call.getArgSVal(0),
138*5ffd83dbSDimitry Andric             nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
139*5ffd83dbSDimitry Andric       }
140*5ffd83dbSDimitry Andric     }
141480093f4SDimitry Andric   }
142480093f4SDimitry Andric }
143480093f4SDimitry Andric 
144*5ffd83dbSDimitry Andric void IteratorRangeChecker::checkPreStmt(const UnaryOperator *UO,
145*5ffd83dbSDimitry Andric                                         CheckerContext &C) const {
146*5ffd83dbSDimitry Andric   if (isa<CXXThisExpr>(UO->getSubExpr()))
147*5ffd83dbSDimitry Andric     return;
148*5ffd83dbSDimitry Andric 
149*5ffd83dbSDimitry Andric   ProgramStateRef State = C.getState();
150*5ffd83dbSDimitry Andric   UnaryOperatorKind OK = UO->getOpcode();
151*5ffd83dbSDimitry Andric   SVal SubVal = State->getSVal(UO->getSubExpr(), C.getLocationContext());
152*5ffd83dbSDimitry Andric 
153*5ffd83dbSDimitry Andric   if (isDereferenceOperator(OK)) {
154*5ffd83dbSDimitry Andric     verifyDereference(C, SubVal);
155*5ffd83dbSDimitry Andric   } else if (isIncrementOperator(OK)) {
156*5ffd83dbSDimitry Andric     verifyIncrement(C, SubVal);
157*5ffd83dbSDimitry Andric   } else if (isDecrementOperator(OK)) {
158*5ffd83dbSDimitry Andric     verifyDecrement(C, SubVal);
159*5ffd83dbSDimitry Andric   }
160*5ffd83dbSDimitry Andric }
161*5ffd83dbSDimitry Andric 
162*5ffd83dbSDimitry Andric void IteratorRangeChecker::checkPreStmt(const BinaryOperator *BO,
163*5ffd83dbSDimitry Andric                                         CheckerContext &C) const {
164*5ffd83dbSDimitry Andric   ProgramStateRef State = C.getState();
165*5ffd83dbSDimitry Andric   BinaryOperatorKind OK = BO->getOpcode();
166*5ffd83dbSDimitry Andric   SVal LVal = State->getSVal(BO->getLHS(), C.getLocationContext());
167*5ffd83dbSDimitry Andric 
168*5ffd83dbSDimitry Andric   if (isDereferenceOperator(OK)) {
169*5ffd83dbSDimitry Andric     verifyDereference(C, LVal);
170*5ffd83dbSDimitry Andric   } else if (isRandomIncrOrDecrOperator(OK)) {
171*5ffd83dbSDimitry Andric     SVal RVal = State->getSVal(BO->getRHS(), C.getLocationContext());
172*5ffd83dbSDimitry Andric     verifyRandomIncrOrDecr(C, BinaryOperator::getOverloadedOperator(OK), LVal,
173*5ffd83dbSDimitry Andric                            RVal);
174*5ffd83dbSDimitry Andric   }
175*5ffd83dbSDimitry Andric }
176*5ffd83dbSDimitry Andric 
177*5ffd83dbSDimitry Andric void IteratorRangeChecker::checkPreStmt(const ArraySubscriptExpr *ASE,
178*5ffd83dbSDimitry Andric                                         CheckerContext &C) const {
179*5ffd83dbSDimitry Andric   ProgramStateRef State = C.getState();
180*5ffd83dbSDimitry Andric   SVal LVal = State->getSVal(ASE->getLHS(), C.getLocationContext());
181*5ffd83dbSDimitry Andric   verifyDereference(C, LVal);
182*5ffd83dbSDimitry Andric }
183*5ffd83dbSDimitry Andric 
184*5ffd83dbSDimitry Andric void IteratorRangeChecker::checkPreStmt(const MemberExpr *ME,
185*5ffd83dbSDimitry Andric                                         CheckerContext &C) const {
186*5ffd83dbSDimitry Andric   if (!ME->isArrow() || ME->isImplicitAccess())
187*5ffd83dbSDimitry Andric     return;
188*5ffd83dbSDimitry Andric 
189*5ffd83dbSDimitry Andric   ProgramStateRef State = C.getState();
190*5ffd83dbSDimitry Andric   SVal BaseVal = State->getSVal(ME->getBase(), C.getLocationContext());
191*5ffd83dbSDimitry Andric   verifyDereference(C, BaseVal);
192*5ffd83dbSDimitry Andric }
193*5ffd83dbSDimitry Andric 
194480093f4SDimitry Andric void IteratorRangeChecker::verifyDereference(CheckerContext &C,
195*5ffd83dbSDimitry Andric                                              SVal Val) const {
196480093f4SDimitry Andric   auto State = C.getState();
197480093f4SDimitry Andric   const auto *Pos = getIteratorPosition(State, Val);
198480093f4SDimitry Andric   if (Pos && isPastTheEnd(State, *Pos)) {
199480093f4SDimitry Andric     auto *N = C.generateErrorNode(State);
200480093f4SDimitry Andric     if (!N)
201480093f4SDimitry Andric       return;
202480093f4SDimitry Andric     reportBug("Past-the-end iterator dereferenced.", Val, C, N);
203480093f4SDimitry Andric     return;
204480093f4SDimitry Andric   }
205480093f4SDimitry Andric }
206480093f4SDimitry Andric 
207*5ffd83dbSDimitry Andric void IteratorRangeChecker::verifyIncrement(CheckerContext &C, SVal Iter) const {
208480093f4SDimitry Andric   auto &BVF = C.getSValBuilder().getBasicValueFactory();
209480093f4SDimitry Andric   verifyRandomIncrOrDecr(C, OO_Plus, Iter,
210480093f4SDimitry Andric                      nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
211480093f4SDimitry Andric }
212480093f4SDimitry Andric 
213*5ffd83dbSDimitry Andric void IteratorRangeChecker::verifyDecrement(CheckerContext &C, SVal Iter) const {
214480093f4SDimitry Andric   auto &BVF = C.getSValBuilder().getBasicValueFactory();
215480093f4SDimitry Andric   verifyRandomIncrOrDecr(C, OO_Minus, Iter,
216480093f4SDimitry Andric                      nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
217480093f4SDimitry Andric }
218480093f4SDimitry Andric 
219480093f4SDimitry Andric void IteratorRangeChecker::verifyRandomIncrOrDecr(CheckerContext &C,
220480093f4SDimitry Andric                                                   OverloadedOperatorKind Op,
221*5ffd83dbSDimitry Andric                                                   SVal LHS, SVal RHS) const {
222480093f4SDimitry Andric   auto State = C.getState();
223480093f4SDimitry Andric 
224480093f4SDimitry Andric   auto Value = RHS;
225480093f4SDimitry Andric   if (auto ValAsLoc = RHS.getAs<Loc>()) {
226480093f4SDimitry Andric     Value = State->getRawSVal(*ValAsLoc);
227480093f4SDimitry Andric   }
228480093f4SDimitry Andric 
229480093f4SDimitry Andric   if (Value.isUnknown())
230480093f4SDimitry Andric     return;
231480093f4SDimitry Andric 
232480093f4SDimitry Andric   // Incremention or decremention by 0 is never a bug.
233480093f4SDimitry Andric   if (isZero(State, Value.castAs<NonLoc>()))
234480093f4SDimitry Andric     return;
235480093f4SDimitry Andric 
236480093f4SDimitry Andric   // The result may be the past-end iterator of the container, but any other
237480093f4SDimitry Andric   // out of range position is undefined behaviour
238480093f4SDimitry Andric   auto StateAfter = advancePosition(State, LHS, Op, Value);
239480093f4SDimitry Andric   if (!StateAfter)
240480093f4SDimitry Andric     return;
241480093f4SDimitry Andric 
242480093f4SDimitry Andric   const auto *PosAfter = getIteratorPosition(StateAfter, LHS);
243480093f4SDimitry Andric   assert(PosAfter &&
244480093f4SDimitry Andric          "Iterator should have position after successful advancement");
245480093f4SDimitry Andric   if (isAheadOfRange(State, *PosAfter)) {
246480093f4SDimitry Andric     auto *N = C.generateErrorNode(State);
247480093f4SDimitry Andric     if (!N)
248480093f4SDimitry Andric       return;
249480093f4SDimitry Andric     reportBug("Iterator decremented ahead of its valid range.", LHS,
250480093f4SDimitry Andric                         C, N);
251480093f4SDimitry Andric   }
252480093f4SDimitry Andric   if (isBehindPastTheEnd(State, *PosAfter)) {
253480093f4SDimitry Andric     auto *N = C.generateErrorNode(State);
254480093f4SDimitry Andric     if (!N)
255480093f4SDimitry Andric       return;
256480093f4SDimitry Andric     reportBug("Iterator incremented behind the past-the-end "
257480093f4SDimitry Andric                         "iterator.", LHS, C, N);
258480093f4SDimitry Andric   }
259480093f4SDimitry Andric }
260480093f4SDimitry Andric 
261*5ffd83dbSDimitry Andric void IteratorRangeChecker::verifyAdvance(CheckerContext &C, SVal LHS,
262*5ffd83dbSDimitry Andric                                          SVal RHS) const {
263*5ffd83dbSDimitry Andric   verifyRandomIncrOrDecr(C, OO_PlusEqual, LHS, RHS);
264*5ffd83dbSDimitry Andric }
265*5ffd83dbSDimitry Andric 
266*5ffd83dbSDimitry Andric void IteratorRangeChecker::verifyPrev(CheckerContext &C, SVal LHS,
267*5ffd83dbSDimitry Andric                                       SVal RHS) const {
268*5ffd83dbSDimitry Andric   verifyRandomIncrOrDecr(C, OO_Minus, LHS, RHS);
269*5ffd83dbSDimitry Andric }
270*5ffd83dbSDimitry Andric 
271*5ffd83dbSDimitry Andric void IteratorRangeChecker::verifyNext(CheckerContext &C, SVal LHS,
272*5ffd83dbSDimitry Andric                                       SVal RHS) const {
273*5ffd83dbSDimitry Andric   verifyRandomIncrOrDecr(C, OO_Plus, LHS, RHS);
274*5ffd83dbSDimitry Andric }
275*5ffd83dbSDimitry Andric 
276*5ffd83dbSDimitry Andric void IteratorRangeChecker::reportBug(const StringRef &Message, SVal Val,
277*5ffd83dbSDimitry Andric                                      CheckerContext &C,
278480093f4SDimitry Andric                                      ExplodedNode *ErrNode) const {
279480093f4SDimitry Andric   auto R = std::make_unique<PathSensitiveBugReport>(*OutOfRangeBugType, Message,
280480093f4SDimitry Andric                                                     ErrNode);
281*5ffd83dbSDimitry Andric 
282*5ffd83dbSDimitry Andric   const auto *Pos = getIteratorPosition(C.getState(), Val);
283*5ffd83dbSDimitry Andric   assert(Pos && "Iterator without known position cannot be out-of-range.");
284*5ffd83dbSDimitry Andric 
285480093f4SDimitry Andric   R->markInteresting(Val);
286*5ffd83dbSDimitry Andric   R->markInteresting(Pos->getContainer());
287480093f4SDimitry Andric   C.emitReport(std::move(R));
288480093f4SDimitry Andric }
289480093f4SDimitry Andric 
290480093f4SDimitry Andric namespace {
291480093f4SDimitry Andric 
292480093f4SDimitry Andric bool isLess(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2);
293480093f4SDimitry Andric bool isGreater(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2);
294480093f4SDimitry Andric bool isEqual(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2);
295480093f4SDimitry Andric 
296480093f4SDimitry Andric bool isZero(ProgramStateRef State, const NonLoc &Val) {
297480093f4SDimitry Andric   auto &BVF = State->getBasicVals();
298480093f4SDimitry Andric   return compare(State, Val,
299480093f4SDimitry Andric                  nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))),
300480093f4SDimitry Andric                  BO_EQ);
301480093f4SDimitry Andric }
302480093f4SDimitry Andric 
303480093f4SDimitry Andric bool isPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos) {
304480093f4SDimitry Andric   const auto *Cont = Pos.getContainer();
305480093f4SDimitry Andric   const auto *CData = getContainerData(State, Cont);
306480093f4SDimitry Andric   if (!CData)
307480093f4SDimitry Andric     return false;
308480093f4SDimitry Andric 
309480093f4SDimitry Andric   const auto End = CData->getEnd();
310480093f4SDimitry Andric   if (End) {
311480093f4SDimitry Andric     if (isEqual(State, Pos.getOffset(), End)) {
312480093f4SDimitry Andric       return true;
313480093f4SDimitry Andric     }
314480093f4SDimitry Andric   }
315480093f4SDimitry Andric 
316480093f4SDimitry Andric   return false;
317480093f4SDimitry Andric }
318480093f4SDimitry Andric 
319480093f4SDimitry Andric bool isAheadOfRange(ProgramStateRef State, const IteratorPosition &Pos) {
320480093f4SDimitry Andric   const auto *Cont = Pos.getContainer();
321480093f4SDimitry Andric   const auto *CData = getContainerData(State, Cont);
322480093f4SDimitry Andric   if (!CData)
323480093f4SDimitry Andric     return false;
324480093f4SDimitry Andric 
325480093f4SDimitry Andric   const auto Beg = CData->getBegin();
326480093f4SDimitry Andric   if (Beg) {
327480093f4SDimitry Andric     if (isLess(State, Pos.getOffset(), Beg)) {
328480093f4SDimitry Andric       return true;
329480093f4SDimitry Andric     }
330480093f4SDimitry Andric   }
331480093f4SDimitry Andric 
332480093f4SDimitry Andric   return false;
333480093f4SDimitry Andric }
334480093f4SDimitry Andric 
335480093f4SDimitry Andric bool isBehindPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos) {
336480093f4SDimitry Andric   const auto *Cont = Pos.getContainer();
337480093f4SDimitry Andric   const auto *CData = getContainerData(State, Cont);
338480093f4SDimitry Andric   if (!CData)
339480093f4SDimitry Andric     return false;
340480093f4SDimitry Andric 
341480093f4SDimitry Andric   const auto End = CData->getEnd();
342480093f4SDimitry Andric   if (End) {
343480093f4SDimitry Andric     if (isGreater(State, Pos.getOffset(), End)) {
344480093f4SDimitry Andric       return true;
345480093f4SDimitry Andric     }
346480093f4SDimitry Andric   }
347480093f4SDimitry Andric 
348480093f4SDimitry Andric   return false;
349480093f4SDimitry Andric }
350480093f4SDimitry Andric 
351480093f4SDimitry Andric bool isLess(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) {
352480093f4SDimitry Andric   return compare(State, Sym1, Sym2, BO_LT);
353480093f4SDimitry Andric }
354480093f4SDimitry Andric 
355480093f4SDimitry Andric bool isGreater(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) {
356480093f4SDimitry Andric   return compare(State, Sym1, Sym2, BO_GT);
357480093f4SDimitry Andric }
358480093f4SDimitry Andric 
359480093f4SDimitry Andric bool isEqual(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) {
360480093f4SDimitry Andric   return compare(State, Sym1, Sym2, BO_EQ);
361480093f4SDimitry Andric }
362480093f4SDimitry Andric 
363480093f4SDimitry Andric } // namespace
364480093f4SDimitry Andric 
365480093f4SDimitry Andric void ento::registerIteratorRangeChecker(CheckerManager &mgr) {
366480093f4SDimitry Andric   mgr.registerChecker<IteratorRangeChecker>();
367480093f4SDimitry Andric }
368480093f4SDimitry Andric 
369*5ffd83dbSDimitry Andric bool ento::shouldRegisterIteratorRangeChecker(const CheckerManager &mgr) {
370480093f4SDimitry Andric   return true;
371480093f4SDimitry Andric }
372