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 30*5ffd83dbSDimitry Andric : public Checker<check::PreCall, check::PreStmt<UnaryOperator>, 31*5ffd83dbSDimitry Andric check::PreStmt<BinaryOperator>, 32*5ffd83dbSDimitry Andric check::PreStmt<ArraySubscriptExpr>, 33*5ffd83dbSDimitry Andric check::PreStmt<MemberExpr>> { 34480093f4SDimitry Andric 35480093f4SDimitry Andric std::unique_ptr<BugType> OutOfRangeBugType; 36480093f4SDimitry Andric 37*5ffd83dbSDimitry Andric void verifyDereference(CheckerContext &C, SVal Val) const; 38*5ffd83dbSDimitry Andric void verifyIncrement(CheckerContext &C, SVal Iter) const; 39*5ffd83dbSDimitry Andric void verifyDecrement(CheckerContext &C, SVal Iter) const; 40480093f4SDimitry Andric void verifyRandomIncrOrDecr(CheckerContext &C, OverloadedOperatorKind Op, 41*5ffd83dbSDimitry Andric SVal LHS, SVal RHS) const; 42*5ffd83dbSDimitry Andric void verifyAdvance(CheckerContext &C, SVal LHS, SVal RHS) const; 43*5ffd83dbSDimitry Andric void verifyPrev(CheckerContext &C, SVal LHS, SVal RHS) const; 44*5ffd83dbSDimitry Andric void verifyNext(CheckerContext &C, SVal LHS, SVal RHS) const; 45*5ffd83dbSDimitry Andric void reportBug(const StringRef &Message, SVal Val, CheckerContext &C, 46*5ffd83dbSDimitry Andric ExplodedNode *ErrNode) const; 47*5ffd83dbSDimitry Andric 48480093f4SDimitry Andric public: 49480093f4SDimitry Andric IteratorRangeChecker(); 50480093f4SDimitry Andric 51480093f4SDimitry Andric void checkPreCall(const CallEvent &Call, CheckerContext &C) const; 52*5ffd83dbSDimitry Andric void checkPreStmt(const UnaryOperator *UO, CheckerContext &C) const; 53*5ffd83dbSDimitry Andric void checkPreStmt(const BinaryOperator *BO, CheckerContext &C) const; 54*5ffd83dbSDimitry Andric void checkPreStmt(const ArraySubscriptExpr *ASE, CheckerContext &C) const; 55*5ffd83dbSDimitry Andric void checkPreStmt(const MemberExpr *ME, CheckerContext &C) const; 56480093f4SDimitry Andric 57*5ffd83dbSDimitry Andric using AdvanceFn = void (IteratorRangeChecker::*)(CheckerContext &, SVal, 58*5ffd83dbSDimitry Andric SVal) const; 59*5ffd83dbSDimitry Andric 60*5ffd83dbSDimitry Andric CallDescriptionMap<AdvanceFn> AdvanceFunctions = { 61*5ffd83dbSDimitry Andric {{{"std", "advance"}, 2}, &IteratorRangeChecker::verifyAdvance}, 62*5ffd83dbSDimitry Andric {{{"std", "prev"}, 2}, &IteratorRangeChecker::verifyPrev}, 63*5ffd83dbSDimitry Andric {{{"std", "next"}, 2}, &IteratorRangeChecker::verifyNext}, 64*5ffd83dbSDimitry 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 } 129*5ffd83dbSDimitry Andric } else { 130*5ffd83dbSDimitry Andric const AdvanceFn *Verifier = AdvanceFunctions.lookup(Call); 131*5ffd83dbSDimitry Andric if (Verifier) { 132*5ffd83dbSDimitry Andric if (Call.getNumArgs() > 1) { 133*5ffd83dbSDimitry Andric (this->**Verifier)(C, Call.getArgSVal(0), Call.getArgSVal(1)); 134*5ffd83dbSDimitry Andric } else { 135*5ffd83dbSDimitry Andric auto &BVF = C.getSValBuilder().getBasicValueFactory(); 136*5ffd83dbSDimitry Andric (this->**Verifier)( 137*5ffd83dbSDimitry Andric C, Call.getArgSVal(0), 138*5ffd83dbSDimitry Andric nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1)))); 139*5ffd83dbSDimitry Andric } 140*5ffd83dbSDimitry Andric } 141480093f4SDimitry Andric } 142480093f4SDimitry Andric } 143480093f4SDimitry Andric 144*5ffd83dbSDimitry Andric void IteratorRangeChecker::checkPreStmt(const UnaryOperator *UO, 145*5ffd83dbSDimitry Andric CheckerContext &C) const { 146*5ffd83dbSDimitry Andric if (isa<CXXThisExpr>(UO->getSubExpr())) 147*5ffd83dbSDimitry Andric return; 148*5ffd83dbSDimitry Andric 149*5ffd83dbSDimitry Andric ProgramStateRef State = C.getState(); 150*5ffd83dbSDimitry Andric UnaryOperatorKind OK = UO->getOpcode(); 151*5ffd83dbSDimitry Andric SVal SubVal = State->getSVal(UO->getSubExpr(), C.getLocationContext()); 152*5ffd83dbSDimitry Andric 153*5ffd83dbSDimitry Andric if (isDereferenceOperator(OK)) { 154*5ffd83dbSDimitry Andric verifyDereference(C, SubVal); 155*5ffd83dbSDimitry Andric } else if (isIncrementOperator(OK)) { 156*5ffd83dbSDimitry Andric verifyIncrement(C, SubVal); 157*5ffd83dbSDimitry Andric } else if (isDecrementOperator(OK)) { 158*5ffd83dbSDimitry Andric verifyDecrement(C, SubVal); 159*5ffd83dbSDimitry Andric } 160*5ffd83dbSDimitry Andric } 161*5ffd83dbSDimitry Andric 162*5ffd83dbSDimitry Andric void IteratorRangeChecker::checkPreStmt(const BinaryOperator *BO, 163*5ffd83dbSDimitry Andric CheckerContext &C) const { 164*5ffd83dbSDimitry Andric ProgramStateRef State = C.getState(); 165*5ffd83dbSDimitry Andric BinaryOperatorKind OK = BO->getOpcode(); 166*5ffd83dbSDimitry Andric SVal LVal = State->getSVal(BO->getLHS(), C.getLocationContext()); 167*5ffd83dbSDimitry Andric 168*5ffd83dbSDimitry Andric if (isDereferenceOperator(OK)) { 169*5ffd83dbSDimitry Andric verifyDereference(C, LVal); 170*5ffd83dbSDimitry Andric } else if (isRandomIncrOrDecrOperator(OK)) { 171*5ffd83dbSDimitry Andric SVal RVal = State->getSVal(BO->getRHS(), C.getLocationContext()); 172*5ffd83dbSDimitry Andric verifyRandomIncrOrDecr(C, BinaryOperator::getOverloadedOperator(OK), LVal, 173*5ffd83dbSDimitry Andric RVal); 174*5ffd83dbSDimitry Andric } 175*5ffd83dbSDimitry Andric } 176*5ffd83dbSDimitry Andric 177*5ffd83dbSDimitry Andric void IteratorRangeChecker::checkPreStmt(const ArraySubscriptExpr *ASE, 178*5ffd83dbSDimitry Andric CheckerContext &C) const { 179*5ffd83dbSDimitry Andric ProgramStateRef State = C.getState(); 180*5ffd83dbSDimitry Andric SVal LVal = State->getSVal(ASE->getLHS(), C.getLocationContext()); 181*5ffd83dbSDimitry Andric verifyDereference(C, LVal); 182*5ffd83dbSDimitry Andric } 183*5ffd83dbSDimitry Andric 184*5ffd83dbSDimitry Andric void IteratorRangeChecker::checkPreStmt(const MemberExpr *ME, 185*5ffd83dbSDimitry Andric CheckerContext &C) const { 186*5ffd83dbSDimitry Andric if (!ME->isArrow() || ME->isImplicitAccess()) 187*5ffd83dbSDimitry Andric return; 188*5ffd83dbSDimitry Andric 189*5ffd83dbSDimitry Andric ProgramStateRef State = C.getState(); 190*5ffd83dbSDimitry Andric SVal BaseVal = State->getSVal(ME->getBase(), C.getLocationContext()); 191*5ffd83dbSDimitry Andric verifyDereference(C, BaseVal); 192*5ffd83dbSDimitry Andric } 193*5ffd83dbSDimitry Andric 194480093f4SDimitry Andric void IteratorRangeChecker::verifyDereference(CheckerContext &C, 195*5ffd83dbSDimitry Andric SVal Val) const { 196480093f4SDimitry Andric auto State = C.getState(); 197480093f4SDimitry Andric const auto *Pos = getIteratorPosition(State, Val); 198480093f4SDimitry Andric if (Pos && isPastTheEnd(State, *Pos)) { 199480093f4SDimitry Andric auto *N = C.generateErrorNode(State); 200480093f4SDimitry Andric if (!N) 201480093f4SDimitry Andric return; 202480093f4SDimitry Andric reportBug("Past-the-end iterator dereferenced.", Val, C, N); 203480093f4SDimitry Andric return; 204480093f4SDimitry Andric } 205480093f4SDimitry Andric } 206480093f4SDimitry Andric 207*5ffd83dbSDimitry Andric void IteratorRangeChecker::verifyIncrement(CheckerContext &C, SVal Iter) const { 208480093f4SDimitry Andric auto &BVF = C.getSValBuilder().getBasicValueFactory(); 209480093f4SDimitry Andric verifyRandomIncrOrDecr(C, OO_Plus, Iter, 210480093f4SDimitry Andric nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1)))); 211480093f4SDimitry Andric } 212480093f4SDimitry Andric 213*5ffd83dbSDimitry Andric void IteratorRangeChecker::verifyDecrement(CheckerContext &C, SVal Iter) const { 214480093f4SDimitry Andric auto &BVF = C.getSValBuilder().getBasicValueFactory(); 215480093f4SDimitry Andric verifyRandomIncrOrDecr(C, OO_Minus, Iter, 216480093f4SDimitry Andric nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1)))); 217480093f4SDimitry Andric } 218480093f4SDimitry Andric 219480093f4SDimitry Andric void IteratorRangeChecker::verifyRandomIncrOrDecr(CheckerContext &C, 220480093f4SDimitry Andric OverloadedOperatorKind Op, 221*5ffd83dbSDimitry Andric SVal LHS, SVal RHS) const { 222480093f4SDimitry Andric auto State = C.getState(); 223480093f4SDimitry Andric 224480093f4SDimitry Andric auto Value = RHS; 225480093f4SDimitry Andric if (auto ValAsLoc = RHS.getAs<Loc>()) { 226480093f4SDimitry Andric Value = State->getRawSVal(*ValAsLoc); 227480093f4SDimitry Andric } 228480093f4SDimitry Andric 229480093f4SDimitry Andric if (Value.isUnknown()) 230480093f4SDimitry Andric return; 231480093f4SDimitry Andric 232480093f4SDimitry Andric // Incremention or decremention by 0 is never a bug. 233480093f4SDimitry Andric if (isZero(State, Value.castAs<NonLoc>())) 234480093f4SDimitry Andric return; 235480093f4SDimitry Andric 236480093f4SDimitry Andric // The result may be the past-end iterator of the container, but any other 237480093f4SDimitry Andric // out of range position is undefined behaviour 238480093f4SDimitry Andric auto StateAfter = advancePosition(State, LHS, Op, Value); 239480093f4SDimitry Andric if (!StateAfter) 240480093f4SDimitry Andric return; 241480093f4SDimitry Andric 242480093f4SDimitry Andric const auto *PosAfter = getIteratorPosition(StateAfter, LHS); 243480093f4SDimitry Andric assert(PosAfter && 244480093f4SDimitry Andric "Iterator should have position after successful advancement"); 245480093f4SDimitry Andric if (isAheadOfRange(State, *PosAfter)) { 246480093f4SDimitry Andric auto *N = C.generateErrorNode(State); 247480093f4SDimitry Andric if (!N) 248480093f4SDimitry Andric return; 249480093f4SDimitry Andric reportBug("Iterator decremented ahead of its valid range.", LHS, 250480093f4SDimitry Andric C, N); 251480093f4SDimitry Andric } 252480093f4SDimitry Andric if (isBehindPastTheEnd(State, *PosAfter)) { 253480093f4SDimitry Andric auto *N = C.generateErrorNode(State); 254480093f4SDimitry Andric if (!N) 255480093f4SDimitry Andric return; 256480093f4SDimitry Andric reportBug("Iterator incremented behind the past-the-end " 257480093f4SDimitry Andric "iterator.", LHS, C, N); 258480093f4SDimitry Andric } 259480093f4SDimitry Andric } 260480093f4SDimitry Andric 261*5ffd83dbSDimitry Andric void IteratorRangeChecker::verifyAdvance(CheckerContext &C, SVal LHS, 262*5ffd83dbSDimitry Andric SVal RHS) const { 263*5ffd83dbSDimitry Andric verifyRandomIncrOrDecr(C, OO_PlusEqual, LHS, RHS); 264*5ffd83dbSDimitry Andric } 265*5ffd83dbSDimitry Andric 266*5ffd83dbSDimitry Andric void IteratorRangeChecker::verifyPrev(CheckerContext &C, SVal LHS, 267*5ffd83dbSDimitry Andric SVal RHS) const { 268*5ffd83dbSDimitry Andric verifyRandomIncrOrDecr(C, OO_Minus, LHS, RHS); 269*5ffd83dbSDimitry Andric } 270*5ffd83dbSDimitry Andric 271*5ffd83dbSDimitry Andric void IteratorRangeChecker::verifyNext(CheckerContext &C, SVal LHS, 272*5ffd83dbSDimitry Andric SVal RHS) const { 273*5ffd83dbSDimitry Andric verifyRandomIncrOrDecr(C, OO_Plus, LHS, RHS); 274*5ffd83dbSDimitry Andric } 275*5ffd83dbSDimitry Andric 276*5ffd83dbSDimitry Andric void IteratorRangeChecker::reportBug(const StringRef &Message, SVal Val, 277*5ffd83dbSDimitry Andric CheckerContext &C, 278480093f4SDimitry Andric ExplodedNode *ErrNode) const { 279480093f4SDimitry Andric auto R = std::make_unique<PathSensitiveBugReport>(*OutOfRangeBugType, Message, 280480093f4SDimitry Andric ErrNode); 281*5ffd83dbSDimitry Andric 282*5ffd83dbSDimitry Andric const auto *Pos = getIteratorPosition(C.getState(), Val); 283*5ffd83dbSDimitry Andric assert(Pos && "Iterator without known position cannot be out-of-range."); 284*5ffd83dbSDimitry Andric 285480093f4SDimitry Andric R->markInteresting(Val); 286*5ffd83dbSDimitry Andric R->markInteresting(Pos->getContainer()); 287480093f4SDimitry Andric C.emitReport(std::move(R)); 288480093f4SDimitry Andric } 289480093f4SDimitry Andric 290480093f4SDimitry Andric namespace { 291480093f4SDimitry Andric 292480093f4SDimitry Andric bool isLess(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2); 293480093f4SDimitry Andric bool isGreater(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2); 294480093f4SDimitry Andric bool isEqual(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2); 295480093f4SDimitry Andric 296480093f4SDimitry Andric bool isZero(ProgramStateRef State, const NonLoc &Val) { 297480093f4SDimitry Andric auto &BVF = State->getBasicVals(); 298480093f4SDimitry Andric return compare(State, Val, 299480093f4SDimitry Andric nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))), 300480093f4SDimitry Andric BO_EQ); 301480093f4SDimitry Andric } 302480093f4SDimitry Andric 303480093f4SDimitry Andric bool isPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos) { 304480093f4SDimitry Andric const auto *Cont = Pos.getContainer(); 305480093f4SDimitry Andric const auto *CData = getContainerData(State, Cont); 306480093f4SDimitry Andric if (!CData) 307480093f4SDimitry Andric return false; 308480093f4SDimitry Andric 309480093f4SDimitry Andric const auto End = CData->getEnd(); 310480093f4SDimitry Andric if (End) { 311480093f4SDimitry Andric if (isEqual(State, Pos.getOffset(), End)) { 312480093f4SDimitry Andric return true; 313480093f4SDimitry Andric } 314480093f4SDimitry Andric } 315480093f4SDimitry Andric 316480093f4SDimitry Andric return false; 317480093f4SDimitry Andric } 318480093f4SDimitry Andric 319480093f4SDimitry Andric bool isAheadOfRange(ProgramStateRef State, const IteratorPosition &Pos) { 320480093f4SDimitry Andric const auto *Cont = Pos.getContainer(); 321480093f4SDimitry Andric const auto *CData = getContainerData(State, Cont); 322480093f4SDimitry Andric if (!CData) 323480093f4SDimitry Andric return false; 324480093f4SDimitry Andric 325480093f4SDimitry Andric const auto Beg = CData->getBegin(); 326480093f4SDimitry Andric if (Beg) { 327480093f4SDimitry Andric if (isLess(State, Pos.getOffset(), Beg)) { 328480093f4SDimitry Andric return true; 329480093f4SDimitry Andric } 330480093f4SDimitry Andric } 331480093f4SDimitry Andric 332480093f4SDimitry Andric return false; 333480093f4SDimitry Andric } 334480093f4SDimitry Andric 335480093f4SDimitry Andric bool isBehindPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos) { 336480093f4SDimitry Andric const auto *Cont = Pos.getContainer(); 337480093f4SDimitry Andric const auto *CData = getContainerData(State, Cont); 338480093f4SDimitry Andric if (!CData) 339480093f4SDimitry Andric return false; 340480093f4SDimitry Andric 341480093f4SDimitry Andric const auto End = CData->getEnd(); 342480093f4SDimitry Andric if (End) { 343480093f4SDimitry Andric if (isGreater(State, Pos.getOffset(), End)) { 344480093f4SDimitry Andric return true; 345480093f4SDimitry Andric } 346480093f4SDimitry Andric } 347480093f4SDimitry Andric 348480093f4SDimitry Andric return false; 349480093f4SDimitry Andric } 350480093f4SDimitry Andric 351480093f4SDimitry Andric bool isLess(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) { 352480093f4SDimitry Andric return compare(State, Sym1, Sym2, BO_LT); 353480093f4SDimitry Andric } 354480093f4SDimitry Andric 355480093f4SDimitry Andric bool isGreater(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) { 356480093f4SDimitry Andric return compare(State, Sym1, Sym2, BO_GT); 357480093f4SDimitry Andric } 358480093f4SDimitry Andric 359480093f4SDimitry Andric bool isEqual(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) { 360480093f4SDimitry Andric return compare(State, Sym1, Sym2, BO_EQ); 361480093f4SDimitry Andric } 362480093f4SDimitry Andric 363480093f4SDimitry Andric } // namespace 364480093f4SDimitry Andric 365480093f4SDimitry Andric void ento::registerIteratorRangeChecker(CheckerManager &mgr) { 366480093f4SDimitry Andric mgr.registerChecker<IteratorRangeChecker>(); 367480093f4SDimitry Andric } 368480093f4SDimitry Andric 369*5ffd83dbSDimitry Andric bool ento::shouldRegisterIteratorRangeChecker(const CheckerManager &mgr) { 370480093f4SDimitry Andric return true; 371480093f4SDimitry Andric } 372