xref: /freebsd-src/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp (revision e8d8bef961a50d4dc22501cde4fb9fb0be1b2532)
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
305ffd83dbSDimitry Andric   : public Checker<check::PreCall, check::PreStmt<UnaryOperator>,
315ffd83dbSDimitry Andric                    check::PreStmt<BinaryOperator>,
325ffd83dbSDimitry Andric                    check::PreStmt<ArraySubscriptExpr>,
335ffd83dbSDimitry Andric                    check::PreStmt<MemberExpr>> {
34480093f4SDimitry Andric 
35480093f4SDimitry Andric   std::unique_ptr<BugType> OutOfRangeBugType;
36480093f4SDimitry Andric 
375ffd83dbSDimitry Andric   void verifyDereference(CheckerContext &C, SVal Val) const;
385ffd83dbSDimitry Andric   void verifyIncrement(CheckerContext &C, SVal Iter) const;
395ffd83dbSDimitry Andric   void verifyDecrement(CheckerContext &C, SVal Iter) const;
40480093f4SDimitry Andric   void verifyRandomIncrOrDecr(CheckerContext &C, OverloadedOperatorKind Op,
415ffd83dbSDimitry Andric                               SVal LHS, SVal RHS) const;
425ffd83dbSDimitry Andric   void verifyAdvance(CheckerContext &C, SVal LHS, SVal RHS) const;
435ffd83dbSDimitry Andric   void verifyPrev(CheckerContext &C, SVal LHS, SVal RHS) const;
445ffd83dbSDimitry Andric   void verifyNext(CheckerContext &C, SVal LHS, SVal RHS) const;
455ffd83dbSDimitry Andric   void reportBug(const StringRef &Message, SVal Val, CheckerContext &C,
465ffd83dbSDimitry Andric                  ExplodedNode *ErrNode) const;
475ffd83dbSDimitry Andric 
48480093f4SDimitry Andric public:
49480093f4SDimitry Andric   IteratorRangeChecker();
50480093f4SDimitry Andric 
51480093f4SDimitry Andric   void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
525ffd83dbSDimitry Andric   void checkPreStmt(const UnaryOperator *UO, CheckerContext &C) const;
535ffd83dbSDimitry Andric   void checkPreStmt(const BinaryOperator *BO, CheckerContext &C) const;
545ffd83dbSDimitry Andric   void checkPreStmt(const ArraySubscriptExpr *ASE, CheckerContext &C) const;
555ffd83dbSDimitry Andric   void checkPreStmt(const MemberExpr *ME, CheckerContext &C) const;
56480093f4SDimitry Andric 
575ffd83dbSDimitry Andric   using AdvanceFn = void (IteratorRangeChecker::*)(CheckerContext &, SVal,
585ffd83dbSDimitry Andric                                                    SVal) const;
595ffd83dbSDimitry Andric 
605ffd83dbSDimitry Andric   CallDescriptionMap<AdvanceFn> AdvanceFunctions = {
615ffd83dbSDimitry Andric       {{{"std", "advance"}, 2}, &IteratorRangeChecker::verifyAdvance},
625ffd83dbSDimitry Andric       {{{"std", "prev"}, 2}, &IteratorRangeChecker::verifyPrev},
635ffd83dbSDimitry Andric       {{{"std", "next"}, 2}, &IteratorRangeChecker::verifyNext},
645ffd83dbSDimitry 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     }
1295ffd83dbSDimitry Andric   } else {
1305ffd83dbSDimitry Andric     const AdvanceFn *Verifier = AdvanceFunctions.lookup(Call);
1315ffd83dbSDimitry Andric     if (Verifier) {
1325ffd83dbSDimitry Andric       if (Call.getNumArgs() > 1) {
1335ffd83dbSDimitry Andric         (this->**Verifier)(C, Call.getArgSVal(0), Call.getArgSVal(1));
1345ffd83dbSDimitry Andric       } else {
1355ffd83dbSDimitry Andric         auto &BVF = C.getSValBuilder().getBasicValueFactory();
1365ffd83dbSDimitry Andric         (this->**Verifier)(
1375ffd83dbSDimitry Andric             C, Call.getArgSVal(0),
1385ffd83dbSDimitry Andric             nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
1395ffd83dbSDimitry Andric       }
1405ffd83dbSDimitry Andric     }
141480093f4SDimitry Andric   }
142480093f4SDimitry Andric }
143480093f4SDimitry Andric 
1445ffd83dbSDimitry Andric void IteratorRangeChecker::checkPreStmt(const UnaryOperator *UO,
1455ffd83dbSDimitry Andric                                         CheckerContext &C) const {
1465ffd83dbSDimitry Andric   if (isa<CXXThisExpr>(UO->getSubExpr()))
1475ffd83dbSDimitry Andric     return;
1485ffd83dbSDimitry Andric 
1495ffd83dbSDimitry Andric   ProgramStateRef State = C.getState();
1505ffd83dbSDimitry Andric   UnaryOperatorKind OK = UO->getOpcode();
1515ffd83dbSDimitry Andric   SVal SubVal = State->getSVal(UO->getSubExpr(), C.getLocationContext());
1525ffd83dbSDimitry Andric 
1535ffd83dbSDimitry Andric   if (isDereferenceOperator(OK)) {
1545ffd83dbSDimitry Andric     verifyDereference(C, SubVal);
1555ffd83dbSDimitry Andric   } else if (isIncrementOperator(OK)) {
1565ffd83dbSDimitry Andric     verifyIncrement(C, SubVal);
1575ffd83dbSDimitry Andric   } else if (isDecrementOperator(OK)) {
1585ffd83dbSDimitry Andric     verifyDecrement(C, SubVal);
1595ffd83dbSDimitry Andric   }
1605ffd83dbSDimitry Andric }
1615ffd83dbSDimitry Andric 
1625ffd83dbSDimitry Andric void IteratorRangeChecker::checkPreStmt(const BinaryOperator *BO,
1635ffd83dbSDimitry Andric                                         CheckerContext &C) const {
1645ffd83dbSDimitry Andric   ProgramStateRef State = C.getState();
1655ffd83dbSDimitry Andric   BinaryOperatorKind OK = BO->getOpcode();
1665ffd83dbSDimitry Andric   SVal LVal = State->getSVal(BO->getLHS(), C.getLocationContext());
1675ffd83dbSDimitry Andric 
1685ffd83dbSDimitry Andric   if (isDereferenceOperator(OK)) {
1695ffd83dbSDimitry Andric     verifyDereference(C, LVal);
1705ffd83dbSDimitry Andric   } else if (isRandomIncrOrDecrOperator(OK)) {
1715ffd83dbSDimitry Andric     SVal RVal = State->getSVal(BO->getRHS(), C.getLocationContext());
172*e8d8bef9SDimitry Andric     if (!BO->getRHS()->getType()->isIntegralOrEnumerationType())
173*e8d8bef9SDimitry Andric       return;
1745ffd83dbSDimitry Andric     verifyRandomIncrOrDecr(C, BinaryOperator::getOverloadedOperator(OK), LVal,
1755ffd83dbSDimitry Andric                            RVal);
1765ffd83dbSDimitry Andric   }
1775ffd83dbSDimitry Andric }
1785ffd83dbSDimitry Andric 
1795ffd83dbSDimitry Andric void IteratorRangeChecker::checkPreStmt(const ArraySubscriptExpr *ASE,
1805ffd83dbSDimitry Andric                                         CheckerContext &C) const {
1815ffd83dbSDimitry Andric   ProgramStateRef State = C.getState();
1825ffd83dbSDimitry Andric   SVal LVal = State->getSVal(ASE->getLHS(), C.getLocationContext());
1835ffd83dbSDimitry Andric   verifyDereference(C, LVal);
1845ffd83dbSDimitry Andric }
1855ffd83dbSDimitry Andric 
1865ffd83dbSDimitry Andric void IteratorRangeChecker::checkPreStmt(const MemberExpr *ME,
1875ffd83dbSDimitry Andric                                         CheckerContext &C) const {
1885ffd83dbSDimitry Andric   if (!ME->isArrow() || ME->isImplicitAccess())
1895ffd83dbSDimitry Andric     return;
1905ffd83dbSDimitry Andric 
1915ffd83dbSDimitry Andric   ProgramStateRef State = C.getState();
1925ffd83dbSDimitry Andric   SVal BaseVal = State->getSVal(ME->getBase(), C.getLocationContext());
1935ffd83dbSDimitry Andric   verifyDereference(C, BaseVal);
1945ffd83dbSDimitry Andric }
1955ffd83dbSDimitry Andric 
196480093f4SDimitry Andric void IteratorRangeChecker::verifyDereference(CheckerContext &C,
1975ffd83dbSDimitry Andric                                              SVal Val) const {
198480093f4SDimitry Andric   auto State = C.getState();
199480093f4SDimitry Andric   const auto *Pos = getIteratorPosition(State, Val);
200480093f4SDimitry Andric   if (Pos && isPastTheEnd(State, *Pos)) {
201480093f4SDimitry Andric     auto *N = C.generateErrorNode(State);
202480093f4SDimitry Andric     if (!N)
203480093f4SDimitry Andric       return;
204480093f4SDimitry Andric     reportBug("Past-the-end iterator dereferenced.", Val, C, N);
205480093f4SDimitry Andric     return;
206480093f4SDimitry Andric   }
207480093f4SDimitry Andric }
208480093f4SDimitry Andric 
2095ffd83dbSDimitry Andric void IteratorRangeChecker::verifyIncrement(CheckerContext &C, SVal Iter) const {
210480093f4SDimitry Andric   auto &BVF = C.getSValBuilder().getBasicValueFactory();
211480093f4SDimitry Andric   verifyRandomIncrOrDecr(C, OO_Plus, Iter,
212480093f4SDimitry Andric                      nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
213480093f4SDimitry Andric }
214480093f4SDimitry Andric 
2155ffd83dbSDimitry Andric void IteratorRangeChecker::verifyDecrement(CheckerContext &C, SVal Iter) const {
216480093f4SDimitry Andric   auto &BVF = C.getSValBuilder().getBasicValueFactory();
217480093f4SDimitry Andric   verifyRandomIncrOrDecr(C, OO_Minus, Iter,
218480093f4SDimitry Andric                      nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
219480093f4SDimitry Andric }
220480093f4SDimitry Andric 
221480093f4SDimitry Andric void IteratorRangeChecker::verifyRandomIncrOrDecr(CheckerContext &C,
222480093f4SDimitry Andric                                                   OverloadedOperatorKind Op,
2235ffd83dbSDimitry Andric                                                   SVal LHS, SVal RHS) const {
224480093f4SDimitry Andric   auto State = C.getState();
225480093f4SDimitry Andric 
226480093f4SDimitry Andric   auto Value = RHS;
227480093f4SDimitry Andric   if (auto ValAsLoc = RHS.getAs<Loc>()) {
228480093f4SDimitry Andric     Value = State->getRawSVal(*ValAsLoc);
229480093f4SDimitry Andric   }
230480093f4SDimitry Andric 
231480093f4SDimitry Andric   if (Value.isUnknown())
232480093f4SDimitry Andric     return;
233480093f4SDimitry Andric 
234480093f4SDimitry Andric   // Incremention or decremention by 0 is never a bug.
235480093f4SDimitry Andric   if (isZero(State, Value.castAs<NonLoc>()))
236480093f4SDimitry Andric     return;
237480093f4SDimitry Andric 
238480093f4SDimitry Andric   // The result may be the past-end iterator of the container, but any other
239480093f4SDimitry Andric   // out of range position is undefined behaviour
240480093f4SDimitry Andric   auto StateAfter = advancePosition(State, LHS, Op, Value);
241480093f4SDimitry Andric   if (!StateAfter)
242480093f4SDimitry Andric     return;
243480093f4SDimitry Andric 
244480093f4SDimitry Andric   const auto *PosAfter = getIteratorPosition(StateAfter, LHS);
245480093f4SDimitry Andric   assert(PosAfter &&
246480093f4SDimitry Andric          "Iterator should have position after successful advancement");
247480093f4SDimitry Andric   if (isAheadOfRange(State, *PosAfter)) {
248480093f4SDimitry Andric     auto *N = C.generateErrorNode(State);
249480093f4SDimitry Andric     if (!N)
250480093f4SDimitry Andric       return;
251480093f4SDimitry Andric     reportBug("Iterator decremented ahead of its valid range.", LHS,
252480093f4SDimitry Andric                         C, N);
253480093f4SDimitry Andric   }
254480093f4SDimitry Andric   if (isBehindPastTheEnd(State, *PosAfter)) {
255480093f4SDimitry Andric     auto *N = C.generateErrorNode(State);
256480093f4SDimitry Andric     if (!N)
257480093f4SDimitry Andric       return;
258480093f4SDimitry Andric     reportBug("Iterator incremented behind the past-the-end "
259480093f4SDimitry Andric                         "iterator.", LHS, C, N);
260480093f4SDimitry Andric   }
261480093f4SDimitry Andric }
262480093f4SDimitry Andric 
2635ffd83dbSDimitry Andric void IteratorRangeChecker::verifyAdvance(CheckerContext &C, SVal LHS,
2645ffd83dbSDimitry Andric                                          SVal RHS) const {
2655ffd83dbSDimitry Andric   verifyRandomIncrOrDecr(C, OO_PlusEqual, LHS, RHS);
2665ffd83dbSDimitry Andric }
2675ffd83dbSDimitry Andric 
2685ffd83dbSDimitry Andric void IteratorRangeChecker::verifyPrev(CheckerContext &C, SVal LHS,
2695ffd83dbSDimitry Andric                                       SVal RHS) const {
2705ffd83dbSDimitry Andric   verifyRandomIncrOrDecr(C, OO_Minus, LHS, RHS);
2715ffd83dbSDimitry Andric }
2725ffd83dbSDimitry Andric 
2735ffd83dbSDimitry Andric void IteratorRangeChecker::verifyNext(CheckerContext &C, SVal LHS,
2745ffd83dbSDimitry Andric                                       SVal RHS) const {
2755ffd83dbSDimitry Andric   verifyRandomIncrOrDecr(C, OO_Plus, LHS, RHS);
2765ffd83dbSDimitry Andric }
2775ffd83dbSDimitry Andric 
2785ffd83dbSDimitry Andric void IteratorRangeChecker::reportBug(const StringRef &Message, SVal Val,
2795ffd83dbSDimitry Andric                                      CheckerContext &C,
280480093f4SDimitry Andric                                      ExplodedNode *ErrNode) const {
281480093f4SDimitry Andric   auto R = std::make_unique<PathSensitiveBugReport>(*OutOfRangeBugType, Message,
282480093f4SDimitry Andric                                                     ErrNode);
2835ffd83dbSDimitry Andric 
2845ffd83dbSDimitry Andric   const auto *Pos = getIteratorPosition(C.getState(), Val);
2855ffd83dbSDimitry Andric   assert(Pos && "Iterator without known position cannot be out-of-range.");
2865ffd83dbSDimitry Andric 
287480093f4SDimitry Andric   R->markInteresting(Val);
2885ffd83dbSDimitry Andric   R->markInteresting(Pos->getContainer());
289480093f4SDimitry Andric   C.emitReport(std::move(R));
290480093f4SDimitry Andric }
291480093f4SDimitry Andric 
292480093f4SDimitry Andric namespace {
293480093f4SDimitry Andric 
294480093f4SDimitry Andric bool isLess(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2);
295480093f4SDimitry Andric bool isGreater(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2);
296480093f4SDimitry Andric bool isEqual(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2);
297480093f4SDimitry Andric 
298480093f4SDimitry Andric bool isZero(ProgramStateRef State, const NonLoc &Val) {
299480093f4SDimitry Andric   auto &BVF = State->getBasicVals();
300480093f4SDimitry Andric   return compare(State, Val,
301480093f4SDimitry Andric                  nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))),
302480093f4SDimitry Andric                  BO_EQ);
303480093f4SDimitry Andric }
304480093f4SDimitry Andric 
305480093f4SDimitry Andric bool isPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos) {
306480093f4SDimitry Andric   const auto *Cont = Pos.getContainer();
307480093f4SDimitry Andric   const auto *CData = getContainerData(State, Cont);
308480093f4SDimitry Andric   if (!CData)
309480093f4SDimitry Andric     return false;
310480093f4SDimitry Andric 
311480093f4SDimitry Andric   const auto End = CData->getEnd();
312480093f4SDimitry Andric   if (End) {
313480093f4SDimitry Andric     if (isEqual(State, Pos.getOffset(), End)) {
314480093f4SDimitry Andric       return true;
315480093f4SDimitry Andric     }
316480093f4SDimitry Andric   }
317480093f4SDimitry Andric 
318480093f4SDimitry Andric   return false;
319480093f4SDimitry Andric }
320480093f4SDimitry Andric 
321480093f4SDimitry Andric bool isAheadOfRange(ProgramStateRef State, const IteratorPosition &Pos) {
322480093f4SDimitry Andric   const auto *Cont = Pos.getContainer();
323480093f4SDimitry Andric   const auto *CData = getContainerData(State, Cont);
324480093f4SDimitry Andric   if (!CData)
325480093f4SDimitry Andric     return false;
326480093f4SDimitry Andric 
327480093f4SDimitry Andric   const auto Beg = CData->getBegin();
328480093f4SDimitry Andric   if (Beg) {
329480093f4SDimitry Andric     if (isLess(State, Pos.getOffset(), Beg)) {
330480093f4SDimitry Andric       return true;
331480093f4SDimitry Andric     }
332480093f4SDimitry Andric   }
333480093f4SDimitry Andric 
334480093f4SDimitry Andric   return false;
335480093f4SDimitry Andric }
336480093f4SDimitry Andric 
337480093f4SDimitry Andric bool isBehindPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos) {
338480093f4SDimitry Andric   const auto *Cont = Pos.getContainer();
339480093f4SDimitry Andric   const auto *CData = getContainerData(State, Cont);
340480093f4SDimitry Andric   if (!CData)
341480093f4SDimitry Andric     return false;
342480093f4SDimitry Andric 
343480093f4SDimitry Andric   const auto End = CData->getEnd();
344480093f4SDimitry Andric   if (End) {
345480093f4SDimitry Andric     if (isGreater(State, Pos.getOffset(), End)) {
346480093f4SDimitry Andric       return true;
347480093f4SDimitry Andric     }
348480093f4SDimitry Andric   }
349480093f4SDimitry Andric 
350480093f4SDimitry Andric   return false;
351480093f4SDimitry Andric }
352480093f4SDimitry Andric 
353480093f4SDimitry Andric bool isLess(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) {
354480093f4SDimitry Andric   return compare(State, Sym1, Sym2, BO_LT);
355480093f4SDimitry Andric }
356480093f4SDimitry Andric 
357480093f4SDimitry Andric bool isGreater(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) {
358480093f4SDimitry Andric   return compare(State, Sym1, Sym2, BO_GT);
359480093f4SDimitry Andric }
360480093f4SDimitry Andric 
361480093f4SDimitry Andric bool isEqual(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) {
362480093f4SDimitry Andric   return compare(State, Sym1, Sym2, BO_EQ);
363480093f4SDimitry Andric }
364480093f4SDimitry Andric 
365480093f4SDimitry Andric } // namespace
366480093f4SDimitry Andric 
367480093f4SDimitry Andric void ento::registerIteratorRangeChecker(CheckerManager &mgr) {
368480093f4SDimitry Andric   mgr.registerChecker<IteratorRangeChecker>();
369480093f4SDimitry Andric }
370480093f4SDimitry Andric 
3715ffd83dbSDimitry Andric bool ento::shouldRegisterIteratorRangeChecker(const CheckerManager &mgr) {
372480093f4SDimitry Andric   return true;
373480093f4SDimitry Andric }
374