|
@@ -238,14 +238,17 @@ class IteratorChecker
|
|
void handleEraseAfter(CheckerContext &C, const SVal &Iter) const;
|
|
void handleEraseAfter(CheckerContext &C, const SVal &Iter) const;
|
|
void handleEraseAfter(CheckerContext &C, const SVal &Iter1,
|
|
void handleEraseAfter(CheckerContext &C, const SVal &Iter1,
|
|
const SVal &Iter2) const;
|
|
const SVal &Iter2) const;
|
|
|
|
+ void verifyIncrement(CheckerContext &C, const SVal &Iter) const;
|
|
|
|
+ void verifyDecrement(CheckerContext &C, const SVal &Iter) const;
|
|
void verifyRandomIncrOrDecr(CheckerContext &C, OverloadedOperatorKind Op,
|
|
void verifyRandomIncrOrDecr(CheckerContext &C, OverloadedOperatorKind Op,
|
|
- const SVal &RetVal, const SVal &LHS,
|
|
|
|
- const SVal &RHS) const;
|
|
|
|
|
|
+ const SVal &LHS, const SVal &RHS) const;
|
|
void verifyMatch(CheckerContext &C, const SVal &Iter,
|
|
void verifyMatch(CheckerContext &C, const SVal &Iter,
|
|
const MemRegion *Cont) const;
|
|
const MemRegion *Cont) const;
|
|
void verifyMatch(CheckerContext &C, const SVal &Iter1,
|
|
void verifyMatch(CheckerContext &C, const SVal &Iter1,
|
|
const SVal &Iter2) const;
|
|
const SVal &Iter2) const;
|
|
-
|
|
|
|
|
|
+ IteratorPosition advancePosition(CheckerContext &C, OverloadedOperatorKind Op,
|
|
|
|
+ const IteratorPosition &Pos,
|
|
|
|
+ const SVal &Distance) const;
|
|
void reportOutOfRangeBug(const StringRef &Message, const SVal &Val,
|
|
void reportOutOfRangeBug(const StringRef &Message, const SVal &Val,
|
|
CheckerContext &C, ExplodedNode *ErrNode) const;
|
|
CheckerContext &C, ExplodedNode *ErrNode) const;
|
|
void reportMismatchedBug(const StringRef &Message, const SVal &Val1,
|
|
void reportMismatchedBug(const StringRef &Message, const SVal &Val1,
|
|
@@ -388,7 +391,9 @@ ProgramStateRef setContainerData(ProgramStateRef State, const MemRegion *Cont,
|
|
bool hasLiveIterators(ProgramStateRef State, const MemRegion *Cont);
|
|
bool hasLiveIterators(ProgramStateRef State, const MemRegion *Cont);
|
|
bool isBoundThroughLazyCompoundVal(const Environment &Env,
|
|
bool isBoundThroughLazyCompoundVal(const Environment &Env,
|
|
const MemRegion *Reg);
|
|
const MemRegion *Reg);
|
|
-bool isOutOfRange(ProgramStateRef State, const IteratorPosition &Pos);
|
|
|
|
|
|
+bool isPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos);
|
|
|
|
+bool isAheadOfRange(ProgramStateRef State, const IteratorPosition &Pos);
|
|
|
|
+bool isBehindPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos);
|
|
bool isZero(ProgramStateRef State, const NonLoc &Val);
|
|
bool isZero(ProgramStateRef State, const NonLoc &Val);
|
|
} // namespace
|
|
} // namespace
|
|
|
|
|
|
@@ -422,29 +427,46 @@ void IteratorChecker::checkPreCall(const CallEvent &Call,
|
|
verifyAccess(C, Call.getArgSVal(0));
|
|
verifyAccess(C, Call.getArgSVal(0));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- if (ChecksEnabled[CK_IteratorRangeChecker] &&
|
|
|
|
- isRandomIncrOrDecrOperator(Func->getOverloadedOperator())) {
|
|
|
|
- if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
|
|
|
|
- // Check for out-of-range incrementions and decrementions
|
|
|
|
- if (Call.getNumArgs() >= 1) {
|
|
|
|
- verifyRandomIncrOrDecr(C, Func->getOverloadedOperator(),
|
|
|
|
- Call.getReturnValue(),
|
|
|
|
- InstCall->getCXXThisVal(), Call.getArgSVal(0));
|
|
|
|
|
|
+ if (ChecksEnabled[CK_IteratorRangeChecker]) {
|
|
|
|
+ if (isIncrementOperator(Func->getOverloadedOperator())) {
|
|
|
|
+ // Check for out-of-range incrementions
|
|
|
|
+ if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
|
|
|
|
+ verifyIncrement(C, InstCall->getCXXThisVal());
|
|
|
|
+ } else {
|
|
|
|
+ if (Call.getNumArgs() >= 1) {
|
|
|
|
+ verifyIncrement(C, Call.getArgSVal(0));
|
|
|
|
+ }
|
|
}
|
|
}
|
|
- } else {
|
|
|
|
- if (Call.getNumArgs() >= 2) {
|
|
|
|
- verifyRandomIncrOrDecr(C, Func->getOverloadedOperator(),
|
|
|
|
- Call.getReturnValue(), Call.getArgSVal(0),
|
|
|
|
- Call.getArgSVal(1));
|
|
|
|
|
|
+ } else if (isDecrementOperator(Func->getOverloadedOperator())) {
|
|
|
|
+ // Check for out-of-range decrementions
|
|
|
|
+ if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
|
|
|
|
+ verifyDecrement(C, InstCall->getCXXThisVal());
|
|
|
|
+ } else {
|
|
|
|
+ if (Call.getNumArgs() >= 1) {
|
|
|
|
+ verifyDecrement(C, Call.getArgSVal(0));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ } else if (isRandomIncrOrDecrOperator(Func->getOverloadedOperator())) {
|
|
|
|
+ if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
|
|
|
|
+ // Check for out-of-range incrementions and decrementions
|
|
|
|
+ if (Call.getNumArgs() >= 1) {
|
|
|
|
+ verifyRandomIncrOrDecr(C, Func->getOverloadedOperator(),
|
|
|
|
+ InstCall->getCXXThisVal(),
|
|
|
|
+ Call.getArgSVal(0));
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ if (Call.getNumArgs() >= 2) {
|
|
|
|
+ verifyRandomIncrOrDecr(C, Func->getOverloadedOperator(),
|
|
|
|
+ Call.getArgSVal(0), Call.getArgSVal(1));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ } else if (isDereferenceOperator(Func->getOverloadedOperator())) {
|
|
|
|
+ // Check for dereference of out-of-range iterators
|
|
|
|
+ if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
|
|
|
|
+ verifyDereference(C, InstCall->getCXXThisVal());
|
|
|
|
+ } else {
|
|
|
|
+ verifyDereference(C, Call.getArgSVal(0));
|
|
}
|
|
}
|
|
- }
|
|
|
|
- } else if (ChecksEnabled[CK_IteratorRangeChecker] &&
|
|
|
|
- isDereferenceOperator(Func->getOverloadedOperator())) {
|
|
|
|
- // Check for dereference of out-of-range iterators
|
|
|
|
- if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
|
|
|
|
- verifyDereference(C, InstCall->getCXXThisVal());
|
|
|
|
- } else {
|
|
|
|
- verifyDereference(C, Call.getArgSVal(0));
|
|
|
|
}
|
|
}
|
|
} else if (ChecksEnabled[CK_MismatchedIteratorChecker] &&
|
|
} else if (ChecksEnabled[CK_MismatchedIteratorChecker] &&
|
|
isComparisonOperator(Func->getOverloadedOperator())) {
|
|
isComparisonOperator(Func->getOverloadedOperator())) {
|
|
@@ -895,11 +917,12 @@ void IteratorChecker::verifyDereference(CheckerContext &C,
|
|
const SVal &Val) const {
|
|
const SVal &Val) const {
|
|
auto State = C.getState();
|
|
auto State = C.getState();
|
|
const auto *Pos = getIteratorPosition(State, Val);
|
|
const auto *Pos = getIteratorPosition(State, Val);
|
|
- if (Pos && isOutOfRange(State, *Pos)) {
|
|
|
|
|
|
+ if (Pos && isPastTheEnd(State, *Pos)) {
|
|
auto *N = C.generateNonFatalErrorNode(State);
|
|
auto *N = C.generateNonFatalErrorNode(State);
|
|
if (!N)
|
|
if (!N)
|
|
return;
|
|
return;
|
|
- reportOutOfRangeBug("Iterator accessed outside of its range.", Val, C, N);
|
|
|
|
|
|
+ reportOutOfRangeBug("Past-the-end iterator dereferenced.", Val, C, N);
|
|
|
|
+ return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -924,14 +947,9 @@ void IteratorChecker::handleIncrement(CheckerContext &C, const SVal &RetVal,
|
|
if (Pos) {
|
|
if (Pos) {
|
|
auto &SymMgr = C.getSymbolManager();
|
|
auto &SymMgr = C.getSymbolManager();
|
|
auto &BVF = SymMgr.getBasicVals();
|
|
auto &BVF = SymMgr.getBasicVals();
|
|
- auto &SVB = C.getSValBuilder();
|
|
|
|
- const auto OldOffset = Pos->getOffset();
|
|
|
|
- auto NewOffset =
|
|
|
|
- SVB.evalBinOp(State, BO_Add,
|
|
|
|
- nonloc::SymbolVal(OldOffset),
|
|
|
|
- nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
|
|
|
|
- SymMgr.getType(OldOffset)).getAsSymbol();
|
|
|
|
- auto NewPos = Pos->setTo(NewOffset);
|
|
|
|
|
|
+ const auto NewPos =
|
|
|
|
+ advancePosition(C, OO_Plus, *Pos,
|
|
|
|
+ nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
|
|
State = setIteratorPosition(State, Iter, NewPos);
|
|
State = setIteratorPosition(State, Iter, NewPos);
|
|
State = setIteratorPosition(State, RetVal, Postfix ? *Pos : NewPos);
|
|
State = setIteratorPosition(State, RetVal, Postfix ? *Pos : NewPos);
|
|
C.addTransition(State);
|
|
C.addTransition(State);
|
|
@@ -947,14 +965,9 @@ void IteratorChecker::handleDecrement(CheckerContext &C, const SVal &RetVal,
|
|
if (Pos) {
|
|
if (Pos) {
|
|
auto &SymMgr = C.getSymbolManager();
|
|
auto &SymMgr = C.getSymbolManager();
|
|
auto &BVF = SymMgr.getBasicVals();
|
|
auto &BVF = SymMgr.getBasicVals();
|
|
- auto &SVB = C.getSValBuilder();
|
|
|
|
- const auto OldOffset = Pos->getOffset();
|
|
|
|
- auto NewOffset =
|
|
|
|
- SVB.evalBinOp(State, BO_Sub,
|
|
|
|
- nonloc::SymbolVal(OldOffset),
|
|
|
|
- nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
|
|
|
|
- SymMgr.getType(OldOffset)).getAsSymbol();
|
|
|
|
- auto NewPos = Pos->setTo(NewOffset);
|
|
|
|
|
|
+ const auto NewPos =
|
|
|
|
+ advancePosition(C, OO_Minus, *Pos,
|
|
|
|
+ nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
|
|
State = setIteratorPosition(State, Iter, NewPos);
|
|
State = setIteratorPosition(State, Iter, NewPos);
|
|
State = setIteratorPosition(State, RetVal, Postfix ? *Pos : NewPos);
|
|
State = setIteratorPosition(State, RetVal, Postfix ? *Pos : NewPos);
|
|
C.addTransition(State);
|
|
C.addTransition(State);
|
|
@@ -1020,69 +1033,64 @@ void IteratorChecker::handleRandomIncrOrDecr(CheckerContext &C,
|
|
value = &val;
|
|
value = &val;
|
|
}
|
|
}
|
|
|
|
|
|
- auto &SymMgr = C.getSymbolManager();
|
|
|
|
- auto &SVB = C.getSValBuilder();
|
|
|
|
- auto BinOp = (Op == OO_Plus || Op == OO_PlusEqual) ? BO_Add : BO_Sub;
|
|
|
|
- const auto OldOffset = Pos->getOffset();
|
|
|
|
- SymbolRef NewOffset;
|
|
|
|
- if (const auto intValue = value->getAs<nonloc::ConcreteInt>()) {
|
|
|
|
- // For concrete integers we can calculate the new position
|
|
|
|
- NewOffset = SVB.evalBinOp(State, BinOp, nonloc::SymbolVal(OldOffset),
|
|
|
|
- *intValue,
|
|
|
|
- SymMgr.getType(OldOffset)).getAsSymbol();
|
|
|
|
- } else {
|
|
|
|
- // For other symbols create a new symbol to keep expressions simple
|
|
|
|
- const auto &LCtx = C.getLocationContext();
|
|
|
|
- NewOffset = SymMgr.conjureSymbol(nullptr, LCtx, SymMgr.getType(OldOffset),
|
|
|
|
- C.blockCount());
|
|
|
|
- State = assumeNoOverflow(State, NewOffset, 4);
|
|
|
|
- }
|
|
|
|
- auto NewPos = Pos->setTo(NewOffset);
|
|
|
|
auto &TgtVal = (Op == OO_PlusEqual || Op == OO_MinusEqual) ? LHS : RetVal;
|
|
auto &TgtVal = (Op == OO_PlusEqual || Op == OO_MinusEqual) ? LHS : RetVal;
|
|
- State = setIteratorPosition(State, TgtVal, NewPos);
|
|
|
|
|
|
+ State =
|
|
|
|
+ setIteratorPosition(State, TgtVal, advancePosition(C, Op, *Pos, *value));
|
|
C.addTransition(State);
|
|
C.addTransition(State);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+void IteratorChecker::verifyIncrement(CheckerContext &C,
|
|
|
|
+ const SVal &Iter) const {
|
|
|
|
+ auto &BVF = C.getSValBuilder().getBasicValueFactory();
|
|
|
|
+ verifyRandomIncrOrDecr(C, OO_Plus, Iter,
|
|
|
|
+ nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void IteratorChecker::verifyDecrement(CheckerContext &C,
|
|
|
|
+ const SVal &Iter) const {
|
|
|
|
+ auto &BVF = C.getSValBuilder().getBasicValueFactory();
|
|
|
|
+ verifyRandomIncrOrDecr(C, OO_Minus, Iter,
|
|
|
|
+ nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
|
|
|
|
+}
|
|
|
|
+
|
|
void IteratorChecker::verifyRandomIncrOrDecr(CheckerContext &C,
|
|
void IteratorChecker::verifyRandomIncrOrDecr(CheckerContext &C,
|
|
OverloadedOperatorKind Op,
|
|
OverloadedOperatorKind Op,
|
|
- const SVal &RetVal,
|
|
|
|
const SVal &LHS,
|
|
const SVal &LHS,
|
|
const SVal &RHS) const {
|
|
const SVal &RHS) const {
|
|
auto State = C.getState();
|
|
auto State = C.getState();
|
|
|
|
|
|
// If the iterator is initially inside its range, then the operation is valid
|
|
// If the iterator is initially inside its range, then the operation is valid
|
|
const auto *Pos = getIteratorPosition(State, LHS);
|
|
const auto *Pos = getIteratorPosition(State, LHS);
|
|
- if (!Pos || !isOutOfRange(State, *Pos))
|
|
|
|
|
|
+ if (!Pos)
|
|
return;
|
|
return;
|
|
|
|
|
|
- auto value = RHS;
|
|
|
|
- if (auto loc = RHS.getAs<Loc>()) {
|
|
|
|
- value = State->getRawSVal(*loc);
|
|
|
|
|
|
+ auto Value = RHS;
|
|
|
|
+ if (auto ValAsLoc = RHS.getAs<Loc>()) {
|
|
|
|
+ Value = State->getRawSVal(*ValAsLoc);
|
|
}
|
|
}
|
|
|
|
|
|
- // Incremention or decremention by 0 is never bug
|
|
|
|
- if (isZero(State, value.castAs<NonLoc>()))
|
|
|
|
|
|
+ if (Value.isUnknown())
|
|
return;
|
|
return;
|
|
|
|
|
|
- auto &SymMgr = C.getSymbolManager();
|
|
|
|
- auto &SVB = C.getSValBuilder();
|
|
|
|
- auto BinOp = (Op == OO_Plus || Op == OO_PlusEqual) ? BO_Add : BO_Sub;
|
|
|
|
- const auto OldOffset = Pos->getOffset();
|
|
|
|
- const auto intValue = value.getAs<nonloc::ConcreteInt>();
|
|
|
|
- if (!intValue)
|
|
|
|
|
|
+ // Incremention or decremention by 0 is never a bug.
|
|
|
|
+ if (isZero(State, Value.castAs<NonLoc>()))
|
|
return;
|
|
return;
|
|
|
|
|
|
- auto NewOffset = SVB.evalBinOp(State, BinOp, nonloc::SymbolVal(OldOffset),
|
|
|
|
- *intValue,
|
|
|
|
- SymMgr.getType(OldOffset)).getAsSymbol();
|
|
|
|
- auto NewPos = Pos->setTo(NewOffset);
|
|
|
|
-
|
|
|
|
- // If out of range, the only valid operation is to step into the range
|
|
|
|
- if (isOutOfRange(State, NewPos)) {
|
|
|
|
|
|
+ // The result may be the past-end iterator of the container, but any other
|
|
|
|
+ // out of range position is undefined behaviour
|
|
|
|
+ if (isAheadOfRange(State, advancePosition(C, Op, *Pos, Value))) {
|
|
auto *N = C.generateNonFatalErrorNode(State);
|
|
auto *N = C.generateNonFatalErrorNode(State);
|
|
if (!N)
|
|
if (!N)
|
|
return;
|
|
return;
|
|
- reportOutOfRangeBug("Iterator accessed past its end.", LHS, C, N);
|
|
|
|
|
|
+ reportOutOfRangeBug("Iterator decremented ahead of its valid range.", LHS,
|
|
|
|
+ C, N);
|
|
|
|
+ }
|
|
|
|
+ if (isBehindPastTheEnd(State, advancePosition(C, Op, *Pos, Value))) {
|
|
|
|
+ auto *N = C.generateNonFatalErrorNode(State);
|
|
|
|
+ if (!N)
|
|
|
|
+ return;
|
|
|
|
+ reportOutOfRangeBug("Iterator incremented behind the past-the-end "
|
|
|
|
+ "iterator.", LHS, C, N);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1544,6 +1552,35 @@ void IteratorChecker::handleEraseAfter(CheckerContext &C, const SVal &Iter1,
|
|
C.addTransition(State);
|
|
C.addTransition(State);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+IteratorPosition IteratorChecker::advancePosition(CheckerContext &C,
|
|
|
|
+ OverloadedOperatorKind Op,
|
|
|
|
+ const IteratorPosition &Pos,
|
|
|
|
+ const SVal &Distance) const {
|
|
|
|
+ auto State = C.getState();
|
|
|
|
+ auto &SymMgr = C.getSymbolManager();
|
|
|
|
+ auto &SVB = C.getSValBuilder();
|
|
|
|
+
|
|
|
|
+ assert ((Op == OO_Plus || Op == OO_PlusEqual ||
|
|
|
|
+ Op == OO_Minus || Op == OO_MinusEqual) &&
|
|
|
|
+ "Advance operator must be one of +, -, += and -=.");
|
|
|
|
+ auto BinOp = (Op == OO_Plus || Op == OO_PlusEqual) ? BO_Add : BO_Sub;
|
|
|
|
+ if (const auto IntDist = Distance.getAs<nonloc::ConcreteInt>()) {
|
|
|
|
+ // For concrete integers we can calculate the new position
|
|
|
|
+ return Pos.setTo(SVB.evalBinOp(State, BinOp,
|
|
|
|
+ nonloc::SymbolVal(Pos.getOffset()), *IntDist,
|
|
|
|
+ SymMgr.getType(Pos.getOffset()))
|
|
|
|
+ .getAsSymbol());
|
|
|
|
+ } else {
|
|
|
|
+ // For other symbols create a new symbol to keep expressions simple
|
|
|
|
+ const auto &LCtx = C.getLocationContext();
|
|
|
|
+ const auto NewPosSym = SymMgr.conjureSymbol(nullptr, LCtx,
|
|
|
|
+ SymMgr.getType(Pos.getOffset()),
|
|
|
|
+ C.blockCount());
|
|
|
|
+ State = assumeNoOverflow(State, NewPosSym, 4);
|
|
|
|
+ return Pos.setTo(NewPosSym);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
void IteratorChecker::reportOutOfRangeBug(const StringRef &Message,
|
|
void IteratorChecker::reportOutOfRangeBug(const StringRef &Message,
|
|
const SVal &Val, CheckerContext &C,
|
|
const SVal &Val, CheckerContext &C,
|
|
ExplodedNode *ErrNode) const {
|
|
ExplodedNode *ErrNode) const {
|
|
@@ -1583,7 +1620,8 @@ void IteratorChecker::reportInvalidatedBug(const StringRef &Message,
|
|
namespace {
|
|
namespace {
|
|
|
|
|
|
bool isLess(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2);
|
|
bool isLess(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2);
|
|
-bool isGreaterOrEqual(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2);
|
|
|
|
|
|
+bool isGreater(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2);
|
|
|
|
+bool isEqual(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2);
|
|
bool compare(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2,
|
|
bool compare(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2,
|
|
BinaryOperator::Opcode Opc);
|
|
BinaryOperator::Opcode Opc);
|
|
bool compare(ProgramStateRef State, NonLoc NL1, NonLoc NL2,
|
|
bool compare(ProgramStateRef State, NonLoc NL1, NonLoc NL2,
|
|
@@ -2276,14 +2314,27 @@ bool isZero(ProgramStateRef State, const NonLoc &Val) {
|
|
BO_EQ);
|
|
BO_EQ);
|
|
}
|
|
}
|
|
|
|
|
|
-bool isOutOfRange(ProgramStateRef State, const IteratorPosition &Pos) {
|
|
|
|
|
|
+bool isPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos) {
|
|
const auto *Cont = Pos.getContainer();
|
|
const auto *Cont = Pos.getContainer();
|
|
const auto *CData = getContainerData(State, Cont);
|
|
const auto *CData = getContainerData(State, Cont);
|
|
if (!CData)
|
|
if (!CData)
|
|
return false;
|
|
return false;
|
|
|
|
|
|
- // Out of range means less than the begin symbol or greater or equal to the
|
|
|
|
- // end symbol.
|
|
|
|
|
|
+ const auto End = CData->getEnd();
|
|
|
|
+ if (End) {
|
|
|
|
+ if (isEqual(State, Pos.getOffset(), End)) {
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return false;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+bool isAheadOfRange(ProgramStateRef State, const IteratorPosition &Pos) {
|
|
|
|
+ const auto *Cont = Pos.getContainer();
|
|
|
|
+ const auto *CData = getContainerData(State, Cont);
|
|
|
|
+ if (!CData)
|
|
|
|
+ return false;
|
|
|
|
|
|
const auto Beg = CData->getBegin();
|
|
const auto Beg = CData->getBegin();
|
|
if (Beg) {
|
|
if (Beg) {
|
|
@@ -2292,9 +2343,18 @@ bool isOutOfRange(ProgramStateRef State, const IteratorPosition &Pos) {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ return false;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+bool isBehindPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos) {
|
|
|
|
+ const auto *Cont = Pos.getContainer();
|
|
|
|
+ const auto *CData = getContainerData(State, Cont);
|
|
|
|
+ if (!CData)
|
|
|
|
+ return false;
|
|
|
|
+
|
|
const auto End = CData->getEnd();
|
|
const auto End = CData->getEnd();
|
|
if (End) {
|
|
if (End) {
|
|
- if (isGreaterOrEqual(State, Pos.getOffset(), End)) {
|
|
|
|
|
|
+ if (isGreater(State, Pos.getOffset(), End)) {
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -2306,8 +2366,12 @@ bool isLess(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) {
|
|
return compare(State, Sym1, Sym2, BO_LT);
|
|
return compare(State, Sym1, Sym2, BO_LT);
|
|
}
|
|
}
|
|
|
|
|
|
-bool isGreaterOrEqual(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) {
|
|
|
|
- return compare(State, Sym1, Sym2, BO_GE);
|
|
|
|
|
|
+bool isGreater(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) {
|
|
|
|
+ return compare(State, Sym1, Sym2, BO_GT);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+bool isEqual(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) {
|
|
|
|
+ return compare(State, Sym1, Sym2, BO_EQ);
|
|
}
|
|
}
|
|
|
|
|
|
bool compare(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2,
|
|
bool compare(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2,
|