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
checkPreCall(const CallEvent & Call,CheckerContext & C) const78480093f4SDimitry 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
checkPreStmt(const UnaryOperator * UO,CheckerContext & C) const1435ffd83dbSDimitry 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
checkPreStmt(const BinaryOperator * BO,CheckerContext & C) const1615ffd83dbSDimitry 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
checkPreStmt(const ArraySubscriptExpr * ASE,CheckerContext & C) const1785ffd83dbSDimitry 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
checkPreStmt(const MemberExpr * ME,CheckerContext & C) const1855ffd83dbSDimitry 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
verifyDereference(CheckerContext & C,SVal Val) const195480093f4SDimitry 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
verifyIncrement(CheckerContext & C,SVal Iter) const2085ffd83dbSDimitry 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
verifyDecrement(CheckerContext & C,SVal Iter) const2145ffd83dbSDimitry 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
verifyRandomIncrOrDecr(CheckerContext & C,OverloadedOperatorKind Op,SVal LHS,SVal RHS) const220480093f4SDimitry 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
verifyAdvance(CheckerContext & C,SVal LHS,SVal RHS) const2625ffd83dbSDimitry 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
verifyPrev(CheckerContext & C,SVal LHS,SVal RHS) const2675ffd83dbSDimitry 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
verifyNext(CheckerContext & C,SVal LHS,SVal RHS) const2725ffd83dbSDimitry 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
reportBug(StringRef Message,SVal Val,CheckerContext & C,ExplodedNode * ErrNode) const277647cbc5dSDimitry 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
isZero(ProgramStateRef State,NonLoc Val)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
isPastTheEnd(ProgramStateRef State,const IteratorPosition & Pos)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
isAheadOfRange(ProgramStateRef State,const IteratorPosition & Pos)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
isBehindPastTheEnd(ProgramStateRef State,const IteratorPosition & Pos)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
isLess(ProgramStateRef State,SymbolRef Sym1,SymbolRef Sym2)352480093f4SDimitry Andric bool isLess(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) {
353480093f4SDimitry Andric return compare(State, Sym1, Sym2, BO_LT);
354480093f4SDimitry Andric }
355480093f4SDimitry Andric
isGreater(ProgramStateRef State,SymbolRef Sym1,SymbolRef Sym2)356480093f4SDimitry Andric bool isGreater(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) {
357480093f4SDimitry Andric return compare(State, Sym1, Sym2, BO_GT);
358480093f4SDimitry Andric }
359480093f4SDimitry Andric
isEqual(ProgramStateRef State,SymbolRef Sym1,SymbolRef Sym2)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
registerIteratorRangeChecker(CheckerManager & mgr)366480093f4SDimitry Andric void ento::registerIteratorRangeChecker(CheckerManager &mgr) {
367480093f4SDimitry Andric mgr.registerChecker<IteratorRangeChecker>();
368480093f4SDimitry Andric }
369480093f4SDimitry Andric
shouldRegisterIteratorRangeChecker(const CheckerManager & mgr)3705ffd83dbSDimitry Andric bool ento::shouldRegisterIteratorRangeChecker(const CheckerManager &mgr) {
371480093f4SDimitry Andric return true;
372480093f4SDimitry Andric }
373