xref: /llvm-project/clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp (revision 06eedffe0d2782922e63cc25cb927f4acdaf7b30)
1afb13afcSAdam Balogh //===-- IteratorRangeChecker.cpp ----------------------------------*- C++ -*--//
2afb13afcSAdam Balogh //
3afb13afcSAdam Balogh // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4afb13afcSAdam Balogh // See https://llvm.org/LICENSE.txt for license information.
5afb13afcSAdam Balogh // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6afb13afcSAdam Balogh //
7afb13afcSAdam Balogh //===----------------------------------------------------------------------===//
8afb13afcSAdam Balogh //
9afb13afcSAdam Balogh // Defines a checker for dereference of the past-the-end iterator and
10afb13afcSAdam Balogh // out-of-range increments and decrements.
11afb13afcSAdam Balogh //
12afb13afcSAdam Balogh //===----------------------------------------------------------------------===//
13afb13afcSAdam Balogh 
14afb13afcSAdam Balogh #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
15afb13afcSAdam Balogh #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
16afb13afcSAdam Balogh #include "clang/StaticAnalyzer/Core/Checker.h"
170b9d3a6eSBalazs Benics #include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
18afb13afcSAdam Balogh #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
19afb13afcSAdam Balogh #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
20afb13afcSAdam Balogh 
21afb13afcSAdam Balogh #include "Iterator.h"
22afb13afcSAdam Balogh 
23afb13afcSAdam Balogh using namespace clang;
24afb13afcSAdam Balogh using namespace ento;
25afb13afcSAdam Balogh using namespace iterator;
26afb13afcSAdam Balogh 
27afb13afcSAdam Balogh namespace {
28afb13afcSAdam Balogh 
29afb13afcSAdam Balogh class IteratorRangeChecker
309e63b190SAdam Balogh   : public Checker<check::PreCall, check::PreStmt<UnaryOperator>,
319e63b190SAdam Balogh                    check::PreStmt<BinaryOperator>,
329e63b190SAdam Balogh                    check::PreStmt<ArraySubscriptExpr>,
339e63b190SAdam Balogh                    check::PreStmt<MemberExpr>> {
34afb13afcSAdam Balogh 
3518f219c5SBalazs Benics   const BugType OutOfRangeBugType{this, "Iterator out of range",
3618f219c5SBalazs Benics                                   "Misuse of STL APIs"};
37afb13afcSAdam Balogh 
38ccc0d351SAdam Balogh   void verifyDereference(CheckerContext &C, SVal Val) const;
39ccc0d351SAdam Balogh   void verifyIncrement(CheckerContext &C, SVal Iter) const;
40ccc0d351SAdam Balogh   void verifyDecrement(CheckerContext &C, SVal Iter) const;
41afb13afcSAdam Balogh   void verifyRandomIncrOrDecr(CheckerContext &C, OverloadedOperatorKind Op,
42ccc0d351SAdam Balogh                               SVal LHS, SVal RHS) const;
43ccc0d351SAdam Balogh   void verifyAdvance(CheckerContext &C, SVal LHS, SVal RHS) const;
44ccc0d351SAdam Balogh   void verifyPrev(CheckerContext &C, SVal LHS, SVal RHS) const;
45ccc0d351SAdam Balogh   void verifyNext(CheckerContext &C, SVal LHS, SVal RHS) const;
467619050cSBalazs Benics   void reportBug(StringRef Message, SVal Val, CheckerContext &C,
47ccc0d351SAdam Balogh                  ExplodedNode *ErrNode) const;
48ccc0d351SAdam Balogh 
49afb13afcSAdam Balogh public:
50afb13afcSAdam Balogh   void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
519e63b190SAdam Balogh   void checkPreStmt(const UnaryOperator *UO, CheckerContext &C) const;
529e63b190SAdam Balogh   void checkPreStmt(const BinaryOperator *BO, CheckerContext &C) const;
539e63b190SAdam Balogh   void checkPreStmt(const ArraySubscriptExpr *ASE, CheckerContext &C) const;
549e63b190SAdam Balogh   void checkPreStmt(const MemberExpr *ME, CheckerContext &C) const;
55afb13afcSAdam Balogh 
56ccc0d351SAdam Balogh   using AdvanceFn = void (IteratorRangeChecker::*)(CheckerContext &, SVal,
57ccc0d351SAdam Balogh                                                    SVal) const;
58ccc0d351SAdam Balogh 
59*06eedffeSNagyDonat   // FIXME: these three functions are also listed in IteratorModeling.cpp,
60*06eedffeSNagyDonat   // perhaps unify their handling?
61ccc0d351SAdam Balogh   CallDescriptionMap<AdvanceFn> AdvanceFunctions = {
62*06eedffeSNagyDonat       {{CDM::SimpleFunc, {"std", "advance"}, 2},
63*06eedffeSNagyDonat        &IteratorRangeChecker::verifyAdvance},
64*06eedffeSNagyDonat       {{CDM::SimpleFunc, {"std", "prev"}, 2},
65*06eedffeSNagyDonat        &IteratorRangeChecker::verifyPrev},
66*06eedffeSNagyDonat       {{CDM::SimpleFunc, {"std", "next"}, 2},
67*06eedffeSNagyDonat        &IteratorRangeChecker::verifyNext},
68ccc0d351SAdam Balogh   };
69afb13afcSAdam Balogh };
70afb13afcSAdam Balogh 
71afb13afcSAdam Balogh bool isPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos);
72afb13afcSAdam Balogh bool isAheadOfRange(ProgramStateRef State, const IteratorPosition &Pos);
73afb13afcSAdam Balogh bool isBehindPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos);
748ee3dfd7SBalazs Benics bool isZero(ProgramStateRef State, NonLoc Val);
75afb13afcSAdam Balogh 
76afb13afcSAdam Balogh } // namespace
77afb13afcSAdam Balogh 
checkPreCall(const CallEvent & Call,CheckerContext & C) const78afb13afcSAdam Balogh void IteratorRangeChecker::checkPreCall(const CallEvent &Call,
79afb13afcSAdam Balogh                                         CheckerContext &C) const {
80afb13afcSAdam Balogh   // Check for out of range access
81afb13afcSAdam Balogh   const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
82afb13afcSAdam Balogh   if (!Func)
83afb13afcSAdam Balogh     return;
84afb13afcSAdam Balogh 
85afb13afcSAdam Balogh   if (Func->isOverloadedOperator()) {
86afb13afcSAdam Balogh     if (isIncrementOperator(Func->getOverloadedOperator())) {
87afb13afcSAdam Balogh       // Check for out-of-range incrementions
88afb13afcSAdam Balogh       if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
89afb13afcSAdam Balogh         verifyIncrement(C, InstCall->getCXXThisVal());
90afb13afcSAdam Balogh       } else {
91afb13afcSAdam Balogh         if (Call.getNumArgs() >= 1) {
92afb13afcSAdam Balogh           verifyIncrement(C, Call.getArgSVal(0));
93afb13afcSAdam Balogh         }
94afb13afcSAdam Balogh       }
95afb13afcSAdam Balogh     } else if (isDecrementOperator(Func->getOverloadedOperator())) {
96afb13afcSAdam Balogh       // Check for out-of-range decrementions
97afb13afcSAdam Balogh       if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
98afb13afcSAdam Balogh         verifyDecrement(C, InstCall->getCXXThisVal());
99afb13afcSAdam Balogh       } else {
100afb13afcSAdam Balogh         if (Call.getNumArgs() >= 1) {
101afb13afcSAdam Balogh           verifyDecrement(C, Call.getArgSVal(0));
102afb13afcSAdam Balogh         }
103afb13afcSAdam Balogh       }
104afb13afcSAdam Balogh     } else if (isRandomIncrOrDecrOperator(Func->getOverloadedOperator())) {
105afb13afcSAdam Balogh       if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
106afb13afcSAdam Balogh         // Check for out-of-range incrementions and decrementions
107afb13afcSAdam Balogh         if (Call.getNumArgs() >= 1 &&
108afb13afcSAdam Balogh             Call.getArgExpr(0)->getType()->isIntegralOrEnumerationType()) {
109afb13afcSAdam Balogh           verifyRandomIncrOrDecr(C, Func->getOverloadedOperator(),
110afb13afcSAdam Balogh                                  InstCall->getCXXThisVal(),
111afb13afcSAdam Balogh                                  Call.getArgSVal(0));
112afb13afcSAdam Balogh         }
113afb13afcSAdam Balogh       } else {
114afb13afcSAdam Balogh         if (Call.getNumArgs() >= 2 &&
115afb13afcSAdam Balogh             Call.getArgExpr(1)->getType()->isIntegralOrEnumerationType()) {
116afb13afcSAdam Balogh           verifyRandomIncrOrDecr(C, Func->getOverloadedOperator(),
117afb13afcSAdam Balogh                                  Call.getArgSVal(0), Call.getArgSVal(1));
118afb13afcSAdam Balogh         }
119afb13afcSAdam Balogh       }
120afb13afcSAdam Balogh     } else if (isDereferenceOperator(Func->getOverloadedOperator())) {
121afb13afcSAdam Balogh       // Check for dereference of out-of-range iterators
122afb13afcSAdam Balogh       if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
123afb13afcSAdam Balogh         verifyDereference(C, InstCall->getCXXThisVal());
124afb13afcSAdam Balogh       } else {
125afb13afcSAdam Balogh         verifyDereference(C, Call.getArgSVal(0));
126afb13afcSAdam Balogh       }
127afb13afcSAdam Balogh     }
128ccc0d351SAdam Balogh   } else {
129ccc0d351SAdam Balogh     const AdvanceFn *Verifier = AdvanceFunctions.lookup(Call);
130ccc0d351SAdam Balogh     if (Verifier) {
131ccc0d351SAdam Balogh       if (Call.getNumArgs() > 1) {
132ccc0d351SAdam Balogh         (this->**Verifier)(C, Call.getArgSVal(0), Call.getArgSVal(1));
133ccc0d351SAdam Balogh       } else {
134ccc0d351SAdam Balogh         auto &BVF = C.getSValBuilder().getBasicValueFactory();
135ccc0d351SAdam Balogh         (this->**Verifier)(
136ccc0d351SAdam Balogh             C, Call.getArgSVal(0),
137ccc0d351SAdam Balogh             nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
138ccc0d351SAdam Balogh       }
139ccc0d351SAdam Balogh     }
140afb13afcSAdam Balogh   }
141afb13afcSAdam Balogh }
142afb13afcSAdam Balogh 
checkPreStmt(const UnaryOperator * UO,CheckerContext & C) const1439e63b190SAdam Balogh void IteratorRangeChecker::checkPreStmt(const UnaryOperator *UO,
1449e63b190SAdam Balogh                                         CheckerContext &C) const {
1459e63b190SAdam Balogh   if (isa<CXXThisExpr>(UO->getSubExpr()))
1469e63b190SAdam Balogh     return;
1479e63b190SAdam Balogh 
1489e63b190SAdam Balogh   ProgramStateRef State = C.getState();
1499e63b190SAdam Balogh   UnaryOperatorKind OK = UO->getOpcode();
1509e63b190SAdam Balogh   SVal SubVal = State->getSVal(UO->getSubExpr(), C.getLocationContext());
1519e63b190SAdam Balogh 
1529e63b190SAdam Balogh   if (isDereferenceOperator(OK)) {
1539e63b190SAdam Balogh     verifyDereference(C, SubVal);
1549e63b190SAdam Balogh   } else if (isIncrementOperator(OK)) {
1559e63b190SAdam Balogh     verifyIncrement(C, SubVal);
1569e63b190SAdam Balogh   } else if (isDecrementOperator(OK)) {
1579e63b190SAdam Balogh     verifyDecrement(C, SubVal);
1589e63b190SAdam Balogh   }
1599e63b190SAdam Balogh }
1609e63b190SAdam Balogh 
checkPreStmt(const BinaryOperator * BO,CheckerContext & C) const1619e63b190SAdam Balogh void IteratorRangeChecker::checkPreStmt(const BinaryOperator *BO,
1629e63b190SAdam Balogh                                         CheckerContext &C) const {
1639e63b190SAdam Balogh   ProgramStateRef State = C.getState();
1649e63b190SAdam Balogh   BinaryOperatorKind OK = BO->getOpcode();
1659e63b190SAdam Balogh   SVal LVal = State->getSVal(BO->getLHS(), C.getLocationContext());
1669e63b190SAdam Balogh 
1679e63b190SAdam Balogh   if (isDereferenceOperator(OK)) {
1689e63b190SAdam Balogh     verifyDereference(C, LVal);
1699e63b190SAdam Balogh   } else if (isRandomIncrOrDecrOperator(OK)) {
1709e63b190SAdam Balogh     SVal RVal = State->getSVal(BO->getRHS(), C.getLocationContext());
171a59d4ae4SAdam Balogh     if (!BO->getRHS()->getType()->isIntegralOrEnumerationType())
172a59d4ae4SAdam Balogh       return;
1739e63b190SAdam Balogh     verifyRandomIncrOrDecr(C, BinaryOperator::getOverloadedOperator(OK), LVal,
1749e63b190SAdam Balogh                            RVal);
1759e63b190SAdam Balogh   }
1769e63b190SAdam Balogh }
1779e63b190SAdam Balogh 
checkPreStmt(const ArraySubscriptExpr * ASE,CheckerContext & C) const1789e63b190SAdam Balogh void IteratorRangeChecker::checkPreStmt(const ArraySubscriptExpr *ASE,
1799e63b190SAdam Balogh                                         CheckerContext &C) const {
1809e63b190SAdam Balogh   ProgramStateRef State = C.getState();
1819e63b190SAdam Balogh   SVal LVal = State->getSVal(ASE->getLHS(), C.getLocationContext());
1829e63b190SAdam Balogh   verifyDereference(C, LVal);
1839e63b190SAdam Balogh }
1849e63b190SAdam Balogh 
checkPreStmt(const MemberExpr * ME,CheckerContext & C) const1859e63b190SAdam Balogh void IteratorRangeChecker::checkPreStmt(const MemberExpr *ME,
1869e63b190SAdam Balogh                                         CheckerContext &C) const {
1879e63b190SAdam Balogh   if (!ME->isArrow() || ME->isImplicitAccess())
1889e63b190SAdam Balogh     return;
1899e63b190SAdam Balogh 
1909e63b190SAdam Balogh   ProgramStateRef State = C.getState();
1919e63b190SAdam Balogh   SVal BaseVal = State->getSVal(ME->getBase(), C.getLocationContext());
1929e63b190SAdam Balogh   verifyDereference(C, BaseVal);
1939e63b190SAdam Balogh }
1949e63b190SAdam Balogh 
verifyDereference(CheckerContext & C,SVal Val) const195afb13afcSAdam Balogh void IteratorRangeChecker::verifyDereference(CheckerContext &C,
196ccc0d351SAdam Balogh                                              SVal Val) const {
197afb13afcSAdam Balogh   auto State = C.getState();
198afb13afcSAdam Balogh   const auto *Pos = getIteratorPosition(State, Val);
199afb13afcSAdam Balogh   if (Pos && isPastTheEnd(State, *Pos)) {
200afb13afcSAdam Balogh     auto *N = C.generateErrorNode(State);
201afb13afcSAdam Balogh     if (!N)
202afb13afcSAdam Balogh       return;
203afb13afcSAdam Balogh     reportBug("Past-the-end iterator dereferenced.", Val, C, N);
204afb13afcSAdam Balogh     return;
205afb13afcSAdam Balogh   }
206afb13afcSAdam Balogh }
207afb13afcSAdam Balogh 
verifyIncrement(CheckerContext & C,SVal Iter) const208ccc0d351SAdam Balogh void IteratorRangeChecker::verifyIncrement(CheckerContext &C, SVal Iter) const {
209afb13afcSAdam Balogh   auto &BVF = C.getSValBuilder().getBasicValueFactory();
210afb13afcSAdam Balogh   verifyRandomIncrOrDecr(C, OO_Plus, Iter,
211afb13afcSAdam Balogh                      nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
212afb13afcSAdam Balogh }
213afb13afcSAdam Balogh 
verifyDecrement(CheckerContext & C,SVal Iter) const214ccc0d351SAdam Balogh void IteratorRangeChecker::verifyDecrement(CheckerContext &C, SVal Iter) const {
215afb13afcSAdam Balogh   auto &BVF = C.getSValBuilder().getBasicValueFactory();
216afb13afcSAdam Balogh   verifyRandomIncrOrDecr(C, OO_Minus, Iter,
217afb13afcSAdam Balogh                      nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
218afb13afcSAdam Balogh }
219afb13afcSAdam Balogh 
verifyRandomIncrOrDecr(CheckerContext & C,OverloadedOperatorKind Op,SVal LHS,SVal RHS) const220afb13afcSAdam Balogh void IteratorRangeChecker::verifyRandomIncrOrDecr(CheckerContext &C,
221afb13afcSAdam Balogh                                                   OverloadedOperatorKind Op,
222ccc0d351SAdam Balogh                                                   SVal LHS, SVal RHS) const {
223afb13afcSAdam Balogh   auto State = C.getState();
224afb13afcSAdam Balogh 
225afb13afcSAdam Balogh   auto Value = RHS;
226afb13afcSAdam Balogh   if (auto ValAsLoc = RHS.getAs<Loc>()) {
227afb13afcSAdam Balogh     Value = State->getRawSVal(*ValAsLoc);
228afb13afcSAdam Balogh   }
229afb13afcSAdam Balogh 
230985e3996SBalazs Benics   if (Value.isUnknownOrUndef() || !isa<NonLoc>(Value))
231afb13afcSAdam Balogh     return;
232afb13afcSAdam Balogh 
233afb13afcSAdam Balogh   // Incremention or decremention by 0 is never a bug.
234afb13afcSAdam Balogh   if (isZero(State, Value.castAs<NonLoc>()))
235afb13afcSAdam Balogh     return;
236afb13afcSAdam Balogh 
237afb13afcSAdam Balogh   // The result may be the past-end iterator of the container, but any other
238afb13afcSAdam Balogh   // out of range position is undefined behaviour
239afb13afcSAdam Balogh   auto StateAfter = advancePosition(State, LHS, Op, Value);
240afb13afcSAdam Balogh   if (!StateAfter)
241afb13afcSAdam Balogh     return;
242afb13afcSAdam Balogh 
243afb13afcSAdam Balogh   const auto *PosAfter = getIteratorPosition(StateAfter, LHS);
244afb13afcSAdam Balogh   assert(PosAfter &&
245afb13afcSAdam Balogh          "Iterator should have position after successful advancement");
246afb13afcSAdam Balogh   if (isAheadOfRange(State, *PosAfter)) {
247afb13afcSAdam Balogh     auto *N = C.generateErrorNode(State);
248afb13afcSAdam Balogh     if (!N)
249afb13afcSAdam Balogh       return;
250afb13afcSAdam Balogh     reportBug("Iterator decremented ahead of its valid range.", LHS,
251afb13afcSAdam Balogh                         C, N);
252afb13afcSAdam Balogh   }
253afb13afcSAdam Balogh   if (isBehindPastTheEnd(State, *PosAfter)) {
254afb13afcSAdam Balogh     auto *N = C.generateErrorNode(State);
255afb13afcSAdam Balogh     if (!N)
256afb13afcSAdam Balogh       return;
257afb13afcSAdam Balogh     reportBug("Iterator incremented behind the past-the-end "
258afb13afcSAdam Balogh                         "iterator.", LHS, C, N);
259afb13afcSAdam Balogh   }
260afb13afcSAdam Balogh }
261afb13afcSAdam Balogh 
verifyAdvance(CheckerContext & C,SVal LHS,SVal RHS) const262ccc0d351SAdam Balogh void IteratorRangeChecker::verifyAdvance(CheckerContext &C, SVal LHS,
263ccc0d351SAdam Balogh                                          SVal RHS) const {
264ccc0d351SAdam Balogh   verifyRandomIncrOrDecr(C, OO_PlusEqual, LHS, RHS);
265ccc0d351SAdam Balogh }
266ccc0d351SAdam Balogh 
verifyPrev(CheckerContext & C,SVal LHS,SVal RHS) const267ccc0d351SAdam Balogh void IteratorRangeChecker::verifyPrev(CheckerContext &C, SVal LHS,
268ccc0d351SAdam Balogh                                       SVal RHS) const {
269ccc0d351SAdam Balogh   verifyRandomIncrOrDecr(C, OO_Minus, LHS, RHS);
270ccc0d351SAdam Balogh }
271ccc0d351SAdam Balogh 
verifyNext(CheckerContext & C,SVal LHS,SVal RHS) const272ccc0d351SAdam Balogh void IteratorRangeChecker::verifyNext(CheckerContext &C, SVal LHS,
273ccc0d351SAdam Balogh                                       SVal RHS) const {
274ccc0d351SAdam Balogh   verifyRandomIncrOrDecr(C, OO_Plus, LHS, RHS);
275ccc0d351SAdam Balogh }
276ccc0d351SAdam Balogh 
reportBug(StringRef Message,SVal Val,CheckerContext & C,ExplodedNode * ErrNode) const2777619050cSBalazs Benics void IteratorRangeChecker::reportBug(StringRef Message, SVal Val,
278ccc0d351SAdam Balogh                                      CheckerContext &C,
279afb13afcSAdam Balogh                                      ExplodedNode *ErrNode) const {
28018f219c5SBalazs Benics   auto R = std::make_unique<PathSensitiveBugReport>(OutOfRangeBugType, Message,
281afb13afcSAdam Balogh                                                     ErrNode);
282a3f4d17aSAdam Balogh 
283a3f4d17aSAdam Balogh   const auto *Pos = getIteratorPosition(C.getState(), Val);
284a3f4d17aSAdam Balogh   assert(Pos && "Iterator without known position cannot be out-of-range.");
285a3f4d17aSAdam Balogh 
286afb13afcSAdam Balogh   R->markInteresting(Val);
287a3f4d17aSAdam Balogh   R->markInteresting(Pos->getContainer());
288afb13afcSAdam Balogh   C.emitReport(std::move(R));
289afb13afcSAdam Balogh }
290afb13afcSAdam Balogh 
291afb13afcSAdam Balogh namespace {
292afb13afcSAdam Balogh 
293afb13afcSAdam Balogh bool isLess(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2);
294afb13afcSAdam Balogh bool isGreater(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2);
295afb13afcSAdam Balogh bool isEqual(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2);
296afb13afcSAdam Balogh 
isZero(ProgramStateRef State,NonLoc Val)2978ee3dfd7SBalazs Benics bool isZero(ProgramStateRef State, NonLoc Val) {
298afb13afcSAdam Balogh   auto &BVF = State->getBasicVals();
299afb13afcSAdam Balogh   return compare(State, Val,
300afb13afcSAdam Balogh                  nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))),
301afb13afcSAdam Balogh                  BO_EQ);
302afb13afcSAdam Balogh }
303afb13afcSAdam Balogh 
isPastTheEnd(ProgramStateRef State,const IteratorPosition & Pos)304afb13afcSAdam Balogh bool isPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos) {
305afb13afcSAdam Balogh   const auto *Cont = Pos.getContainer();
306afb13afcSAdam Balogh   const auto *CData = getContainerData(State, Cont);
307afb13afcSAdam Balogh   if (!CData)
308afb13afcSAdam Balogh     return false;
309afb13afcSAdam Balogh 
310afb13afcSAdam Balogh   const auto End = CData->getEnd();
311afb13afcSAdam Balogh   if (End) {
312afb13afcSAdam Balogh     if (isEqual(State, Pos.getOffset(), End)) {
313afb13afcSAdam Balogh       return true;
314afb13afcSAdam Balogh     }
315afb13afcSAdam Balogh   }
316afb13afcSAdam Balogh 
317afb13afcSAdam Balogh   return false;
318afb13afcSAdam Balogh }
319afb13afcSAdam Balogh 
isAheadOfRange(ProgramStateRef State,const IteratorPosition & Pos)320afb13afcSAdam Balogh bool isAheadOfRange(ProgramStateRef State, const IteratorPosition &Pos) {
321afb13afcSAdam Balogh   const auto *Cont = Pos.getContainer();
322afb13afcSAdam Balogh   const auto *CData = getContainerData(State, Cont);
323afb13afcSAdam Balogh   if (!CData)
324afb13afcSAdam Balogh     return false;
325afb13afcSAdam Balogh 
326afb13afcSAdam Balogh   const auto Beg = CData->getBegin();
327afb13afcSAdam Balogh   if (Beg) {
328afb13afcSAdam Balogh     if (isLess(State, Pos.getOffset(), Beg)) {
329afb13afcSAdam Balogh       return true;
330afb13afcSAdam Balogh     }
331afb13afcSAdam Balogh   }
332afb13afcSAdam Balogh 
333afb13afcSAdam Balogh   return false;
334afb13afcSAdam Balogh }
335afb13afcSAdam Balogh 
isBehindPastTheEnd(ProgramStateRef State,const IteratorPosition & Pos)336afb13afcSAdam Balogh bool isBehindPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos) {
337afb13afcSAdam Balogh   const auto *Cont = Pos.getContainer();
338afb13afcSAdam Balogh   const auto *CData = getContainerData(State, Cont);
339afb13afcSAdam Balogh   if (!CData)
340afb13afcSAdam Balogh     return false;
341afb13afcSAdam Balogh 
342afb13afcSAdam Balogh   const auto End = CData->getEnd();
343afb13afcSAdam Balogh   if (End) {
344afb13afcSAdam Balogh     if (isGreater(State, Pos.getOffset(), End)) {
345afb13afcSAdam Balogh       return true;
346afb13afcSAdam Balogh     }
347afb13afcSAdam Balogh   }
348afb13afcSAdam Balogh 
349afb13afcSAdam Balogh   return false;
350afb13afcSAdam Balogh }
351afb13afcSAdam Balogh 
isLess(ProgramStateRef State,SymbolRef Sym1,SymbolRef Sym2)352afb13afcSAdam Balogh bool isLess(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) {
353afb13afcSAdam Balogh   return compare(State, Sym1, Sym2, BO_LT);
354afb13afcSAdam Balogh }
355afb13afcSAdam Balogh 
isGreater(ProgramStateRef State,SymbolRef Sym1,SymbolRef Sym2)356afb13afcSAdam Balogh bool isGreater(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) {
357afb13afcSAdam Balogh   return compare(State, Sym1, Sym2, BO_GT);
358afb13afcSAdam Balogh }
359afb13afcSAdam Balogh 
isEqual(ProgramStateRef State,SymbolRef Sym1,SymbolRef Sym2)360afb13afcSAdam Balogh bool isEqual(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) {
361afb13afcSAdam Balogh   return compare(State, Sym1, Sym2, BO_EQ);
362afb13afcSAdam Balogh }
363afb13afcSAdam Balogh 
364afb13afcSAdam Balogh } // namespace
365afb13afcSAdam Balogh 
registerIteratorRangeChecker(CheckerManager & mgr)366afb13afcSAdam Balogh void ento::registerIteratorRangeChecker(CheckerManager &mgr) {
367afb13afcSAdam Balogh   mgr.registerChecker<IteratorRangeChecker>();
368afb13afcSAdam Balogh }
369afb13afcSAdam Balogh 
shouldRegisterIteratorRangeChecker(const CheckerManager & mgr)370bda3dd0dSKirstóf Umann bool ento::shouldRegisterIteratorRangeChecker(const CheckerManager &mgr) {
371afb13afcSAdam Balogh   return true;
372afb13afcSAdam Balogh }
373