xref: /openbsd-src/gnu/llvm/clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp (revision 12c855180aad702bbcca06e0398d774beeafb155)
1e5dd7070Spatrick //===-- IteratorRangeChecker.cpp ----------------------------------*- C++ -*--//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick //
9e5dd7070Spatrick // Defines a checker for dereference of the past-the-end iterator and
10e5dd7070Spatrick // out-of-range increments and decrements.
11e5dd7070Spatrick //
12e5dd7070Spatrick //===----------------------------------------------------------------------===//
13e5dd7070Spatrick 
14e5dd7070Spatrick #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
15e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
16e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/Checker.h"
17*12c85518Srobert #include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
18e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
19e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
20e5dd7070Spatrick 
21e5dd7070Spatrick #include "Iterator.h"
22e5dd7070Spatrick 
23e5dd7070Spatrick using namespace clang;
24e5dd7070Spatrick using namespace ento;
25e5dd7070Spatrick using namespace iterator;
26e5dd7070Spatrick 
27e5dd7070Spatrick namespace {
28e5dd7070Spatrick 
29e5dd7070Spatrick class IteratorRangeChecker
30ec727ea7Spatrick   : public Checker<check::PreCall, check::PreStmt<UnaryOperator>,
31ec727ea7Spatrick                    check::PreStmt<BinaryOperator>,
32ec727ea7Spatrick                    check::PreStmt<ArraySubscriptExpr>,
33ec727ea7Spatrick                    check::PreStmt<MemberExpr>> {
34e5dd7070Spatrick 
35e5dd7070Spatrick   std::unique_ptr<BugType> OutOfRangeBugType;
36e5dd7070Spatrick 
37ec727ea7Spatrick   void verifyDereference(CheckerContext &C, SVal Val) const;
38ec727ea7Spatrick   void verifyIncrement(CheckerContext &C, SVal Iter) const;
39ec727ea7Spatrick   void verifyDecrement(CheckerContext &C, SVal Iter) const;
40e5dd7070Spatrick   void verifyRandomIncrOrDecr(CheckerContext &C, OverloadedOperatorKind Op,
41ec727ea7Spatrick                               SVal LHS, SVal RHS) const;
42ec727ea7Spatrick   void verifyAdvance(CheckerContext &C, SVal LHS, SVal RHS) const;
43ec727ea7Spatrick   void verifyPrev(CheckerContext &C, SVal LHS, SVal RHS) const;
44ec727ea7Spatrick   void verifyNext(CheckerContext &C, SVal LHS, SVal RHS) const;
45ec727ea7Spatrick   void reportBug(const StringRef &Message, SVal Val, CheckerContext &C,
46ec727ea7Spatrick                  ExplodedNode *ErrNode) const;
47ec727ea7Spatrick 
48e5dd7070Spatrick public:
49e5dd7070Spatrick   IteratorRangeChecker();
50e5dd7070Spatrick 
51e5dd7070Spatrick   void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
52ec727ea7Spatrick   void checkPreStmt(const UnaryOperator *UO, CheckerContext &C) const;
53ec727ea7Spatrick   void checkPreStmt(const BinaryOperator *BO, CheckerContext &C) const;
54ec727ea7Spatrick   void checkPreStmt(const ArraySubscriptExpr *ASE, CheckerContext &C) const;
55ec727ea7Spatrick   void checkPreStmt(const MemberExpr *ME, CheckerContext &C) const;
56e5dd7070Spatrick 
57ec727ea7Spatrick   using AdvanceFn = void (IteratorRangeChecker::*)(CheckerContext &, SVal,
58ec727ea7Spatrick                                                    SVal) const;
59ec727ea7Spatrick 
60ec727ea7Spatrick   CallDescriptionMap<AdvanceFn> AdvanceFunctions = {
61ec727ea7Spatrick       {{{"std", "advance"}, 2}, &IteratorRangeChecker::verifyAdvance},
62ec727ea7Spatrick       {{{"std", "prev"}, 2}, &IteratorRangeChecker::verifyPrev},
63ec727ea7Spatrick       {{{"std", "next"}, 2}, &IteratorRangeChecker::verifyNext},
64ec727ea7Spatrick   };
65e5dd7070Spatrick };
66e5dd7070Spatrick 
67e5dd7070Spatrick bool isPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos);
68e5dd7070Spatrick bool isAheadOfRange(ProgramStateRef State, const IteratorPosition &Pos);
69e5dd7070Spatrick bool isBehindPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos);
70e5dd7070Spatrick bool isZero(ProgramStateRef State, const NonLoc &Val);
71e5dd7070Spatrick 
72e5dd7070Spatrick } //namespace
73e5dd7070Spatrick 
IteratorRangeChecker()74e5dd7070Spatrick IteratorRangeChecker::IteratorRangeChecker() {
75e5dd7070Spatrick   OutOfRangeBugType.reset(
76e5dd7070Spatrick       new BugType(this, "Iterator out of range", "Misuse of STL APIs"));
77e5dd7070Spatrick }
78e5dd7070Spatrick 
checkPreCall(const CallEvent & Call,CheckerContext & C) const79e5dd7070Spatrick void IteratorRangeChecker::checkPreCall(const CallEvent &Call,
80e5dd7070Spatrick                                         CheckerContext &C) const {
81e5dd7070Spatrick   // Check for out of range access
82e5dd7070Spatrick   const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
83e5dd7070Spatrick   if (!Func)
84e5dd7070Spatrick     return;
85e5dd7070Spatrick 
86e5dd7070Spatrick   if (Func->isOverloadedOperator()) {
87e5dd7070Spatrick     if (isIncrementOperator(Func->getOverloadedOperator())) {
88e5dd7070Spatrick       // Check for out-of-range incrementions
89e5dd7070Spatrick       if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
90e5dd7070Spatrick         verifyIncrement(C, InstCall->getCXXThisVal());
91e5dd7070Spatrick       } else {
92e5dd7070Spatrick         if (Call.getNumArgs() >= 1) {
93e5dd7070Spatrick           verifyIncrement(C, Call.getArgSVal(0));
94e5dd7070Spatrick         }
95e5dd7070Spatrick       }
96e5dd7070Spatrick     } else if (isDecrementOperator(Func->getOverloadedOperator())) {
97e5dd7070Spatrick       // Check for out-of-range decrementions
98e5dd7070Spatrick       if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
99e5dd7070Spatrick         verifyDecrement(C, InstCall->getCXXThisVal());
100e5dd7070Spatrick       } else {
101e5dd7070Spatrick         if (Call.getNumArgs() >= 1) {
102e5dd7070Spatrick           verifyDecrement(C, Call.getArgSVal(0));
103e5dd7070Spatrick         }
104e5dd7070Spatrick       }
105e5dd7070Spatrick     } else if (isRandomIncrOrDecrOperator(Func->getOverloadedOperator())) {
106e5dd7070Spatrick       if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
107e5dd7070Spatrick         // Check for out-of-range incrementions and decrementions
108e5dd7070Spatrick         if (Call.getNumArgs() >= 1 &&
109e5dd7070Spatrick             Call.getArgExpr(0)->getType()->isIntegralOrEnumerationType()) {
110e5dd7070Spatrick           verifyRandomIncrOrDecr(C, Func->getOverloadedOperator(),
111e5dd7070Spatrick                                  InstCall->getCXXThisVal(),
112e5dd7070Spatrick                                  Call.getArgSVal(0));
113e5dd7070Spatrick         }
114e5dd7070Spatrick       } else {
115e5dd7070Spatrick         if (Call.getNumArgs() >= 2 &&
116e5dd7070Spatrick             Call.getArgExpr(1)->getType()->isIntegralOrEnumerationType()) {
117e5dd7070Spatrick           verifyRandomIncrOrDecr(C, Func->getOverloadedOperator(),
118e5dd7070Spatrick                                  Call.getArgSVal(0), Call.getArgSVal(1));
119e5dd7070Spatrick         }
120e5dd7070Spatrick       }
121e5dd7070Spatrick     } else if (isDereferenceOperator(Func->getOverloadedOperator())) {
122e5dd7070Spatrick       // Check for dereference of out-of-range iterators
123e5dd7070Spatrick       if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
124e5dd7070Spatrick         verifyDereference(C, InstCall->getCXXThisVal());
125e5dd7070Spatrick       } else {
126e5dd7070Spatrick         verifyDereference(C, Call.getArgSVal(0));
127e5dd7070Spatrick       }
128e5dd7070Spatrick     }
129ec727ea7Spatrick   } else {
130ec727ea7Spatrick     const AdvanceFn *Verifier = AdvanceFunctions.lookup(Call);
131ec727ea7Spatrick     if (Verifier) {
132ec727ea7Spatrick       if (Call.getNumArgs() > 1) {
133ec727ea7Spatrick         (this->**Verifier)(C, Call.getArgSVal(0), Call.getArgSVal(1));
134ec727ea7Spatrick       } else {
135ec727ea7Spatrick         auto &BVF = C.getSValBuilder().getBasicValueFactory();
136ec727ea7Spatrick         (this->**Verifier)(
137ec727ea7Spatrick             C, Call.getArgSVal(0),
138ec727ea7Spatrick             nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
139ec727ea7Spatrick       }
140ec727ea7Spatrick     }
141e5dd7070Spatrick   }
142e5dd7070Spatrick }
143e5dd7070Spatrick 
checkPreStmt(const UnaryOperator * UO,CheckerContext & C) const144ec727ea7Spatrick void IteratorRangeChecker::checkPreStmt(const UnaryOperator *UO,
145ec727ea7Spatrick                                         CheckerContext &C) const {
146ec727ea7Spatrick   if (isa<CXXThisExpr>(UO->getSubExpr()))
147ec727ea7Spatrick     return;
148ec727ea7Spatrick 
149ec727ea7Spatrick   ProgramStateRef State = C.getState();
150ec727ea7Spatrick   UnaryOperatorKind OK = UO->getOpcode();
151ec727ea7Spatrick   SVal SubVal = State->getSVal(UO->getSubExpr(), C.getLocationContext());
152ec727ea7Spatrick 
153ec727ea7Spatrick   if (isDereferenceOperator(OK)) {
154ec727ea7Spatrick     verifyDereference(C, SubVal);
155ec727ea7Spatrick   } else if (isIncrementOperator(OK)) {
156ec727ea7Spatrick     verifyIncrement(C, SubVal);
157ec727ea7Spatrick   } else if (isDecrementOperator(OK)) {
158ec727ea7Spatrick     verifyDecrement(C, SubVal);
159ec727ea7Spatrick   }
160ec727ea7Spatrick }
161ec727ea7Spatrick 
checkPreStmt(const BinaryOperator * BO,CheckerContext & C) const162ec727ea7Spatrick void IteratorRangeChecker::checkPreStmt(const BinaryOperator *BO,
163ec727ea7Spatrick                                         CheckerContext &C) const {
164ec727ea7Spatrick   ProgramStateRef State = C.getState();
165ec727ea7Spatrick   BinaryOperatorKind OK = BO->getOpcode();
166ec727ea7Spatrick   SVal LVal = State->getSVal(BO->getLHS(), C.getLocationContext());
167ec727ea7Spatrick 
168ec727ea7Spatrick   if (isDereferenceOperator(OK)) {
169ec727ea7Spatrick     verifyDereference(C, LVal);
170ec727ea7Spatrick   } else if (isRandomIncrOrDecrOperator(OK)) {
171ec727ea7Spatrick     SVal RVal = State->getSVal(BO->getRHS(), C.getLocationContext());
172a9ac8606Spatrick     if (!BO->getRHS()->getType()->isIntegralOrEnumerationType())
173a9ac8606Spatrick       return;
174ec727ea7Spatrick     verifyRandomIncrOrDecr(C, BinaryOperator::getOverloadedOperator(OK), LVal,
175ec727ea7Spatrick                            RVal);
176ec727ea7Spatrick   }
177ec727ea7Spatrick }
178ec727ea7Spatrick 
checkPreStmt(const ArraySubscriptExpr * ASE,CheckerContext & C) const179ec727ea7Spatrick void IteratorRangeChecker::checkPreStmt(const ArraySubscriptExpr *ASE,
180ec727ea7Spatrick                                         CheckerContext &C) const {
181ec727ea7Spatrick   ProgramStateRef State = C.getState();
182ec727ea7Spatrick   SVal LVal = State->getSVal(ASE->getLHS(), C.getLocationContext());
183ec727ea7Spatrick   verifyDereference(C, LVal);
184ec727ea7Spatrick }
185ec727ea7Spatrick 
checkPreStmt(const MemberExpr * ME,CheckerContext & C) const186ec727ea7Spatrick void IteratorRangeChecker::checkPreStmt(const MemberExpr *ME,
187ec727ea7Spatrick                                         CheckerContext &C) const {
188ec727ea7Spatrick   if (!ME->isArrow() || ME->isImplicitAccess())
189ec727ea7Spatrick     return;
190ec727ea7Spatrick 
191ec727ea7Spatrick   ProgramStateRef State = C.getState();
192ec727ea7Spatrick   SVal BaseVal = State->getSVal(ME->getBase(), C.getLocationContext());
193ec727ea7Spatrick   verifyDereference(C, BaseVal);
194ec727ea7Spatrick }
195ec727ea7Spatrick 
verifyDereference(CheckerContext & C,SVal Val) const196e5dd7070Spatrick void IteratorRangeChecker::verifyDereference(CheckerContext &C,
197ec727ea7Spatrick                                              SVal Val) const {
198e5dd7070Spatrick   auto State = C.getState();
199e5dd7070Spatrick   const auto *Pos = getIteratorPosition(State, Val);
200e5dd7070Spatrick   if (Pos && isPastTheEnd(State, *Pos)) {
201e5dd7070Spatrick     auto *N = C.generateErrorNode(State);
202e5dd7070Spatrick     if (!N)
203e5dd7070Spatrick       return;
204e5dd7070Spatrick     reportBug("Past-the-end iterator dereferenced.", Val, C, N);
205e5dd7070Spatrick     return;
206e5dd7070Spatrick   }
207e5dd7070Spatrick }
208e5dd7070Spatrick 
verifyIncrement(CheckerContext & C,SVal Iter) const209ec727ea7Spatrick void IteratorRangeChecker::verifyIncrement(CheckerContext &C, SVal Iter) const {
210e5dd7070Spatrick   auto &BVF = C.getSValBuilder().getBasicValueFactory();
211e5dd7070Spatrick   verifyRandomIncrOrDecr(C, OO_Plus, Iter,
212e5dd7070Spatrick                      nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
213e5dd7070Spatrick }
214e5dd7070Spatrick 
verifyDecrement(CheckerContext & C,SVal Iter) const215ec727ea7Spatrick void IteratorRangeChecker::verifyDecrement(CheckerContext &C, SVal Iter) const {
216e5dd7070Spatrick   auto &BVF = C.getSValBuilder().getBasicValueFactory();
217e5dd7070Spatrick   verifyRandomIncrOrDecr(C, OO_Minus, Iter,
218e5dd7070Spatrick                      nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
219e5dd7070Spatrick }
220e5dd7070Spatrick 
verifyRandomIncrOrDecr(CheckerContext & C,OverloadedOperatorKind Op,SVal LHS,SVal RHS) const221e5dd7070Spatrick void IteratorRangeChecker::verifyRandomIncrOrDecr(CheckerContext &C,
222e5dd7070Spatrick                                                   OverloadedOperatorKind Op,
223ec727ea7Spatrick                                                   SVal LHS, SVal RHS) const {
224e5dd7070Spatrick   auto State = C.getState();
225e5dd7070Spatrick 
226e5dd7070Spatrick   auto Value = RHS;
227e5dd7070Spatrick   if (auto ValAsLoc = RHS.getAs<Loc>()) {
228e5dd7070Spatrick     Value = State->getRawSVal(*ValAsLoc);
229e5dd7070Spatrick   }
230e5dd7070Spatrick 
231a9ac8606Spatrick   if (Value.isUnknownOrUndef())
232e5dd7070Spatrick     return;
233e5dd7070Spatrick 
234e5dd7070Spatrick   // Incremention or decremention by 0 is never a bug.
235e5dd7070Spatrick   if (isZero(State, Value.castAs<NonLoc>()))
236e5dd7070Spatrick     return;
237e5dd7070Spatrick 
238e5dd7070Spatrick   // The result may be the past-end iterator of the container, but any other
239e5dd7070Spatrick   // out of range position is undefined behaviour
240e5dd7070Spatrick   auto StateAfter = advancePosition(State, LHS, Op, Value);
241e5dd7070Spatrick   if (!StateAfter)
242e5dd7070Spatrick     return;
243e5dd7070Spatrick 
244e5dd7070Spatrick   const auto *PosAfter = getIteratorPosition(StateAfter, LHS);
245e5dd7070Spatrick   assert(PosAfter &&
246e5dd7070Spatrick          "Iterator should have position after successful advancement");
247e5dd7070Spatrick   if (isAheadOfRange(State, *PosAfter)) {
248e5dd7070Spatrick     auto *N = C.generateErrorNode(State);
249e5dd7070Spatrick     if (!N)
250e5dd7070Spatrick       return;
251e5dd7070Spatrick     reportBug("Iterator decremented ahead of its valid range.", LHS,
252e5dd7070Spatrick                         C, N);
253e5dd7070Spatrick   }
254e5dd7070Spatrick   if (isBehindPastTheEnd(State, *PosAfter)) {
255e5dd7070Spatrick     auto *N = C.generateErrorNode(State);
256e5dd7070Spatrick     if (!N)
257e5dd7070Spatrick       return;
258e5dd7070Spatrick     reportBug("Iterator incremented behind the past-the-end "
259e5dd7070Spatrick                         "iterator.", LHS, C, N);
260e5dd7070Spatrick   }
261e5dd7070Spatrick }
262e5dd7070Spatrick 
verifyAdvance(CheckerContext & C,SVal LHS,SVal RHS) const263ec727ea7Spatrick void IteratorRangeChecker::verifyAdvance(CheckerContext &C, SVal LHS,
264ec727ea7Spatrick                                          SVal RHS) const {
265ec727ea7Spatrick   verifyRandomIncrOrDecr(C, OO_PlusEqual, LHS, RHS);
266ec727ea7Spatrick }
267ec727ea7Spatrick 
verifyPrev(CheckerContext & C,SVal LHS,SVal RHS) const268ec727ea7Spatrick void IteratorRangeChecker::verifyPrev(CheckerContext &C, SVal LHS,
269ec727ea7Spatrick                                       SVal RHS) const {
270ec727ea7Spatrick   verifyRandomIncrOrDecr(C, OO_Minus, LHS, RHS);
271ec727ea7Spatrick }
272ec727ea7Spatrick 
verifyNext(CheckerContext & C,SVal LHS,SVal RHS) const273ec727ea7Spatrick void IteratorRangeChecker::verifyNext(CheckerContext &C, SVal LHS,
274ec727ea7Spatrick                                       SVal RHS) const {
275ec727ea7Spatrick   verifyRandomIncrOrDecr(C, OO_Plus, LHS, RHS);
276ec727ea7Spatrick }
277ec727ea7Spatrick 
reportBug(const StringRef & Message,SVal Val,CheckerContext & C,ExplodedNode * ErrNode) const278ec727ea7Spatrick void IteratorRangeChecker::reportBug(const StringRef &Message, SVal Val,
279ec727ea7Spatrick                                      CheckerContext &C,
280e5dd7070Spatrick                                      ExplodedNode *ErrNode) const {
281e5dd7070Spatrick   auto R = std::make_unique<PathSensitiveBugReport>(*OutOfRangeBugType, Message,
282e5dd7070Spatrick                                                     ErrNode);
283ec727ea7Spatrick 
284ec727ea7Spatrick   const auto *Pos = getIteratorPosition(C.getState(), Val);
285ec727ea7Spatrick   assert(Pos && "Iterator without known position cannot be out-of-range.");
286ec727ea7Spatrick 
287e5dd7070Spatrick   R->markInteresting(Val);
288ec727ea7Spatrick   R->markInteresting(Pos->getContainer());
289e5dd7070Spatrick   C.emitReport(std::move(R));
290e5dd7070Spatrick }
291e5dd7070Spatrick 
292e5dd7070Spatrick namespace {
293e5dd7070Spatrick 
294e5dd7070Spatrick bool isLess(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2);
295e5dd7070Spatrick bool isGreater(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2);
296e5dd7070Spatrick bool isEqual(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2);
297e5dd7070Spatrick 
isZero(ProgramStateRef State,const NonLoc & Val)298e5dd7070Spatrick bool isZero(ProgramStateRef State, const NonLoc &Val) {
299e5dd7070Spatrick   auto &BVF = State->getBasicVals();
300e5dd7070Spatrick   return compare(State, Val,
301e5dd7070Spatrick                  nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))),
302e5dd7070Spatrick                  BO_EQ);
303e5dd7070Spatrick }
304e5dd7070Spatrick 
isPastTheEnd(ProgramStateRef State,const IteratorPosition & Pos)305e5dd7070Spatrick bool isPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos) {
306e5dd7070Spatrick   const auto *Cont = Pos.getContainer();
307e5dd7070Spatrick   const auto *CData = getContainerData(State, Cont);
308e5dd7070Spatrick   if (!CData)
309e5dd7070Spatrick     return false;
310e5dd7070Spatrick 
311e5dd7070Spatrick   const auto End = CData->getEnd();
312e5dd7070Spatrick   if (End) {
313e5dd7070Spatrick     if (isEqual(State, Pos.getOffset(), End)) {
314e5dd7070Spatrick       return true;
315e5dd7070Spatrick     }
316e5dd7070Spatrick   }
317e5dd7070Spatrick 
318e5dd7070Spatrick   return false;
319e5dd7070Spatrick }
320e5dd7070Spatrick 
isAheadOfRange(ProgramStateRef State,const IteratorPosition & Pos)321e5dd7070Spatrick bool isAheadOfRange(ProgramStateRef State, const IteratorPosition &Pos) {
322e5dd7070Spatrick   const auto *Cont = Pos.getContainer();
323e5dd7070Spatrick   const auto *CData = getContainerData(State, Cont);
324e5dd7070Spatrick   if (!CData)
325e5dd7070Spatrick     return false;
326e5dd7070Spatrick 
327e5dd7070Spatrick   const auto Beg = CData->getBegin();
328e5dd7070Spatrick   if (Beg) {
329e5dd7070Spatrick     if (isLess(State, Pos.getOffset(), Beg)) {
330e5dd7070Spatrick       return true;
331e5dd7070Spatrick     }
332e5dd7070Spatrick   }
333e5dd7070Spatrick 
334e5dd7070Spatrick   return false;
335e5dd7070Spatrick }
336e5dd7070Spatrick 
isBehindPastTheEnd(ProgramStateRef State,const IteratorPosition & Pos)337e5dd7070Spatrick bool isBehindPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos) {
338e5dd7070Spatrick   const auto *Cont = Pos.getContainer();
339e5dd7070Spatrick   const auto *CData = getContainerData(State, Cont);
340e5dd7070Spatrick   if (!CData)
341e5dd7070Spatrick     return false;
342e5dd7070Spatrick 
343e5dd7070Spatrick   const auto End = CData->getEnd();
344e5dd7070Spatrick   if (End) {
345e5dd7070Spatrick     if (isGreater(State, Pos.getOffset(), End)) {
346e5dd7070Spatrick       return true;
347e5dd7070Spatrick     }
348e5dd7070Spatrick   }
349e5dd7070Spatrick 
350e5dd7070Spatrick   return false;
351e5dd7070Spatrick }
352e5dd7070Spatrick 
isLess(ProgramStateRef State,SymbolRef Sym1,SymbolRef Sym2)353e5dd7070Spatrick bool isLess(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) {
354e5dd7070Spatrick   return compare(State, Sym1, Sym2, BO_LT);
355e5dd7070Spatrick }
356e5dd7070Spatrick 
isGreater(ProgramStateRef State,SymbolRef Sym1,SymbolRef Sym2)357e5dd7070Spatrick bool isGreater(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) {
358e5dd7070Spatrick   return compare(State, Sym1, Sym2, BO_GT);
359e5dd7070Spatrick }
360e5dd7070Spatrick 
isEqual(ProgramStateRef State,SymbolRef Sym1,SymbolRef Sym2)361e5dd7070Spatrick bool isEqual(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) {
362e5dd7070Spatrick   return compare(State, Sym1, Sym2, BO_EQ);
363e5dd7070Spatrick }
364e5dd7070Spatrick 
365e5dd7070Spatrick } // namespace
366e5dd7070Spatrick 
registerIteratorRangeChecker(CheckerManager & mgr)367e5dd7070Spatrick void ento::registerIteratorRangeChecker(CheckerManager &mgr) {
368e5dd7070Spatrick   mgr.registerChecker<IteratorRangeChecker>();
369e5dd7070Spatrick }
370e5dd7070Spatrick 
shouldRegisterIteratorRangeChecker(const CheckerManager & mgr)371ec727ea7Spatrick bool ento::shouldRegisterIteratorRangeChecker(const CheckerManager &mgr) {
372e5dd7070Spatrick   return true;
373e5dd7070Spatrick }
374