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 78480093f4SDimitry 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 1435ffd83dbSDimitry 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 1615ffd83dbSDimitry 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 1785ffd83dbSDimitry 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 1855ffd83dbSDimitry 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 195480093f4SDimitry 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 2085ffd83dbSDimitry 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 2145ffd83dbSDimitry 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 220480093f4SDimitry 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 2625ffd83dbSDimitry 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 2675ffd83dbSDimitry 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 2725ffd83dbSDimitry 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 277647cbc5dSDimitry 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 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 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 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 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 352480093f4SDimitry Andric bool isLess(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) { 353480093f4SDimitry Andric return compare(State, Sym1, Sym2, BO_LT); 354480093f4SDimitry Andric } 355480093f4SDimitry Andric 356480093f4SDimitry Andric bool isGreater(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) { 357480093f4SDimitry Andric return compare(State, Sym1, Sym2, BO_GT); 358480093f4SDimitry Andric } 359480093f4SDimitry Andric 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 366480093f4SDimitry Andric void ento::registerIteratorRangeChecker(CheckerManager &mgr) { 367480093f4SDimitry Andric mgr.registerChecker<IteratorRangeChecker>(); 368480093f4SDimitry Andric } 369480093f4SDimitry Andric 3705ffd83dbSDimitry Andric bool ento::shouldRegisterIteratorRangeChecker(const CheckerManager &mgr) { 371480093f4SDimitry Andric return true; 372480093f4SDimitry Andric } 373