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"
17*0b9d3a6eSBalazs 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
35afb13afcSAdam Balogh std::unique_ptr<BugType> OutOfRangeBugType;
36afb13afcSAdam Balogh
37ccc0d351SAdam Balogh void verifyDereference(CheckerContext &C, SVal Val) const;
38ccc0d351SAdam Balogh void verifyIncrement(CheckerContext &C, SVal Iter) const;
39ccc0d351SAdam Balogh void verifyDecrement(CheckerContext &C, SVal Iter) const;
40afb13afcSAdam Balogh void verifyRandomIncrOrDecr(CheckerContext &C, OverloadedOperatorKind Op,
41ccc0d351SAdam Balogh SVal LHS, SVal RHS) const;
42ccc0d351SAdam Balogh void verifyAdvance(CheckerContext &C, SVal LHS, SVal RHS) const;
43ccc0d351SAdam Balogh void verifyPrev(CheckerContext &C, SVal LHS, SVal RHS) const;
44ccc0d351SAdam Balogh void verifyNext(CheckerContext &C, SVal LHS, SVal RHS) const;
45ccc0d351SAdam Balogh void reportBug(const StringRef &Message, SVal Val, CheckerContext &C,
46ccc0d351SAdam Balogh ExplodedNode *ErrNode) const;
47ccc0d351SAdam Balogh
48afb13afcSAdam Balogh public:
49afb13afcSAdam Balogh IteratorRangeChecker();
50afb13afcSAdam Balogh
51afb13afcSAdam Balogh void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
529e63b190SAdam Balogh void checkPreStmt(const UnaryOperator *UO, CheckerContext &C) const;
539e63b190SAdam Balogh void checkPreStmt(const BinaryOperator *BO, CheckerContext &C) const;
549e63b190SAdam Balogh void checkPreStmt(const ArraySubscriptExpr *ASE, CheckerContext &C) const;
559e63b190SAdam Balogh void checkPreStmt(const MemberExpr *ME, CheckerContext &C) const;
56afb13afcSAdam Balogh
57ccc0d351SAdam Balogh using AdvanceFn = void (IteratorRangeChecker::*)(CheckerContext &, SVal,
58ccc0d351SAdam Balogh SVal) const;
59ccc0d351SAdam Balogh
60ccc0d351SAdam Balogh CallDescriptionMap<AdvanceFn> AdvanceFunctions = {
61ccc0d351SAdam Balogh {{{"std", "advance"}, 2}, &IteratorRangeChecker::verifyAdvance},
62ccc0d351SAdam Balogh {{{"std", "prev"}, 2}, &IteratorRangeChecker::verifyPrev},
63ccc0d351SAdam Balogh {{{"std", "next"}, 2}, &IteratorRangeChecker::verifyNext},
64ccc0d351SAdam Balogh };
65afb13afcSAdam Balogh };
66afb13afcSAdam Balogh
67afb13afcSAdam Balogh bool isPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos);
68afb13afcSAdam Balogh bool isAheadOfRange(ProgramStateRef State, const IteratorPosition &Pos);
69afb13afcSAdam Balogh bool isBehindPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos);
70afb13afcSAdam Balogh bool isZero(ProgramStateRef State, const NonLoc &Val);
71afb13afcSAdam Balogh
72afb13afcSAdam Balogh } //namespace
73afb13afcSAdam Balogh
IteratorRangeChecker()74afb13afcSAdam Balogh IteratorRangeChecker::IteratorRangeChecker() {
75afb13afcSAdam Balogh OutOfRangeBugType.reset(
76afb13afcSAdam Balogh new BugType(this, "Iterator out of range", "Misuse of STL APIs"));
77afb13afcSAdam Balogh }
78afb13afcSAdam Balogh
checkPreCall(const CallEvent & Call,CheckerContext & C) const79afb13afcSAdam Balogh void IteratorRangeChecker::checkPreCall(const CallEvent &Call,
80afb13afcSAdam Balogh CheckerContext &C) const {
81afb13afcSAdam Balogh // Check for out of range access
82afb13afcSAdam Balogh const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
83afb13afcSAdam Balogh if (!Func)
84afb13afcSAdam Balogh return;
85afb13afcSAdam Balogh
86afb13afcSAdam Balogh if (Func->isOverloadedOperator()) {
87afb13afcSAdam Balogh if (isIncrementOperator(Func->getOverloadedOperator())) {
88afb13afcSAdam Balogh // Check for out-of-range incrementions
89afb13afcSAdam Balogh if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
90afb13afcSAdam Balogh verifyIncrement(C, InstCall->getCXXThisVal());
91afb13afcSAdam Balogh } else {
92afb13afcSAdam Balogh if (Call.getNumArgs() >= 1) {
93afb13afcSAdam Balogh verifyIncrement(C, Call.getArgSVal(0));
94afb13afcSAdam Balogh }
95afb13afcSAdam Balogh }
96afb13afcSAdam Balogh } else if (isDecrementOperator(Func->getOverloadedOperator())) {
97afb13afcSAdam Balogh // Check for out-of-range decrementions
98afb13afcSAdam Balogh if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
99afb13afcSAdam Balogh verifyDecrement(C, InstCall->getCXXThisVal());
100afb13afcSAdam Balogh } else {
101afb13afcSAdam Balogh if (Call.getNumArgs() >= 1) {
102afb13afcSAdam Balogh verifyDecrement(C, Call.getArgSVal(0));
103afb13afcSAdam Balogh }
104afb13afcSAdam Balogh }
105afb13afcSAdam Balogh } else if (isRandomIncrOrDecrOperator(Func->getOverloadedOperator())) {
106afb13afcSAdam Balogh if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
107afb13afcSAdam Balogh // Check for out-of-range incrementions and decrementions
108afb13afcSAdam Balogh if (Call.getNumArgs() >= 1 &&
109afb13afcSAdam Balogh Call.getArgExpr(0)->getType()->isIntegralOrEnumerationType()) {
110afb13afcSAdam Balogh verifyRandomIncrOrDecr(C, Func->getOverloadedOperator(),
111afb13afcSAdam Balogh InstCall->getCXXThisVal(),
112afb13afcSAdam Balogh Call.getArgSVal(0));
113afb13afcSAdam Balogh }
114afb13afcSAdam Balogh } else {
115afb13afcSAdam Balogh if (Call.getNumArgs() >= 2 &&
116afb13afcSAdam Balogh Call.getArgExpr(1)->getType()->isIntegralOrEnumerationType()) {
117afb13afcSAdam Balogh verifyRandomIncrOrDecr(C, Func->getOverloadedOperator(),
118afb13afcSAdam Balogh Call.getArgSVal(0), Call.getArgSVal(1));
119afb13afcSAdam Balogh }
120afb13afcSAdam Balogh }
121afb13afcSAdam Balogh } else if (isDereferenceOperator(Func->getOverloadedOperator())) {
122afb13afcSAdam Balogh // Check for dereference of out-of-range iterators
123afb13afcSAdam Balogh if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
124afb13afcSAdam Balogh verifyDereference(C, InstCall->getCXXThisVal());
125afb13afcSAdam Balogh } else {
126afb13afcSAdam Balogh verifyDereference(C, Call.getArgSVal(0));
127afb13afcSAdam Balogh }
128afb13afcSAdam Balogh }
129ccc0d351SAdam Balogh } else {
130ccc0d351SAdam Balogh const AdvanceFn *Verifier = AdvanceFunctions.lookup(Call);
131ccc0d351SAdam Balogh if (Verifier) {
132ccc0d351SAdam Balogh if (Call.getNumArgs() > 1) {
133ccc0d351SAdam Balogh (this->**Verifier)(C, Call.getArgSVal(0), Call.getArgSVal(1));
134ccc0d351SAdam Balogh } else {
135ccc0d351SAdam Balogh auto &BVF = C.getSValBuilder().getBasicValueFactory();
136ccc0d351SAdam Balogh (this->**Verifier)(
137ccc0d351SAdam Balogh C, Call.getArgSVal(0),
138ccc0d351SAdam Balogh nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
139ccc0d351SAdam Balogh }
140ccc0d351SAdam Balogh }
141afb13afcSAdam Balogh }
142afb13afcSAdam Balogh }
143afb13afcSAdam Balogh
checkPreStmt(const UnaryOperator * UO,CheckerContext & C) const1449e63b190SAdam Balogh void IteratorRangeChecker::checkPreStmt(const UnaryOperator *UO,
1459e63b190SAdam Balogh CheckerContext &C) const {
1469e63b190SAdam Balogh if (isa<CXXThisExpr>(UO->getSubExpr()))
1479e63b190SAdam Balogh return;
1489e63b190SAdam Balogh
1499e63b190SAdam Balogh ProgramStateRef State = C.getState();
1509e63b190SAdam Balogh UnaryOperatorKind OK = UO->getOpcode();
1519e63b190SAdam Balogh SVal SubVal = State->getSVal(UO->getSubExpr(), C.getLocationContext());
1529e63b190SAdam Balogh
1539e63b190SAdam Balogh if (isDereferenceOperator(OK)) {
1549e63b190SAdam Balogh verifyDereference(C, SubVal);
1559e63b190SAdam Balogh } else if (isIncrementOperator(OK)) {
1569e63b190SAdam Balogh verifyIncrement(C, SubVal);
1579e63b190SAdam Balogh } else if (isDecrementOperator(OK)) {
1589e63b190SAdam Balogh verifyDecrement(C, SubVal);
1599e63b190SAdam Balogh }
1609e63b190SAdam Balogh }
1619e63b190SAdam Balogh
checkPreStmt(const BinaryOperator * BO,CheckerContext & C) const1629e63b190SAdam Balogh void IteratorRangeChecker::checkPreStmt(const BinaryOperator *BO,
1639e63b190SAdam Balogh CheckerContext &C) const {
1649e63b190SAdam Balogh ProgramStateRef State = C.getState();
1659e63b190SAdam Balogh BinaryOperatorKind OK = BO->getOpcode();
1669e63b190SAdam Balogh SVal LVal = State->getSVal(BO->getLHS(), C.getLocationContext());
1679e63b190SAdam Balogh
1689e63b190SAdam Balogh if (isDereferenceOperator(OK)) {
1699e63b190SAdam Balogh verifyDereference(C, LVal);
1709e63b190SAdam Balogh } else if (isRandomIncrOrDecrOperator(OK)) {
1719e63b190SAdam Balogh SVal RVal = State->getSVal(BO->getRHS(), C.getLocationContext());
172a59d4ae4SAdam Balogh if (!BO->getRHS()->getType()->isIntegralOrEnumerationType())
173a59d4ae4SAdam Balogh return;
1749e63b190SAdam Balogh verifyRandomIncrOrDecr(C, BinaryOperator::getOverloadedOperator(OK), LVal,
1759e63b190SAdam Balogh RVal);
1769e63b190SAdam Balogh }
1779e63b190SAdam Balogh }
1789e63b190SAdam Balogh
checkPreStmt(const ArraySubscriptExpr * ASE,CheckerContext & C) const1799e63b190SAdam Balogh void IteratorRangeChecker::checkPreStmt(const ArraySubscriptExpr *ASE,
1809e63b190SAdam Balogh CheckerContext &C) const {
1819e63b190SAdam Balogh ProgramStateRef State = C.getState();
1829e63b190SAdam Balogh SVal LVal = State->getSVal(ASE->getLHS(), C.getLocationContext());
1839e63b190SAdam Balogh verifyDereference(C, LVal);
1849e63b190SAdam Balogh }
1859e63b190SAdam Balogh
checkPreStmt(const MemberExpr * ME,CheckerContext & C) const1869e63b190SAdam Balogh void IteratorRangeChecker::checkPreStmt(const MemberExpr *ME,
1879e63b190SAdam Balogh CheckerContext &C) const {
1889e63b190SAdam Balogh if (!ME->isArrow() || ME->isImplicitAccess())
1899e63b190SAdam Balogh return;
1909e63b190SAdam Balogh
1919e63b190SAdam Balogh ProgramStateRef State = C.getState();
1929e63b190SAdam Balogh SVal BaseVal = State->getSVal(ME->getBase(), C.getLocationContext());
1939e63b190SAdam Balogh verifyDereference(C, BaseVal);
1949e63b190SAdam Balogh }
1959e63b190SAdam Balogh
verifyDereference(CheckerContext & C,SVal Val) const196afb13afcSAdam Balogh void IteratorRangeChecker::verifyDereference(CheckerContext &C,
197ccc0d351SAdam Balogh SVal Val) const {
198afb13afcSAdam Balogh auto State = C.getState();
199afb13afcSAdam Balogh const auto *Pos = getIteratorPosition(State, Val);
200afb13afcSAdam Balogh if (Pos && isPastTheEnd(State, *Pos)) {
201afb13afcSAdam Balogh auto *N = C.generateErrorNode(State);
202afb13afcSAdam Balogh if (!N)
203afb13afcSAdam Balogh return;
204afb13afcSAdam Balogh reportBug("Past-the-end iterator dereferenced.", Val, C, N);
205afb13afcSAdam Balogh return;
206afb13afcSAdam Balogh }
207afb13afcSAdam Balogh }
208afb13afcSAdam Balogh
verifyIncrement(CheckerContext & C,SVal Iter) const209ccc0d351SAdam Balogh void IteratorRangeChecker::verifyIncrement(CheckerContext &C, SVal Iter) const {
210afb13afcSAdam Balogh auto &BVF = C.getSValBuilder().getBasicValueFactory();
211afb13afcSAdam Balogh verifyRandomIncrOrDecr(C, OO_Plus, Iter,
212afb13afcSAdam Balogh nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
213afb13afcSAdam Balogh }
214afb13afcSAdam Balogh
verifyDecrement(CheckerContext & C,SVal Iter) const215ccc0d351SAdam Balogh void IteratorRangeChecker::verifyDecrement(CheckerContext &C, SVal Iter) const {
216afb13afcSAdam Balogh auto &BVF = C.getSValBuilder().getBasicValueFactory();
217afb13afcSAdam Balogh verifyRandomIncrOrDecr(C, OO_Minus, Iter,
218afb13afcSAdam Balogh nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
219afb13afcSAdam Balogh }
220afb13afcSAdam Balogh
verifyRandomIncrOrDecr(CheckerContext & C,OverloadedOperatorKind Op,SVal LHS,SVal RHS) const221afb13afcSAdam Balogh void IteratorRangeChecker::verifyRandomIncrOrDecr(CheckerContext &C,
222afb13afcSAdam Balogh OverloadedOperatorKind Op,
223ccc0d351SAdam Balogh SVal LHS, SVal RHS) const {
224afb13afcSAdam Balogh auto State = C.getState();
225afb13afcSAdam Balogh
226afb13afcSAdam Balogh auto Value = RHS;
227afb13afcSAdam Balogh if (auto ValAsLoc = RHS.getAs<Loc>()) {
228afb13afcSAdam Balogh Value = State->getRawSVal(*ValAsLoc);
229afb13afcSAdam Balogh }
230afb13afcSAdam Balogh
231bcc66248SAdam Balogh if (Value.isUnknownOrUndef())
232afb13afcSAdam Balogh return;
233afb13afcSAdam Balogh
234afb13afcSAdam Balogh // Incremention or decremention by 0 is never a bug.
235afb13afcSAdam Balogh if (isZero(State, Value.castAs<NonLoc>()))
236afb13afcSAdam Balogh return;
237afb13afcSAdam Balogh
238afb13afcSAdam Balogh // The result may be the past-end iterator of the container, but any other
239afb13afcSAdam Balogh // out of range position is undefined behaviour
240afb13afcSAdam Balogh auto StateAfter = advancePosition(State, LHS, Op, Value);
241afb13afcSAdam Balogh if (!StateAfter)
242afb13afcSAdam Balogh return;
243afb13afcSAdam Balogh
244afb13afcSAdam Balogh const auto *PosAfter = getIteratorPosition(StateAfter, LHS);
245afb13afcSAdam Balogh assert(PosAfter &&
246afb13afcSAdam Balogh "Iterator should have position after successful advancement");
247afb13afcSAdam Balogh if (isAheadOfRange(State, *PosAfter)) {
248afb13afcSAdam Balogh auto *N = C.generateErrorNode(State);
249afb13afcSAdam Balogh if (!N)
250afb13afcSAdam Balogh return;
251afb13afcSAdam Balogh reportBug("Iterator decremented ahead of its valid range.", LHS,
252afb13afcSAdam Balogh C, N);
253afb13afcSAdam Balogh }
254afb13afcSAdam Balogh if (isBehindPastTheEnd(State, *PosAfter)) {
255afb13afcSAdam Balogh auto *N = C.generateErrorNode(State);
256afb13afcSAdam Balogh if (!N)
257afb13afcSAdam Balogh return;
258afb13afcSAdam Balogh reportBug("Iterator incremented behind the past-the-end "
259afb13afcSAdam Balogh "iterator.", LHS, C, N);
260afb13afcSAdam Balogh }
261afb13afcSAdam Balogh }
262afb13afcSAdam Balogh
verifyAdvance(CheckerContext & C,SVal LHS,SVal RHS) const263ccc0d351SAdam Balogh void IteratorRangeChecker::verifyAdvance(CheckerContext &C, SVal LHS,
264ccc0d351SAdam Balogh SVal RHS) const {
265ccc0d351SAdam Balogh verifyRandomIncrOrDecr(C, OO_PlusEqual, LHS, RHS);
266ccc0d351SAdam Balogh }
267ccc0d351SAdam Balogh
verifyPrev(CheckerContext & C,SVal LHS,SVal RHS) const268ccc0d351SAdam Balogh void IteratorRangeChecker::verifyPrev(CheckerContext &C, SVal LHS,
269ccc0d351SAdam Balogh SVal RHS) const {
270ccc0d351SAdam Balogh verifyRandomIncrOrDecr(C, OO_Minus, LHS, RHS);
271ccc0d351SAdam Balogh }
272ccc0d351SAdam Balogh
verifyNext(CheckerContext & C,SVal LHS,SVal RHS) const273ccc0d351SAdam Balogh void IteratorRangeChecker::verifyNext(CheckerContext &C, SVal LHS,
274ccc0d351SAdam Balogh SVal RHS) const {
275ccc0d351SAdam Balogh verifyRandomIncrOrDecr(C, OO_Plus, LHS, RHS);
276ccc0d351SAdam Balogh }
277ccc0d351SAdam Balogh
reportBug(const StringRef & Message,SVal Val,CheckerContext & C,ExplodedNode * ErrNode) const278ccc0d351SAdam Balogh void IteratorRangeChecker::reportBug(const StringRef &Message, SVal Val,
279ccc0d351SAdam Balogh CheckerContext &C,
280afb13afcSAdam Balogh ExplodedNode *ErrNode) const {
281afb13afcSAdam Balogh auto R = std::make_unique<PathSensitiveBugReport>(*OutOfRangeBugType, Message,
282afb13afcSAdam Balogh ErrNode);
283a3f4d17aSAdam Balogh
284a3f4d17aSAdam Balogh const auto *Pos = getIteratorPosition(C.getState(), Val);
285a3f4d17aSAdam Balogh assert(Pos && "Iterator without known position cannot be out-of-range.");
286a3f4d17aSAdam Balogh
287afb13afcSAdam Balogh R->markInteresting(Val);
288a3f4d17aSAdam Balogh R->markInteresting(Pos->getContainer());
289afb13afcSAdam Balogh C.emitReport(std::move(R));
290afb13afcSAdam Balogh }
291afb13afcSAdam Balogh
292afb13afcSAdam Balogh namespace {
293afb13afcSAdam Balogh
294afb13afcSAdam Balogh bool isLess(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2);
295afb13afcSAdam Balogh bool isGreater(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2);
296afb13afcSAdam Balogh bool isEqual(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2);
297afb13afcSAdam Balogh
isZero(ProgramStateRef State,const NonLoc & Val)298afb13afcSAdam Balogh bool isZero(ProgramStateRef State, const NonLoc &Val) {
299afb13afcSAdam Balogh auto &BVF = State->getBasicVals();
300afb13afcSAdam Balogh return compare(State, Val,
301afb13afcSAdam Balogh nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))),
302afb13afcSAdam Balogh BO_EQ);
303afb13afcSAdam Balogh }
304afb13afcSAdam Balogh
isPastTheEnd(ProgramStateRef State,const IteratorPosition & Pos)305afb13afcSAdam Balogh bool isPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos) {
306afb13afcSAdam Balogh const auto *Cont = Pos.getContainer();
307afb13afcSAdam Balogh const auto *CData = getContainerData(State, Cont);
308afb13afcSAdam Balogh if (!CData)
309afb13afcSAdam Balogh return false;
310afb13afcSAdam Balogh
311afb13afcSAdam Balogh const auto End = CData->getEnd();
312afb13afcSAdam Balogh if (End) {
313afb13afcSAdam Balogh if (isEqual(State, Pos.getOffset(), End)) {
314afb13afcSAdam Balogh return true;
315afb13afcSAdam Balogh }
316afb13afcSAdam Balogh }
317afb13afcSAdam Balogh
318afb13afcSAdam Balogh return false;
319afb13afcSAdam Balogh }
320afb13afcSAdam Balogh
isAheadOfRange(ProgramStateRef State,const IteratorPosition & Pos)321afb13afcSAdam Balogh bool isAheadOfRange(ProgramStateRef State, const IteratorPosition &Pos) {
322afb13afcSAdam Balogh const auto *Cont = Pos.getContainer();
323afb13afcSAdam Balogh const auto *CData = getContainerData(State, Cont);
324afb13afcSAdam Balogh if (!CData)
325afb13afcSAdam Balogh return false;
326afb13afcSAdam Balogh
327afb13afcSAdam Balogh const auto Beg = CData->getBegin();
328afb13afcSAdam Balogh if (Beg) {
329afb13afcSAdam Balogh if (isLess(State, Pos.getOffset(), Beg)) {
330afb13afcSAdam Balogh return true;
331afb13afcSAdam Balogh }
332afb13afcSAdam Balogh }
333afb13afcSAdam Balogh
334afb13afcSAdam Balogh return false;
335afb13afcSAdam Balogh }
336afb13afcSAdam Balogh
isBehindPastTheEnd(ProgramStateRef State,const IteratorPosition & Pos)337afb13afcSAdam Balogh bool isBehindPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos) {
338afb13afcSAdam Balogh const auto *Cont = Pos.getContainer();
339afb13afcSAdam Balogh const auto *CData = getContainerData(State, Cont);
340afb13afcSAdam Balogh if (!CData)
341afb13afcSAdam Balogh return false;
342afb13afcSAdam Balogh
343afb13afcSAdam Balogh const auto End = CData->getEnd();
344afb13afcSAdam Balogh if (End) {
345afb13afcSAdam Balogh if (isGreater(State, Pos.getOffset(), End)) {
346afb13afcSAdam Balogh return true;
347afb13afcSAdam Balogh }
348afb13afcSAdam Balogh }
349afb13afcSAdam Balogh
350afb13afcSAdam Balogh return false;
351afb13afcSAdam Balogh }
352afb13afcSAdam Balogh
isLess(ProgramStateRef State,SymbolRef Sym1,SymbolRef Sym2)353afb13afcSAdam Balogh bool isLess(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) {
354afb13afcSAdam Balogh return compare(State, Sym1, Sym2, BO_LT);
355afb13afcSAdam Balogh }
356afb13afcSAdam Balogh
isGreater(ProgramStateRef State,SymbolRef Sym1,SymbolRef Sym2)357afb13afcSAdam Balogh bool isGreater(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) {
358afb13afcSAdam Balogh return compare(State, Sym1, Sym2, BO_GT);
359afb13afcSAdam Balogh }
360afb13afcSAdam Balogh
isEqual(ProgramStateRef State,SymbolRef Sym1,SymbolRef Sym2)361afb13afcSAdam Balogh bool isEqual(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) {
362afb13afcSAdam Balogh return compare(State, Sym1, Sym2, BO_EQ);
363afb13afcSAdam Balogh }
364afb13afcSAdam Balogh
365afb13afcSAdam Balogh } // namespace
366afb13afcSAdam Balogh
registerIteratorRangeChecker(CheckerManager & mgr)367afb13afcSAdam Balogh void ento::registerIteratorRangeChecker(CheckerManager &mgr) {
368afb13afcSAdam Balogh mgr.registerChecker<IteratorRangeChecker>();
369afb13afcSAdam Balogh }
370afb13afcSAdam Balogh
shouldRegisterIteratorRangeChecker(const CheckerManager & mgr)371bda3dd0dSKirstóf Umann bool ento::shouldRegisterIteratorRangeChecker(const CheckerManager &mgr) {
372afb13afcSAdam Balogh return true;
373afb13afcSAdam Balogh }
374