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 35*647cbc5dSDimitry Andric const BugType OutOfRangeBugType{this, "Iterator out of range", 36*647cbc5dSDimitry 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; 46*647cbc5dSDimitry 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 595ffd83dbSDimitry Andric CallDescriptionMap<AdvanceFn> AdvanceFunctions = { 605ffd83dbSDimitry Andric {{{"std", "advance"}, 2}, &IteratorRangeChecker::verifyAdvance}, 615ffd83dbSDimitry Andric {{{"std", "prev"}, 2}, &IteratorRangeChecker::verifyPrev}, 625ffd83dbSDimitry Andric {{{"std", "next"}, 2}, &IteratorRangeChecker::verifyNext}, 635ffd83dbSDimitry Andric }; 64480093f4SDimitry Andric }; 65480093f4SDimitry Andric 66480093f4SDimitry Andric bool isPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos); 67480093f4SDimitry Andric bool isAheadOfRange(ProgramStateRef State, const IteratorPosition &Pos); 68480093f4SDimitry Andric bool isBehindPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos); 69*647cbc5dSDimitry Andric bool isZero(ProgramStateRef State, NonLoc Val); 70480093f4SDimitry Andric 71480093f4SDimitry Andric } //namespace 72480093f4SDimitry Andric 73480093f4SDimitry Andric void IteratorRangeChecker::checkPreCall(const CallEvent &Call, 74480093f4SDimitry Andric CheckerContext &C) const { 75480093f4SDimitry Andric // Check for out of range access 76480093f4SDimitry Andric const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl()); 77480093f4SDimitry Andric if (!Func) 78480093f4SDimitry Andric return; 79480093f4SDimitry Andric 80480093f4SDimitry Andric if (Func->isOverloadedOperator()) { 81480093f4SDimitry Andric if (isIncrementOperator(Func->getOverloadedOperator())) { 82480093f4SDimitry Andric // Check for out-of-range incrementions 83480093f4SDimitry Andric if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) { 84480093f4SDimitry Andric verifyIncrement(C, InstCall->getCXXThisVal()); 85480093f4SDimitry Andric } else { 86480093f4SDimitry Andric if (Call.getNumArgs() >= 1) { 87480093f4SDimitry Andric verifyIncrement(C, Call.getArgSVal(0)); 88480093f4SDimitry Andric } 89480093f4SDimitry Andric } 90480093f4SDimitry Andric } else if (isDecrementOperator(Func->getOverloadedOperator())) { 91480093f4SDimitry Andric // Check for out-of-range decrementions 92480093f4SDimitry Andric if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) { 93480093f4SDimitry Andric verifyDecrement(C, InstCall->getCXXThisVal()); 94480093f4SDimitry Andric } else { 95480093f4SDimitry Andric if (Call.getNumArgs() >= 1) { 96480093f4SDimitry Andric verifyDecrement(C, Call.getArgSVal(0)); 97480093f4SDimitry Andric } 98480093f4SDimitry Andric } 99480093f4SDimitry Andric } else if (isRandomIncrOrDecrOperator(Func->getOverloadedOperator())) { 100480093f4SDimitry Andric if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) { 101480093f4SDimitry Andric // Check for out-of-range incrementions and decrementions 102480093f4SDimitry Andric if (Call.getNumArgs() >= 1 && 103480093f4SDimitry Andric Call.getArgExpr(0)->getType()->isIntegralOrEnumerationType()) { 104480093f4SDimitry Andric verifyRandomIncrOrDecr(C, Func->getOverloadedOperator(), 105480093f4SDimitry Andric InstCall->getCXXThisVal(), 106480093f4SDimitry Andric Call.getArgSVal(0)); 107480093f4SDimitry Andric } 108480093f4SDimitry Andric } else { 109480093f4SDimitry Andric if (Call.getNumArgs() >= 2 && 110480093f4SDimitry Andric Call.getArgExpr(1)->getType()->isIntegralOrEnumerationType()) { 111480093f4SDimitry Andric verifyRandomIncrOrDecr(C, Func->getOverloadedOperator(), 112480093f4SDimitry Andric Call.getArgSVal(0), Call.getArgSVal(1)); 113480093f4SDimitry Andric } 114480093f4SDimitry Andric } 115480093f4SDimitry Andric } else if (isDereferenceOperator(Func->getOverloadedOperator())) { 116480093f4SDimitry Andric // Check for dereference of out-of-range iterators 117480093f4SDimitry Andric if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) { 118480093f4SDimitry Andric verifyDereference(C, InstCall->getCXXThisVal()); 119480093f4SDimitry Andric } else { 120480093f4SDimitry Andric verifyDereference(C, Call.getArgSVal(0)); 121480093f4SDimitry Andric } 122480093f4SDimitry Andric } 1235ffd83dbSDimitry Andric } else { 1245ffd83dbSDimitry Andric const AdvanceFn *Verifier = AdvanceFunctions.lookup(Call); 1255ffd83dbSDimitry Andric if (Verifier) { 1265ffd83dbSDimitry Andric if (Call.getNumArgs() > 1) { 1275ffd83dbSDimitry Andric (this->**Verifier)(C, Call.getArgSVal(0), Call.getArgSVal(1)); 1285ffd83dbSDimitry Andric } else { 1295ffd83dbSDimitry Andric auto &BVF = C.getSValBuilder().getBasicValueFactory(); 1305ffd83dbSDimitry Andric (this->**Verifier)( 1315ffd83dbSDimitry Andric C, Call.getArgSVal(0), 1325ffd83dbSDimitry Andric nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1)))); 1335ffd83dbSDimitry Andric } 1345ffd83dbSDimitry Andric } 135480093f4SDimitry Andric } 136480093f4SDimitry Andric } 137480093f4SDimitry Andric 1385ffd83dbSDimitry Andric void IteratorRangeChecker::checkPreStmt(const UnaryOperator *UO, 1395ffd83dbSDimitry Andric CheckerContext &C) const { 1405ffd83dbSDimitry Andric if (isa<CXXThisExpr>(UO->getSubExpr())) 1415ffd83dbSDimitry Andric return; 1425ffd83dbSDimitry Andric 1435ffd83dbSDimitry Andric ProgramStateRef State = C.getState(); 1445ffd83dbSDimitry Andric UnaryOperatorKind OK = UO->getOpcode(); 1455ffd83dbSDimitry Andric SVal SubVal = State->getSVal(UO->getSubExpr(), C.getLocationContext()); 1465ffd83dbSDimitry Andric 1475ffd83dbSDimitry Andric if (isDereferenceOperator(OK)) { 1485ffd83dbSDimitry Andric verifyDereference(C, SubVal); 1495ffd83dbSDimitry Andric } else if (isIncrementOperator(OK)) { 1505ffd83dbSDimitry Andric verifyIncrement(C, SubVal); 1515ffd83dbSDimitry Andric } else if (isDecrementOperator(OK)) { 1525ffd83dbSDimitry Andric verifyDecrement(C, SubVal); 1535ffd83dbSDimitry Andric } 1545ffd83dbSDimitry Andric } 1555ffd83dbSDimitry Andric 1565ffd83dbSDimitry Andric void IteratorRangeChecker::checkPreStmt(const BinaryOperator *BO, 1575ffd83dbSDimitry Andric CheckerContext &C) const { 1585ffd83dbSDimitry Andric ProgramStateRef State = C.getState(); 1595ffd83dbSDimitry Andric BinaryOperatorKind OK = BO->getOpcode(); 1605ffd83dbSDimitry Andric SVal LVal = State->getSVal(BO->getLHS(), C.getLocationContext()); 1615ffd83dbSDimitry Andric 1625ffd83dbSDimitry Andric if (isDereferenceOperator(OK)) { 1635ffd83dbSDimitry Andric verifyDereference(C, LVal); 1645ffd83dbSDimitry Andric } else if (isRandomIncrOrDecrOperator(OK)) { 1655ffd83dbSDimitry Andric SVal RVal = State->getSVal(BO->getRHS(), C.getLocationContext()); 166e8d8bef9SDimitry Andric if (!BO->getRHS()->getType()->isIntegralOrEnumerationType()) 167e8d8bef9SDimitry Andric return; 1685ffd83dbSDimitry Andric verifyRandomIncrOrDecr(C, BinaryOperator::getOverloadedOperator(OK), LVal, 1695ffd83dbSDimitry Andric RVal); 1705ffd83dbSDimitry Andric } 1715ffd83dbSDimitry Andric } 1725ffd83dbSDimitry Andric 1735ffd83dbSDimitry Andric void IteratorRangeChecker::checkPreStmt(const ArraySubscriptExpr *ASE, 1745ffd83dbSDimitry Andric CheckerContext &C) const { 1755ffd83dbSDimitry Andric ProgramStateRef State = C.getState(); 1765ffd83dbSDimitry Andric SVal LVal = State->getSVal(ASE->getLHS(), C.getLocationContext()); 1775ffd83dbSDimitry Andric verifyDereference(C, LVal); 1785ffd83dbSDimitry Andric } 1795ffd83dbSDimitry Andric 1805ffd83dbSDimitry Andric void IteratorRangeChecker::checkPreStmt(const MemberExpr *ME, 1815ffd83dbSDimitry Andric CheckerContext &C) const { 1825ffd83dbSDimitry Andric if (!ME->isArrow() || ME->isImplicitAccess()) 1835ffd83dbSDimitry Andric return; 1845ffd83dbSDimitry Andric 1855ffd83dbSDimitry Andric ProgramStateRef State = C.getState(); 1865ffd83dbSDimitry Andric SVal BaseVal = State->getSVal(ME->getBase(), C.getLocationContext()); 1875ffd83dbSDimitry Andric verifyDereference(C, BaseVal); 1885ffd83dbSDimitry Andric } 1895ffd83dbSDimitry Andric 190480093f4SDimitry Andric void IteratorRangeChecker::verifyDereference(CheckerContext &C, 1915ffd83dbSDimitry Andric SVal Val) const { 192480093f4SDimitry Andric auto State = C.getState(); 193480093f4SDimitry Andric const auto *Pos = getIteratorPosition(State, Val); 194480093f4SDimitry Andric if (Pos && isPastTheEnd(State, *Pos)) { 195480093f4SDimitry Andric auto *N = C.generateErrorNode(State); 196480093f4SDimitry Andric if (!N) 197480093f4SDimitry Andric return; 198480093f4SDimitry Andric reportBug("Past-the-end iterator dereferenced.", Val, C, N); 199480093f4SDimitry Andric return; 200480093f4SDimitry Andric } 201480093f4SDimitry Andric } 202480093f4SDimitry Andric 2035ffd83dbSDimitry Andric void IteratorRangeChecker::verifyIncrement(CheckerContext &C, SVal Iter) const { 204480093f4SDimitry Andric auto &BVF = C.getSValBuilder().getBasicValueFactory(); 205480093f4SDimitry Andric verifyRandomIncrOrDecr(C, OO_Plus, Iter, 206480093f4SDimitry Andric nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1)))); 207480093f4SDimitry Andric } 208480093f4SDimitry Andric 2095ffd83dbSDimitry Andric void IteratorRangeChecker::verifyDecrement(CheckerContext &C, SVal Iter) const { 210480093f4SDimitry Andric auto &BVF = C.getSValBuilder().getBasicValueFactory(); 211480093f4SDimitry Andric verifyRandomIncrOrDecr(C, OO_Minus, Iter, 212480093f4SDimitry Andric nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1)))); 213480093f4SDimitry Andric } 214480093f4SDimitry Andric 215480093f4SDimitry Andric void IteratorRangeChecker::verifyRandomIncrOrDecr(CheckerContext &C, 216480093f4SDimitry Andric OverloadedOperatorKind Op, 2175ffd83dbSDimitry Andric SVal LHS, SVal RHS) const { 218480093f4SDimitry Andric auto State = C.getState(); 219480093f4SDimitry Andric 220480093f4SDimitry Andric auto Value = RHS; 221480093f4SDimitry Andric if (auto ValAsLoc = RHS.getAs<Loc>()) { 222480093f4SDimitry Andric Value = State->getRawSVal(*ValAsLoc); 223480093f4SDimitry Andric } 224480093f4SDimitry Andric 2255f757f3fSDimitry Andric if (Value.isUnknownOrUndef() || !isa<NonLoc>(Value)) 226480093f4SDimitry Andric return; 227480093f4SDimitry Andric 228480093f4SDimitry Andric // Incremention or decremention by 0 is never a bug. 229480093f4SDimitry Andric if (isZero(State, Value.castAs<NonLoc>())) 230480093f4SDimitry Andric return; 231480093f4SDimitry Andric 232480093f4SDimitry Andric // The result may be the past-end iterator of the container, but any other 233480093f4SDimitry Andric // out of range position is undefined behaviour 234480093f4SDimitry Andric auto StateAfter = advancePosition(State, LHS, Op, Value); 235480093f4SDimitry Andric if (!StateAfter) 236480093f4SDimitry Andric return; 237480093f4SDimitry Andric 238480093f4SDimitry Andric const auto *PosAfter = getIteratorPosition(StateAfter, LHS); 239480093f4SDimitry Andric assert(PosAfter && 240480093f4SDimitry Andric "Iterator should have position after successful advancement"); 241480093f4SDimitry Andric if (isAheadOfRange(State, *PosAfter)) { 242480093f4SDimitry Andric auto *N = C.generateErrorNode(State); 243480093f4SDimitry Andric if (!N) 244480093f4SDimitry Andric return; 245480093f4SDimitry Andric reportBug("Iterator decremented ahead of its valid range.", LHS, 246480093f4SDimitry Andric C, N); 247480093f4SDimitry Andric } 248480093f4SDimitry Andric if (isBehindPastTheEnd(State, *PosAfter)) { 249480093f4SDimitry Andric auto *N = C.generateErrorNode(State); 250480093f4SDimitry Andric if (!N) 251480093f4SDimitry Andric return; 252480093f4SDimitry Andric reportBug("Iterator incremented behind the past-the-end " 253480093f4SDimitry Andric "iterator.", LHS, C, N); 254480093f4SDimitry Andric } 255480093f4SDimitry Andric } 256480093f4SDimitry Andric 2575ffd83dbSDimitry Andric void IteratorRangeChecker::verifyAdvance(CheckerContext &C, SVal LHS, 2585ffd83dbSDimitry Andric SVal RHS) const { 2595ffd83dbSDimitry Andric verifyRandomIncrOrDecr(C, OO_PlusEqual, LHS, RHS); 2605ffd83dbSDimitry Andric } 2615ffd83dbSDimitry Andric 2625ffd83dbSDimitry Andric void IteratorRangeChecker::verifyPrev(CheckerContext &C, SVal LHS, 2635ffd83dbSDimitry Andric SVal RHS) const { 2645ffd83dbSDimitry Andric verifyRandomIncrOrDecr(C, OO_Minus, LHS, RHS); 2655ffd83dbSDimitry Andric } 2665ffd83dbSDimitry Andric 2675ffd83dbSDimitry Andric void IteratorRangeChecker::verifyNext(CheckerContext &C, SVal LHS, 2685ffd83dbSDimitry Andric SVal RHS) const { 2695ffd83dbSDimitry Andric verifyRandomIncrOrDecr(C, OO_Plus, LHS, RHS); 2705ffd83dbSDimitry Andric } 2715ffd83dbSDimitry Andric 272*647cbc5dSDimitry Andric void IteratorRangeChecker::reportBug(StringRef Message, SVal Val, 2735ffd83dbSDimitry Andric CheckerContext &C, 274480093f4SDimitry Andric ExplodedNode *ErrNode) const { 275*647cbc5dSDimitry Andric auto R = std::make_unique<PathSensitiveBugReport>(OutOfRangeBugType, Message, 276480093f4SDimitry Andric ErrNode); 2775ffd83dbSDimitry Andric 2785ffd83dbSDimitry Andric const auto *Pos = getIteratorPosition(C.getState(), Val); 2795ffd83dbSDimitry Andric assert(Pos && "Iterator without known position cannot be out-of-range."); 2805ffd83dbSDimitry Andric 281480093f4SDimitry Andric R->markInteresting(Val); 2825ffd83dbSDimitry Andric R->markInteresting(Pos->getContainer()); 283480093f4SDimitry Andric C.emitReport(std::move(R)); 284480093f4SDimitry Andric } 285480093f4SDimitry Andric 286480093f4SDimitry Andric namespace { 287480093f4SDimitry Andric 288480093f4SDimitry Andric bool isLess(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2); 289480093f4SDimitry Andric bool isGreater(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2); 290480093f4SDimitry Andric bool isEqual(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2); 291480093f4SDimitry Andric 292*647cbc5dSDimitry Andric bool isZero(ProgramStateRef State, NonLoc Val) { 293480093f4SDimitry Andric auto &BVF = State->getBasicVals(); 294480093f4SDimitry Andric return compare(State, Val, 295480093f4SDimitry Andric nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))), 296480093f4SDimitry Andric BO_EQ); 297480093f4SDimitry Andric } 298480093f4SDimitry Andric 299480093f4SDimitry Andric bool isPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos) { 300480093f4SDimitry Andric const auto *Cont = Pos.getContainer(); 301480093f4SDimitry Andric const auto *CData = getContainerData(State, Cont); 302480093f4SDimitry Andric if (!CData) 303480093f4SDimitry Andric return false; 304480093f4SDimitry Andric 305480093f4SDimitry Andric const auto End = CData->getEnd(); 306480093f4SDimitry Andric if (End) { 307480093f4SDimitry Andric if (isEqual(State, Pos.getOffset(), End)) { 308480093f4SDimitry Andric return true; 309480093f4SDimitry Andric } 310480093f4SDimitry Andric } 311480093f4SDimitry Andric 312480093f4SDimitry Andric return false; 313480093f4SDimitry Andric } 314480093f4SDimitry Andric 315480093f4SDimitry Andric bool isAheadOfRange(ProgramStateRef State, const IteratorPosition &Pos) { 316480093f4SDimitry Andric const auto *Cont = Pos.getContainer(); 317480093f4SDimitry Andric const auto *CData = getContainerData(State, Cont); 318480093f4SDimitry Andric if (!CData) 319480093f4SDimitry Andric return false; 320480093f4SDimitry Andric 321480093f4SDimitry Andric const auto Beg = CData->getBegin(); 322480093f4SDimitry Andric if (Beg) { 323480093f4SDimitry Andric if (isLess(State, Pos.getOffset(), Beg)) { 324480093f4SDimitry Andric return true; 325480093f4SDimitry Andric } 326480093f4SDimitry Andric } 327480093f4SDimitry Andric 328480093f4SDimitry Andric return false; 329480093f4SDimitry Andric } 330480093f4SDimitry Andric 331480093f4SDimitry Andric bool isBehindPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos) { 332480093f4SDimitry Andric const auto *Cont = Pos.getContainer(); 333480093f4SDimitry Andric const auto *CData = getContainerData(State, Cont); 334480093f4SDimitry Andric if (!CData) 335480093f4SDimitry Andric return false; 336480093f4SDimitry Andric 337480093f4SDimitry Andric const auto End = CData->getEnd(); 338480093f4SDimitry Andric if (End) { 339480093f4SDimitry Andric if (isGreater(State, Pos.getOffset(), End)) { 340480093f4SDimitry Andric return true; 341480093f4SDimitry Andric } 342480093f4SDimitry Andric } 343480093f4SDimitry Andric 344480093f4SDimitry Andric return false; 345480093f4SDimitry Andric } 346480093f4SDimitry Andric 347480093f4SDimitry Andric bool isLess(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) { 348480093f4SDimitry Andric return compare(State, Sym1, Sym2, BO_LT); 349480093f4SDimitry Andric } 350480093f4SDimitry Andric 351480093f4SDimitry Andric bool isGreater(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) { 352480093f4SDimitry Andric return compare(State, Sym1, Sym2, BO_GT); 353480093f4SDimitry Andric } 354480093f4SDimitry Andric 355480093f4SDimitry Andric bool isEqual(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) { 356480093f4SDimitry Andric return compare(State, Sym1, Sym2, BO_EQ); 357480093f4SDimitry Andric } 358480093f4SDimitry Andric 359480093f4SDimitry Andric } // namespace 360480093f4SDimitry Andric 361480093f4SDimitry Andric void ento::registerIteratorRangeChecker(CheckerManager &mgr) { 362480093f4SDimitry Andric mgr.registerChecker<IteratorRangeChecker>(); 363480093f4SDimitry Andric } 364480093f4SDimitry Andric 3655ffd83dbSDimitry Andric bool ento::shouldRegisterIteratorRangeChecker(const CheckerManager &mgr) { 366480093f4SDimitry Andric return true; 367480093f4SDimitry Andric } 368