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