forked from OSchip/llvm-project
[Analyzer] Use note tags to track container begin and and changes
Container operations such as `push_back()`, `pop_front()` etc. increment and decrement the abstract begin and end symbols of containers. This patch introduces note tags to `ContainerModeling` to track these changes. This helps the user to better identify the source of errors related to containers and iterators. Differential Revision: https://reviews.llvm.org/D73720
This commit is contained in:
parent
92744f6247
commit
a3f4d17a1a
|
@ -31,47 +31,43 @@ namespace {
|
||||||
class ContainerModeling
|
class ContainerModeling
|
||||||
: public Checker<check::PostCall, check::LiveSymbols, check::DeadSymbols> {
|
: public Checker<check::PostCall, check::LiveSymbols, check::DeadSymbols> {
|
||||||
|
|
||||||
void handleBegin(CheckerContext &C, const Expr *CE, const SVal &RetVal,
|
void handleBegin(CheckerContext &C, const Expr *CE, SVal RetVal,
|
||||||
const SVal &Cont) const;
|
SVal Cont) const;
|
||||||
void handleEnd(CheckerContext &C, const Expr *CE, const SVal &RetVal,
|
void handleEnd(CheckerContext &C, const Expr *CE, SVal RetVal,
|
||||||
const SVal &Cont) const;
|
SVal Cont) const;
|
||||||
void handleAssignment(CheckerContext &C, const SVal &Cont,
|
void handleAssignment(CheckerContext &C, SVal Cont, const Expr *CE = nullptr,
|
||||||
const Expr *CE = nullptr,
|
SVal OldCont = UndefinedVal()) const;
|
||||||
const SVal &OldCont = UndefinedVal()) const;
|
void handleAssign(CheckerContext &C, SVal Cont, const Expr *ContE) const;
|
||||||
void handleAssign(CheckerContext &C, const SVal &Cont) const;
|
void handleClear(CheckerContext &C, SVal Cont, const Expr *ContE) const;
|
||||||
void handleClear(CheckerContext &C, const SVal &Cont) const;
|
void handlePushBack(CheckerContext &C, SVal Cont, const Expr *ContE) const;
|
||||||
void handlePushBack(CheckerContext &C, const SVal &Cont) const;
|
void handlePopBack(CheckerContext &C, SVal Cont, const Expr *ContE) const;
|
||||||
void handlePopBack(CheckerContext &C, const SVal &Cont) const;
|
void handlePushFront(CheckerContext &C, SVal Cont, const Expr *ContE) const;
|
||||||
void handlePushFront(CheckerContext &C, const SVal &Cont) const;
|
void handlePopFront(CheckerContext &C, SVal Cont, const Expr *ContE) const;
|
||||||
void handlePopFront(CheckerContext &C, const SVal &Cont) const;
|
void handleInsert(CheckerContext &C, SVal Cont, SVal Iter) const;
|
||||||
void handleInsert(CheckerContext &C, const SVal &Cont,
|
void handleErase(CheckerContext &C, SVal Cont, SVal Iter) const;
|
||||||
const SVal &Iter) const;
|
void handleErase(CheckerContext &C, SVal Cont, SVal Iter1, SVal Iter2) const;
|
||||||
void handleErase(CheckerContext &C, const SVal &Cont, const SVal &Iter) const;
|
void handleEraseAfter(CheckerContext &C, SVal Cont, SVal Iter) const;
|
||||||
void handleErase(CheckerContext &C, const SVal &Cont, const SVal &Iter1,
|
void handleEraseAfter(CheckerContext &C, SVal Cont, SVal Iter1,
|
||||||
const SVal &Iter2) const;
|
SVal Iter2) const;
|
||||||
void handleEraseAfter(CheckerContext &C, const SVal &Cont,
|
const NoteTag *getChangeTag(CheckerContext &C, StringRef Text,
|
||||||
const SVal &Iter) const;
|
const MemRegion *ContReg,
|
||||||
void handleEraseAfter(CheckerContext &C, const SVal &Cont, const SVal &Iter1,
|
const Expr *ContE) const;
|
||||||
const SVal &Iter2) const;
|
|
||||||
void printState(raw_ostream &Out, ProgramStateRef State, const char *NL,
|
void printState(raw_ostream &Out, ProgramStateRef State, const char *NL,
|
||||||
const char *Sep) const override;
|
const char *Sep) const override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ContainerModeling() {}
|
ContainerModeling() = default;
|
||||||
|
|
||||||
void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
|
void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
|
||||||
void checkLiveSymbols(ProgramStateRef State, SymbolReaper &SR) const;
|
void checkLiveSymbols(ProgramStateRef State, SymbolReaper &SR) const;
|
||||||
void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
|
void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
|
||||||
|
|
||||||
typedef void (ContainerModeling::*NoItParamFn)(CheckerContext &,
|
using NoItParamFn = void (ContainerModeling::*)(CheckerContext &, SVal,
|
||||||
const SVal &) const;
|
const Expr *) const;
|
||||||
typedef void (ContainerModeling::*OneItParamFn)(CheckerContext &,
|
using OneItParamFn = void (ContainerModeling::*)(CheckerContext &, SVal,
|
||||||
const SVal &,
|
SVal) const;
|
||||||
const SVal &) const;
|
using TwoItParamFn = void (ContainerModeling::*)(CheckerContext &, SVal, SVal,
|
||||||
typedef void (ContainerModeling::*TwoItParamFn)(CheckerContext &,
|
SVal) const;
|
||||||
const SVal &,
|
|
||||||
const SVal &,
|
|
||||||
const SVal &) const;
|
|
||||||
|
|
||||||
CallDescriptionMap<NoItParamFn> NoIterParamFunctions = {
|
CallDescriptionMap<NoItParamFn> NoIterParamFunctions = {
|
||||||
{{0, "clear", 0},
|
{{0, "clear", 0},
|
||||||
|
@ -184,7 +180,8 @@ void ContainerModeling::checkPostCall(const CallEvent &Call,
|
||||||
if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
|
if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
|
||||||
const NoItParamFn *Handler0 = NoIterParamFunctions.lookup(Call);
|
const NoItParamFn *Handler0 = NoIterParamFunctions.lookup(Call);
|
||||||
if (Handler0) {
|
if (Handler0) {
|
||||||
(this->**Handler0)(C, InstCall->getCXXThisVal());
|
(this->**Handler0)(C, InstCall->getCXXThisVal(),
|
||||||
|
InstCall->getCXXThisExpr());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -259,7 +256,7 @@ void ContainerModeling::checkDeadSymbols(SymbolReaper &SR,
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContainerModeling::handleBegin(CheckerContext &C, const Expr *CE,
|
void ContainerModeling::handleBegin(CheckerContext &C, const Expr *CE,
|
||||||
const SVal &RetVal, const SVal &Cont) const {
|
SVal RetVal, SVal Cont) const {
|
||||||
const auto *ContReg = Cont.getAsRegion();
|
const auto *ContReg = Cont.getAsRegion();
|
||||||
if (!ContReg)
|
if (!ContReg)
|
||||||
return;
|
return;
|
||||||
|
@ -281,7 +278,7 @@ void ContainerModeling::handleBegin(CheckerContext &C, const Expr *CE,
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContainerModeling::handleEnd(CheckerContext &C, const Expr *CE,
|
void ContainerModeling::handleEnd(CheckerContext &C, const Expr *CE,
|
||||||
const SVal &RetVal, const SVal &Cont) const {
|
SVal RetVal, SVal Cont) const {
|
||||||
const auto *ContReg = Cont.getAsRegion();
|
const auto *ContReg = Cont.getAsRegion();
|
||||||
if (!ContReg)
|
if (!ContReg)
|
||||||
return;
|
return;
|
||||||
|
@ -302,9 +299,8 @@ void ContainerModeling::handleEnd(CheckerContext &C, const Expr *CE,
|
||||||
C.addTransition(State);
|
C.addTransition(State);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContainerModeling::handleAssignment(CheckerContext &C, const SVal &Cont,
|
void ContainerModeling::handleAssignment(CheckerContext &C, SVal Cont,
|
||||||
const Expr *CE,
|
const Expr *CE, SVal OldCont) const {
|
||||||
const SVal &OldCont) const {
|
|
||||||
const auto *ContReg = Cont.getAsRegion();
|
const auto *ContReg = Cont.getAsRegion();
|
||||||
if (!ContReg)
|
if (!ContReg)
|
||||||
return;
|
return;
|
||||||
|
@ -379,8 +375,8 @@ void ContainerModeling::handleAssignment(CheckerContext &C, const SVal &Cont,
|
||||||
C.addTransition(State);
|
C.addTransition(State);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContainerModeling::handleAssign(CheckerContext &C,
|
void ContainerModeling::handleAssign(CheckerContext &C, SVal Cont,
|
||||||
const SVal &Cont) const {
|
const Expr *ContE) const {
|
||||||
const auto *ContReg = Cont.getAsRegion();
|
const auto *ContReg = Cont.getAsRegion();
|
||||||
if (!ContReg)
|
if (!ContReg)
|
||||||
return;
|
return;
|
||||||
|
@ -393,7 +389,8 @@ void ContainerModeling::handleAssign(CheckerContext &C,
|
||||||
C.addTransition(State);
|
C.addTransition(State);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContainerModeling::handleClear(CheckerContext &C, const SVal &Cont) const {
|
void ContainerModeling::handleClear(CheckerContext &C, SVal Cont,
|
||||||
|
const Expr *ContE) const {
|
||||||
const auto *ContReg = Cont.getAsRegion();
|
const auto *ContReg = Cont.getAsRegion();
|
||||||
if (!ContReg)
|
if (!ContReg)
|
||||||
return;
|
return;
|
||||||
|
@ -415,12 +412,14 @@ void ContainerModeling::handleClear(CheckerContext &C, const SVal &Cont) const {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const NoteTag *ChangeTag =
|
||||||
|
getChangeTag(C, "became empty", ContReg, ContE);
|
||||||
State = invalidateAllIteratorPositions(State, ContReg);
|
State = invalidateAllIteratorPositions(State, ContReg);
|
||||||
C.addTransition(State);
|
C.addTransition(State, ChangeTag);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContainerModeling::handlePushBack(CheckerContext &C,
|
void ContainerModeling::handlePushBack(CheckerContext &C, SVal Cont,
|
||||||
const SVal &Cont) const {
|
const Expr *ContE) const {
|
||||||
const auto *ContReg = Cont.getAsRegion();
|
const auto *ContReg = Cont.getAsRegion();
|
||||||
if (!ContReg)
|
if (!ContReg)
|
||||||
return;
|
return;
|
||||||
|
@ -452,13 +451,15 @@ void ContainerModeling::handlePushBack(CheckerContext &C,
|
||||||
nonloc::SymbolVal(EndSym),
|
nonloc::SymbolVal(EndSym),
|
||||||
nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
|
nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
|
||||||
SymMgr.getType(EndSym)).getAsSymbol();
|
SymMgr.getType(EndSym)).getAsSymbol();
|
||||||
|
const NoteTag *ChangeTag =
|
||||||
|
getChangeTag(C, "extended to the back by 1 position", ContReg, ContE);
|
||||||
State = setContainerData(State, ContReg, CData->newEnd(newEndSym));
|
State = setContainerData(State, ContReg, CData->newEnd(newEndSym));
|
||||||
|
C.addTransition(State, ChangeTag);
|
||||||
}
|
}
|
||||||
C.addTransition(State);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContainerModeling::handlePopBack(CheckerContext &C,
|
void ContainerModeling::handlePopBack(CheckerContext &C, SVal Cont,
|
||||||
const SVal &Cont) const {
|
const Expr *ContE) const {
|
||||||
const auto *ContReg = Cont.getAsRegion();
|
const auto *ContReg = Cont.getAsRegion();
|
||||||
if (!ContReg)
|
if (!ContReg)
|
||||||
return;
|
return;
|
||||||
|
@ -479,6 +480,8 @@ void ContainerModeling::handlePopBack(CheckerContext &C,
|
||||||
nonloc::SymbolVal(EndSym),
|
nonloc::SymbolVal(EndSym),
|
||||||
nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
|
nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
|
||||||
SymMgr.getType(EndSym)).getAsSymbol();
|
SymMgr.getType(EndSym)).getAsSymbol();
|
||||||
|
const NoteTag *ChangeTag =
|
||||||
|
getChangeTag(C, "shrank from the back by 1 position", ContReg, ContE);
|
||||||
// For vector-like and deque-like containers invalidate the last and the
|
// For vector-like and deque-like containers invalidate the last and the
|
||||||
// past-end iterator positions. For list-like containers only invalidate
|
// past-end iterator positions. For list-like containers only invalidate
|
||||||
// the last position
|
// the last position
|
||||||
|
@ -491,12 +494,12 @@ void ContainerModeling::handlePopBack(CheckerContext &C,
|
||||||
}
|
}
|
||||||
auto newEndSym = BackSym;
|
auto newEndSym = BackSym;
|
||||||
State = setContainerData(State, ContReg, CData->newEnd(newEndSym));
|
State = setContainerData(State, ContReg, CData->newEnd(newEndSym));
|
||||||
C.addTransition(State);
|
C.addTransition(State, ChangeTag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContainerModeling::handlePushFront(CheckerContext &C,
|
void ContainerModeling::handlePushFront(CheckerContext &C, SVal Cont,
|
||||||
const SVal &Cont) const {
|
const Expr *ContE) const {
|
||||||
const auto *ContReg = Cont.getAsRegion();
|
const auto *ContReg = Cont.getAsRegion();
|
||||||
if (!ContReg)
|
if (!ContReg)
|
||||||
return;
|
return;
|
||||||
|
@ -522,14 +525,16 @@ void ContainerModeling::handlePushFront(CheckerContext &C,
|
||||||
nonloc::SymbolVal(BeginSym),
|
nonloc::SymbolVal(BeginSym),
|
||||||
nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
|
nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
|
||||||
SymMgr.getType(BeginSym)).getAsSymbol();
|
SymMgr.getType(BeginSym)).getAsSymbol();
|
||||||
|
const NoteTag *ChangeTag =
|
||||||
|
getChangeTag(C, "extended to the front by 1 position", ContReg, ContE);
|
||||||
State = setContainerData(State, ContReg, CData->newBegin(newBeginSym));
|
State = setContainerData(State, ContReg, CData->newBegin(newBeginSym));
|
||||||
C.addTransition(State);
|
C.addTransition(State, ChangeTag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContainerModeling::handlePopFront(CheckerContext &C,
|
void ContainerModeling::handlePopFront(CheckerContext &C, SVal Cont,
|
||||||
const SVal &Cont) const {
|
const Expr *ContE) const {
|
||||||
const auto *ContReg = Cont.getAsRegion();
|
const auto *ContReg = Cont.getAsRegion();
|
||||||
if (!ContReg)
|
if (!ContReg)
|
||||||
return;
|
return;
|
||||||
|
@ -557,13 +562,15 @@ void ContainerModeling::handlePopFront(CheckerContext &C,
|
||||||
nonloc::SymbolVal(BeginSym),
|
nonloc::SymbolVal(BeginSym),
|
||||||
nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
|
nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
|
||||||
SymMgr.getType(BeginSym)).getAsSymbol();
|
SymMgr.getType(BeginSym)).getAsSymbol();
|
||||||
|
const NoteTag *ChangeTag =
|
||||||
|
getChangeTag(C, "shrank from the front by 1 position", ContReg, ContE);
|
||||||
State = setContainerData(State, ContReg, CData->newBegin(newBeginSym));
|
State = setContainerData(State, ContReg, CData->newBegin(newBeginSym));
|
||||||
C.addTransition(State);
|
C.addTransition(State, ChangeTag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContainerModeling::handleInsert(CheckerContext &C, const SVal &Cont,
|
void ContainerModeling::handleInsert(CheckerContext &C, SVal Cont,
|
||||||
const SVal &Iter) const {
|
SVal Iter) const {
|
||||||
const auto *ContReg = Cont.getAsRegion();
|
const auto *ContReg = Cont.getAsRegion();
|
||||||
if (!ContReg)
|
if (!ContReg)
|
||||||
return;
|
return;
|
||||||
|
@ -593,8 +600,8 @@ void ContainerModeling::handleInsert(CheckerContext &C, const SVal &Cont,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContainerModeling::handleErase(CheckerContext &C, const SVal &Cont,
|
void ContainerModeling::handleErase(CheckerContext &C, SVal Cont,
|
||||||
const SVal &Iter) const {
|
SVal Iter) const {
|
||||||
const auto *ContReg = Cont.getAsRegion();
|
const auto *ContReg = Cont.getAsRegion();
|
||||||
if (!ContReg)
|
if (!ContReg)
|
||||||
return;
|
return;
|
||||||
|
@ -627,9 +634,8 @@ void ContainerModeling::handleErase(CheckerContext &C, const SVal &Cont,
|
||||||
C.addTransition(State);
|
C.addTransition(State);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContainerModeling::handleErase(CheckerContext &C, const SVal &Cont,
|
void ContainerModeling::handleErase(CheckerContext &C, SVal Cont, SVal Iter1,
|
||||||
const SVal &Iter1,
|
SVal Iter2) const {
|
||||||
const SVal &Iter2) const {
|
|
||||||
const auto *ContReg = Cont.getAsRegion();
|
const auto *ContReg = Cont.getAsRegion();
|
||||||
if (!ContReg)
|
if (!ContReg)
|
||||||
return;
|
return;
|
||||||
|
@ -664,8 +670,8 @@ void ContainerModeling::handleErase(CheckerContext &C, const SVal &Cont,
|
||||||
C.addTransition(State);
|
C.addTransition(State);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContainerModeling::handleEraseAfter(CheckerContext &C, const SVal &Cont,
|
void ContainerModeling::handleEraseAfter(CheckerContext &C, SVal Cont,
|
||||||
const SVal &Iter) const {
|
SVal Iter) const {
|
||||||
auto State = C.getState();
|
auto State = C.getState();
|
||||||
const auto *Pos = getIteratorPosition(State, Iter);
|
const auto *Pos = getIteratorPosition(State, Iter);
|
||||||
if (!Pos)
|
if (!Pos)
|
||||||
|
@ -685,9 +691,8 @@ void ContainerModeling::handleEraseAfter(CheckerContext &C, const SVal &Cont,
|
||||||
C.addTransition(State);
|
C.addTransition(State);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContainerModeling::handleEraseAfter(CheckerContext &C, const SVal &Cont,
|
void ContainerModeling::handleEraseAfter(CheckerContext &C, SVal Cont,
|
||||||
const SVal &Iter1,
|
SVal Iter1, SVal Iter2) const {
|
||||||
const SVal &Iter2) const {
|
|
||||||
auto State = C.getState();
|
auto State = C.getState();
|
||||||
const auto *Pos1 = getIteratorPosition(State, Iter1);
|
const auto *Pos1 = getIteratorPosition(State, Iter1);
|
||||||
const auto *Pos2 = getIteratorPosition(State, Iter2);
|
const auto *Pos2 = getIteratorPosition(State, Iter2);
|
||||||
|
@ -700,6 +705,30 @@ void ContainerModeling::handleEraseAfter(CheckerContext &C, const SVal &Cont,
|
||||||
C.addTransition(State);
|
C.addTransition(State);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const NoteTag *ContainerModeling::getChangeTag(CheckerContext &C,
|
||||||
|
StringRef Text,
|
||||||
|
const MemRegion *ContReg,
|
||||||
|
const Expr *ContE) const {
|
||||||
|
StringRef Name;
|
||||||
|
// First try to get the name of the variable from the region
|
||||||
|
if (const auto *DR = dyn_cast<DeclRegion>(ContReg)) {
|
||||||
|
Name = DR->getDecl()->getName();
|
||||||
|
// If the region is not a `DeclRegion` then use the expression instead
|
||||||
|
} else if (const auto *DRE =
|
||||||
|
dyn_cast<DeclRefExpr>(ContE->IgnoreParenCasts())) {
|
||||||
|
Name = DRE->getDecl()->getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
return C.getNoteTag(
|
||||||
|
[Text, Name, ContReg](PathSensitiveBugReport &BR) -> std::string {
|
||||||
|
SmallString<256> Msg;
|
||||||
|
llvm::raw_svector_ostream Out(Msg);
|
||||||
|
Out << "Container " << (!Name.empty() ? ("'" + Name.str() + "' ") : "" )
|
||||||
|
<< Text;
|
||||||
|
return std::string(Out.str());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void ContainerModeling::printState(raw_ostream &Out, ProgramStateRef State,
|
void ContainerModeling::printState(raw_ostream &Out, ProgramStateRef State,
|
||||||
const char *NL, const char *Sep) const {
|
const char *NL, const char *Sep) const {
|
||||||
auto ContMap = State->get<ContainerMap>();
|
auto ContMap = State->get<ContainerMap>();
|
||||||
|
|
|
@ -221,7 +221,12 @@ void IteratorRangeChecker::reportBug(const StringRef &Message, SVal Val,
|
||||||
ExplodedNode *ErrNode) const {
|
ExplodedNode *ErrNode) const {
|
||||||
auto R = std::make_unique<PathSensitiveBugReport>(*OutOfRangeBugType, Message,
|
auto R = std::make_unique<PathSensitiveBugReport>(*OutOfRangeBugType, Message,
|
||||||
ErrNode);
|
ErrNode);
|
||||||
|
|
||||||
|
const auto *Pos = getIteratorPosition(C.getState(), Val);
|
||||||
|
assert(Pos && "Iterator without known position cannot be out-of-range.");
|
||||||
|
|
||||||
R->markInteresting(Val);
|
R->markInteresting(Val);
|
||||||
|
R->markInteresting(Pos->getContainer());
|
||||||
C.emitReport(std::move(R));
|
C.emitReport(std::move(R));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,debug.DebugIteratorModeling,debug.ExprInspection -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=false %s -verify
|
// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,debug.DebugIteratorModeling,debug.ExprInspection -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=false %s -analyzer-output=text -verify
|
||||||
|
|
||||||
// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,debug.DebugIteratorModeling,debug.ExprInspection -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=true -DINLINE=1 %s -verify
|
// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,debug.DebugIteratorModeling,debug.ExprInspection -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=true -DINLINE=1 %s -analyzer-output=text -verify
|
||||||
|
|
||||||
// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,alpha.cplusplus.IteratorModeling,debug.ExprInspection -analyzer-config aggressive-binary-operation-simplification=true %s 2>&1 | FileCheck %s
|
// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,alpha.cplusplus.IteratorModeling,debug.ExprInspection -analyzer-config aggressive-binary-operation-simplification=true %s 2>&1 | FileCheck %s
|
||||||
|
|
||||||
|
@ -20,14 +20,16 @@ void begin(const std::vector<int> &V) {
|
||||||
V.begin();
|
V.begin();
|
||||||
|
|
||||||
clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()");
|
clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()");
|
||||||
clang_analyzer_express(clang_analyzer_container_begin(V)); //expected-warning{{$V.begin()}}
|
clang_analyzer_express(clang_analyzer_container_begin(V)); // expected-warning{{$V.begin()}}
|
||||||
|
// expected-note@-1{{$V.begin()}}
|
||||||
}
|
}
|
||||||
|
|
||||||
void end(const std::vector<int> &V) {
|
void end(const std::vector<int> &V) {
|
||||||
V.end();
|
V.end();
|
||||||
|
|
||||||
clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()");
|
clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()");
|
||||||
clang_analyzer_express(clang_analyzer_container_end(V)); //expected-warning{{$V.end()}}
|
clang_analyzer_express(clang_analyzer_container_end(V)); // expected-warning{{$V.end()}}
|
||||||
|
// expected-note@-1{{$V.end()}}
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -48,8 +50,10 @@ void move_assignment(std::vector<int> &V1, std::vector<int> &V2) {
|
||||||
long B2 = clang_analyzer_container_begin(V2);
|
long B2 = clang_analyzer_container_begin(V2);
|
||||||
long E2 = clang_analyzer_container_end(V2);
|
long E2 = clang_analyzer_container_end(V2);
|
||||||
V1 = std::move(V2);
|
V1 = std::move(V2);
|
||||||
clang_analyzer_eval(clang_analyzer_container_begin(V1) == B2); //expected-warning{{TRUE}}
|
clang_analyzer_eval(clang_analyzer_container_begin(V1) == B2); // expected-warning{{TRUE}}
|
||||||
clang_analyzer_eval(clang_analyzer_container_end(V2) == E2); //expected-warning{{TRUE}}
|
// expected-note@-1{{TRUE}}
|
||||||
|
clang_analyzer_eval(clang_analyzer_container_end(V2) == E2); // expected-warning{{TRUE}}
|
||||||
|
// expected-note@-1{{TRUE}}
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -60,9 +64,11 @@ void move_assignment(std::vector<int> &V1, std::vector<int> &V2) {
|
||||||
|
|
||||||
/// push_back()
|
/// push_back()
|
||||||
///
|
///
|
||||||
/// Design decision: extends containers to the ->RIGHT-> (i.e. the
|
/// Design decision: extends containers to the ->BACK-> (i.e. the
|
||||||
/// past-the-end position of the container is incremented).
|
/// past-the-end position of the container is incremented).
|
||||||
|
|
||||||
|
void clang_analyzer_dump(void*);
|
||||||
|
|
||||||
void push_back(std::vector<int> &V, int n) {
|
void push_back(std::vector<int> &V, int n) {
|
||||||
V.cbegin();
|
V.cbegin();
|
||||||
V.cend();
|
V.cend();
|
||||||
|
@ -70,15 +76,18 @@ void push_back(std::vector<int> &V, int n) {
|
||||||
clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()");
|
clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()");
|
||||||
clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()");
|
clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()");
|
||||||
|
|
||||||
V.push_back(n);
|
V.push_back(n); // expected-note{{Container 'V' extended to the back by 1 position}}
|
||||||
|
// expected-note@-1{{Container 'V' extended to the back by 1 position}}
|
||||||
|
|
||||||
clang_analyzer_express(clang_analyzer_container_begin(V)); // expected-warning{{$V.begin()}}
|
clang_analyzer_express(clang_analyzer_container_begin(V)); // expected-warning{{$V.begin()}}
|
||||||
|
// expected-note@-1{{$V.begin()}}
|
||||||
clang_analyzer_express(clang_analyzer_container_end(V)); // expected-warning{{$V.end() + 1}}
|
clang_analyzer_express(clang_analyzer_container_end(V)); // expected-warning{{$V.end() + 1}}
|
||||||
|
// expected-note@-1{{$V.end() + 1}}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// emplace_back()
|
/// emplace_back()
|
||||||
///
|
///
|
||||||
/// Design decision: extends containers to the ->RIGHT-> (i.e. the
|
/// Design decision: extends containers to the ->BACK-> (i.e. the
|
||||||
/// past-the-end position of the container is incremented).
|
/// past-the-end position of the container is incremented).
|
||||||
|
|
||||||
void emplace_back(std::vector<int> &V, int n) {
|
void emplace_back(std::vector<int> &V, int n) {
|
||||||
|
@ -88,15 +97,18 @@ void emplace_back(std::vector<int> &V, int n) {
|
||||||
clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()");
|
clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()");
|
||||||
clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()");
|
clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()");
|
||||||
|
|
||||||
V.emplace_back(n);
|
V.emplace_back(n); // expected-note 2{{Container 'V' extended to the back by 1 position}}
|
||||||
|
|
||||||
|
|
||||||
clang_analyzer_express(clang_analyzer_container_begin(V)); // expected-warning{{$V.begin()}}
|
clang_analyzer_express(clang_analyzer_container_begin(V)); // expected-warning{{$V.begin()}}
|
||||||
|
// expected-note@-1{{$V.begin()}}
|
||||||
clang_analyzer_express(clang_analyzer_container_end(V)); // expected-warning{{$V.end() + 1}}
|
clang_analyzer_express(clang_analyzer_container_end(V)); // expected-warning{{$V.end() + 1}}
|
||||||
|
// expected-note@-1{{$V.end() + 1}}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// pop_back()
|
/// pop_back()
|
||||||
///
|
///
|
||||||
/// Design decision: shrinks containers to the <-LEFT<- (i.e. the
|
/// Design decision: shrinks containers to the <-FRONT<- (i.e. the
|
||||||
/// past-the-end position of the container is decremented).
|
/// past-the-end position of the container is decremented).
|
||||||
|
|
||||||
void pop_back(std::vector<int> &V, int n) {
|
void pop_back(std::vector<int> &V, int n) {
|
||||||
|
@ -106,66 +118,133 @@ void pop_back(std::vector<int> &V, int n) {
|
||||||
clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()");
|
clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()");
|
||||||
clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()");
|
clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()");
|
||||||
|
|
||||||
V.pop_back();
|
V.pop_back(); // expected-note 2{{Container 'V' shrank from the back by 1 position}}
|
||||||
|
|
||||||
|
|
||||||
clang_analyzer_express(clang_analyzer_container_begin(V)); // expected-warning{{$V.begin()}}
|
clang_analyzer_express(clang_analyzer_container_begin(V)); // expected-warning{{$V.begin()}}
|
||||||
|
// expected-note@-1{{$V.begin()}}
|
||||||
clang_analyzer_express(clang_analyzer_container_end(V)); // expected-warning{{$V.end() - 1}}
|
clang_analyzer_express(clang_analyzer_container_end(V)); // expected-warning{{$V.end() - 1}}
|
||||||
|
// expected-note@-1{{$V.end() - 1}}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// push_front()
|
/// push_front()
|
||||||
///
|
///
|
||||||
/// Design decision: extends containers to the <-LEFT<- (i.e. the first
|
/// Design decision: extends containers to the <-FRONT<- (i.e. the first
|
||||||
/// position of the container is decremented).
|
/// position of the container is decremented).
|
||||||
|
|
||||||
void push_front(std::deque<int> &D, int n) {
|
void push_front(std::list<int> &L, int n) {
|
||||||
D.cbegin();
|
L.cbegin();
|
||||||
D.cend();
|
L.cend();
|
||||||
|
|
||||||
clang_analyzer_denote(clang_analyzer_container_begin(D), "$D.begin()");
|
clang_analyzer_denote(clang_analyzer_container_begin(L), "$L.begin()");
|
||||||
clang_analyzer_denote(clang_analyzer_container_end(D), "$D.end()");
|
clang_analyzer_denote(clang_analyzer_container_end(L), "$L.end()");
|
||||||
|
|
||||||
D.push_front(n);
|
L.push_front(n); // expected-note 2{{Container 'L' extended to the front by 1 position}}
|
||||||
|
|
||||||
clang_analyzer_express(clang_analyzer_container_begin(D)); // expected-warning{{$D.begin()}} FIXME: Should be $D.begin() - 1 (to correctly track the container's size)
|
clang_analyzer_express(clang_analyzer_container_begin(L)); // expected-warning{{$L.begin() - 1}}
|
||||||
clang_analyzer_express(clang_analyzer_container_end(D)); // expected-warning{{$D.end()}}
|
// expected-note@-1{{$L.begin() - 1}}
|
||||||
|
clang_analyzer_express(clang_analyzer_container_end(L)); // expected-warning{{$L.end()}}
|
||||||
|
// expected-note@-1{{$L.end()}}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// emplace_front()
|
/// emplace_front()
|
||||||
///
|
///
|
||||||
/// Design decision: extends containers to the <-LEFT<- (i.e. the first
|
/// Design decision: extends containers to the <-FRONT<- (i.e. the first
|
||||||
/// position of the container is decremented).
|
/// position of the container is decremented).
|
||||||
|
|
||||||
void deque_emplace_front(std::deque<int> &D, int n) {
|
void emplace_front(std::list<int> &L, int n) {
|
||||||
D.cbegin();
|
L.cbegin();
|
||||||
D.cend();
|
L.cend();
|
||||||
|
|
||||||
clang_analyzer_denote(clang_analyzer_container_begin(D), "$D.begin()");
|
clang_analyzer_denote(clang_analyzer_container_begin(L), "$L.begin()");
|
||||||
clang_analyzer_denote(clang_analyzer_container_end(D), "$D.end()");
|
clang_analyzer_denote(clang_analyzer_container_end(L), "$L.end()");
|
||||||
|
|
||||||
D.emplace_front(n);
|
L.emplace_front(n); // expected-note 2{{Container 'L' extended to the front by 1 position}}
|
||||||
|
|
||||||
clang_analyzer_express(clang_analyzer_container_begin(D)); // expected-warning{{$D.begin()}} FIXME: Should be $D.begin - 1 (to correctly track the container's size)
|
clang_analyzer_express(clang_analyzer_container_begin(L)); // expected-warning{{$L.begin() - 1}}
|
||||||
clang_analyzer_express(clang_analyzer_container_end(D)); // expected-warning{{$D.end()}}
|
// expected-note@-1{{$L.begin() - 1}}
|
||||||
|
clang_analyzer_express(clang_analyzer_container_end(L)); // expected-warning{{$L.end()}}
|
||||||
|
// expected-note@-1{{$L.end()}}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// pop_front()
|
/// pop_front()
|
||||||
///
|
///
|
||||||
/// Design decision: shrinks containers to the ->RIGHT-> (i.e. the first
|
/// Design decision: shrinks containers to the ->BACK-> (i.e. the first
|
||||||
/// position of the container is incremented).
|
/// position of the container is incremented).
|
||||||
|
|
||||||
void deque_pop_front(std::deque<int> &D, int n) {
|
void pop_front(std::list<int> &L, int n) {
|
||||||
D.cbegin();
|
L.cbegin();
|
||||||
D.cend();
|
L.cend();
|
||||||
|
|
||||||
clang_analyzer_denote(clang_analyzer_container_begin(D), "$D.begin()");
|
clang_analyzer_denote(clang_analyzer_container_begin(L), "$L.begin()");
|
||||||
clang_analyzer_denote(clang_analyzer_container_end(D), "$D.end()");
|
clang_analyzer_denote(clang_analyzer_container_end(L), "$L.end()");
|
||||||
|
|
||||||
D.pop_front();
|
L.pop_front(); // expected-note 2{{Container 'L' shrank from the front by 1 position}}
|
||||||
|
|
||||||
clang_analyzer_express(clang_analyzer_container_begin(D)); // expected-warning{{$D.begin() + 1}}
|
clang_analyzer_express(clang_analyzer_container_begin(L)); // expected-warning{{$L.begin() + 1}}
|
||||||
clang_analyzer_express(clang_analyzer_container_end(D)); // expected-warning{{$D.end()}}
|
// expected-note@-1{{$L.begin() + 1}}
|
||||||
|
clang_analyzer_express(clang_analyzer_container_end(L)); // expected-warning{{$L.end()}}
|
||||||
|
// expected-note@-1{{$L.end()}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
///
|
||||||
|
/// O T H E R T E S T S
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/// Track local variable
|
||||||
|
|
||||||
|
void push_back() {
|
||||||
|
std::vector<int> V;
|
||||||
|
V.end();
|
||||||
|
|
||||||
|
clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()");
|
||||||
|
|
||||||
|
V.push_back(1); // expected-note{{Container 'V' extended to the back by 1 position}}
|
||||||
|
|
||||||
|
clang_analyzer_express(clang_analyzer_container_end(V)); // expected-warning{{$V.end() + 1}}
|
||||||
|
// expected-note@-1{{$V.end() + 1}}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Track the right container only
|
||||||
|
|
||||||
|
void push_back1(std::vector<int> &V1, std::vector<int> &V2, int n) {
|
||||||
|
V1.cbegin();
|
||||||
|
V1.cend();
|
||||||
|
V2.cbegin();
|
||||||
|
V2.cend();
|
||||||
|
|
||||||
|
clang_analyzer_denote(clang_analyzer_container_begin(V1), "$V1.begin()");
|
||||||
|
|
||||||
|
V2.push_back(n); // expected-note{{Container 'V2' extended to the back by 1 position}} FIXME: This note should not appear since `V2` is not affected in the "bug"
|
||||||
|
|
||||||
|
clang_analyzer_express(clang_analyzer_container_begin(V1)); // expected-warning{{$V1.begin()}}
|
||||||
|
// expected-note@-1{{$V1.begin()}}
|
||||||
|
}
|
||||||
|
|
||||||
|
void push_back2(std::vector<int> &V1, std::vector<int> &V2, int n) {
|
||||||
|
V1.cbegin();
|
||||||
|
V1.cend();
|
||||||
|
V2.cbegin();
|
||||||
|
V2.cend();
|
||||||
|
|
||||||
|
clang_analyzer_denote(clang_analyzer_container_begin(V1), "$V1.begin()");
|
||||||
|
clang_analyzer_denote(clang_analyzer_container_begin(V2), "$V2.begin()");
|
||||||
|
|
||||||
|
V1.push_back(n); // expected-note 2{{Container 'V1' extended to the back by 1 position}}
|
||||||
|
// FIXME: This should appear only once since there is only
|
||||||
|
// one "bug" where `V1` is affected
|
||||||
|
|
||||||
|
clang_analyzer_express(clang_analyzer_container_begin(V1)); // expected-warning{{$V1.begin()}}
|
||||||
|
// expected-note@-1{{$V1.begin()}}
|
||||||
|
|
||||||
|
clang_analyzer_express(clang_analyzer_container_begin(V2)); // expected-warning{{$V2.begin()}}
|
||||||
|
// expected-note@-1{{$V2.begin()}}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Print Container Data as Part of the Program State
|
||||||
|
|
||||||
void clang_analyzer_printState();
|
void clang_analyzer_printState();
|
||||||
|
|
||||||
void print_state(std::vector<int> &V) {
|
void print_state(std::vector<int> &V) {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,alpha.cplusplus.IteratorRange -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=false %s -verify
|
// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,alpha.cplusplus.IteratorRange -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=false -analyzer-output=text %s -verify
|
||||||
// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,alpha.cplusplus.IteratorRange -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=true -DINLINE=1 %s -verify
|
// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,alpha.cplusplus.IteratorRange -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=true -DINLINE=1 -analyzer-output=text %s -verify
|
||||||
|
|
||||||
#include "Inputs/system-header-simulator-cxx.h"
|
#include "Inputs/system-header-simulator-cxx.h"
|
||||||
|
|
||||||
|
@ -32,6 +32,7 @@ void deref_ahead_of_end(const std::vector<int> &V) {
|
||||||
void deref_end(const std::vector<int> &V) {
|
void deref_end(const std::vector<int> &V) {
|
||||||
auto i = V.end();
|
auto i = V.end();
|
||||||
*i; // expected-warning{{Past-the-end iterator dereferenced}}
|
*i; // expected-warning{{Past-the-end iterator dereferenced}}
|
||||||
|
// expected-note@-1{{Past-the-end iterator dereferenced}}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prefix increment - operator++()
|
// Prefix increment - operator++()
|
||||||
|
@ -59,6 +60,7 @@ void incr_ahead_of_end(const std::vector<int> &V) {
|
||||||
void incr_end(const std::vector<int> &V) {
|
void incr_end(const std::vector<int> &V) {
|
||||||
auto i = V.end();
|
auto i = V.end();
|
||||||
++i; // expected-warning{{Iterator incremented behind the past-the-end iterator}}
|
++i; // expected-warning{{Iterator incremented behind the past-the-end iterator}}
|
||||||
|
// expected-note@-1{{Iterator incremented behind the past-the-end iterator}}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Postfix increment - operator++(int)
|
// Postfix increment - operator++(int)
|
||||||
|
@ -86,6 +88,7 @@ void ahead_of_end_incr(const std::vector<int> &V) {
|
||||||
void end_incr(const std::vector<int> &V) {
|
void end_incr(const std::vector<int> &V) {
|
||||||
auto i = V.end();
|
auto i = V.end();
|
||||||
i++; // expected-warning{{Iterator incremented behind the past-the-end iterator}}
|
i++; // expected-warning{{Iterator incremented behind the past-the-end iterator}}
|
||||||
|
// expected-note@-1{{Iterator incremented behind the past-the-end iterator}}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prefix decrement - operator--()
|
// Prefix decrement - operator--()
|
||||||
|
@ -93,6 +96,7 @@ void end_incr(const std::vector<int> &V) {
|
||||||
void decr_begin(const std::vector<int> &V) {
|
void decr_begin(const std::vector<int> &V) {
|
||||||
auto i = V.begin();
|
auto i = V.begin();
|
||||||
--i; // expected-warning{{Iterator decremented ahead of its valid range}}
|
--i; // expected-warning{{Iterator decremented ahead of its valid range}}
|
||||||
|
// expected-note@-1{{Iterator decremented ahead of its valid range}}
|
||||||
}
|
}
|
||||||
|
|
||||||
void decr_behind_begin(const std::vector<int> &V) {
|
void decr_behind_begin(const std::vector<int> &V) {
|
||||||
|
@ -120,6 +124,7 @@ void decr_end(const std::vector<int> &V) {
|
||||||
void begin_decr(const std::vector<int> &V) {
|
void begin_decr(const std::vector<int> &V) {
|
||||||
auto i = V.begin();
|
auto i = V.begin();
|
||||||
i--; // expected-warning{{Iterator decremented ahead of its valid range}}
|
i--; // expected-warning{{Iterator decremented ahead of its valid range}}
|
||||||
|
// expected-note@-1{{Iterator decremented ahead of its valid range}}
|
||||||
}
|
}
|
||||||
|
|
||||||
void behind_begin_decr(const std::vector<int> &V) {
|
void behind_begin_decr(const std::vector<int> &V) {
|
||||||
|
@ -168,11 +173,13 @@ void incr_by_2_ahead_by_2_of_end(const std::vector<int> &V) {
|
||||||
void incr_by_2_ahead_of_end(const std::vector<int> &V) {
|
void incr_by_2_ahead_of_end(const std::vector<int> &V) {
|
||||||
auto i = --V.end();
|
auto i = --V.end();
|
||||||
i += 2; // expected-warning{{Iterator incremented behind the past-the-end iterator}}
|
i += 2; // expected-warning{{Iterator incremented behind the past-the-end iterator}}
|
||||||
|
// expected-note@-1{{Iterator incremented behind the past-the-end iterator}}
|
||||||
}
|
}
|
||||||
|
|
||||||
void incr_by_2_end(const std::vector<int> &V) {
|
void incr_by_2_end(const std::vector<int> &V) {
|
||||||
auto i = V.end();
|
auto i = V.end();
|
||||||
i += 2; // expected-warning{{Iterator incremented behind the past-the-end iterator}}
|
i += 2; // expected-warning{{Iterator incremented behind the past-the-end iterator}}
|
||||||
|
// expected-note@-1{{Iterator incremented behind the past-the-end iterator}}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Addition - operator+(int)
|
// Addition - operator+(int)
|
||||||
|
@ -201,11 +208,13 @@ void incr_by_2_copy_ahead_by_2_of_end(const std::vector<int> &V) {
|
||||||
void incr_by_2_copy_ahead_of_end(const std::vector<int> &V) {
|
void incr_by_2_copy_ahead_of_end(const std::vector<int> &V) {
|
||||||
auto i = --V.end();
|
auto i = --V.end();
|
||||||
auto j = i + 2; // expected-warning{{Iterator incremented behind the past-the-end iterator}}
|
auto j = i + 2; // expected-warning{{Iterator incremented behind the past-the-end iterator}}
|
||||||
|
// expected-note@-1{{Iterator incremented behind the past-the-end iterator}}
|
||||||
}
|
}
|
||||||
|
|
||||||
void incr_by_2_copy_end(const std::vector<int> &V) {
|
void incr_by_2_copy_end(const std::vector<int> &V) {
|
||||||
auto i = V.end();
|
auto i = V.end();
|
||||||
auto j = i + 2; // expected-warning{{Iterator incremented behind the past-the-end iterator}}
|
auto j = i + 2; // expected-warning{{Iterator incremented behind the past-the-end iterator}}
|
||||||
|
// expected-note@-1{{Iterator incremented behind the past-the-end iterator}}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Subtraction assignment - operator-=(int)
|
// Subtraction assignment - operator-=(int)
|
||||||
|
@ -213,11 +222,13 @@ void incr_by_2_copy_end(const std::vector<int> &V) {
|
||||||
void decr_by_2_begin(const std::vector<int> &V) {
|
void decr_by_2_begin(const std::vector<int> &V) {
|
||||||
auto i = V.begin();
|
auto i = V.begin();
|
||||||
i -= 2; // expected-warning{{Iterator decremented ahead of its valid range}}
|
i -= 2; // expected-warning{{Iterator decremented ahead of its valid range}}
|
||||||
|
// expected-note@-1{{Iterator decremented ahead of its valid range}}
|
||||||
}
|
}
|
||||||
|
|
||||||
void decr_by_2_behind_begin(const std::vector<int> &V) {
|
void decr_by_2_behind_begin(const std::vector<int> &V) {
|
||||||
auto i = ++V.begin();
|
auto i = ++V.begin();
|
||||||
i -= 2; // expected-warning{{Iterator decremented ahead of its valid range}}
|
i -= 2; // expected-warning{{Iterator decremented ahead of its valid range}}
|
||||||
|
// expected-note@-1{{Iterator decremented ahead of its valid range}}
|
||||||
}
|
}
|
||||||
|
|
||||||
void decr_by_2_behind_begin_by_2(const std::vector<int> &V) {
|
void decr_by_2_behind_begin_by_2(const std::vector<int> &V) {
|
||||||
|
@ -246,11 +257,13 @@ void decr_by_2_end(const std::vector<int> &V) {
|
||||||
void decr_by_2_copy_begin(const std::vector<int> &V) {
|
void decr_by_2_copy_begin(const std::vector<int> &V) {
|
||||||
auto i = V.begin();
|
auto i = V.begin();
|
||||||
auto j = i - 2; // expected-warning{{Iterator decremented ahead of its valid range}}
|
auto j = i - 2; // expected-warning{{Iterator decremented ahead of its valid range}}
|
||||||
|
// expected-note@-1{{Iterator decremented ahead of its valid range}}
|
||||||
}
|
}
|
||||||
|
|
||||||
void decr_by_2_copy_behind_begin(const std::vector<int> &V) {
|
void decr_by_2_copy_behind_begin(const std::vector<int> &V) {
|
||||||
auto i = ++V.begin();
|
auto i = ++V.begin();
|
||||||
auto j = i - 2; // expected-warning{{Iterator decremented ahead of its valid range}}
|
auto j = i - 2; // expected-warning{{Iterator decremented ahead of its valid range}}
|
||||||
|
// expected-note@-1{{Iterator decremented ahead of its valid range}}
|
||||||
}
|
}
|
||||||
|
|
||||||
void decr_by_2_copy_behind_begin_by_2(const std::vector<int> &V) {
|
void decr_by_2_copy_behind_begin_by_2(const std::vector<int> &V) {
|
||||||
|
@ -303,6 +316,7 @@ void subscript_zero_ahead_of_end(const std::vector<int> &V) {
|
||||||
void subscript_zero_end(const std::vector<int> &V) {
|
void subscript_zero_end(const std::vector<int> &V) {
|
||||||
auto i = V.end();
|
auto i = V.end();
|
||||||
auto j = i[0]; // expected-warning{{Past-the-end iterator dereferenced}}
|
auto j = i[0]; // expected-warning{{Past-the-end iterator dereferenced}}
|
||||||
|
// expected-note@-1{{Past-the-end iterator dereferenced}}
|
||||||
}
|
}
|
||||||
|
|
||||||
// By negative number
|
// By negative number
|
||||||
|
@ -329,7 +343,8 @@ void subscript_negative_ahead_of_end(const std::vector<int> &V) {
|
||||||
|
|
||||||
void subscript_negative_end(const std::vector<int> &V) {
|
void subscript_negative_end(const std::vector<int> &V) {
|
||||||
auto i = V.end();
|
auto i = V.end();
|
||||||
auto j = i[-1]; // // expected-warning{{Past-the-end iterator dereferenced}} FIXME: expect no warning
|
auto j = i[-1]; // expected-warning{{Past-the-end iterator dereferenced}} FIXME: expect no warning
|
||||||
|
// expected-note@-1{{Past-the-end iterator dereferenced}}
|
||||||
}
|
}
|
||||||
|
|
||||||
// By positive number
|
// By positive number
|
||||||
|
@ -357,6 +372,7 @@ void subscript_positive_ahead_of_end(const std::vector<int> &V) {
|
||||||
void subscript_positive_end(const std::vector<int> &V) {
|
void subscript_positive_end(const std::vector<int> &V) {
|
||||||
auto i = V.end();
|
auto i = V.end();
|
||||||
auto j = i[1]; // expected-warning{{Past-the-end iterator dereferenced}} FIXME: expect warning Iterator incremented behind the past-the-end iterator
|
auto j = i[1]; // expected-warning{{Past-the-end iterator dereferenced}} FIXME: expect warning Iterator incremented behind the past-the-end iterator
|
||||||
|
// expected-note@-1{{Past-the-end iterator dereferenced}} FIXME: expect note@-1 Iterator incremented behind the past-the-end iterator
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -388,6 +404,7 @@ void advance_plus_1_ahead_of_end(const std::vector<int> &V) {
|
||||||
void advance_plus_1_end(const std::vector<int> &V) {
|
void advance_plus_1_end(const std::vector<int> &V) {
|
||||||
auto i = V.end();
|
auto i = V.end();
|
||||||
std::advance(i, 1); // expected-warning{{Iterator incremented behind the past-the-end iterator}}
|
std::advance(i, 1); // expected-warning{{Iterator incremented behind the past-the-end iterator}}
|
||||||
|
// expected-note@-1{{Iterator incremented behind the past-the-end iterator}}
|
||||||
}
|
}
|
||||||
|
|
||||||
// std::advance() by -1
|
// std::advance() by -1
|
||||||
|
@ -395,6 +412,7 @@ void advance_plus_1_end(const std::vector<int> &V) {
|
||||||
void advance_minus_1_begin(const std::vector<int> &V) {
|
void advance_minus_1_begin(const std::vector<int> &V) {
|
||||||
auto i = V.begin();
|
auto i = V.begin();
|
||||||
std::advance(i, -1); // expected-warning{{Iterator decremented ahead of its valid range}}
|
std::advance(i, -1); // expected-warning{{Iterator decremented ahead of its valid range}}
|
||||||
|
// expected-note@-1{{Iterator decremented ahead of its valid range}}
|
||||||
}
|
}
|
||||||
|
|
||||||
void advance_minus_1_behind_begin(const std::vector<int> &V) {
|
void advance_minus_1_behind_begin(const std::vector<int> &V) {
|
||||||
|
@ -437,11 +455,13 @@ void advance_plus_2_unknown(const std::vector<int> &V) {
|
||||||
void advance_plus_2_ahead_of_end(const std::vector<int> &V) {
|
void advance_plus_2_ahead_of_end(const std::vector<int> &V) {
|
||||||
auto i = --V.end();
|
auto i = --V.end();
|
||||||
std::advance(i, 2); // expected-warning{{Iterator incremented behind the past-the-end iterator}}
|
std::advance(i, 2); // expected-warning{{Iterator incremented behind the past-the-end iterator}}
|
||||||
|
// expected-note@-1{{Iterator incremented behind the past-the-end iterator}}
|
||||||
}
|
}
|
||||||
|
|
||||||
void advance_plus_2_end(const std::vector<int> &V) {
|
void advance_plus_2_end(const std::vector<int> &V) {
|
||||||
auto i = V.end();
|
auto i = V.end();
|
||||||
std::advance(i, 2); // expected-warning{{Iterator incremented behind the past-the-end iterator}}
|
std::advance(i, 2); // expected-warning{{Iterator incremented behind the past-the-end iterator}}
|
||||||
|
// expected-note@-1{{Iterator incremented behind the past-the-end iterator}}
|
||||||
}
|
}
|
||||||
|
|
||||||
// std::advance() by -2
|
// std::advance() by -2
|
||||||
|
@ -449,11 +469,13 @@ void advance_plus_2_end(const std::vector<int> &V) {
|
||||||
void advance_minus_2_begin(const std::vector<int> &V) {
|
void advance_minus_2_begin(const std::vector<int> &V) {
|
||||||
auto i = V.begin();
|
auto i = V.begin();
|
||||||
std::advance(i, -2); // expected-warning{{Iterator decremented ahead of its valid range}}
|
std::advance(i, -2); // expected-warning{{Iterator decremented ahead of its valid range}}
|
||||||
|
// expected-note@-1{{Iterator decremented ahead of its valid range}}
|
||||||
}
|
}
|
||||||
|
|
||||||
void advance_minus_2_behind_begin(const std::vector<int> &V) {
|
void advance_minus_2_behind_begin(const std::vector<int> &V) {
|
||||||
auto i = ++V.begin();
|
auto i = ++V.begin();
|
||||||
std::advance(i, -2); // expected-warning{{Iterator decremented ahead of its valid range}}
|
std::advance(i, -2); // expected-warning{{Iterator decremented ahead of its valid range}}
|
||||||
|
// expected-note@-1{{Iterator decremented ahead of its valid range}}
|
||||||
}
|
}
|
||||||
|
|
||||||
void advance_minus_2_unknown(const std::vector<int> &V) {
|
void advance_minus_2_unknown(const std::vector<int> &V) {
|
||||||
|
@ -527,6 +549,7 @@ void next_plus_1_ahead_of_end(const std::vector<int> &V) {
|
||||||
void next_plus_1_end(const std::vector<int> &V) {
|
void next_plus_1_end(const std::vector<int> &V) {
|
||||||
auto i = V.end();
|
auto i = V.end();
|
||||||
auto j = std::next(i); // expected-warning{{Iterator incremented behind the past-the-end iterator}}
|
auto j = std::next(i); // expected-warning{{Iterator incremented behind the past-the-end iterator}}
|
||||||
|
// expected-note@-1{{Iterator incremented behind the past-the-end iterator}}
|
||||||
}
|
}
|
||||||
|
|
||||||
// std::next() by -1
|
// std::next() by -1
|
||||||
|
@ -534,6 +557,7 @@ void next_plus_1_end(const std::vector<int> &V) {
|
||||||
void next_minus_1_begin(const std::vector<int> &V) {
|
void next_minus_1_begin(const std::vector<int> &V) {
|
||||||
auto i = V.begin();
|
auto i = V.begin();
|
||||||
auto j = std::next(i, -1); // expected-warning{{Iterator decremented ahead of its valid range}}
|
auto j = std::next(i, -1); // expected-warning{{Iterator decremented ahead of its valid range}}
|
||||||
|
// expected-note@-1{{Iterator decremented ahead of its valid range}}
|
||||||
}
|
}
|
||||||
|
|
||||||
void next_minus_1_behind_begin(const std::vector<int> &V) {
|
void next_minus_1_behind_begin(const std::vector<int> &V) {
|
||||||
|
@ -576,11 +600,13 @@ void next_plus_2_unknown(const std::vector<int> &V) {
|
||||||
void next_plus_2_ahead_of_end(const std::vector<int> &V) {
|
void next_plus_2_ahead_of_end(const std::vector<int> &V) {
|
||||||
auto i = --V.end();
|
auto i = --V.end();
|
||||||
auto j = std::next(i, 2); // expected-warning{{Iterator incremented behind the past-the-end iterator}}
|
auto j = std::next(i, 2); // expected-warning{{Iterator incremented behind the past-the-end iterator}}
|
||||||
|
// expected-note@-1{{Iterator incremented behind the past-the-end iterator}}
|
||||||
}
|
}
|
||||||
|
|
||||||
void next_plus_2_end(const std::vector<int> &V) {
|
void next_plus_2_end(const std::vector<int> &V) {
|
||||||
auto i = V.end();
|
auto i = V.end();
|
||||||
auto j = std::next(i, 2); // expected-warning{{Iterator incremented behind the past-the-end iterator}}
|
auto j = std::next(i, 2); // expected-warning{{Iterator incremented behind the past-the-end iterator}}
|
||||||
|
// expected-note@-1{{Iterator incremented behind the past-the-end iterator}}
|
||||||
}
|
}
|
||||||
|
|
||||||
// std::next() by -2
|
// std::next() by -2
|
||||||
|
@ -588,11 +614,13 @@ void next_plus_2_end(const std::vector<int> &V) {
|
||||||
void next_minus_2_begin(const std::vector<int> &V) {
|
void next_minus_2_begin(const std::vector<int> &V) {
|
||||||
auto i = V.begin();
|
auto i = V.begin();
|
||||||
auto j = std::next(i, -2); // expected-warning{{Iterator decremented ahead of its valid range}}
|
auto j = std::next(i, -2); // expected-warning{{Iterator decremented ahead of its valid range}}
|
||||||
|
// expected-note@-1{{Iterator decremented ahead of its valid range}}
|
||||||
}
|
}
|
||||||
|
|
||||||
void next_minus_2_behind_begin(const std::vector<int> &V) {
|
void next_minus_2_behind_begin(const std::vector<int> &V) {
|
||||||
auto i = ++V.begin();
|
auto i = ++V.begin();
|
||||||
auto j = std::next(i, -2); // expected-warning{{Iterator decremented ahead of its valid range}}
|
auto j = std::next(i, -2); // expected-warning{{Iterator decremented ahead of its valid range}}
|
||||||
|
// expected-note@-1{{Iterator decremented ahead of its valid range}}
|
||||||
}
|
}
|
||||||
|
|
||||||
void next_minus_2_unknown(const std::vector<int> &V) {
|
void next_minus_2_unknown(const std::vector<int> &V) {
|
||||||
|
@ -646,6 +674,7 @@ void next_0_end(const std::vector<int> &V) {
|
||||||
void prev_plus_1_begin(const std::vector<int> &V) {
|
void prev_plus_1_begin(const std::vector<int> &V) {
|
||||||
auto i = V.begin();
|
auto i = V.begin();
|
||||||
auto j = std::prev(i); // expected-warning{{Iterator decremented ahead of its valid range}}
|
auto j = std::prev(i); // expected-warning{{Iterator decremented ahead of its valid range}}
|
||||||
|
// expected-note@-1{{Iterator decremented ahead of its valid range}}
|
||||||
}
|
}
|
||||||
|
|
||||||
void prev_plus_1_behind_begin(const std::vector<int> &V) {
|
void prev_plus_1_behind_begin(const std::vector<int> &V) {
|
||||||
|
@ -693,6 +722,7 @@ void prev_minus_1_ahead_of_end(const std::vector<int> &V) {
|
||||||
void prev_minus_1_end(const std::vector<int> &V) {
|
void prev_minus_1_end(const std::vector<int> &V) {
|
||||||
auto i = V.end();
|
auto i = V.end();
|
||||||
auto j = std::prev(i, -1); // expected-warning{{Iterator incremented behind the past-the-end iterator}}
|
auto j = std::prev(i, -1); // expected-warning{{Iterator incremented behind the past-the-end iterator}}
|
||||||
|
// expected-note@-1{{Iterator incremented behind the past-the-end iterator}}
|
||||||
}
|
}
|
||||||
|
|
||||||
// std::prev() by +2
|
// std::prev() by +2
|
||||||
|
@ -700,11 +730,13 @@ void prev_minus_1_end(const std::vector<int> &V) {
|
||||||
void prev_plus_2_begin(const std::vector<int> &V) {
|
void prev_plus_2_begin(const std::vector<int> &V) {
|
||||||
auto i = V.begin();
|
auto i = V.begin();
|
||||||
auto j = std::prev(i, 2); // expected-warning{{Iterator decremented ahead of its valid range}}
|
auto j = std::prev(i, 2); // expected-warning{{Iterator decremented ahead of its valid range}}
|
||||||
|
// expected-note@-1{{Iterator decremented ahead of its valid range}}
|
||||||
}
|
}
|
||||||
|
|
||||||
void prev_plus_2_behind_begin(const std::vector<int> &V) {
|
void prev_plus_2_behind_begin(const std::vector<int> &V) {
|
||||||
auto i = ++V.begin();
|
auto i = ++V.begin();
|
||||||
auto j = std::prev(i, 2); // expected-warning{{Iterator decremented ahead of its valid range}}
|
auto j = std::prev(i, 2); // expected-warning{{Iterator decremented ahead of its valid range}}
|
||||||
|
// expected-note@-1{{Iterator decremented ahead of its valid range}}
|
||||||
}
|
}
|
||||||
|
|
||||||
void prev_plus_2_unknown(const std::vector<int> &V) {
|
void prev_plus_2_unknown(const std::vector<int> &V) {
|
||||||
|
@ -742,11 +774,13 @@ void prev_minus_2_unknown(const std::vector<int> &V) {
|
||||||
void prev_minus_2_ahead_of_end(const std::vector<int> &V) {
|
void prev_minus_2_ahead_of_end(const std::vector<int> &V) {
|
||||||
auto i = --V.end();
|
auto i = --V.end();
|
||||||
auto j = std::prev(i, -2); // expected-warning{{Iterator incremented behind the past-the-end iterator}}
|
auto j = std::prev(i, -2); // expected-warning{{Iterator incremented behind the past-the-end iterator}}
|
||||||
|
// expected-note@-1{{Iterator incremented behind the past-the-end iterator}}
|
||||||
}
|
}
|
||||||
|
|
||||||
void prev_minus_2_end(const std::vector<int> &V) {
|
void prev_minus_2_end(const std::vector<int> &V) {
|
||||||
auto i = V.end();
|
auto i = V.end();
|
||||||
auto j = std::prev(i, -2); // expected-warning{{Iterator incremented behind the past-the-end iterator}}
|
auto j = std::prev(i, -2); // expected-warning{{Iterator incremented behind the past-the-end iterator}}
|
||||||
|
// expected-note@-1{{Iterator incremented behind the past-the-end iterator}}
|
||||||
}
|
}
|
||||||
|
|
||||||
// std::prev() by 0
|
// std::prev() by 0
|
||||||
|
@ -793,5 +827,17 @@ void arrow_deref_begin(const std::vector<S> &V) {
|
||||||
|
|
||||||
void arrow_deref_end(const std::vector<S> &V) {
|
void arrow_deref_end(const std::vector<S> &V) {
|
||||||
auto i = V.end();
|
auto i = V.end();
|
||||||
int n = i->n; // expected-warning{{Past-the-end iterator dereferenced}}
|
int n = i->n; // expected-warning{{Past-the-end iterator dereferenced}}
|
||||||
|
// expected-note@-1{{Past-the-end iterator dereferenced}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Container modification - test path notes
|
||||||
|
|
||||||
|
void deref_end_after_pop_back(std::vector<int> &V) {
|
||||||
|
const auto i = --V.end();
|
||||||
|
|
||||||
|
V.pop_back(); // expected-note{{Container 'V' shrank from the back by 1 position}}
|
||||||
|
|
||||||
|
*i; // expected-warning{{Past-the-end iterator dereferenced}}
|
||||||
|
// expected-note@-1{{Past-the-end iterator dereferenced}}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue