xref: /freebsd-src/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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"
17349cc55cSDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
18480093f4SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
19480093f4SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
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 
35647cbc5dSDimitry Andric   const BugType OutOfRangeBugType{this, "Iterator out of range",
36647cbc5dSDimitry Andric                                   "Misuse of STL APIs"};
37480093f4SDimitry Andric 
385ffd83dbSDimitry Andric   void verifyDereference(CheckerContext &C, SVal Val) const;
395ffd83dbSDimitry Andric   void verifyIncrement(CheckerContext &C, SVal Iter) const;
405ffd83dbSDimitry Andric   void verifyDecrement(CheckerContext &C, SVal Iter) const;
41480093f4SDimitry Andric   void verifyRandomIncrOrDecr(CheckerContext &C, OverloadedOperatorKind Op,
425ffd83dbSDimitry Andric                               SVal LHS, SVal RHS) const;
435ffd83dbSDimitry Andric   void verifyAdvance(CheckerContext &C, SVal LHS, SVal RHS) const;
445ffd83dbSDimitry Andric   void verifyPrev(CheckerContext &C, SVal LHS, SVal RHS) const;
455ffd83dbSDimitry Andric   void verifyNext(CheckerContext &C, SVal LHS, SVal RHS) const;
46647cbc5dSDimitry Andric   void reportBug(StringRef Message, SVal Val, CheckerContext &C,
475ffd83dbSDimitry Andric                  ExplodedNode *ErrNode) const;
485ffd83dbSDimitry Andric 
49480093f4SDimitry Andric public:
50480093f4SDimitry Andric   void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
515ffd83dbSDimitry Andric   void checkPreStmt(const UnaryOperator *UO, CheckerContext &C) const;
525ffd83dbSDimitry Andric   void checkPreStmt(const BinaryOperator *BO, CheckerContext &C) const;
535ffd83dbSDimitry Andric   void checkPreStmt(const ArraySubscriptExpr *ASE, CheckerContext &C) const;
545ffd83dbSDimitry Andric   void checkPreStmt(const MemberExpr *ME, CheckerContext &C) const;
55480093f4SDimitry Andric 
565ffd83dbSDimitry Andric   using AdvanceFn = void (IteratorRangeChecker::*)(CheckerContext &, SVal,
575ffd83dbSDimitry Andric                                                    SVal) const;
585ffd83dbSDimitry Andric 
59*0fca6ea1SDimitry Andric   // FIXME: these three functions are also listed in IteratorModeling.cpp,
60*0fca6ea1SDimitry Andric   // perhaps unify their handling?
615ffd83dbSDimitry Andric   CallDescriptionMap<AdvanceFn> AdvanceFunctions = {
62*0fca6ea1SDimitry Andric       {{CDM::SimpleFunc, {"std", "advance"}, 2},
63*0fca6ea1SDimitry Andric        &IteratorRangeChecker::verifyAdvance},
64*0fca6ea1SDimitry Andric       {{CDM::SimpleFunc, {"std", "prev"}, 2},
65*0fca6ea1SDimitry Andric        &IteratorRangeChecker::verifyPrev},
66*0fca6ea1SDimitry Andric       {{CDM::SimpleFunc, {"std", "next"}, 2},
67*0fca6ea1SDimitry Andric        &IteratorRangeChecker::verifyNext},
685ffd83dbSDimitry Andric   };
69480093f4SDimitry Andric };
70480093f4SDimitry Andric 
71480093f4SDimitry Andric bool isPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos);
72480093f4SDimitry Andric bool isAheadOfRange(ProgramStateRef State, const IteratorPosition &Pos);
73480093f4SDimitry Andric bool isBehindPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos);
74647cbc5dSDimitry Andric bool isZero(ProgramStateRef State, NonLoc Val);
75480093f4SDimitry Andric 
76480093f4SDimitry Andric } // namespace
77480093f4SDimitry Andric 
78480093f4SDimitry Andric void IteratorRangeChecker::checkPreCall(const CallEvent &Call,
79480093f4SDimitry Andric                                         CheckerContext &C) const {
80480093f4SDimitry Andric   // Check for out of range access
81480093f4SDimitry Andric   const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
82480093f4SDimitry Andric   if (!Func)
83480093f4SDimitry Andric     return;
84480093f4SDimitry Andric 
85480093f4SDimitry Andric   if (Func->isOverloadedOperator()) {
86480093f4SDimitry Andric     if (isIncrementOperator(Func->getOverloadedOperator())) {
87480093f4SDimitry Andric       // Check for out-of-range incrementions
88480093f4SDimitry Andric       if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
89480093f4SDimitry Andric         verifyIncrement(C, InstCall->getCXXThisVal());
90480093f4SDimitry Andric       } else {
91480093f4SDimitry Andric         if (Call.getNumArgs() >= 1) {
92480093f4SDimitry Andric           verifyIncrement(C, Call.getArgSVal(0));
93480093f4SDimitry Andric         }
94480093f4SDimitry Andric       }
95480093f4SDimitry Andric     } else if (isDecrementOperator(Func->getOverloadedOperator())) {
96480093f4SDimitry Andric       // Check for out-of-range decrementions
97480093f4SDimitry Andric       if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
98480093f4SDimitry Andric         verifyDecrement(C, InstCall->getCXXThisVal());
99480093f4SDimitry Andric       } else {
100480093f4SDimitry Andric         if (Call.getNumArgs() >= 1) {
101480093f4SDimitry Andric           verifyDecrement(C, Call.getArgSVal(0));
102480093f4SDimitry Andric         }
103480093f4SDimitry Andric       }
104480093f4SDimitry Andric     } else if (isRandomIncrOrDecrOperator(Func->getOverloadedOperator())) {
105480093f4SDimitry Andric       if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
106480093f4SDimitry Andric         // Check for out-of-range incrementions and decrementions
107480093f4SDimitry Andric         if (Call.getNumArgs() >= 1 &&
108480093f4SDimitry Andric             Call.getArgExpr(0)->getType()->isIntegralOrEnumerationType()) {
109480093f4SDimitry Andric           verifyRandomIncrOrDecr(C, Func->getOverloadedOperator(),
110480093f4SDimitry Andric                                  InstCall->getCXXThisVal(),
111480093f4SDimitry Andric                                  Call.getArgSVal(0));
112480093f4SDimitry Andric         }
113480093f4SDimitry Andric       } else {
114480093f4SDimitry Andric         if (Call.getNumArgs() >= 2 &&
115480093f4SDimitry Andric             Call.getArgExpr(1)->getType()->isIntegralOrEnumerationType()) {
116480093f4SDimitry Andric           verifyRandomIncrOrDecr(C, Func->getOverloadedOperator(),
117480093f4SDimitry Andric                                  Call.getArgSVal(0), Call.getArgSVal(1));
118480093f4SDimitry Andric         }
119480093f4SDimitry Andric       }
120480093f4SDimitry Andric     } else if (isDereferenceOperator(Func->getOverloadedOperator())) {
121480093f4SDimitry Andric       // Check for dereference of out-of-range iterators
122480093f4SDimitry Andric       if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
123480093f4SDimitry Andric         verifyDereference(C, InstCall->getCXXThisVal());
124480093f4SDimitry Andric       } else {
125480093f4SDimitry Andric         verifyDereference(C, Call.getArgSVal(0));
126480093f4SDimitry Andric       }
127480093f4SDimitry Andric     }
1285ffd83dbSDimitry Andric   } else {
1295ffd83dbSDimitry Andric     const AdvanceFn *Verifier = AdvanceFunctions.lookup(Call);
1305ffd83dbSDimitry Andric     if (Verifier) {
1315ffd83dbSDimitry Andric       if (Call.getNumArgs() > 1) {
1325ffd83dbSDimitry Andric         (this->**Verifier)(C, Call.getArgSVal(0), Call.getArgSVal(1));
1335ffd83dbSDimitry Andric       } else {
1345ffd83dbSDimitry Andric         auto &BVF = C.getSValBuilder().getBasicValueFactory();
1355ffd83dbSDimitry Andric         (this->**Verifier)(
1365ffd83dbSDimitry Andric             C, Call.getArgSVal(0),
1375ffd83dbSDimitry Andric             nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
1385ffd83dbSDimitry Andric       }
1395ffd83dbSDimitry Andric     }
140480093f4SDimitry Andric   }
141480093f4SDimitry Andric }
142480093f4SDimitry Andric 
1435ffd83dbSDimitry Andric void IteratorRangeChecker::checkPreStmt(const UnaryOperator *UO,
1445ffd83dbSDimitry Andric                                         CheckerContext &C) const {
1455ffd83dbSDimitry Andric   if (isa<CXXThisExpr>(UO->getSubExpr()))
1465ffd83dbSDimitry Andric     return;
1475ffd83dbSDimitry Andric 
1485ffd83dbSDimitry Andric   ProgramStateRef State = C.getState();
1495ffd83dbSDimitry Andric   UnaryOperatorKind OK = UO->getOpcode();
1505ffd83dbSDimitry Andric   SVal SubVal = State->getSVal(UO->getSubExpr(), C.getLocationContext());
1515ffd83dbSDimitry Andric 
1525ffd83dbSDimitry Andric   if (isDereferenceOperator(OK)) {
1535ffd83dbSDimitry Andric     verifyDereference(C, SubVal);
1545ffd83dbSDimitry Andric   } else if (isIncrementOperator(OK)) {
1555ffd83dbSDimitry Andric     verifyIncrement(C, SubVal);
1565ffd83dbSDimitry Andric   } else if (isDecrementOperator(OK)) {
1575ffd83dbSDimitry Andric     verifyDecrement(C, SubVal);
1585ffd83dbSDimitry Andric   }
1595ffd83dbSDimitry Andric }
1605ffd83dbSDimitry Andric 
1615ffd83dbSDimitry Andric void IteratorRangeChecker::checkPreStmt(const BinaryOperator *BO,
1625ffd83dbSDimitry Andric                                         CheckerContext &C) const {
1635ffd83dbSDimitry Andric   ProgramStateRef State = C.getState();
1645ffd83dbSDimitry Andric   BinaryOperatorKind OK = BO->getOpcode();
1655ffd83dbSDimitry Andric   SVal LVal = State->getSVal(BO->getLHS(), C.getLocationContext());
1665ffd83dbSDimitry Andric 
1675ffd83dbSDimitry Andric   if (isDereferenceOperator(OK)) {
1685ffd83dbSDimitry Andric     verifyDereference(C, LVal);
1695ffd83dbSDimitry Andric   } else if (isRandomIncrOrDecrOperator(OK)) {
1705ffd83dbSDimitry Andric     SVal RVal = State->getSVal(BO->getRHS(), C.getLocationContext());
171e8d8bef9SDimitry Andric     if (!BO->getRHS()->getType()->isIntegralOrEnumerationType())
172e8d8bef9SDimitry Andric       return;
1735ffd83dbSDimitry Andric     verifyRandomIncrOrDecr(C, BinaryOperator::getOverloadedOperator(OK), LVal,
1745ffd83dbSDimitry Andric                            RVal);
1755ffd83dbSDimitry Andric   }
1765ffd83dbSDimitry Andric }
1775ffd83dbSDimitry Andric 
1785ffd83dbSDimitry Andric void IteratorRangeChecker::checkPreStmt(const ArraySubscriptExpr *ASE,
1795ffd83dbSDimitry Andric                                         CheckerContext &C) const {
1805ffd83dbSDimitry Andric   ProgramStateRef State = C.getState();
1815ffd83dbSDimitry Andric   SVal LVal = State->getSVal(ASE->getLHS(), C.getLocationContext());
1825ffd83dbSDimitry Andric   verifyDereference(C, LVal);
1835ffd83dbSDimitry Andric }
1845ffd83dbSDimitry Andric 
1855ffd83dbSDimitry Andric void IteratorRangeChecker::checkPreStmt(const MemberExpr *ME,
1865ffd83dbSDimitry Andric                                         CheckerContext &C) const {
1875ffd83dbSDimitry Andric   if (!ME->isArrow() || ME->isImplicitAccess())
1885ffd83dbSDimitry Andric     return;
1895ffd83dbSDimitry Andric 
1905ffd83dbSDimitry Andric   ProgramStateRef State = C.getState();
1915ffd83dbSDimitry Andric   SVal BaseVal = State->getSVal(ME->getBase(), C.getLocationContext());
1925ffd83dbSDimitry Andric   verifyDereference(C, BaseVal);
1935ffd83dbSDimitry Andric }
1945ffd83dbSDimitry Andric 
195480093f4SDimitry Andric void IteratorRangeChecker::verifyDereference(CheckerContext &C,
1965ffd83dbSDimitry Andric                                              SVal Val) const {
197480093f4SDimitry Andric   auto State = C.getState();
198480093f4SDimitry Andric   const auto *Pos = getIteratorPosition(State, Val);
199480093f4SDimitry Andric   if (Pos && isPastTheEnd(State, *Pos)) {
200480093f4SDimitry Andric     auto *N = C.generateErrorNode(State);
201480093f4SDimitry Andric     if (!N)
202480093f4SDimitry Andric       return;
203480093f4SDimitry Andric     reportBug("Past-the-end iterator dereferenced.", Val, C, N);
204480093f4SDimitry Andric     return;
205480093f4SDimitry Andric   }
206480093f4SDimitry Andric }
207480093f4SDimitry Andric 
2085ffd83dbSDimitry Andric void IteratorRangeChecker::verifyIncrement(CheckerContext &C, SVal Iter) const {
209480093f4SDimitry Andric   auto &BVF = C.getSValBuilder().getBasicValueFactory();
210480093f4SDimitry Andric   verifyRandomIncrOrDecr(C, OO_Plus, Iter,
211480093f4SDimitry Andric                      nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
212480093f4SDimitry Andric }
213480093f4SDimitry Andric 
2145ffd83dbSDimitry Andric void IteratorRangeChecker::verifyDecrement(CheckerContext &C, SVal Iter) const {
215480093f4SDimitry Andric   auto &BVF = C.getSValBuilder().getBasicValueFactory();
216480093f4SDimitry Andric   verifyRandomIncrOrDecr(C, OO_Minus, Iter,
217480093f4SDimitry Andric                      nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
218480093f4SDimitry Andric }
219480093f4SDimitry Andric 
220480093f4SDimitry Andric void IteratorRangeChecker::verifyRandomIncrOrDecr(CheckerContext &C,
221480093f4SDimitry Andric                                                   OverloadedOperatorKind Op,
2225ffd83dbSDimitry Andric                                                   SVal LHS, SVal RHS) const {
223480093f4SDimitry Andric   auto State = C.getState();
224480093f4SDimitry Andric 
225480093f4SDimitry Andric   auto Value = RHS;
226480093f4SDimitry Andric   if (auto ValAsLoc = RHS.getAs<Loc>()) {
227480093f4SDimitry Andric     Value = State->getRawSVal(*ValAsLoc);
228480093f4SDimitry Andric   }
229480093f4SDimitry Andric 
2305f757f3fSDimitry Andric   if (Value.isUnknownOrUndef() || !isa<NonLoc>(Value))
231480093f4SDimitry Andric     return;
232480093f4SDimitry Andric 
233480093f4SDimitry Andric   // Incremention or decremention by 0 is never a bug.
234480093f4SDimitry Andric   if (isZero(State, Value.castAs<NonLoc>()))
235480093f4SDimitry Andric     return;
236480093f4SDimitry Andric 
237480093f4SDimitry Andric   // The result may be the past-end iterator of the container, but any other
238480093f4SDimitry Andric   // out of range position is undefined behaviour
239480093f4SDimitry Andric   auto StateAfter = advancePosition(State, LHS, Op, Value);
240480093f4SDimitry Andric   if (!StateAfter)
241480093f4SDimitry Andric     return;
242480093f4SDimitry Andric 
243480093f4SDimitry Andric   const auto *PosAfter = getIteratorPosition(StateAfter, LHS);
244480093f4SDimitry Andric   assert(PosAfter &&
245480093f4SDimitry Andric          "Iterator should have position after successful advancement");
246480093f4SDimitry Andric   if (isAheadOfRange(State, *PosAfter)) {
247480093f4SDimitry Andric     auto *N = C.generateErrorNode(State);
248480093f4SDimitry Andric     if (!N)
249480093f4SDimitry Andric       return;
250480093f4SDimitry Andric     reportBug("Iterator decremented ahead of its valid range.", LHS,
251480093f4SDimitry Andric                         C, N);
252480093f4SDimitry Andric   }
253480093f4SDimitry Andric   if (isBehindPastTheEnd(State, *PosAfter)) {
254480093f4SDimitry Andric     auto *N = C.generateErrorNode(State);
255480093f4SDimitry Andric     if (!N)
256480093f4SDimitry Andric       return;
257480093f4SDimitry Andric     reportBug("Iterator incremented behind the past-the-end "
258480093f4SDimitry Andric                         "iterator.", LHS, C, N);
259480093f4SDimitry Andric   }
260480093f4SDimitry Andric }
261480093f4SDimitry Andric 
2625ffd83dbSDimitry Andric void IteratorRangeChecker::verifyAdvance(CheckerContext &C, SVal LHS,
2635ffd83dbSDimitry Andric                                          SVal RHS) const {
2645ffd83dbSDimitry Andric   verifyRandomIncrOrDecr(C, OO_PlusEqual, LHS, RHS);
2655ffd83dbSDimitry Andric }
2665ffd83dbSDimitry Andric 
2675ffd83dbSDimitry Andric void IteratorRangeChecker::verifyPrev(CheckerContext &C, SVal LHS,
2685ffd83dbSDimitry Andric                                       SVal RHS) const {
2695ffd83dbSDimitry Andric   verifyRandomIncrOrDecr(C, OO_Minus, LHS, RHS);
2705ffd83dbSDimitry Andric }
2715ffd83dbSDimitry Andric 
2725ffd83dbSDimitry Andric void IteratorRangeChecker::verifyNext(CheckerContext &C, SVal LHS,
2735ffd83dbSDimitry Andric                                       SVal RHS) const {
2745ffd83dbSDimitry Andric   verifyRandomIncrOrDecr(C, OO_Plus, LHS, RHS);
2755ffd83dbSDimitry Andric }
2765ffd83dbSDimitry Andric 
277647cbc5dSDimitry Andric void IteratorRangeChecker::reportBug(StringRef Message, SVal Val,
2785ffd83dbSDimitry Andric                                      CheckerContext &C,
279480093f4SDimitry Andric                                      ExplodedNode *ErrNode) const {
280647cbc5dSDimitry Andric   auto R = std::make_unique<PathSensitiveBugReport>(OutOfRangeBugType, Message,
281480093f4SDimitry Andric                                                     ErrNode);
2825ffd83dbSDimitry Andric 
2835ffd83dbSDimitry Andric   const auto *Pos = getIteratorPosition(C.getState(), Val);
2845ffd83dbSDimitry Andric   assert(Pos && "Iterator without known position cannot be out-of-range.");
2855ffd83dbSDimitry Andric 
286480093f4SDimitry Andric   R->markInteresting(Val);
2875ffd83dbSDimitry Andric   R->markInteresting(Pos->getContainer());
288480093f4SDimitry Andric   C.emitReport(std::move(R));
289480093f4SDimitry Andric }
290480093f4SDimitry Andric 
291480093f4SDimitry Andric namespace {
292480093f4SDimitry Andric 
293480093f4SDimitry Andric bool isLess(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2);
294480093f4SDimitry Andric bool isGreater(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2);
295480093f4SDimitry Andric bool isEqual(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2);
296480093f4SDimitry Andric 
297647cbc5dSDimitry Andric bool isZero(ProgramStateRef State, NonLoc Val) {
298480093f4SDimitry Andric   auto &BVF = State->getBasicVals();
299480093f4SDimitry Andric   return compare(State, Val,
300480093f4SDimitry Andric                  nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))),
301480093f4SDimitry Andric                  BO_EQ);
302480093f4SDimitry Andric }
303480093f4SDimitry Andric 
304480093f4SDimitry Andric bool isPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos) {
305480093f4SDimitry Andric   const auto *Cont = Pos.getContainer();
306480093f4SDimitry Andric   const auto *CData = getContainerData(State, Cont);
307480093f4SDimitry Andric   if (!CData)
308480093f4SDimitry Andric     return false;
309480093f4SDimitry Andric 
310480093f4SDimitry Andric   const auto End = CData->getEnd();
311480093f4SDimitry Andric   if (End) {
312480093f4SDimitry Andric     if (isEqual(State, Pos.getOffset(), End)) {
313480093f4SDimitry Andric       return true;
314480093f4SDimitry Andric     }
315480093f4SDimitry Andric   }
316480093f4SDimitry Andric 
317480093f4SDimitry Andric   return false;
318480093f4SDimitry Andric }
319480093f4SDimitry Andric 
320480093f4SDimitry Andric bool isAheadOfRange(ProgramStateRef State, const IteratorPosition &Pos) {
321480093f4SDimitry Andric   const auto *Cont = Pos.getContainer();
322480093f4SDimitry Andric   const auto *CData = getContainerData(State, Cont);
323480093f4SDimitry Andric   if (!CData)
324480093f4SDimitry Andric     return false;
325480093f4SDimitry Andric 
326480093f4SDimitry Andric   const auto Beg = CData->getBegin();
327480093f4SDimitry Andric   if (Beg) {
328480093f4SDimitry Andric     if (isLess(State, Pos.getOffset(), Beg)) {
329480093f4SDimitry Andric       return true;
330480093f4SDimitry Andric     }
331480093f4SDimitry Andric   }
332480093f4SDimitry Andric 
333480093f4SDimitry Andric   return false;
334480093f4SDimitry Andric }
335480093f4SDimitry Andric 
336480093f4SDimitry Andric bool isBehindPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos) {
337480093f4SDimitry Andric   const auto *Cont = Pos.getContainer();
338480093f4SDimitry Andric   const auto *CData = getContainerData(State, Cont);
339480093f4SDimitry Andric   if (!CData)
340480093f4SDimitry Andric     return false;
341480093f4SDimitry Andric 
342480093f4SDimitry Andric   const auto End = CData->getEnd();
343480093f4SDimitry Andric   if (End) {
344480093f4SDimitry Andric     if (isGreater(State, Pos.getOffset(), End)) {
345480093f4SDimitry Andric       return true;
346480093f4SDimitry Andric     }
347480093f4SDimitry Andric   }
348480093f4SDimitry Andric 
349480093f4SDimitry Andric   return false;
350480093f4SDimitry Andric }
351480093f4SDimitry Andric 
352480093f4SDimitry Andric bool isLess(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) {
353480093f4SDimitry Andric   return compare(State, Sym1, Sym2, BO_LT);
354480093f4SDimitry Andric }
355480093f4SDimitry Andric 
356480093f4SDimitry Andric bool isGreater(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) {
357480093f4SDimitry Andric   return compare(State, Sym1, Sym2, BO_GT);
358480093f4SDimitry Andric }
359480093f4SDimitry Andric 
360480093f4SDimitry Andric bool isEqual(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) {
361480093f4SDimitry Andric   return compare(State, Sym1, Sym2, BO_EQ);
362480093f4SDimitry Andric }
363480093f4SDimitry Andric 
364480093f4SDimitry Andric } // namespace
365480093f4SDimitry Andric 
366480093f4SDimitry Andric void ento::registerIteratorRangeChecker(CheckerManager &mgr) {
367480093f4SDimitry Andric   mgr.registerChecker<IteratorRangeChecker>();
368480093f4SDimitry Andric }
369480093f4SDimitry Andric 
3705ffd83dbSDimitry Andric bool ento::shouldRegisterIteratorRangeChecker(const CheckerManager &mgr) {
371480093f4SDimitry Andric   return true;
372480093f4SDimitry Andric }
373