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 
35*647cbc5dSDimitry Andric   const BugType OutOfRangeBugType{this, "Iterator out of range",
36*647cbc5dSDimitry 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;
46*647cbc5dSDimitry 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 
595ffd83dbSDimitry Andric   CallDescriptionMap<AdvanceFn> AdvanceFunctions = {
605ffd83dbSDimitry Andric       {{{"std", "advance"}, 2}, &IteratorRangeChecker::verifyAdvance},
615ffd83dbSDimitry Andric       {{{"std", "prev"}, 2}, &IteratorRangeChecker::verifyPrev},
625ffd83dbSDimitry Andric       {{{"std", "next"}, 2}, &IteratorRangeChecker::verifyNext},
635ffd83dbSDimitry Andric   };
64480093f4SDimitry Andric };
65480093f4SDimitry Andric 
66480093f4SDimitry Andric bool isPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos);
67480093f4SDimitry Andric bool isAheadOfRange(ProgramStateRef State, const IteratorPosition &Pos);
68480093f4SDimitry Andric bool isBehindPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos);
69*647cbc5dSDimitry Andric bool isZero(ProgramStateRef State, NonLoc Val);
70480093f4SDimitry Andric 
71480093f4SDimitry Andric } //namespace
72480093f4SDimitry Andric 
checkPreCall(const CallEvent & Call,CheckerContext & C) const73480093f4SDimitry Andric void IteratorRangeChecker::checkPreCall(const CallEvent &Call,
74480093f4SDimitry Andric                                         CheckerContext &C) const {
75480093f4SDimitry Andric   // Check for out of range access
76480093f4SDimitry Andric   const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
77480093f4SDimitry Andric   if (!Func)
78480093f4SDimitry Andric     return;
79480093f4SDimitry Andric 
80480093f4SDimitry Andric   if (Func->isOverloadedOperator()) {
81480093f4SDimitry Andric     if (isIncrementOperator(Func->getOverloadedOperator())) {
82480093f4SDimitry Andric       // Check for out-of-range incrementions
83480093f4SDimitry Andric       if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
84480093f4SDimitry Andric         verifyIncrement(C, InstCall->getCXXThisVal());
85480093f4SDimitry Andric       } else {
86480093f4SDimitry Andric         if (Call.getNumArgs() >= 1) {
87480093f4SDimitry Andric           verifyIncrement(C, Call.getArgSVal(0));
88480093f4SDimitry Andric         }
89480093f4SDimitry Andric       }
90480093f4SDimitry Andric     } else if (isDecrementOperator(Func->getOverloadedOperator())) {
91480093f4SDimitry Andric       // Check for out-of-range decrementions
92480093f4SDimitry Andric       if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
93480093f4SDimitry Andric         verifyDecrement(C, InstCall->getCXXThisVal());
94480093f4SDimitry Andric       } else {
95480093f4SDimitry Andric         if (Call.getNumArgs() >= 1) {
96480093f4SDimitry Andric           verifyDecrement(C, Call.getArgSVal(0));
97480093f4SDimitry Andric         }
98480093f4SDimitry Andric       }
99480093f4SDimitry Andric     } else if (isRandomIncrOrDecrOperator(Func->getOverloadedOperator())) {
100480093f4SDimitry Andric       if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
101480093f4SDimitry Andric         // Check for out-of-range incrementions and decrementions
102480093f4SDimitry Andric         if (Call.getNumArgs() >= 1 &&
103480093f4SDimitry Andric             Call.getArgExpr(0)->getType()->isIntegralOrEnumerationType()) {
104480093f4SDimitry Andric           verifyRandomIncrOrDecr(C, Func->getOverloadedOperator(),
105480093f4SDimitry Andric                                  InstCall->getCXXThisVal(),
106480093f4SDimitry Andric                                  Call.getArgSVal(0));
107480093f4SDimitry Andric         }
108480093f4SDimitry Andric       } else {
109480093f4SDimitry Andric         if (Call.getNumArgs() >= 2 &&
110480093f4SDimitry Andric             Call.getArgExpr(1)->getType()->isIntegralOrEnumerationType()) {
111480093f4SDimitry Andric           verifyRandomIncrOrDecr(C, Func->getOverloadedOperator(),
112480093f4SDimitry Andric                                  Call.getArgSVal(0), Call.getArgSVal(1));
113480093f4SDimitry Andric         }
114480093f4SDimitry Andric       }
115480093f4SDimitry Andric     } else if (isDereferenceOperator(Func->getOverloadedOperator())) {
116480093f4SDimitry Andric       // Check for dereference of out-of-range iterators
117480093f4SDimitry Andric       if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
118480093f4SDimitry Andric         verifyDereference(C, InstCall->getCXXThisVal());
119480093f4SDimitry Andric       } else {
120480093f4SDimitry Andric         verifyDereference(C, Call.getArgSVal(0));
121480093f4SDimitry Andric       }
122480093f4SDimitry Andric     }
1235ffd83dbSDimitry Andric   } else {
1245ffd83dbSDimitry Andric     const AdvanceFn *Verifier = AdvanceFunctions.lookup(Call);
1255ffd83dbSDimitry Andric     if (Verifier) {
1265ffd83dbSDimitry Andric       if (Call.getNumArgs() > 1) {
1275ffd83dbSDimitry Andric         (this->**Verifier)(C, Call.getArgSVal(0), Call.getArgSVal(1));
1285ffd83dbSDimitry Andric       } else {
1295ffd83dbSDimitry Andric         auto &BVF = C.getSValBuilder().getBasicValueFactory();
1305ffd83dbSDimitry Andric         (this->**Verifier)(
1315ffd83dbSDimitry Andric             C, Call.getArgSVal(0),
1325ffd83dbSDimitry Andric             nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
1335ffd83dbSDimitry Andric       }
1345ffd83dbSDimitry Andric     }
135480093f4SDimitry Andric   }
136480093f4SDimitry Andric }
137480093f4SDimitry Andric 
checkPreStmt(const UnaryOperator * UO,CheckerContext & C) const1385ffd83dbSDimitry Andric void IteratorRangeChecker::checkPreStmt(const UnaryOperator *UO,
1395ffd83dbSDimitry Andric                                         CheckerContext &C) const {
1405ffd83dbSDimitry Andric   if (isa<CXXThisExpr>(UO->getSubExpr()))
1415ffd83dbSDimitry Andric     return;
1425ffd83dbSDimitry Andric 
1435ffd83dbSDimitry Andric   ProgramStateRef State = C.getState();
1445ffd83dbSDimitry Andric   UnaryOperatorKind OK = UO->getOpcode();
1455ffd83dbSDimitry Andric   SVal SubVal = State->getSVal(UO->getSubExpr(), C.getLocationContext());
1465ffd83dbSDimitry Andric 
1475ffd83dbSDimitry Andric   if (isDereferenceOperator(OK)) {
1485ffd83dbSDimitry Andric     verifyDereference(C, SubVal);
1495ffd83dbSDimitry Andric   } else if (isIncrementOperator(OK)) {
1505ffd83dbSDimitry Andric     verifyIncrement(C, SubVal);
1515ffd83dbSDimitry Andric   } else if (isDecrementOperator(OK)) {
1525ffd83dbSDimitry Andric     verifyDecrement(C, SubVal);
1535ffd83dbSDimitry Andric   }
1545ffd83dbSDimitry Andric }
1555ffd83dbSDimitry Andric 
checkPreStmt(const BinaryOperator * BO,CheckerContext & C) const1565ffd83dbSDimitry Andric void IteratorRangeChecker::checkPreStmt(const BinaryOperator *BO,
1575ffd83dbSDimitry Andric                                         CheckerContext &C) const {
1585ffd83dbSDimitry Andric   ProgramStateRef State = C.getState();
1595ffd83dbSDimitry Andric   BinaryOperatorKind OK = BO->getOpcode();
1605ffd83dbSDimitry Andric   SVal LVal = State->getSVal(BO->getLHS(), C.getLocationContext());
1615ffd83dbSDimitry Andric 
1625ffd83dbSDimitry Andric   if (isDereferenceOperator(OK)) {
1635ffd83dbSDimitry Andric     verifyDereference(C, LVal);
1645ffd83dbSDimitry Andric   } else if (isRandomIncrOrDecrOperator(OK)) {
1655ffd83dbSDimitry Andric     SVal RVal = State->getSVal(BO->getRHS(), C.getLocationContext());
166e8d8bef9SDimitry Andric     if (!BO->getRHS()->getType()->isIntegralOrEnumerationType())
167e8d8bef9SDimitry Andric       return;
1685ffd83dbSDimitry Andric     verifyRandomIncrOrDecr(C, BinaryOperator::getOverloadedOperator(OK), LVal,
1695ffd83dbSDimitry Andric                            RVal);
1705ffd83dbSDimitry Andric   }
1715ffd83dbSDimitry Andric }
1725ffd83dbSDimitry Andric 
checkPreStmt(const ArraySubscriptExpr * ASE,CheckerContext & C) const1735ffd83dbSDimitry Andric void IteratorRangeChecker::checkPreStmt(const ArraySubscriptExpr *ASE,
1745ffd83dbSDimitry Andric                                         CheckerContext &C) const {
1755ffd83dbSDimitry Andric   ProgramStateRef State = C.getState();
1765ffd83dbSDimitry Andric   SVal LVal = State->getSVal(ASE->getLHS(), C.getLocationContext());
1775ffd83dbSDimitry Andric   verifyDereference(C, LVal);
1785ffd83dbSDimitry Andric }
1795ffd83dbSDimitry Andric 
checkPreStmt(const MemberExpr * ME,CheckerContext & C) const1805ffd83dbSDimitry Andric void IteratorRangeChecker::checkPreStmt(const MemberExpr *ME,
1815ffd83dbSDimitry Andric                                         CheckerContext &C) const {
1825ffd83dbSDimitry Andric   if (!ME->isArrow() || ME->isImplicitAccess())
1835ffd83dbSDimitry Andric     return;
1845ffd83dbSDimitry Andric 
1855ffd83dbSDimitry Andric   ProgramStateRef State = C.getState();
1865ffd83dbSDimitry Andric   SVal BaseVal = State->getSVal(ME->getBase(), C.getLocationContext());
1875ffd83dbSDimitry Andric   verifyDereference(C, BaseVal);
1885ffd83dbSDimitry Andric }
1895ffd83dbSDimitry Andric 
verifyDereference(CheckerContext & C,SVal Val) const190480093f4SDimitry Andric void IteratorRangeChecker::verifyDereference(CheckerContext &C,
1915ffd83dbSDimitry Andric                                              SVal Val) const {
192480093f4SDimitry Andric   auto State = C.getState();
193480093f4SDimitry Andric   const auto *Pos = getIteratorPosition(State, Val);
194480093f4SDimitry Andric   if (Pos && isPastTheEnd(State, *Pos)) {
195480093f4SDimitry Andric     auto *N = C.generateErrorNode(State);
196480093f4SDimitry Andric     if (!N)
197480093f4SDimitry Andric       return;
198480093f4SDimitry Andric     reportBug("Past-the-end iterator dereferenced.", Val, C, N);
199480093f4SDimitry Andric     return;
200480093f4SDimitry Andric   }
201480093f4SDimitry Andric }
202480093f4SDimitry Andric 
verifyIncrement(CheckerContext & C,SVal Iter) const2035ffd83dbSDimitry Andric void IteratorRangeChecker::verifyIncrement(CheckerContext &C, SVal Iter) const {
204480093f4SDimitry Andric   auto &BVF = C.getSValBuilder().getBasicValueFactory();
205480093f4SDimitry Andric   verifyRandomIncrOrDecr(C, OO_Plus, Iter,
206480093f4SDimitry Andric                      nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
207480093f4SDimitry Andric }
208480093f4SDimitry Andric 
verifyDecrement(CheckerContext & C,SVal Iter) const2095ffd83dbSDimitry Andric void IteratorRangeChecker::verifyDecrement(CheckerContext &C, SVal Iter) const {
210480093f4SDimitry Andric   auto &BVF = C.getSValBuilder().getBasicValueFactory();
211480093f4SDimitry Andric   verifyRandomIncrOrDecr(C, OO_Minus, Iter,
212480093f4SDimitry Andric                      nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
213480093f4SDimitry Andric }
214480093f4SDimitry Andric 
verifyRandomIncrOrDecr(CheckerContext & C,OverloadedOperatorKind Op,SVal LHS,SVal RHS) const215480093f4SDimitry Andric void IteratorRangeChecker::verifyRandomIncrOrDecr(CheckerContext &C,
216480093f4SDimitry Andric                                                   OverloadedOperatorKind Op,
2175ffd83dbSDimitry Andric                                                   SVal LHS, SVal RHS) const {
218480093f4SDimitry Andric   auto State = C.getState();
219480093f4SDimitry Andric 
220480093f4SDimitry Andric   auto Value = RHS;
221480093f4SDimitry Andric   if (auto ValAsLoc = RHS.getAs<Loc>()) {
222480093f4SDimitry Andric     Value = State->getRawSVal(*ValAsLoc);
223480093f4SDimitry Andric   }
224480093f4SDimitry Andric 
2255f757f3fSDimitry Andric   if (Value.isUnknownOrUndef() || !isa<NonLoc>(Value))
226480093f4SDimitry Andric     return;
227480093f4SDimitry Andric 
228480093f4SDimitry Andric   // Incremention or decremention by 0 is never a bug.
229480093f4SDimitry Andric   if (isZero(State, Value.castAs<NonLoc>()))
230480093f4SDimitry Andric     return;
231480093f4SDimitry Andric 
232480093f4SDimitry Andric   // The result may be the past-end iterator of the container, but any other
233480093f4SDimitry Andric   // out of range position is undefined behaviour
234480093f4SDimitry Andric   auto StateAfter = advancePosition(State, LHS, Op, Value);
235480093f4SDimitry Andric   if (!StateAfter)
236480093f4SDimitry Andric     return;
237480093f4SDimitry Andric 
238480093f4SDimitry Andric   const auto *PosAfter = getIteratorPosition(StateAfter, LHS);
239480093f4SDimitry Andric   assert(PosAfter &&
240480093f4SDimitry Andric          "Iterator should have position after successful advancement");
241480093f4SDimitry Andric   if (isAheadOfRange(State, *PosAfter)) {
242480093f4SDimitry Andric     auto *N = C.generateErrorNode(State);
243480093f4SDimitry Andric     if (!N)
244480093f4SDimitry Andric       return;
245480093f4SDimitry Andric     reportBug("Iterator decremented ahead of its valid range.", LHS,
246480093f4SDimitry Andric                         C, N);
247480093f4SDimitry Andric   }
248480093f4SDimitry Andric   if (isBehindPastTheEnd(State, *PosAfter)) {
249480093f4SDimitry Andric     auto *N = C.generateErrorNode(State);
250480093f4SDimitry Andric     if (!N)
251480093f4SDimitry Andric       return;
252480093f4SDimitry Andric     reportBug("Iterator incremented behind the past-the-end "
253480093f4SDimitry Andric                         "iterator.", LHS, C, N);
254480093f4SDimitry Andric   }
255480093f4SDimitry Andric }
256480093f4SDimitry Andric 
verifyAdvance(CheckerContext & C,SVal LHS,SVal RHS) const2575ffd83dbSDimitry Andric void IteratorRangeChecker::verifyAdvance(CheckerContext &C, SVal LHS,
2585ffd83dbSDimitry Andric                                          SVal RHS) const {
2595ffd83dbSDimitry Andric   verifyRandomIncrOrDecr(C, OO_PlusEqual, LHS, RHS);
2605ffd83dbSDimitry Andric }
2615ffd83dbSDimitry Andric 
verifyPrev(CheckerContext & C,SVal LHS,SVal RHS) const2625ffd83dbSDimitry Andric void IteratorRangeChecker::verifyPrev(CheckerContext &C, SVal LHS,
2635ffd83dbSDimitry Andric                                       SVal RHS) const {
2645ffd83dbSDimitry Andric   verifyRandomIncrOrDecr(C, OO_Minus, LHS, RHS);
2655ffd83dbSDimitry Andric }
2665ffd83dbSDimitry Andric 
verifyNext(CheckerContext & C,SVal LHS,SVal RHS) const2675ffd83dbSDimitry Andric void IteratorRangeChecker::verifyNext(CheckerContext &C, SVal LHS,
2685ffd83dbSDimitry Andric                                       SVal RHS) const {
2695ffd83dbSDimitry Andric   verifyRandomIncrOrDecr(C, OO_Plus, LHS, RHS);
2705ffd83dbSDimitry Andric }
2715ffd83dbSDimitry Andric 
reportBug(StringRef Message,SVal Val,CheckerContext & C,ExplodedNode * ErrNode) const272*647cbc5dSDimitry Andric void IteratorRangeChecker::reportBug(StringRef Message, SVal Val,
2735ffd83dbSDimitry Andric                                      CheckerContext &C,
274480093f4SDimitry Andric                                      ExplodedNode *ErrNode) const {
275*647cbc5dSDimitry Andric   auto R = std::make_unique<PathSensitiveBugReport>(OutOfRangeBugType, Message,
276480093f4SDimitry Andric                                                     ErrNode);
2775ffd83dbSDimitry Andric 
2785ffd83dbSDimitry Andric   const auto *Pos = getIteratorPosition(C.getState(), Val);
2795ffd83dbSDimitry Andric   assert(Pos && "Iterator without known position cannot be out-of-range.");
2805ffd83dbSDimitry Andric 
281480093f4SDimitry Andric   R->markInteresting(Val);
2825ffd83dbSDimitry Andric   R->markInteresting(Pos->getContainer());
283480093f4SDimitry Andric   C.emitReport(std::move(R));
284480093f4SDimitry Andric }
285480093f4SDimitry Andric 
286480093f4SDimitry Andric namespace {
287480093f4SDimitry Andric 
288480093f4SDimitry Andric bool isLess(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2);
289480093f4SDimitry Andric bool isGreater(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2);
290480093f4SDimitry Andric bool isEqual(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2);
291480093f4SDimitry Andric 
isZero(ProgramStateRef State,NonLoc Val)292*647cbc5dSDimitry Andric bool isZero(ProgramStateRef State, NonLoc Val) {
293480093f4SDimitry Andric   auto &BVF = State->getBasicVals();
294480093f4SDimitry Andric   return compare(State, Val,
295480093f4SDimitry Andric                  nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))),
296480093f4SDimitry Andric                  BO_EQ);
297480093f4SDimitry Andric }
298480093f4SDimitry Andric 
isPastTheEnd(ProgramStateRef State,const IteratorPosition & Pos)299480093f4SDimitry Andric bool isPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos) {
300480093f4SDimitry Andric   const auto *Cont = Pos.getContainer();
301480093f4SDimitry Andric   const auto *CData = getContainerData(State, Cont);
302480093f4SDimitry Andric   if (!CData)
303480093f4SDimitry Andric     return false;
304480093f4SDimitry Andric 
305480093f4SDimitry Andric   const auto End = CData->getEnd();
306480093f4SDimitry Andric   if (End) {
307480093f4SDimitry Andric     if (isEqual(State, Pos.getOffset(), End)) {
308480093f4SDimitry Andric       return true;
309480093f4SDimitry Andric     }
310480093f4SDimitry Andric   }
311480093f4SDimitry Andric 
312480093f4SDimitry Andric   return false;
313480093f4SDimitry Andric }
314480093f4SDimitry Andric 
isAheadOfRange(ProgramStateRef State,const IteratorPosition & Pos)315480093f4SDimitry Andric bool isAheadOfRange(ProgramStateRef State, const IteratorPosition &Pos) {
316480093f4SDimitry Andric   const auto *Cont = Pos.getContainer();
317480093f4SDimitry Andric   const auto *CData = getContainerData(State, Cont);
318480093f4SDimitry Andric   if (!CData)
319480093f4SDimitry Andric     return false;
320480093f4SDimitry Andric 
321480093f4SDimitry Andric   const auto Beg = CData->getBegin();
322480093f4SDimitry Andric   if (Beg) {
323480093f4SDimitry Andric     if (isLess(State, Pos.getOffset(), Beg)) {
324480093f4SDimitry Andric       return true;
325480093f4SDimitry Andric     }
326480093f4SDimitry Andric   }
327480093f4SDimitry Andric 
328480093f4SDimitry Andric   return false;
329480093f4SDimitry Andric }
330480093f4SDimitry Andric 
isBehindPastTheEnd(ProgramStateRef State,const IteratorPosition & Pos)331480093f4SDimitry Andric bool isBehindPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos) {
332480093f4SDimitry Andric   const auto *Cont = Pos.getContainer();
333480093f4SDimitry Andric   const auto *CData = getContainerData(State, Cont);
334480093f4SDimitry Andric   if (!CData)
335480093f4SDimitry Andric     return false;
336480093f4SDimitry Andric 
337480093f4SDimitry Andric   const auto End = CData->getEnd();
338480093f4SDimitry Andric   if (End) {
339480093f4SDimitry Andric     if (isGreater(State, Pos.getOffset(), End)) {
340480093f4SDimitry Andric       return true;
341480093f4SDimitry Andric     }
342480093f4SDimitry Andric   }
343480093f4SDimitry Andric 
344480093f4SDimitry Andric   return false;
345480093f4SDimitry Andric }
346480093f4SDimitry Andric 
isLess(ProgramStateRef State,SymbolRef Sym1,SymbolRef Sym2)347480093f4SDimitry Andric bool isLess(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) {
348480093f4SDimitry Andric   return compare(State, Sym1, Sym2, BO_LT);
349480093f4SDimitry Andric }
350480093f4SDimitry Andric 
isGreater(ProgramStateRef State,SymbolRef Sym1,SymbolRef Sym2)351480093f4SDimitry Andric bool isGreater(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) {
352480093f4SDimitry Andric   return compare(State, Sym1, Sym2, BO_GT);
353480093f4SDimitry Andric }
354480093f4SDimitry Andric 
isEqual(ProgramStateRef State,SymbolRef Sym1,SymbolRef Sym2)355480093f4SDimitry Andric bool isEqual(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) {
356480093f4SDimitry Andric   return compare(State, Sym1, Sym2, BO_EQ);
357480093f4SDimitry Andric }
358480093f4SDimitry Andric 
359480093f4SDimitry Andric } // namespace
360480093f4SDimitry Andric 
registerIteratorRangeChecker(CheckerManager & mgr)361480093f4SDimitry Andric void ento::registerIteratorRangeChecker(CheckerManager &mgr) {
362480093f4SDimitry Andric   mgr.registerChecker<IteratorRangeChecker>();
363480093f4SDimitry Andric }
364480093f4SDimitry Andric 
shouldRegisterIteratorRangeChecker(const CheckerManager & mgr)3655ffd83dbSDimitry Andric bool ento::shouldRegisterIteratorRangeChecker(const CheckerManager &mgr) {
366480093f4SDimitry Andric   return true;
367480093f4SDimitry Andric }
368