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" 17480093f4SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" 18480093f4SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 19480093f4SDimitry Andric 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 35480093f4SDimitry Andric std::unique_ptr<BugType> OutOfRangeBugType; 36480093f4SDimitry Andric 375ffd83dbSDimitry Andric void verifyDereference(CheckerContext &C, SVal Val) const; 385ffd83dbSDimitry Andric void verifyIncrement(CheckerContext &C, SVal Iter) const; 395ffd83dbSDimitry Andric void verifyDecrement(CheckerContext &C, SVal Iter) const; 40480093f4SDimitry Andric void verifyRandomIncrOrDecr(CheckerContext &C, OverloadedOperatorKind Op, 415ffd83dbSDimitry Andric SVal LHS, SVal RHS) const; 425ffd83dbSDimitry Andric void verifyAdvance(CheckerContext &C, SVal LHS, SVal RHS) const; 435ffd83dbSDimitry Andric void verifyPrev(CheckerContext &C, SVal LHS, SVal RHS) const; 445ffd83dbSDimitry Andric void verifyNext(CheckerContext &C, SVal LHS, SVal RHS) const; 455ffd83dbSDimitry Andric void reportBug(const StringRef &Message, SVal Val, CheckerContext &C, 465ffd83dbSDimitry Andric ExplodedNode *ErrNode) const; 475ffd83dbSDimitry Andric 48480093f4SDimitry Andric public: 49480093f4SDimitry Andric IteratorRangeChecker(); 50480093f4SDimitry Andric 51480093f4SDimitry Andric void checkPreCall(const CallEvent &Call, CheckerContext &C) const; 525ffd83dbSDimitry Andric void checkPreStmt(const UnaryOperator *UO, CheckerContext &C) const; 535ffd83dbSDimitry Andric void checkPreStmt(const BinaryOperator *BO, CheckerContext &C) const; 545ffd83dbSDimitry Andric void checkPreStmt(const ArraySubscriptExpr *ASE, CheckerContext &C) const; 555ffd83dbSDimitry Andric void checkPreStmt(const MemberExpr *ME, CheckerContext &C) const; 56480093f4SDimitry Andric 575ffd83dbSDimitry Andric using AdvanceFn = void (IteratorRangeChecker::*)(CheckerContext &, SVal, 585ffd83dbSDimitry Andric SVal) const; 595ffd83dbSDimitry Andric 605ffd83dbSDimitry Andric CallDescriptionMap<AdvanceFn> AdvanceFunctions = { 615ffd83dbSDimitry Andric {{{"std", "advance"}, 2}, &IteratorRangeChecker::verifyAdvance}, 625ffd83dbSDimitry Andric {{{"std", "prev"}, 2}, &IteratorRangeChecker::verifyPrev}, 635ffd83dbSDimitry Andric {{{"std", "next"}, 2}, &IteratorRangeChecker::verifyNext}, 645ffd83dbSDimitry Andric }; 65480093f4SDimitry Andric }; 66480093f4SDimitry Andric 67480093f4SDimitry Andric bool isPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos); 68480093f4SDimitry Andric bool isAheadOfRange(ProgramStateRef State, const IteratorPosition &Pos); 69480093f4SDimitry Andric bool isBehindPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos); 70480093f4SDimitry Andric bool isZero(ProgramStateRef State, const NonLoc &Val); 71480093f4SDimitry Andric 72480093f4SDimitry Andric } //namespace 73480093f4SDimitry Andric 74480093f4SDimitry Andric IteratorRangeChecker::IteratorRangeChecker() { 75480093f4SDimitry Andric OutOfRangeBugType.reset( 76480093f4SDimitry Andric new BugType(this, "Iterator out of range", "Misuse of STL APIs")); 77480093f4SDimitry Andric } 78480093f4SDimitry Andric 79480093f4SDimitry Andric void IteratorRangeChecker::checkPreCall(const CallEvent &Call, 80480093f4SDimitry Andric CheckerContext &C) const { 81480093f4SDimitry Andric // Check for out of range access 82480093f4SDimitry Andric const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl()); 83480093f4SDimitry Andric if (!Func) 84480093f4SDimitry Andric return; 85480093f4SDimitry Andric 86480093f4SDimitry Andric if (Func->isOverloadedOperator()) { 87480093f4SDimitry Andric if (isIncrementOperator(Func->getOverloadedOperator())) { 88480093f4SDimitry Andric // Check for out-of-range incrementions 89480093f4SDimitry Andric if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) { 90480093f4SDimitry Andric verifyIncrement(C, InstCall->getCXXThisVal()); 91480093f4SDimitry Andric } else { 92480093f4SDimitry Andric if (Call.getNumArgs() >= 1) { 93480093f4SDimitry Andric verifyIncrement(C, Call.getArgSVal(0)); 94480093f4SDimitry Andric } 95480093f4SDimitry Andric } 96480093f4SDimitry Andric } else if (isDecrementOperator(Func->getOverloadedOperator())) { 97480093f4SDimitry Andric // Check for out-of-range decrementions 98480093f4SDimitry Andric if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) { 99480093f4SDimitry Andric verifyDecrement(C, InstCall->getCXXThisVal()); 100480093f4SDimitry Andric } else { 101480093f4SDimitry Andric if (Call.getNumArgs() >= 1) { 102480093f4SDimitry Andric verifyDecrement(C, Call.getArgSVal(0)); 103480093f4SDimitry Andric } 104480093f4SDimitry Andric } 105480093f4SDimitry Andric } else if (isRandomIncrOrDecrOperator(Func->getOverloadedOperator())) { 106480093f4SDimitry Andric if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) { 107480093f4SDimitry Andric // Check for out-of-range incrementions and decrementions 108480093f4SDimitry Andric if (Call.getNumArgs() >= 1 && 109480093f4SDimitry Andric Call.getArgExpr(0)->getType()->isIntegralOrEnumerationType()) { 110480093f4SDimitry Andric verifyRandomIncrOrDecr(C, Func->getOverloadedOperator(), 111480093f4SDimitry Andric InstCall->getCXXThisVal(), 112480093f4SDimitry Andric Call.getArgSVal(0)); 113480093f4SDimitry Andric } 114480093f4SDimitry Andric } else { 115480093f4SDimitry Andric if (Call.getNumArgs() >= 2 && 116480093f4SDimitry Andric Call.getArgExpr(1)->getType()->isIntegralOrEnumerationType()) { 117480093f4SDimitry Andric verifyRandomIncrOrDecr(C, Func->getOverloadedOperator(), 118480093f4SDimitry Andric Call.getArgSVal(0), Call.getArgSVal(1)); 119480093f4SDimitry Andric } 120480093f4SDimitry Andric } 121480093f4SDimitry Andric } else if (isDereferenceOperator(Func->getOverloadedOperator())) { 122480093f4SDimitry Andric // Check for dereference of out-of-range iterators 123480093f4SDimitry Andric if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) { 124480093f4SDimitry Andric verifyDereference(C, InstCall->getCXXThisVal()); 125480093f4SDimitry Andric } else { 126480093f4SDimitry Andric verifyDereference(C, Call.getArgSVal(0)); 127480093f4SDimitry Andric } 128480093f4SDimitry Andric } 1295ffd83dbSDimitry Andric } else { 1305ffd83dbSDimitry Andric const AdvanceFn *Verifier = AdvanceFunctions.lookup(Call); 1315ffd83dbSDimitry Andric if (Verifier) { 1325ffd83dbSDimitry Andric if (Call.getNumArgs() > 1) { 1335ffd83dbSDimitry Andric (this->**Verifier)(C, Call.getArgSVal(0), Call.getArgSVal(1)); 1345ffd83dbSDimitry Andric } else { 1355ffd83dbSDimitry Andric auto &BVF = C.getSValBuilder().getBasicValueFactory(); 1365ffd83dbSDimitry Andric (this->**Verifier)( 1375ffd83dbSDimitry Andric C, Call.getArgSVal(0), 1385ffd83dbSDimitry Andric nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1)))); 1395ffd83dbSDimitry Andric } 1405ffd83dbSDimitry Andric } 141480093f4SDimitry Andric } 142480093f4SDimitry Andric } 143480093f4SDimitry Andric 1445ffd83dbSDimitry Andric void IteratorRangeChecker::checkPreStmt(const UnaryOperator *UO, 1455ffd83dbSDimitry Andric CheckerContext &C) const { 1465ffd83dbSDimitry Andric if (isa<CXXThisExpr>(UO->getSubExpr())) 1475ffd83dbSDimitry Andric return; 1485ffd83dbSDimitry Andric 1495ffd83dbSDimitry Andric ProgramStateRef State = C.getState(); 1505ffd83dbSDimitry Andric UnaryOperatorKind OK = UO->getOpcode(); 1515ffd83dbSDimitry Andric SVal SubVal = State->getSVal(UO->getSubExpr(), C.getLocationContext()); 1525ffd83dbSDimitry Andric 1535ffd83dbSDimitry Andric if (isDereferenceOperator(OK)) { 1545ffd83dbSDimitry Andric verifyDereference(C, SubVal); 1555ffd83dbSDimitry Andric } else if (isIncrementOperator(OK)) { 1565ffd83dbSDimitry Andric verifyIncrement(C, SubVal); 1575ffd83dbSDimitry Andric } else if (isDecrementOperator(OK)) { 1585ffd83dbSDimitry Andric verifyDecrement(C, SubVal); 1595ffd83dbSDimitry Andric } 1605ffd83dbSDimitry Andric } 1615ffd83dbSDimitry Andric 1625ffd83dbSDimitry Andric void IteratorRangeChecker::checkPreStmt(const BinaryOperator *BO, 1635ffd83dbSDimitry Andric CheckerContext &C) const { 1645ffd83dbSDimitry Andric ProgramStateRef State = C.getState(); 1655ffd83dbSDimitry Andric BinaryOperatorKind OK = BO->getOpcode(); 1665ffd83dbSDimitry Andric SVal LVal = State->getSVal(BO->getLHS(), C.getLocationContext()); 1675ffd83dbSDimitry Andric 1685ffd83dbSDimitry Andric if (isDereferenceOperator(OK)) { 1695ffd83dbSDimitry Andric verifyDereference(C, LVal); 1705ffd83dbSDimitry Andric } else if (isRandomIncrOrDecrOperator(OK)) { 1715ffd83dbSDimitry Andric SVal RVal = State->getSVal(BO->getRHS(), C.getLocationContext()); 172*e8d8bef9SDimitry Andric if (!BO->getRHS()->getType()->isIntegralOrEnumerationType()) 173*e8d8bef9SDimitry Andric return; 1745ffd83dbSDimitry Andric verifyRandomIncrOrDecr(C, BinaryOperator::getOverloadedOperator(OK), LVal, 1755ffd83dbSDimitry Andric RVal); 1765ffd83dbSDimitry Andric } 1775ffd83dbSDimitry Andric } 1785ffd83dbSDimitry Andric 1795ffd83dbSDimitry Andric void IteratorRangeChecker::checkPreStmt(const ArraySubscriptExpr *ASE, 1805ffd83dbSDimitry Andric CheckerContext &C) const { 1815ffd83dbSDimitry Andric ProgramStateRef State = C.getState(); 1825ffd83dbSDimitry Andric SVal LVal = State->getSVal(ASE->getLHS(), C.getLocationContext()); 1835ffd83dbSDimitry Andric verifyDereference(C, LVal); 1845ffd83dbSDimitry Andric } 1855ffd83dbSDimitry Andric 1865ffd83dbSDimitry Andric void IteratorRangeChecker::checkPreStmt(const MemberExpr *ME, 1875ffd83dbSDimitry Andric CheckerContext &C) const { 1885ffd83dbSDimitry Andric if (!ME->isArrow() || ME->isImplicitAccess()) 1895ffd83dbSDimitry Andric return; 1905ffd83dbSDimitry Andric 1915ffd83dbSDimitry Andric ProgramStateRef State = C.getState(); 1925ffd83dbSDimitry Andric SVal BaseVal = State->getSVal(ME->getBase(), C.getLocationContext()); 1935ffd83dbSDimitry Andric verifyDereference(C, BaseVal); 1945ffd83dbSDimitry Andric } 1955ffd83dbSDimitry Andric 196480093f4SDimitry Andric void IteratorRangeChecker::verifyDereference(CheckerContext &C, 1975ffd83dbSDimitry Andric SVal Val) const { 198480093f4SDimitry Andric auto State = C.getState(); 199480093f4SDimitry Andric const auto *Pos = getIteratorPosition(State, Val); 200480093f4SDimitry Andric if (Pos && isPastTheEnd(State, *Pos)) { 201480093f4SDimitry Andric auto *N = C.generateErrorNode(State); 202480093f4SDimitry Andric if (!N) 203480093f4SDimitry Andric return; 204480093f4SDimitry Andric reportBug("Past-the-end iterator dereferenced.", Val, C, N); 205480093f4SDimitry Andric return; 206480093f4SDimitry Andric } 207480093f4SDimitry Andric } 208480093f4SDimitry Andric 2095ffd83dbSDimitry Andric void IteratorRangeChecker::verifyIncrement(CheckerContext &C, SVal Iter) const { 210480093f4SDimitry Andric auto &BVF = C.getSValBuilder().getBasicValueFactory(); 211480093f4SDimitry Andric verifyRandomIncrOrDecr(C, OO_Plus, Iter, 212480093f4SDimitry Andric nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1)))); 213480093f4SDimitry Andric } 214480093f4SDimitry Andric 2155ffd83dbSDimitry Andric void IteratorRangeChecker::verifyDecrement(CheckerContext &C, SVal Iter) const { 216480093f4SDimitry Andric auto &BVF = C.getSValBuilder().getBasicValueFactory(); 217480093f4SDimitry Andric verifyRandomIncrOrDecr(C, OO_Minus, Iter, 218480093f4SDimitry Andric nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1)))); 219480093f4SDimitry Andric } 220480093f4SDimitry Andric 221480093f4SDimitry Andric void IteratorRangeChecker::verifyRandomIncrOrDecr(CheckerContext &C, 222480093f4SDimitry Andric OverloadedOperatorKind Op, 2235ffd83dbSDimitry Andric SVal LHS, SVal RHS) const { 224480093f4SDimitry Andric auto State = C.getState(); 225480093f4SDimitry Andric 226480093f4SDimitry Andric auto Value = RHS; 227480093f4SDimitry Andric if (auto ValAsLoc = RHS.getAs<Loc>()) { 228480093f4SDimitry Andric Value = State->getRawSVal(*ValAsLoc); 229480093f4SDimitry Andric } 230480093f4SDimitry Andric 231480093f4SDimitry Andric if (Value.isUnknown()) 232480093f4SDimitry Andric return; 233480093f4SDimitry Andric 234480093f4SDimitry Andric // Incremention or decremention by 0 is never a bug. 235480093f4SDimitry Andric if (isZero(State, Value.castAs<NonLoc>())) 236480093f4SDimitry Andric return; 237480093f4SDimitry Andric 238480093f4SDimitry Andric // The result may be the past-end iterator of the container, but any other 239480093f4SDimitry Andric // out of range position is undefined behaviour 240480093f4SDimitry Andric auto StateAfter = advancePosition(State, LHS, Op, Value); 241480093f4SDimitry Andric if (!StateAfter) 242480093f4SDimitry Andric return; 243480093f4SDimitry Andric 244480093f4SDimitry Andric const auto *PosAfter = getIteratorPosition(StateAfter, LHS); 245480093f4SDimitry Andric assert(PosAfter && 246480093f4SDimitry Andric "Iterator should have position after successful advancement"); 247480093f4SDimitry Andric if (isAheadOfRange(State, *PosAfter)) { 248480093f4SDimitry Andric auto *N = C.generateErrorNode(State); 249480093f4SDimitry Andric if (!N) 250480093f4SDimitry Andric return; 251480093f4SDimitry Andric reportBug("Iterator decremented ahead of its valid range.", LHS, 252480093f4SDimitry Andric C, N); 253480093f4SDimitry Andric } 254480093f4SDimitry Andric if (isBehindPastTheEnd(State, *PosAfter)) { 255480093f4SDimitry Andric auto *N = C.generateErrorNode(State); 256480093f4SDimitry Andric if (!N) 257480093f4SDimitry Andric return; 258480093f4SDimitry Andric reportBug("Iterator incremented behind the past-the-end " 259480093f4SDimitry Andric "iterator.", LHS, C, N); 260480093f4SDimitry Andric } 261480093f4SDimitry Andric } 262480093f4SDimitry Andric 2635ffd83dbSDimitry Andric void IteratorRangeChecker::verifyAdvance(CheckerContext &C, SVal LHS, 2645ffd83dbSDimitry Andric SVal RHS) const { 2655ffd83dbSDimitry Andric verifyRandomIncrOrDecr(C, OO_PlusEqual, LHS, RHS); 2665ffd83dbSDimitry Andric } 2675ffd83dbSDimitry Andric 2685ffd83dbSDimitry Andric void IteratorRangeChecker::verifyPrev(CheckerContext &C, SVal LHS, 2695ffd83dbSDimitry Andric SVal RHS) const { 2705ffd83dbSDimitry Andric verifyRandomIncrOrDecr(C, OO_Minus, LHS, RHS); 2715ffd83dbSDimitry Andric } 2725ffd83dbSDimitry Andric 2735ffd83dbSDimitry Andric void IteratorRangeChecker::verifyNext(CheckerContext &C, SVal LHS, 2745ffd83dbSDimitry Andric SVal RHS) const { 2755ffd83dbSDimitry Andric verifyRandomIncrOrDecr(C, OO_Plus, LHS, RHS); 2765ffd83dbSDimitry Andric } 2775ffd83dbSDimitry Andric 2785ffd83dbSDimitry Andric void IteratorRangeChecker::reportBug(const StringRef &Message, SVal Val, 2795ffd83dbSDimitry Andric CheckerContext &C, 280480093f4SDimitry Andric ExplodedNode *ErrNode) const { 281480093f4SDimitry Andric auto R = std::make_unique<PathSensitiveBugReport>(*OutOfRangeBugType, Message, 282480093f4SDimitry Andric ErrNode); 2835ffd83dbSDimitry Andric 2845ffd83dbSDimitry Andric const auto *Pos = getIteratorPosition(C.getState(), Val); 2855ffd83dbSDimitry Andric assert(Pos && "Iterator without known position cannot be out-of-range."); 2865ffd83dbSDimitry Andric 287480093f4SDimitry Andric R->markInteresting(Val); 2885ffd83dbSDimitry Andric R->markInteresting(Pos->getContainer()); 289480093f4SDimitry Andric C.emitReport(std::move(R)); 290480093f4SDimitry Andric } 291480093f4SDimitry Andric 292480093f4SDimitry Andric namespace { 293480093f4SDimitry Andric 294480093f4SDimitry Andric bool isLess(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2); 295480093f4SDimitry Andric bool isGreater(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2); 296480093f4SDimitry Andric bool isEqual(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2); 297480093f4SDimitry Andric 298480093f4SDimitry Andric bool isZero(ProgramStateRef State, const NonLoc &Val) { 299480093f4SDimitry Andric auto &BVF = State->getBasicVals(); 300480093f4SDimitry Andric return compare(State, Val, 301480093f4SDimitry Andric nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))), 302480093f4SDimitry Andric BO_EQ); 303480093f4SDimitry Andric } 304480093f4SDimitry Andric 305480093f4SDimitry Andric bool isPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos) { 306480093f4SDimitry Andric const auto *Cont = Pos.getContainer(); 307480093f4SDimitry Andric const auto *CData = getContainerData(State, Cont); 308480093f4SDimitry Andric if (!CData) 309480093f4SDimitry Andric return false; 310480093f4SDimitry Andric 311480093f4SDimitry Andric const auto End = CData->getEnd(); 312480093f4SDimitry Andric if (End) { 313480093f4SDimitry Andric if (isEqual(State, Pos.getOffset(), End)) { 314480093f4SDimitry Andric return true; 315480093f4SDimitry Andric } 316480093f4SDimitry Andric } 317480093f4SDimitry Andric 318480093f4SDimitry Andric return false; 319480093f4SDimitry Andric } 320480093f4SDimitry Andric 321480093f4SDimitry Andric bool isAheadOfRange(ProgramStateRef State, const IteratorPosition &Pos) { 322480093f4SDimitry Andric const auto *Cont = Pos.getContainer(); 323480093f4SDimitry Andric const auto *CData = getContainerData(State, Cont); 324480093f4SDimitry Andric if (!CData) 325480093f4SDimitry Andric return false; 326480093f4SDimitry Andric 327480093f4SDimitry Andric const auto Beg = CData->getBegin(); 328480093f4SDimitry Andric if (Beg) { 329480093f4SDimitry Andric if (isLess(State, Pos.getOffset(), Beg)) { 330480093f4SDimitry Andric return true; 331480093f4SDimitry Andric } 332480093f4SDimitry Andric } 333480093f4SDimitry Andric 334480093f4SDimitry Andric return false; 335480093f4SDimitry Andric } 336480093f4SDimitry Andric 337480093f4SDimitry Andric bool isBehindPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos) { 338480093f4SDimitry Andric const auto *Cont = Pos.getContainer(); 339480093f4SDimitry Andric const auto *CData = getContainerData(State, Cont); 340480093f4SDimitry Andric if (!CData) 341480093f4SDimitry Andric return false; 342480093f4SDimitry Andric 343480093f4SDimitry Andric const auto End = CData->getEnd(); 344480093f4SDimitry Andric if (End) { 345480093f4SDimitry Andric if (isGreater(State, Pos.getOffset(), End)) { 346480093f4SDimitry Andric return true; 347480093f4SDimitry Andric } 348480093f4SDimitry Andric } 349480093f4SDimitry Andric 350480093f4SDimitry Andric return false; 351480093f4SDimitry Andric } 352480093f4SDimitry Andric 353480093f4SDimitry Andric bool isLess(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) { 354480093f4SDimitry Andric return compare(State, Sym1, Sym2, BO_LT); 355480093f4SDimitry Andric } 356480093f4SDimitry Andric 357480093f4SDimitry Andric bool isGreater(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) { 358480093f4SDimitry Andric return compare(State, Sym1, Sym2, BO_GT); 359480093f4SDimitry Andric } 360480093f4SDimitry Andric 361480093f4SDimitry Andric bool isEqual(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) { 362480093f4SDimitry Andric return compare(State, Sym1, Sym2, BO_EQ); 363480093f4SDimitry Andric } 364480093f4SDimitry Andric 365480093f4SDimitry Andric } // namespace 366480093f4SDimitry Andric 367480093f4SDimitry Andric void ento::registerIteratorRangeChecker(CheckerManager &mgr) { 368480093f4SDimitry Andric mgr.registerChecker<IteratorRangeChecker>(); 369480093f4SDimitry Andric } 370480093f4SDimitry Andric 3715ffd83dbSDimitry Andric bool ento::shouldRegisterIteratorRangeChecker(const CheckerManager &mgr) { 372480093f4SDimitry Andric return true; 373480093f4SDimitry Andric } 374