Index: clang/include/clang/StaticAnalyzer/Checkers/Checkers.td =================================================================== --- clang/include/clang/StaticAnalyzer/Checkers/Checkers.td +++ clang/include/clang/StaticAnalyzer/Checkers/Checkers.td @@ -602,6 +602,11 @@ let ParentPackage = CplusplusAlpha in { +def ContainerModeling : Checker<"ContainerModeling">, + HelpText<"Models C++ containers">, + Documentation, + Hidden; + def DeleteWithNonVirtualDtorChecker : Checker<"DeleteWithNonVirtualDtor">, HelpText<"Reports destructions of polymorphic objects with a non-virtual " "destructor in their base class">, @@ -613,6 +618,7 @@ def IteratorModeling : Checker<"IteratorModeling">, HelpText<"Models iterators of C++ containers">, + Dependencies<[ContainerModeling]>, Documentation, Hidden; @@ -1373,9 +1379,14 @@ HelpText<"Emits a warning for every statement.">, Documentation; +def DebugContainerModeling : Checker<"DebugContainerModeling">, + HelpText<"Check the analyzer's understanding of C++ containers">, + Dependencies<[ContainerModeling]>, + Documentation; + def DebugIteratorModeling : Checker<"DebugIteratorModeling">, HelpText<"Check the analyzer's understanding of C++ iterators">, - Dependencies<[IteratorModeling]>, + Dependencies<[DebugContainerModeling, IteratorModeling]>, Documentation; } // end "debug" Index: clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt =================================================================== --- clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt +++ clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt @@ -25,10 +25,12 @@ CheckerDocumentation.cpp ChrootChecker.cpp CloneChecker.cpp + ContainerModeling.cpp ConversionChecker.cpp CXXSelfAssignmentChecker.cpp DeadStoresChecker.cpp DebugCheckers.cpp + DebugContainerModeling.cpp DebugIteratorModeling.cpp DeleteWithNonVirtualDtorChecker.cpp DereferenceChecker.cpp Index: clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp =================================================================== --- /dev/null +++ clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp @@ -0,0 +1,1040 @@ +//===-- ContainerModeling.cpp -------------------------------------*- C++ -*--// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Defines a modeling-checker for modeling STL container-like containers. +// +//===----------------------------------------------------------------------===// + +#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h" + +#include "Iterator.h" + +#include + +using namespace clang; +using namespace ento; +using namespace iterator; + +namespace { + +class ContainerModeling + : public Checker { + + void handleBegin(CheckerContext &C, const Expr *CE, const SVal &RetVal, + const SVal &Cont) const; + void handleEnd(CheckerContext &C, const Expr *CE, const SVal &RetVal, + const SVal &Cont) const; + void handleAssignment(CheckerContext &C, const SVal &Cont, + const Expr *CE = nullptr, + const SVal &OldCont = UndefinedVal()) const; + void handleAssign(CheckerContext &C, const SVal &Cont) const; + void handleClear(CheckerContext &C, const SVal &Cont) const; + void handlePushBack(CheckerContext &C, const SVal &Cont) const; + void handlePopBack(CheckerContext &C, const SVal &Cont) const; + void handlePushFront(CheckerContext &C, const SVal &Cont) const; + void handlePopFront(CheckerContext &C, const SVal &Cont) const; + void handleInsert(CheckerContext &C, const SVal &Cont, + const SVal &Iter) const; + void handleErase(CheckerContext &C, const SVal &Cont, const SVal &Iter) const; + void handleErase(CheckerContext &C, const SVal &Cont, const SVal &Iter1, + const SVal &Iter2) const; + void handleEraseAfter(CheckerContext &C, const SVal &Cont, + const SVal &Iter) const; + void handleEraseAfter(CheckerContext &C, const SVal &Cont, const SVal &Iter1, + const SVal &Iter2) const; + void printState(raw_ostream &Out, ProgramStateRef State, const char *NL, + const char *Sep) const override; + +public: + ContainerModeling() {} + + void checkPostCall(const CallEvent &Call, CheckerContext &C) const; + void checkLiveSymbols(ProgramStateRef State, SymbolReaper &SR) const; + void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const; + + typedef void (ContainerModeling::*NoItParamFn)(CheckerContext &, + const SVal &) const; + typedef void (ContainerModeling::*OneItParamFn)(CheckerContext &, + const SVal &, + const SVal &) const; + typedef void (ContainerModeling::*TwoItParamFn)(CheckerContext &, + const SVal &, + const SVal &, + const SVal &) const; + + CallDescriptionMap NoIterParamFunctions = { + {{0, "clear", 0}, + &ContainerModeling::handleClear}, + {{0, "assign", 2}, + &ContainerModeling::handleAssign}, + {{0, "push_back", 1}, + &ContainerModeling::handlePushBack}, + {{0, "emplace_back", 1}, + &ContainerModeling::handlePushBack}, + {{0, "pop_back", 0}, + &ContainerModeling::handlePopBack}, + {{0, "push_front", 1}, + &ContainerModeling::handlePushFront}, + {{0, "emplace_front", 1}, + &ContainerModeling::handlePushFront}, + {{0, "pop_front", 0}, + &ContainerModeling::handlePopFront}, + }; + + CallDescriptionMap OneIterParamFunctions = { + {{0, "insert", 2}, + &ContainerModeling::handleInsert}, + {{0, "emplace", 2}, + &ContainerModeling::handleInsert}, + {{0, "erase", 1}, + &ContainerModeling::handleErase}, + {{0, "erase_after", 1}, + &ContainerModeling::handleEraseAfter}, + }; + + CallDescriptionMap TwoIterParamFunctions = { + {{0, "erase", 2}, + &ContainerModeling::handleErase}, + {{0, "erase_after", 2}, + &ContainerModeling::handleEraseAfter}, + }; + +}; + +bool isBeginCall(const FunctionDecl *Func); +bool isEndCall(const FunctionDecl *Func); +bool hasSubscriptOperator(ProgramStateRef State, const MemRegion *Reg); +bool frontModifiable(ProgramStateRef State, const MemRegion *Reg); +bool backModifiable(ProgramStateRef State, const MemRegion *Reg); +SymbolRef getContainerBegin(ProgramStateRef State, const MemRegion *Cont); +SymbolRef getContainerEnd(ProgramStateRef State, const MemRegion *Cont); +ProgramStateRef createContainerBegin(ProgramStateRef State, + const MemRegion *Cont, const Expr *E, + QualType T, const LocationContext *LCtx, + unsigned BlockCount); +ProgramStateRef createContainerEnd(ProgramStateRef State, const MemRegion *Cont, + const Expr *E, QualType T, + const LocationContext *LCtx, + unsigned BlockCount); +ProgramStateRef setContainerData(ProgramStateRef State, const MemRegion *Cont, + const ContainerData &CData); +ProgramStateRef invalidateAllIteratorPositions(ProgramStateRef State, + const MemRegion *Cont); +ProgramStateRef +invalidateAllIteratorPositionsExcept(ProgramStateRef State, + const MemRegion *Cont, SymbolRef Offset, + BinaryOperator::Opcode Opc); +ProgramStateRef invalidateIteratorPositions(ProgramStateRef State, + SymbolRef Offset, + BinaryOperator::Opcode Opc); +ProgramStateRef invalidateIteratorPositions(ProgramStateRef State, + SymbolRef Offset1, + BinaryOperator::Opcode Opc1, + SymbolRef Offset2, + BinaryOperator::Opcode Opc2); +ProgramStateRef reassignAllIteratorPositions(ProgramStateRef State, + const MemRegion *Cont, + const MemRegion *NewCont); +ProgramStateRef reassignAllIteratorPositionsUnless(ProgramStateRef State, + const MemRegion *Cont, + const MemRegion *NewCont, + SymbolRef Offset, + BinaryOperator::Opcode Opc); +ProgramStateRef rebaseSymbolInIteratorPositionsIf( + ProgramStateRef State, SValBuilder &SVB, SymbolRef OldSym, + SymbolRef NewSym, SymbolRef CondSym, BinaryOperator::Opcode Opc); +SymbolRef rebaseSymbol(ProgramStateRef State, SValBuilder &SVB, SymbolRef Expr, + SymbolRef OldSym, SymbolRef NewSym); +bool hasLiveIterators(ProgramStateRef State, const MemRegion *Cont); + +} // namespace + +void ContainerModeling::checkPostCall(const CallEvent &Call, + CheckerContext &C) const { + const auto *Func = dyn_cast_or_null(Call.getDecl()); + if (!Func) + return; + + if (Func->isOverloadedOperator()) { + const auto Op = Func->getOverloadedOperator(); + if (Op == OO_Equal) { + // Overloaded 'operator=' must be a non-static member function. + const auto *InstCall = cast(&Call); + if (cast(Func)->isMoveAssignmentOperator()) { + handleAssignment(C, InstCall->getCXXThisVal(), Call.getOriginExpr(), + Call.getArgSVal(0)); + return; + } + + handleAssignment(C, InstCall->getCXXThisVal()); + return; + } + } else { + if (const auto *InstCall = dyn_cast(&Call)) { + const NoItParamFn *Handler0 = NoIterParamFunctions.lookup(Call); + if (Handler0) { + (this->**Handler0)(C, InstCall->getCXXThisVal()); + return; + } + + const OneItParamFn *Handler1 = OneIterParamFunctions.lookup(Call); + if (Handler1) { + (this->**Handler1)(C, InstCall->getCXXThisVal(), Call.getArgSVal(0)); + return; + } + + const TwoItParamFn *Handler2 = TwoIterParamFunctions.lookup(Call); + if (Handler2) { + (this->**Handler2)(C, InstCall->getCXXThisVal(), Call.getArgSVal(0), + Call.getArgSVal(1)); + return; + } + + const auto *OrigExpr = Call.getOriginExpr(); + if (!OrigExpr) + return; + + if (isBeginCall(Func)) { + handleBegin(C, OrigExpr, Call.getReturnValue(), + InstCall->getCXXThisVal()); + return; + } + + if (isEndCall(Func)) { + handleEnd(C, OrigExpr, Call.getReturnValue(), + InstCall->getCXXThisVal()); + return; + } + } + } +} + +void ContainerModeling::checkLiveSymbols(ProgramStateRef State, + SymbolReaper &SR) const { + // Keep symbolic expressions of container begins and ends alive + auto ContMap = State->get(); + for (const auto &Cont : ContMap) { + const auto CData = Cont.second; + if (CData.getBegin()) { + SR.markLive(CData.getBegin()); + if(const auto *SIE = dyn_cast(CData.getBegin())) + SR.markLive(SIE->getLHS()); + } + if (CData.getEnd()) { + SR.markLive(CData.getEnd()); + if(const auto *SIE = dyn_cast(CData.getEnd())) + SR.markLive(SIE->getLHS()); + } + } +} + +void ContainerModeling::checkDeadSymbols(SymbolReaper &SR, + CheckerContext &C) const { + // Cleanup + auto State = C.getState(); + + auto ContMap = State->get(); + for (const auto &Cont : ContMap) { + if (!SR.isLiveRegion(Cont.first)) { + // We must keep the container data while it has live iterators to be able + // to compare them to the begin and the end of the container. + if (!hasLiveIterators(State, Cont.first)) { + State = State->remove(Cont.first); + } + } + } + + C.addTransition(State); +} + +void ContainerModeling::handleBegin(CheckerContext &C, const Expr *CE, + const SVal &RetVal, const SVal &Cont) const { + const auto *ContReg = Cont.getAsRegion(); + if (!ContReg) + return; + + ContReg = ContReg->getMostDerivedObjectRegion(); + + // If the container already has a begin symbol then use it. Otherwise first + // create a new one. + auto State = C.getState(); + auto BeginSym = getContainerBegin(State, ContReg); + if (!BeginSym) { + State = createContainerBegin(State, ContReg, CE, C.getASTContext().LongTy, + C.getLocationContext(), C.blockCount()); + BeginSym = getContainerBegin(State, ContReg); + } + State = setIteratorPosition(State, RetVal, + IteratorPosition::getPosition(ContReg, BeginSym)); + C.addTransition(State); +} + +void ContainerModeling::handleEnd(CheckerContext &C, const Expr *CE, + const SVal &RetVal, const SVal &Cont) const { + const auto *ContReg = Cont.getAsRegion(); + if (!ContReg) + return; + + ContReg = ContReg->getMostDerivedObjectRegion(); + + // If the container already has an end symbol then use it. Otherwise first + // create a new one. + auto State = C.getState(); + auto EndSym = getContainerEnd(State, ContReg); + if (!EndSym) { + State = createContainerEnd(State, ContReg, CE, C.getASTContext().LongTy, + C.getLocationContext(), C.blockCount()); + EndSym = getContainerEnd(State, ContReg); + } + State = setIteratorPosition(State, RetVal, + IteratorPosition::getPosition(ContReg, EndSym)); + C.addTransition(State); +} + +void ContainerModeling::handleAssignment(CheckerContext &C, const SVal &Cont, + const Expr *CE, + const SVal &OldCont) const { + const auto *ContReg = Cont.getAsRegion(); + if (!ContReg) + return; + + ContReg = ContReg->getMostDerivedObjectRegion(); + + // Assignment of a new value to a container always invalidates all its + // iterators + auto State = C.getState(); + const auto CData = getContainerData(State, ContReg); + if (CData) { + State = invalidateAllIteratorPositions(State, ContReg); + } + + // In case of move, iterators of the old container (except the past-end + // iterators) remain valid but refer to the new container + if (!OldCont.isUndef()) { + const auto *OldContReg = OldCont.getAsRegion(); + if (OldContReg) { + OldContReg = OldContReg->getMostDerivedObjectRegion(); + const auto OldCData = getContainerData(State, OldContReg); + if (OldCData) { + if (const auto OldEndSym = OldCData->getEnd()) { + // If we already assigned an "end" symbol to the old container, then + // first reassign all iterator positions to the new container which + // are not past the container (thus not greater or equal to the + // current "end" symbol). + State = reassignAllIteratorPositionsUnless(State, OldContReg, ContReg, + OldEndSym, BO_GE); + auto &SymMgr = C.getSymbolManager(); + auto &SVB = C.getSValBuilder(); + // Then generate and assign a new "end" symbol for the new container. + auto NewEndSym = + SymMgr.conjureSymbol(CE, C.getLocationContext(), + C.getASTContext().LongTy, C.blockCount()); + State = assumeNoOverflow(State, NewEndSym, 4); + if (CData) { + State = setContainerData(State, ContReg, CData->newEnd(NewEndSym)); + } else { + State = setContainerData(State, ContReg, + ContainerData::fromEnd(NewEndSym)); + } + // Finally, replace the old "end" symbol in the already reassigned + // iterator positions with the new "end" symbol. + State = rebaseSymbolInIteratorPositionsIf( + State, SVB, OldEndSym, NewEndSym, OldEndSym, BO_LT); + } else { + // There was no "end" symbol assigned yet to the old container, + // so reassign all iterator positions to the new container. + State = reassignAllIteratorPositions(State, OldContReg, ContReg); + } + if (const auto OldBeginSym = OldCData->getBegin()) { + // If we already assigned a "begin" symbol to the old container, then + // assign it to the new container and remove it from the old one. + if (CData) { + State = + setContainerData(State, ContReg, CData->newBegin(OldBeginSym)); + } else { + State = setContainerData(State, ContReg, + ContainerData::fromBegin(OldBeginSym)); + } + State = + setContainerData(State, OldContReg, OldCData->newBegin(nullptr)); + } + } else { + // There was neither "begin" nor "end" symbol assigned yet to the old + // container, so reassign all iterator positions to the new container. + State = reassignAllIteratorPositions(State, OldContReg, ContReg); + } + } + } + C.addTransition(State); +} + +void ContainerModeling::handleAssign(CheckerContext &C, + const SVal &Cont) const { + const auto *ContReg = Cont.getAsRegion(); + if (!ContReg) + return; + + ContReg = ContReg->getMostDerivedObjectRegion(); + + // The assign() operation invalidates all the iterators + auto State = C.getState(); + State = invalidateAllIteratorPositions(State, ContReg); + C.addTransition(State); +} + +void ContainerModeling::handleClear(CheckerContext &C, const SVal &Cont) const { + const auto *ContReg = Cont.getAsRegion(); + if (!ContReg) + return; + + ContReg = ContReg->getMostDerivedObjectRegion(); + + // The clear() operation invalidates all the iterators, except the past-end + // iterators of list-like containers + auto State = C.getState(); + if (!hasSubscriptOperator(State, ContReg) || + !backModifiable(State, ContReg)) { + const auto CData = getContainerData(State, ContReg); + if (CData) { + if (const auto EndSym = CData->getEnd()) { + State = + invalidateAllIteratorPositionsExcept(State, ContReg, EndSym, BO_GE); + C.addTransition(State); + return; + } + } + } + State = invalidateAllIteratorPositions(State, ContReg); + C.addTransition(State); +} + +void ContainerModeling::handlePushBack(CheckerContext &C, + const SVal &Cont) const { + const auto *ContReg = Cont.getAsRegion(); + if (!ContReg) + return; + + ContReg = ContReg->getMostDerivedObjectRegion(); + + // For deque-like containers invalidate all iterator positions + auto State = C.getState(); + if (hasSubscriptOperator(State, ContReg) && frontModifiable(State, ContReg)) { + State = invalidateAllIteratorPositions(State, ContReg); + C.addTransition(State); + return; + } + + const auto CData = getContainerData(State, ContReg); + if (!CData) + return; + + // For vector-like containers invalidate the past-end iterator positions + if (const auto EndSym = CData->getEnd()) { + if (hasSubscriptOperator(State, ContReg)) { + State = invalidateIteratorPositions(State, EndSym, BO_GE); + } + auto &SymMgr = C.getSymbolManager(); + auto &BVF = SymMgr.getBasicVals(); + auto &SVB = C.getSValBuilder(); + const auto newEndSym = + SVB.evalBinOp(State, BO_Add, + nonloc::SymbolVal(EndSym), + nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))), + SymMgr.getType(EndSym)).getAsSymbol(); + State = setContainerData(State, ContReg, CData->newEnd(newEndSym)); + } + C.addTransition(State); +} + +void ContainerModeling::handlePopBack(CheckerContext &C, + const SVal &Cont) const { + const auto *ContReg = Cont.getAsRegion(); + if (!ContReg) + return; + + ContReg = ContReg->getMostDerivedObjectRegion(); + + auto State = C.getState(); + const auto CData = getContainerData(State, ContReg); + if (!CData) + return; + + if (const auto EndSym = CData->getEnd()) { + auto &SymMgr = C.getSymbolManager(); + auto &BVF = SymMgr.getBasicVals(); + auto &SVB = C.getSValBuilder(); + const auto BackSym = + SVB.evalBinOp(State, BO_Sub, + nonloc::SymbolVal(EndSym), + nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))), + SymMgr.getType(EndSym)).getAsSymbol(); + // For vector-like and deque-like containers invalidate the last and the + // past-end iterator positions. For list-like containers only invalidate + // the last position + if (hasSubscriptOperator(State, ContReg) && + backModifiable(State, ContReg)) { + State = invalidateIteratorPositions(State, BackSym, BO_GE); + State = setContainerData(State, ContReg, CData->newEnd(nullptr)); + } else { + State = invalidateIteratorPositions(State, BackSym, BO_EQ); + } + auto newEndSym = BackSym; + State = setContainerData(State, ContReg, CData->newEnd(newEndSym)); + C.addTransition(State); + } +} + +void ContainerModeling::handlePushFront(CheckerContext &C, + const SVal &Cont) const { + const auto *ContReg = Cont.getAsRegion(); + if (!ContReg) + return; + + ContReg = ContReg->getMostDerivedObjectRegion(); + + // For deque-like containers invalidate all iterator positions + auto State = C.getState(); + if (hasSubscriptOperator(State, ContReg)) { + State = invalidateAllIteratorPositions(State, ContReg); + C.addTransition(State); + } else { + const auto CData = getContainerData(State, ContReg); + if (!CData) + return; + + if (const auto BeginSym = CData->getBegin()) { + auto &SymMgr = C.getSymbolManager(); + auto &BVF = SymMgr.getBasicVals(); + auto &SVB = C.getSValBuilder(); + const auto newBeginSym = + SVB.evalBinOp(State, BO_Sub, + nonloc::SymbolVal(BeginSym), + nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))), + SymMgr.getType(BeginSym)).getAsSymbol(); + State = setContainerData(State, ContReg, CData->newBegin(newBeginSym)); + C.addTransition(State); + } + } +} + +void ContainerModeling::handlePopFront(CheckerContext &C, + const SVal &Cont) const { + const auto *ContReg = Cont.getAsRegion(); + if (!ContReg) + return; + + ContReg = ContReg->getMostDerivedObjectRegion(); + + auto State = C.getState(); + const auto CData = getContainerData(State, ContReg); + if (!CData) + return; + + // For deque-like containers invalidate all iterator positions. For list-like + // iterators only invalidate the first position + if (const auto BeginSym = CData->getBegin()) { + if (hasSubscriptOperator(State, ContReg)) { + State = invalidateIteratorPositions(State, BeginSym, BO_LE); + } else { + State = invalidateIteratorPositions(State, BeginSym, BO_EQ); + } + auto &SymMgr = C.getSymbolManager(); + auto &BVF = SymMgr.getBasicVals(); + auto &SVB = C.getSValBuilder(); + const auto newBeginSym = + SVB.evalBinOp(State, BO_Add, + nonloc::SymbolVal(BeginSym), + nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))), + SymMgr.getType(BeginSym)).getAsSymbol(); + State = setContainerData(State, ContReg, CData->newBegin(newBeginSym)); + C.addTransition(State); + } +} + +void ContainerModeling::handleInsert(CheckerContext &C, const SVal &Cont, + const SVal &Iter) const { + const auto *ContReg = Cont.getAsRegion(); + if (!ContReg) + return; + + ContReg = ContReg->getMostDerivedObjectRegion(); + + auto State = C.getState(); + const auto *Pos = getIteratorPosition(State, Iter); + if (!Pos) + return; + + // For deque-like containers invalidate all iterator positions. For + // vector-like containers invalidate iterator positions after the insertion. + if (hasSubscriptOperator(State, ContReg) && backModifiable(State, ContReg)) { + if (frontModifiable(State, ContReg)) { + State = invalidateAllIteratorPositions(State, ContReg); + } else { + State = invalidateIteratorPositions(State, Pos->getOffset(), BO_GE); + } + if (const auto *CData = getContainerData(State, ContReg)) { + if (const auto EndSym = CData->getEnd()) { + State = invalidateIteratorPositions(State, EndSym, BO_GE); + State = setContainerData(State, ContReg, CData->newEnd(nullptr)); + } + } + C.addTransition(State); + } +} + +void ContainerModeling::handleErase(CheckerContext &C, const SVal &Cont, + const SVal &Iter) const { + const auto *ContReg = Cont.getAsRegion(); + if (!ContReg) + return; + + ContReg = ContReg->getMostDerivedObjectRegion(); + + auto State = C.getState(); + const auto *Pos = getIteratorPosition(State, Iter); + if (!Pos) + return; + + // For deque-like containers invalidate all iterator positions. For + // vector-like containers invalidate iterator positions at and after the + // deletion. For list-like containers only invalidate the deleted position. + if (hasSubscriptOperator(State, ContReg) && backModifiable(State, ContReg)) { + if (frontModifiable(State, ContReg)) { + State = invalidateAllIteratorPositions(State, ContReg); + } else { + State = invalidateIteratorPositions(State, Pos->getOffset(), BO_GE); + } + if (const auto *CData = getContainerData(State, ContReg)) { + if (const auto EndSym = CData->getEnd()) { + State = invalidateIteratorPositions(State, EndSym, BO_GE); + State = setContainerData(State, ContReg, CData->newEnd(nullptr)); + } + } + } else { + State = invalidateIteratorPositions(State, Pos->getOffset(), BO_EQ); + } + C.addTransition(State); +} + +void ContainerModeling::handleErase(CheckerContext &C, const SVal &Cont, + const SVal &Iter1, + const SVal &Iter2) const { + const auto *ContReg = Cont.getAsRegion(); + if (!ContReg) + return; + + ContReg = ContReg->getMostDerivedObjectRegion(); + auto State = C.getState(); + const auto *Pos1 = getIteratorPosition(State, Iter1); + const auto *Pos2 = getIteratorPosition(State, Iter2); + if (!Pos1 || !Pos2) + return; + + // For deque-like containers invalidate all iterator positions. For + // vector-like containers invalidate iterator positions at and after the + // deletion range. For list-like containers only invalidate the deleted + // position range [first..last]. + if (hasSubscriptOperator(State, ContReg) && backModifiable(State, ContReg)) { + if (frontModifiable(State, ContReg)) { + State = invalidateAllIteratorPositions(State, ContReg); + } else { + State = invalidateIteratorPositions(State, Pos1->getOffset(), BO_GE); + } + if (const auto *CData = getContainerData(State, ContReg)) { + if (const auto EndSym = CData->getEnd()) { + State = invalidateIteratorPositions(State, EndSym, BO_GE); + State = setContainerData(State, ContReg, CData->newEnd(nullptr)); + } + } + } else { + State = invalidateIteratorPositions(State, Pos1->getOffset(), BO_GE, + Pos2->getOffset(), BO_LT); + } + C.addTransition(State); +} + +void ContainerModeling::handleEraseAfter(CheckerContext &C, const SVal &Cont, + const SVal &Iter) const { + auto State = C.getState(); + const auto *Pos = getIteratorPosition(State, Iter); + if (!Pos) + return; + + // Invalidate the deleted iterator position, which is the position of the + // parameter plus one. + auto &SymMgr = C.getSymbolManager(); + auto &BVF = SymMgr.getBasicVals(); + auto &SVB = C.getSValBuilder(); + const auto NextSym = + SVB.evalBinOp(State, BO_Add, + nonloc::SymbolVal(Pos->getOffset()), + nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))), + SymMgr.getType(Pos->getOffset())).getAsSymbol(); + State = invalidateIteratorPositions(State, NextSym, BO_EQ); + C.addTransition(State); +} + +void ContainerModeling::handleEraseAfter(CheckerContext &C, const SVal &Cont, + const SVal &Iter1, + const SVal &Iter2) const { + auto State = C.getState(); + const auto *Pos1 = getIteratorPosition(State, Iter1); + const auto *Pos2 = getIteratorPosition(State, Iter2); + if (!Pos1 || !Pos2) + return; + + // Invalidate the deleted iterator position range (first..last) + State = invalidateIteratorPositions(State, Pos1->getOffset(), BO_GT, + Pos2->getOffset(), BO_LT); + C.addTransition(State); +} + +void ContainerModeling::printState(raw_ostream &Out, ProgramStateRef State, + const char *NL, const char *Sep) const { + auto ContMap = State->get(); + + if (!ContMap.isEmpty()) { + Out << Sep << "Container Data :" << NL; + for (const auto &Cont : ContMap) { + Cont.first->dumpToStream(Out); + Out << " : [ "; + const auto CData = Cont.second; + if (CData.getBegin()) + CData.getBegin()->dumpToStream(Out); + else + Out << ""; + Out << " .. "; + if (CData.getEnd()) + CData.getEnd()->dumpToStream(Out); + else + Out << ""; + Out << " ]"; + } + } +} + +namespace { + +bool isBeginCall(const FunctionDecl *Func) { + const auto *IdInfo = Func->getIdentifier(); + if (!IdInfo) + return false; + return IdInfo->getName().endswith_lower("begin"); +} + +bool isEndCall(const FunctionDecl *Func) { + const auto *IdInfo = Func->getIdentifier(); + if (!IdInfo) + return false; + return IdInfo->getName().endswith_lower("end"); +} + +const CXXRecordDecl *getCXXRecordDecl(ProgramStateRef State, + const MemRegion *Reg) { + auto TI = getDynamicTypeInfo(State, Reg); + if (!TI.isValid()) + return nullptr; + + auto Type = TI.getType(); + if (const auto *RefT = Type->getAs()) { + Type = RefT->getPointeeType(); + } + + return Type->getUnqualifiedDesugaredType()->getAsCXXRecordDecl(); +} + +bool hasSubscriptOperator(ProgramStateRef State, const MemRegion *Reg) { + const auto *CRD = getCXXRecordDecl(State, Reg); + if (!CRD) + return false; + + for (const auto *Method : CRD->methods()) { + if (!Method->isOverloadedOperator()) + continue; + const auto OPK = Method->getOverloadedOperator(); + if (OPK == OO_Subscript) { + return true; + } + } + return false; +} + +bool frontModifiable(ProgramStateRef State, const MemRegion *Reg) { + const auto *CRD = getCXXRecordDecl(State, Reg); + if (!CRD) + return false; + + for (const auto *Method : CRD->methods()) { + if (!Method->getDeclName().isIdentifier()) + continue; + if (Method->getName() == "push_front" || Method->getName() == "pop_front") { + return true; + } + } + return false; +} + +bool backModifiable(ProgramStateRef State, const MemRegion *Reg) { + const auto *CRD = getCXXRecordDecl(State, Reg); + if (!CRD) + return false; + + for (const auto *Method : CRD->methods()) { + if (!Method->getDeclName().isIdentifier()) + continue; + if (Method->getName() == "push_back" || Method->getName() == "pop_back") { + return true; + } + } + return false; +} + +SymbolRef getContainerBegin(ProgramStateRef State, const MemRegion *Cont) { + const auto *CDataPtr = getContainerData(State, Cont); + if (!CDataPtr) + return nullptr; + + return CDataPtr->getBegin(); +} + +SymbolRef getContainerEnd(ProgramStateRef State, const MemRegion *Cont) { + const auto *CDataPtr = getContainerData(State, Cont); + if (!CDataPtr) + return nullptr; + + return CDataPtr->getEnd(); +} + +ProgramStateRef createContainerBegin(ProgramStateRef State, + const MemRegion *Cont, const Expr *E, + QualType T, const LocationContext *LCtx, + unsigned BlockCount) { + // Only create if it does not exist + const auto *CDataPtr = getContainerData(State, Cont); + if (CDataPtr && CDataPtr->getBegin()) + return State; + + auto &SymMgr = State->getSymbolManager(); + const SymbolConjured *Sym = SymMgr.conjureSymbol(E, LCtx, T, BlockCount, + "begin"); + State = assumeNoOverflow(State, Sym, 4); + + if (CDataPtr) { + const auto CData = CDataPtr->newBegin(Sym); + return setContainerData(State, Cont, CData); + } + + const auto CData = ContainerData::fromBegin(Sym); + return setContainerData(State, Cont, CData); +} + +ProgramStateRef createContainerEnd(ProgramStateRef State, const MemRegion *Cont, + const Expr *E, QualType T, + const LocationContext *LCtx, + unsigned BlockCount) { + // Only create if it does not exist + const auto *CDataPtr = getContainerData(State, Cont); + if (CDataPtr && CDataPtr->getEnd()) + return State; + + auto &SymMgr = State->getSymbolManager(); + const SymbolConjured *Sym = SymMgr.conjureSymbol(E, LCtx, T, BlockCount, + "end"); + State = assumeNoOverflow(State, Sym, 4); + + if (CDataPtr) { + const auto CData = CDataPtr->newEnd(Sym); + return setContainerData(State, Cont, CData); + } + + const auto CData = ContainerData::fromEnd(Sym); + return setContainerData(State, Cont, CData); +} + +ProgramStateRef setContainerData(ProgramStateRef State, const MemRegion *Cont, + const ContainerData &CData) { + return State->set(Cont, CData); +} + +template +ProgramStateRef processIteratorPositions(ProgramStateRef State, Condition Cond, + Process Proc) { + auto &RegionMapFactory = State->get_context(); + auto RegionMap = State->get(); + bool Changed = false; + for (const auto &Reg : RegionMap) { + if (Cond(Reg.second)) { + RegionMap = RegionMapFactory.add(RegionMap, Reg.first, Proc(Reg.second)); + Changed = true; + } + } + + if (Changed) + State = State->set(RegionMap); + + auto &SymbolMapFactory = State->get_context(); + auto SymbolMap = State->get(); + Changed = false; + for (const auto &Sym : SymbolMap) { + if (Cond(Sym.second)) { + SymbolMap = SymbolMapFactory.add(SymbolMap, Sym.first, Proc(Sym.second)); + Changed = true; + } + } + + if (Changed) + State = State->set(SymbolMap); + + return State; +} + +ProgramStateRef invalidateAllIteratorPositions(ProgramStateRef State, + const MemRegion *Cont) { + auto MatchCont = [&](const IteratorPosition &Pos) { + return Pos.getContainer() == Cont; + }; + auto Invalidate = [&](const IteratorPosition &Pos) { + return Pos.invalidate(); + }; + return processIteratorPositions(State, MatchCont, Invalidate); +} + +ProgramStateRef +invalidateAllIteratorPositionsExcept(ProgramStateRef State, + const MemRegion *Cont, SymbolRef Offset, + BinaryOperator::Opcode Opc) { + auto MatchContAndCompare = [&](const IteratorPosition &Pos) { + return Pos.getContainer() == Cont && + !compare(State, Pos.getOffset(), Offset, Opc); + }; + auto Invalidate = [&](const IteratorPosition &Pos) { + return Pos.invalidate(); + }; + return processIteratorPositions(State, MatchContAndCompare, Invalidate); +} + +ProgramStateRef invalidateIteratorPositions(ProgramStateRef State, + SymbolRef Offset, + BinaryOperator::Opcode Opc) { + auto Compare = [&](const IteratorPosition &Pos) { + return compare(State, Pos.getOffset(), Offset, Opc); + }; + auto Invalidate = [&](const IteratorPosition &Pos) { + return Pos.invalidate(); + }; + return processIteratorPositions(State, Compare, Invalidate); +} + +ProgramStateRef invalidateIteratorPositions(ProgramStateRef State, + SymbolRef Offset1, + BinaryOperator::Opcode Opc1, + SymbolRef Offset2, + BinaryOperator::Opcode Opc2) { + auto Compare = [&](const IteratorPosition &Pos) { + return compare(State, Pos.getOffset(), Offset1, Opc1) && + compare(State, Pos.getOffset(), Offset2, Opc2); + }; + auto Invalidate = [&](const IteratorPosition &Pos) { + return Pos.invalidate(); + }; + return processIteratorPositions(State, Compare, Invalidate); +} + +ProgramStateRef reassignAllIteratorPositions(ProgramStateRef State, + const MemRegion *Cont, + const MemRegion *NewCont) { + auto MatchCont = [&](const IteratorPosition &Pos) { + return Pos.getContainer() == Cont; + }; + auto ReAssign = [&](const IteratorPosition &Pos) { + return Pos.reAssign(NewCont); + }; + return processIteratorPositions(State, MatchCont, ReAssign); +} + +ProgramStateRef reassignAllIteratorPositionsUnless(ProgramStateRef State, + const MemRegion *Cont, + const MemRegion *NewCont, + SymbolRef Offset, + BinaryOperator::Opcode Opc) { + auto MatchContAndCompare = [&](const IteratorPosition &Pos) { + return Pos.getContainer() == Cont && + !compare(State, Pos.getOffset(), Offset, Opc); + }; + auto ReAssign = [&](const IteratorPosition &Pos) { + return Pos.reAssign(NewCont); + }; + return processIteratorPositions(State, MatchContAndCompare, ReAssign); +} + +// This function rebases symbolic expression `OldSym + Int` to `NewSym + Int`, +// `OldSym - Int` to `NewSym - Int` and `OldSym` to `NewSym` in any iterator +// position offsets where `CondSym` is true. +ProgramStateRef rebaseSymbolInIteratorPositionsIf( + ProgramStateRef State, SValBuilder &SVB, SymbolRef OldSym, + SymbolRef NewSym, SymbolRef CondSym, BinaryOperator::Opcode Opc) { + auto LessThanEnd = [&](const IteratorPosition &Pos) { + return compare(State, Pos.getOffset(), CondSym, Opc); + }; + auto RebaseSymbol = [&](const IteratorPosition &Pos) { + return Pos.setTo(rebaseSymbol(State, SVB, Pos.getOffset(), OldSym, + NewSym)); + }; + return processIteratorPositions(State, LessThanEnd, RebaseSymbol); +} + +// This function rebases symbolic expression `OldExpr + Int` to `NewExpr + Int`, +// `OldExpr - Int` to `NewExpr - Int` and `OldExpr` to `NewExpr` in expression +// `OrigExpr`. +SymbolRef rebaseSymbol(ProgramStateRef State, SValBuilder &SVB, + SymbolRef OrigExpr, SymbolRef OldExpr, + SymbolRef NewSym) { + auto &SymMgr = SVB.getSymbolManager(); + auto Diff = SVB.evalBinOpNN(State, BO_Sub, nonloc::SymbolVal(OrigExpr), + nonloc::SymbolVal(OldExpr), + SymMgr.getType(OrigExpr)); + + const auto DiffInt = Diff.getAs(); + if (!DiffInt) + return OrigExpr; + + return SVB.evalBinOpNN(State, BO_Add, *DiffInt, nonloc::SymbolVal(NewSym), + SymMgr.getType(OrigExpr)).getAsSymbol(); +} + +bool hasLiveIterators(ProgramStateRef State, const MemRegion *Cont) { + auto RegionMap = State->get(); + for (const auto &Reg : RegionMap) { + if (Reg.second.getContainer() == Cont) + return true; + } + + auto SymbolMap = State->get(); + for (const auto &Sym : SymbolMap) { + if (Sym.second.getContainer() == Cont) + return true; + } + + return false; +} + +} // namespace + +void ento::registerContainerModeling(CheckerManager &mgr) { + mgr.registerChecker(); +} + +bool ento::shouldRegisterContainerModeling(const LangOptions &LO) { + return true; +} Index: clang/lib/StaticAnalyzer/Checkers/DebugContainerModeling.cpp =================================================================== --- /dev/null +++ clang/lib/StaticAnalyzer/Checkers/DebugContainerModeling.cpp @@ -0,0 +1,138 @@ +//==-- DebugContainerModeling.cpp ---------------------------------*- C++ -*--// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Defines a checker for debugging iterator modeling. +// +//===----------------------------------------------------------------------===// + +#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" + +#include "Iterator.h" + +using namespace clang; +using namespace ento; +using namespace iterator; + +namespace { + +class DebugContainerModeling + : public Checker { + + std::unique_ptr DebugMsgBugType; + + template + void analyzerContainerDataField(const CallExpr *CE, CheckerContext &C, + Getter get) const; + void analyzerContainerBegin(const CallExpr *CE, CheckerContext &C) const; + void analyzerContainerEnd(const CallExpr *CE, CheckerContext &C) const; + ExplodedNode *reportDebugMsg(llvm::StringRef Msg, CheckerContext &C) const; + + typedef void (DebugContainerModeling::*FnCheck)(const CallExpr *, + CheckerContext &) const; + + CallDescriptionMap Callbacks = { + {{0, "clang_analyzer_container_begin", 1}, + &DebugContainerModeling::analyzerContainerBegin}, + {{0, "clang_analyzer_container_end", 1}, + &DebugContainerModeling::analyzerContainerEnd}, + }; + +public: + DebugContainerModeling(); + + bool evalCall(const CallEvent &Call, CheckerContext &C) const; +}; + +} //namespace + +DebugContainerModeling::DebugContainerModeling() { + DebugMsgBugType.reset( + new BugType(this, "Checking analyzer assumptions", "debug", + /*SuppressOnSink=*/true)); +} + +bool DebugContainerModeling::evalCall(const CallEvent &Call, + CheckerContext &C) const { + const auto *CE = dyn_cast_or_null(Call.getOriginExpr()); + if (!CE) + return false; + + const FnCheck *Handler = Callbacks.lookup(Call); + if (!Handler) + return false; + + (this->**Handler)(CE, C); + return true; +} + +template +void DebugContainerModeling::analyzerContainerDataField(const CallExpr *CE, + CheckerContext &C, + Getter get) const { + if (CE->getNumArgs() == 0) { + reportDebugMsg("Missing container argument", C); + return; + } + + auto State = C.getState(); + const MemRegion *Cont = C.getSVal(CE->getArg(0)).getAsRegion(); + if (Cont) { + const auto *Data = getContainerData(State, Cont); + if (Data) { + SymbolRef Field = get(Data); + if (Field) { + State = State->BindExpr(CE, C.getLocationContext(), + nonloc::SymbolVal(Field)); + C.addTransition(State); + return; + } + } + } + + auto &BVF = C.getSValBuilder().getBasicValueFactory(); + State = State->BindExpr(CE, C.getLocationContext(), + nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0)))); +} + +void DebugContainerModeling::analyzerContainerBegin(const CallExpr *CE, + CheckerContext &C) const { + analyzerContainerDataField(CE, C, [](const ContainerData *D) { + return D->getBegin(); + }); +} + +void DebugContainerModeling::analyzerContainerEnd(const CallExpr *CE, + CheckerContext &C) const { + analyzerContainerDataField(CE, C, [](const ContainerData *D) { + return D->getEnd(); + }); +} + +ExplodedNode *DebugContainerModeling::reportDebugMsg(llvm::StringRef Msg, + CheckerContext &C) const { + ExplodedNode *N = C.generateNonFatalErrorNode(); + if (!N) + return nullptr; + + auto &BR = C.getBugReporter(); + BR.emitReport(std::make_unique(*DebugMsgBugType, + Msg, N)); + return N; +} + +void ento::registerDebugContainerModeling(CheckerManager &mgr) { + mgr.registerChecker(); +} + +bool ento::shouldRegisterDebugContainerModeling(const LangOptions &LO) { + return true; +} Index: clang/lib/StaticAnalyzer/Checkers/DebugIteratorModeling.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/DebugIteratorModeling.cpp +++ clang/lib/StaticAnalyzer/Checkers/DebugIteratorModeling.cpp @@ -29,11 +29,6 @@ std::unique_ptr DebugMsgBugType; - template - void analyzerContainerDataField(const CallExpr *CE, CheckerContext &C, - Getter get) const; - void analyzerContainerBegin(const CallExpr *CE, CheckerContext &C) const; - void analyzerContainerEnd(const CallExpr *CE, CheckerContext &C) const; template void analyzerIteratorDataField(const CallExpr *CE, CheckerContext &C, Getter get, SVal Default) const; @@ -46,10 +41,6 @@ CheckerContext &) const; CallDescriptionMap Callbacks = { - {{0, "clang_analyzer_container_begin", 1}, - &DebugIteratorModeling::analyzerContainerBegin}, - {{0, "clang_analyzer_container_end", 1}, - &DebugIteratorModeling::analyzerContainerEnd}, {{0, "clang_analyzer_iterator_position", 1}, &DebugIteratorModeling::analyzerIteratorPosition}, {{0, "clang_analyzer_iterator_container", 1}, @@ -86,49 +77,6 @@ return true; } -template -void DebugIteratorModeling::analyzerContainerDataField(const CallExpr *CE, - CheckerContext &C, - Getter get) const { - if (CE->getNumArgs() == 0) { - reportDebugMsg("Missing container argument", C); - return; - } - - auto State = C.getState(); - const MemRegion *Cont = C.getSVal(CE->getArg(0)).getAsRegion(); - if (Cont) { - const auto *Data = getContainerData(State, Cont); - if (Data) { - SymbolRef Field = get(Data); - if (Field) { - State = State->BindExpr(CE, C.getLocationContext(), - nonloc::SymbolVal(Field)); - C.addTransition(State); - return; - } - } - } - - auto &BVF = C.getSValBuilder().getBasicValueFactory(); - State = State->BindExpr(CE, C.getLocationContext(), - nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0)))); -} - -void DebugIteratorModeling::analyzerContainerBegin(const CallExpr *CE, - CheckerContext &C) const { - analyzerContainerDataField(CE, C, [](const ContainerData *D) { - return D->getBegin(); - }); -} - -void DebugIteratorModeling::analyzerContainerEnd(const CallExpr *CE, - CheckerContext &C) const { - analyzerContainerDataField(CE, C, [](const ContainerData *D) { - return D->getEnd(); - }); -} - template void DebugIteratorModeling::analyzerIteratorDataField(const CallExpr *CE, CheckerContext &C, Index: clang/lib/StaticAnalyzer/Checkers/Iterator.h =================================================================== --- clang/lib/StaticAnalyzer/Checkers/Iterator.h +++ clang/lib/StaticAnalyzer/Checkers/Iterator.h @@ -163,6 +163,8 @@ const SVal &Iter, OverloadedOperatorKind Op, const SVal &Distance); +ProgramStateRef assumeNoOverflow(ProgramStateRef State, SymbolRef Sym, + long Scale); bool compare(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2, BinaryOperator::Opcode Opc); bool compare(ProgramStateRef State, NonLoc NL1, NonLoc NL2, Index: clang/lib/StaticAnalyzer/Checkers/Iterator.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/Iterator.cpp +++ clang/lib/StaticAnalyzer/Checkers/Iterator.cpp @@ -204,6 +204,47 @@ return nullptr; } +// This function tells the analyzer's engine that symbols produced by our +// checker, most notably iterator positions, are relatively small. +// A distance between items in the container should not be very large. +// By assuming that it is within around 1/8 of the address space, +// we can help the analyzer perform operations on these symbols +// without being afraid of integer overflows. +// FIXME: Should we provide it as an API, so that all checkers could use it? +ProgramStateRef assumeNoOverflow(ProgramStateRef State, SymbolRef Sym, + long Scale) { + SValBuilder &SVB = State->getStateManager().getSValBuilder(); + BasicValueFactory &BV = SVB.getBasicValueFactory(); + + QualType T = Sym->getType(); + assert(T->isSignedIntegerOrEnumerationType()); + APSIntType AT = BV.getAPSIntType(T); + + ProgramStateRef NewState = State; + + llvm::APSInt Max = AT.getMaxValue() / AT.getValue(Scale); + SVal IsCappedFromAbove = + SVB.evalBinOpNN(State, BO_LE, nonloc::SymbolVal(Sym), + nonloc::ConcreteInt(Max), SVB.getConditionType()); + if (auto DV = IsCappedFromAbove.getAs()) { + NewState = NewState->assume(*DV, true); + if (!NewState) + return State; + } + + llvm::APSInt Min = -Max; + SVal IsCappedFromBelow = + SVB.evalBinOpNN(State, BO_GE, nonloc::SymbolVal(Sym), + nonloc::ConcreteInt(Min), SVB.getConditionType()); + if (auto DV = IsCappedFromBelow.getAs()) { + NewState = NewState->assume(*DV, true); + if (!NewState) + return State; + } + + return NewState; +} + bool compare(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2, BinaryOperator::Opcode Opc) { return compare(State, nonloc::SymbolVal(Sym1), nonloc::SymbolVal(Sym2), Opc); Index: clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp +++ clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp @@ -6,8 +6,7 @@ // //===----------------------------------------------------------------------===// // -// Defines a checker for using iterators outside their range (past end). Usage -// means here dereferencing, incrementing etc. +// Defines a modeling-checker for modeling STL iterator-like iterators. // //===----------------------------------------------------------------------===// // @@ -100,27 +99,8 @@ void handleRandomIncrOrDecr(CheckerContext &C, const Expr *CE, OverloadedOperatorKind Op, const SVal &RetVal, const SVal &LHS, const SVal &RHS) const; - void handleBegin(CheckerContext &C, const Expr *CE, const SVal &RetVal, - const SVal &Cont) const; - void handleEnd(CheckerContext &C, const Expr *CE, const SVal &RetVal, - const SVal &Cont) const; void assignToContainer(CheckerContext &C, const Expr *CE, const SVal &RetVal, const MemRegion *Cont) const; - void handleAssign(CheckerContext &C, const SVal &Cont, - const Expr *CE = nullptr, - const SVal &OldCont = UndefinedVal()) const; - void handleClear(CheckerContext &C, const SVal &Cont) const; - void handlePushBack(CheckerContext &C, const SVal &Cont) const; - void handlePopBack(CheckerContext &C, const SVal &Cont) const; - void handlePushFront(CheckerContext &C, const SVal &Cont) const; - void handlePopFront(CheckerContext &C, const SVal &Cont) const; - void handleInsert(CheckerContext &C, const SVal &Iter) const; - void handleErase(CheckerContext &C, const SVal &Iter) const; - void handleErase(CheckerContext &C, const SVal &Iter1, - const SVal &Iter2) const; - void handleEraseAfter(CheckerContext &C, const SVal &Iter) const; - void handleEraseAfter(CheckerContext &C, const SVal &Iter1, - const SVal &Iter2) const; void printState(raw_ostream &Out, ProgramStateRef State, const char *NL, const char *Sep) const override; @@ -137,66 +117,10 @@ void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const; }; -bool isBeginCall(const FunctionDecl *Func); -bool isEndCall(const FunctionDecl *Func); -bool isAssignCall(const FunctionDecl *Func); -bool isClearCall(const FunctionDecl *Func); -bool isPushBackCall(const FunctionDecl *Func); -bool isEmplaceBackCall(const FunctionDecl *Func); -bool isPopBackCall(const FunctionDecl *Func); -bool isPushFrontCall(const FunctionDecl *Func); -bool isEmplaceFrontCall(const FunctionDecl *Func); -bool isPopFrontCall(const FunctionDecl *Func); -bool isAssignmentOperator(OverloadedOperatorKind OK); bool isSimpleComparisonOperator(OverloadedOperatorKind OK); -bool hasSubscriptOperator(ProgramStateRef State, const MemRegion *Reg); -bool frontModifiable(ProgramStateRef State, const MemRegion *Reg); -bool backModifiable(ProgramStateRef State, const MemRegion *Reg); -SymbolRef getContainerBegin(ProgramStateRef State, const MemRegion *Cont); -SymbolRef getContainerEnd(ProgramStateRef State, const MemRegion *Cont); -ProgramStateRef createContainerBegin(ProgramStateRef State, - const MemRegion *Cont, const Expr *E, - QualType T, const LocationContext *LCtx, - unsigned BlockCount); -ProgramStateRef createContainerEnd(ProgramStateRef State, const MemRegion *Cont, - const Expr *E, QualType T, - const LocationContext *LCtx, - unsigned BlockCount); -ProgramStateRef setContainerData(ProgramStateRef State, const MemRegion *Cont, - const ContainerData &CData); ProgramStateRef removeIteratorPosition(ProgramStateRef State, const SVal &Val); -ProgramStateRef assumeNoOverflow(ProgramStateRef State, SymbolRef Sym, - long Scale); -ProgramStateRef invalidateAllIteratorPositions(ProgramStateRef State, - const MemRegion *Cont); -ProgramStateRef -invalidateAllIteratorPositionsExcept(ProgramStateRef State, - const MemRegion *Cont, SymbolRef Offset, - BinaryOperator::Opcode Opc); -ProgramStateRef invalidateIteratorPositions(ProgramStateRef State, - SymbolRef Offset, - BinaryOperator::Opcode Opc); -ProgramStateRef invalidateIteratorPositions(ProgramStateRef State, - SymbolRef Offset1, - BinaryOperator::Opcode Opc1, - SymbolRef Offset2, - BinaryOperator::Opcode Opc2); -ProgramStateRef reassignAllIteratorPositions(ProgramStateRef State, - const MemRegion *Cont, - const MemRegion *NewCont); -ProgramStateRef reassignAllIteratorPositionsUnless(ProgramStateRef State, - const MemRegion *Cont, - const MemRegion *NewCont, - SymbolRef Offset, - BinaryOperator::Opcode Opc); -ProgramStateRef rebaseSymbolInIteratorPositionsIf( - ProgramStateRef State, SValBuilder &SVB, SymbolRef OldSym, - SymbolRef NewSym, SymbolRef CondSym, BinaryOperator::Opcode Opc); ProgramStateRef relateSymbols(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2, bool Equal); -SymbolRef rebaseSymbol(ProgramStateRef State, SValBuilder &SVB, SymbolRef Expr, - SymbolRef OldSym, SymbolRef NewSym); -bool hasLiveIterators(ProgramStateRef State, const MemRegion *Cont); bool isBoundThroughLazyCompoundVal(const Environment &Env, const MemRegion *Reg); @@ -211,18 +135,7 @@ if (Func->isOverloadedOperator()) { const auto Op = Func->getOverloadedOperator(); - if (isAssignmentOperator(Op)) { - // Overloaded 'operator=' must be a non-static member function. - const auto *InstCall = cast(&Call); - if (cast(Func)->isMoveAssignmentOperator()) { - handleAssign(C, InstCall->getCXXThisVal(), Call.getOriginExpr(), - Call.getArgSVal(0)); - return; - } - - handleAssign(C, InstCall->getCXXThisVal()); - return; - } else if (isSimpleComparisonOperator(Op)) { + if (isSimpleComparisonOperator(Op)) { const auto *OrigExpr = Call.getOriginExpr(); if (!OrigExpr) return; @@ -280,90 +193,15 @@ return; } } else { - if (const auto *InstCall = dyn_cast(&Call)) { - if (isAssignCall(Func)) { - handleAssign(C, InstCall->getCXXThisVal()); - return; - } - - if (isClearCall(Func)) { - handleClear(C, InstCall->getCXXThisVal()); - return; - } - - if (isPushBackCall(Func) || isEmplaceBackCall(Func)) { - handlePushBack(C, InstCall->getCXXThisVal()); - return; - } - - if (isPopBackCall(Func)) { - handlePopBack(C, InstCall->getCXXThisVal()); - return; - } - - if (isPushFrontCall(Func) || isEmplaceFrontCall(Func)) { - handlePushFront(C, InstCall->getCXXThisVal()); - return; - } - - if (isPopFrontCall(Func)) { - handlePopFront(C, InstCall->getCXXThisVal()); - return; - } - - if (isInsertCall(Func) || isEmplaceCall(Func)) { - handleInsert(C, Call.getArgSVal(0)); - return; - } - - if (isEraseCall(Func)) { - if (Call.getNumArgs() == 1) { - handleErase(C, Call.getArgSVal(0)); - return; - } - - if (Call.getNumArgs() == 2) { - handleErase(C, Call.getArgSVal(0), Call.getArgSVal(1)); - return; - } - } - - if (isEraseAfterCall(Func)) { - if (Call.getNumArgs() == 1) { - handleEraseAfter(C, Call.getArgSVal(0)); - return; - } - - if (Call.getNumArgs() == 2) { - handleEraseAfter(C, Call.getArgSVal(0), Call.getArgSVal(1)); - return; - } - } - } + if (!isIteratorType(Call.getResultType())) + return; const auto *OrigExpr = Call.getOriginExpr(); if (!OrigExpr) return; - if (!isIteratorType(Call.getResultType())) - return; - auto State = C.getState(); - if (const auto *InstCall = dyn_cast(&Call)) { - if (isBeginCall(Func)) { - handleBegin(C, OrigExpr, Call.getReturnValue(), - InstCall->getCXXThisVal()); - return; - } - - if (isEndCall(Func)) { - handleEnd(C, OrigExpr, Call.getReturnValue(), - InstCall->getCXXThisVal()); - return; - } - } - // Already bound to container? if (getIteratorPosition(State, Call.getReturnValue())) return; @@ -426,8 +264,7 @@ void IteratorModeling::checkLiveSymbols(ProgramStateRef State, SymbolReaper &SR) const { - // Keep symbolic expressions of iterator positions, container begins and ends - // alive + // Keep symbolic expressions of iterator positions alive auto RegionMap = State->get(); for (const auto &Reg : RegionMap) { const auto Offset = Reg.second.getOffset(); @@ -444,20 +281,6 @@ SR.markLive(*i); } - auto ContMap = State->get(); - for (const auto &Cont : ContMap) { - const auto CData = Cont.second; - if (CData.getBegin()) { - SR.markLive(CData.getBegin()); - if(const auto *SIE = dyn_cast(CData.getBegin())) - SR.markLive(SIE->getLHS()); - } - if (CData.getEnd()) { - SR.markLive(CData.getEnd()); - if(const auto *SIE = dyn_cast(CData.getEnd())) - SR.markLive(SIE->getLHS()); - } - } } void IteratorModeling::checkDeadSymbols(SymbolReaper &SR, @@ -484,17 +307,6 @@ } } - auto ContMap = State->get(); - for (const auto &Cont : ContMap) { - if (!SR.isLiveRegion(Cont.first)) { - // We must keep the container data while it has live iterators to be able - // to compare them to the begin and the end of the container. - if (!hasLiveIterators(State, Cont.first)) { - State = State->remove(Cont.first); - } - } - } - C.addTransition(State); } @@ -669,50 +481,6 @@ } } -void IteratorModeling::handleBegin(CheckerContext &C, const Expr *CE, - const SVal &RetVal, const SVal &Cont) const { - const auto *ContReg = Cont.getAsRegion(); - if (!ContReg) - return; - - ContReg = ContReg->getMostDerivedObjectRegion(); - - // If the container already has a begin symbol then use it. Otherwise first - // create a new one. - auto State = C.getState(); - auto BeginSym = getContainerBegin(State, ContReg); - if (!BeginSym) { - State = createContainerBegin(State, ContReg, CE, C.getASTContext().LongTy, - C.getLocationContext(), C.blockCount()); - BeginSym = getContainerBegin(State, ContReg); - } - State = setIteratorPosition(State, RetVal, - IteratorPosition::getPosition(ContReg, BeginSym)); - C.addTransition(State); -} - -void IteratorModeling::handleEnd(CheckerContext &C, const Expr *CE, - const SVal &RetVal, const SVal &Cont) const { - const auto *ContReg = Cont.getAsRegion(); - if (!ContReg) - return; - - ContReg = ContReg->getMostDerivedObjectRegion(); - - // If the container already has an end symbol then use it. Otherwise first - // create a new one. - auto State = C.getState(); - auto EndSym = getContainerEnd(State, ContReg); - if (!EndSym) { - State = createContainerEnd(State, ContReg, CE, C.getASTContext().LongTy, - C.getLocationContext(), C.blockCount()); - EndSym = getContainerEnd(State, ContReg); - } - State = setIteratorPosition(State, RetVal, - IteratorPosition::getPosition(ContReg, EndSym)); - C.addTransition(State); -} - void IteratorModeling::assignToContainer(CheckerContext &C, const Expr *CE, const SVal &RetVal, const MemRegion *Cont) const { @@ -728,395 +496,8 @@ C.addTransition(State); } -void IteratorModeling::handleAssign(CheckerContext &C, const SVal &Cont, - const Expr *CE, const SVal &OldCont) const { - const auto *ContReg = Cont.getAsRegion(); - if (!ContReg) - return; - - ContReg = ContReg->getMostDerivedObjectRegion(); - - // Assignment of a new value to a container always invalidates all its - // iterators - auto State = C.getState(); - const auto CData = getContainerData(State, ContReg); - if (CData) { - State = invalidateAllIteratorPositions(State, ContReg); - } - - // In case of move, iterators of the old container (except the past-end - // iterators) remain valid but refer to the new container - if (!OldCont.isUndef()) { - const auto *OldContReg = OldCont.getAsRegion(); - if (OldContReg) { - OldContReg = OldContReg->getMostDerivedObjectRegion(); - const auto OldCData = getContainerData(State, OldContReg); - if (OldCData) { - if (const auto OldEndSym = OldCData->getEnd()) { - // If we already assigned an "end" symbol to the old container, then - // first reassign all iterator positions to the new container which - // are not past the container (thus not greater or equal to the - // current "end" symbol). - State = reassignAllIteratorPositionsUnless(State, OldContReg, ContReg, - OldEndSym, BO_GE); - auto &SymMgr = C.getSymbolManager(); - auto &SVB = C.getSValBuilder(); - // Then generate and assign a new "end" symbol for the new container. - auto NewEndSym = - SymMgr.conjureSymbol(CE, C.getLocationContext(), - C.getASTContext().LongTy, C.blockCount()); - State = assumeNoOverflow(State, NewEndSym, 4); - if (CData) { - State = setContainerData(State, ContReg, CData->newEnd(NewEndSym)); - } else { - State = setContainerData(State, ContReg, - ContainerData::fromEnd(NewEndSym)); - } - // Finally, replace the old "end" symbol in the already reassigned - // iterator positions with the new "end" symbol. - State = rebaseSymbolInIteratorPositionsIf( - State, SVB, OldEndSym, NewEndSym, OldEndSym, BO_LT); - } else { - // There was no "end" symbol assigned yet to the old container, - // so reassign all iterator positions to the new container. - State = reassignAllIteratorPositions(State, OldContReg, ContReg); - } - if (const auto OldBeginSym = OldCData->getBegin()) { - // If we already assigned a "begin" symbol to the old container, then - // assign it to the new container and remove it from the old one. - if (CData) { - State = - setContainerData(State, ContReg, CData->newBegin(OldBeginSym)); - } else { - State = setContainerData(State, ContReg, - ContainerData::fromBegin(OldBeginSym)); - } - State = - setContainerData(State, OldContReg, OldCData->newEnd(nullptr)); - } - } else { - // There was neither "begin" nor "end" symbol assigned yet to the old - // container, so reassign all iterator positions to the new container. - State = reassignAllIteratorPositions(State, OldContReg, ContReg); - } - } - } - C.addTransition(State); -} - -void IteratorModeling::handleClear(CheckerContext &C, const SVal &Cont) const { - const auto *ContReg = Cont.getAsRegion(); - if (!ContReg) - return; - - ContReg = ContReg->getMostDerivedObjectRegion(); - - // The clear() operation invalidates all the iterators, except the past-end - // iterators of list-like containers - auto State = C.getState(); - if (!hasSubscriptOperator(State, ContReg) || - !backModifiable(State, ContReg)) { - const auto CData = getContainerData(State, ContReg); - if (CData) { - if (const auto EndSym = CData->getEnd()) { - State = - invalidateAllIteratorPositionsExcept(State, ContReg, EndSym, BO_GE); - C.addTransition(State); - return; - } - } - } - State = invalidateAllIteratorPositions(State, ContReg); - C.addTransition(State); -} - -void IteratorModeling::handlePushBack(CheckerContext &C, - const SVal &Cont) const { - const auto *ContReg = Cont.getAsRegion(); - if (!ContReg) - return; - - ContReg = ContReg->getMostDerivedObjectRegion(); - - // For deque-like containers invalidate all iterator positions - auto State = C.getState(); - if (hasSubscriptOperator(State, ContReg) && frontModifiable(State, ContReg)) { - State = invalidateAllIteratorPositions(State, ContReg); - C.addTransition(State); - return; - } - - const auto CData = getContainerData(State, ContReg); - if (!CData) - return; - - // For vector-like containers invalidate the past-end iterator positions - if (const auto EndSym = CData->getEnd()) { - if (hasSubscriptOperator(State, ContReg)) { - State = invalidateIteratorPositions(State, EndSym, BO_GE); - } - auto &SymMgr = C.getSymbolManager(); - auto &BVF = SymMgr.getBasicVals(); - auto &SVB = C.getSValBuilder(); - const auto newEndSym = - SVB.evalBinOp(State, BO_Add, - nonloc::SymbolVal(EndSym), - nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))), - SymMgr.getType(EndSym)).getAsSymbol(); - State = setContainerData(State, ContReg, CData->newEnd(newEndSym)); - } - C.addTransition(State); -} - -void IteratorModeling::handlePopBack(CheckerContext &C, - const SVal &Cont) const { - const auto *ContReg = Cont.getAsRegion(); - if (!ContReg) - return; - - ContReg = ContReg->getMostDerivedObjectRegion(); - - auto State = C.getState(); - const auto CData = getContainerData(State, ContReg); - if (!CData) - return; - - if (const auto EndSym = CData->getEnd()) { - auto &SymMgr = C.getSymbolManager(); - auto &BVF = SymMgr.getBasicVals(); - auto &SVB = C.getSValBuilder(); - const auto BackSym = - SVB.evalBinOp(State, BO_Sub, - nonloc::SymbolVal(EndSym), - nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))), - SymMgr.getType(EndSym)).getAsSymbol(); - // For vector-like and deque-like containers invalidate the last and the - // past-end iterator positions. For list-like containers only invalidate - // the last position - if (hasSubscriptOperator(State, ContReg) && - backModifiable(State, ContReg)) { - State = invalidateIteratorPositions(State, BackSym, BO_GE); - State = setContainerData(State, ContReg, CData->newEnd(nullptr)); - } else { - State = invalidateIteratorPositions(State, BackSym, BO_EQ); - } - auto newEndSym = BackSym; - State = setContainerData(State, ContReg, CData->newEnd(newEndSym)); - C.addTransition(State); - } -} - -void IteratorModeling::handlePushFront(CheckerContext &C, - const SVal &Cont) const { - const auto *ContReg = Cont.getAsRegion(); - if (!ContReg) - return; - - ContReg = ContReg->getMostDerivedObjectRegion(); - - // For deque-like containers invalidate all iterator positions - auto State = C.getState(); - if (hasSubscriptOperator(State, ContReg)) { - State = invalidateAllIteratorPositions(State, ContReg); - C.addTransition(State); - } else { - const auto CData = getContainerData(State, ContReg); - if (!CData) - return; - - if (const auto BeginSym = CData->getBegin()) { - auto &SymMgr = C.getSymbolManager(); - auto &BVF = SymMgr.getBasicVals(); - auto &SVB = C.getSValBuilder(); - const auto newBeginSym = - SVB.evalBinOp(State, BO_Sub, - nonloc::SymbolVal(BeginSym), - nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))), - SymMgr.getType(BeginSym)).getAsSymbol(); - State = setContainerData(State, ContReg, CData->newBegin(newBeginSym)); - C.addTransition(State); - } - } -} - -void IteratorModeling::handlePopFront(CheckerContext &C, - const SVal &Cont) const { - const auto *ContReg = Cont.getAsRegion(); - if (!ContReg) - return; - - ContReg = ContReg->getMostDerivedObjectRegion(); - - auto State = C.getState(); - const auto CData = getContainerData(State, ContReg); - if (!CData) - return; - - // For deque-like containers invalidate all iterator positions. For list-like - // iterators only invalidate the first position - if (const auto BeginSym = CData->getBegin()) { - if (hasSubscriptOperator(State, ContReg)) { - State = invalidateIteratorPositions(State, BeginSym, BO_LE); - } else { - State = invalidateIteratorPositions(State, BeginSym, BO_EQ); - } - auto &SymMgr = C.getSymbolManager(); - auto &BVF = SymMgr.getBasicVals(); - auto &SVB = C.getSValBuilder(); - const auto newBeginSym = - SVB.evalBinOp(State, BO_Add, - nonloc::SymbolVal(BeginSym), - nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))), - SymMgr.getType(BeginSym)).getAsSymbol(); - State = setContainerData(State, ContReg, CData->newBegin(newBeginSym)); - C.addTransition(State); - } -} - -void IteratorModeling::handleInsert(CheckerContext &C, const SVal &Iter) const { - auto State = C.getState(); - const auto *Pos = getIteratorPosition(State, Iter); - if (!Pos) - return; - - // For deque-like containers invalidate all iterator positions. For - // vector-like containers invalidate iterator positions after the insertion. - const auto *Cont = Pos->getContainer(); - if (hasSubscriptOperator(State, Cont) && backModifiable(State, Cont)) { - if (frontModifiable(State, Cont)) { - State = invalidateAllIteratorPositions(State, Cont); - } else { - State = invalidateIteratorPositions(State, Pos->getOffset(), BO_GE); - } - if (const auto *CData = getContainerData(State, Cont)) { - if (const auto EndSym = CData->getEnd()) { - State = invalidateIteratorPositions(State, EndSym, BO_GE); - State = setContainerData(State, Cont, CData->newEnd(nullptr)); - } - } - C.addTransition(State); - } -} - -void IteratorModeling::handleErase(CheckerContext &C, const SVal &Iter) const { - auto State = C.getState(); - const auto *Pos = getIteratorPosition(State, Iter); - if (!Pos) - return; - - // For deque-like containers invalidate all iterator positions. For - // vector-like containers invalidate iterator positions at and after the - // deletion. For list-like containers only invalidate the deleted position. - const auto *Cont = Pos->getContainer(); - if (hasSubscriptOperator(State, Cont) && backModifiable(State, Cont)) { - if (frontModifiable(State, Cont)) { - State = invalidateAllIteratorPositions(State, Cont); - } else { - State = invalidateIteratorPositions(State, Pos->getOffset(), BO_GE); - } - if (const auto *CData = getContainerData(State, Cont)) { - if (const auto EndSym = CData->getEnd()) { - State = invalidateIteratorPositions(State, EndSym, BO_GE); - State = setContainerData(State, Cont, CData->newEnd(nullptr)); - } - } - } else { - State = invalidateIteratorPositions(State, Pos->getOffset(), BO_EQ); - } - C.addTransition(State); -} - -void IteratorModeling::handleErase(CheckerContext &C, const SVal &Iter1, - const SVal &Iter2) const { - auto State = C.getState(); - const auto *Pos1 = getIteratorPosition(State, Iter1); - const auto *Pos2 = getIteratorPosition(State, Iter2); - if (!Pos1 || !Pos2) - return; - - // For deque-like containers invalidate all iterator positions. For - // vector-like containers invalidate iterator positions at and after the - // deletion range. For list-like containers only invalidate the deleted - // position range [first..last]. - const auto *Cont = Pos1->getContainer(); - if (hasSubscriptOperator(State, Cont) && backModifiable(State, Cont)) { - if (frontModifiable(State, Cont)) { - State = invalidateAllIteratorPositions(State, Cont); - } else { - State = invalidateIteratorPositions(State, Pos1->getOffset(), BO_GE); - } - if (const auto *CData = getContainerData(State, Cont)) { - if (const auto EndSym = CData->getEnd()) { - State = invalidateIteratorPositions(State, EndSym, BO_GE); - State = setContainerData(State, Cont, CData->newEnd(nullptr)); - } - } - } else { - State = invalidateIteratorPositions(State, Pos1->getOffset(), BO_GE, - Pos2->getOffset(), BO_LT); - } - C.addTransition(State); -} - -void IteratorModeling::handleEraseAfter(CheckerContext &C, - const SVal &Iter) const { - auto State = C.getState(); - const auto *Pos = getIteratorPosition(State, Iter); - if (!Pos) - return; - - // Invalidate the deleted iterator position, which is the position of the - // parameter plus one. - auto &SymMgr = C.getSymbolManager(); - auto &BVF = SymMgr.getBasicVals(); - auto &SVB = C.getSValBuilder(); - const auto NextSym = - SVB.evalBinOp(State, BO_Add, - nonloc::SymbolVal(Pos->getOffset()), - nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))), - SymMgr.getType(Pos->getOffset())).getAsSymbol(); - State = invalidateIteratorPositions(State, NextSym, BO_EQ); - C.addTransition(State); -} - -void IteratorModeling::handleEraseAfter(CheckerContext &C, const SVal &Iter1, - const SVal &Iter2) const { - auto State = C.getState(); - const auto *Pos1 = getIteratorPosition(State, Iter1); - const auto *Pos2 = getIteratorPosition(State, Iter2); - if (!Pos1 || !Pos2) - return; - - // Invalidate the deleted iterator position range (first..last) - State = invalidateIteratorPositions(State, Pos1->getOffset(), BO_GT, - Pos2->getOffset(), BO_LT); - C.addTransition(State); -} - void IteratorModeling::printState(raw_ostream &Out, ProgramStateRef State, const char *NL, const char *Sep) const { - - auto ContMap = State->get(); - - if (!ContMap.isEmpty()) { - Out << Sep << "Container Data :" << NL; - for (const auto &Cont : ContMap) { - Cont.first->dumpToStream(Out); - Out << " : [ "; - const auto CData = Cont.second; - if (CData.getBegin()) - CData.getBegin()->dumpToStream(Out); - else - Out << ""; - Out << " .. "; - if (CData.getEnd()) - CData.getEnd()->dumpToStream(Out); - else - Out << ""; - Out << " ]" << NL; - } - } - auto SymbolMap = State->get(); auto RegionMap = State->get(); @@ -1144,231 +525,12 @@ } } - namespace { -const CXXRecordDecl *getCXXRecordDecl(ProgramStateRef State, - const MemRegion *Reg); - -bool isBeginCall(const FunctionDecl *Func) { - const auto *IdInfo = Func->getIdentifier(); - if (!IdInfo) - return false; - return IdInfo->getName().endswith_lower("begin"); -} - -bool isEndCall(const FunctionDecl *Func) { - const auto *IdInfo = Func->getIdentifier(); - if (!IdInfo) - return false; - return IdInfo->getName().endswith_lower("end"); -} - -bool isAssignCall(const FunctionDecl *Func) { - const auto *IdInfo = Func->getIdentifier(); - if (!IdInfo) - return false; - if (Func->getNumParams() > 2) - return false; - return IdInfo->getName() == "assign"; -} - -bool isClearCall(const FunctionDecl *Func) { - const auto *IdInfo = Func->getIdentifier(); - if (!IdInfo) - return false; - if (Func->getNumParams() > 0) - return false; - return IdInfo->getName() == "clear"; -} - -bool isPushBackCall(const FunctionDecl *Func) { - const auto *IdInfo = Func->getIdentifier(); - if (!IdInfo) - return false; - if (Func->getNumParams() != 1) - return false; - return IdInfo->getName() == "push_back"; -} - -bool isEmplaceBackCall(const FunctionDecl *Func) { - const auto *IdInfo = Func->getIdentifier(); - if (!IdInfo) - return false; - if (Func->getNumParams() < 1) - return false; - return IdInfo->getName() == "emplace_back"; -} - -bool isPopBackCall(const FunctionDecl *Func) { - const auto *IdInfo = Func->getIdentifier(); - if (!IdInfo) - return false; - if (Func->getNumParams() > 0) - return false; - return IdInfo->getName() == "pop_back"; -} - -bool isPushFrontCall(const FunctionDecl *Func) { - const auto *IdInfo = Func->getIdentifier(); - if (!IdInfo) - return false; - if (Func->getNumParams() != 1) - return false; - return IdInfo->getName() == "push_front"; -} - -bool isEmplaceFrontCall(const FunctionDecl *Func) { - const auto *IdInfo = Func->getIdentifier(); - if (!IdInfo) - return false; - if (Func->getNumParams() < 1) - return false; - return IdInfo->getName() == "emplace_front"; -} - -bool isPopFrontCall(const FunctionDecl *Func) { - const auto *IdInfo = Func->getIdentifier(); - if (!IdInfo) - return false; - if (Func->getNumParams() > 0) - return false; - return IdInfo->getName() == "pop_front"; -} - -bool isAssignmentOperator(OverloadedOperatorKind OK) { return OK == OO_Equal; } - bool isSimpleComparisonOperator(OverloadedOperatorKind OK) { return OK == OO_EqualEqual || OK == OO_ExclaimEqual; } -bool hasSubscriptOperator(ProgramStateRef State, const MemRegion *Reg) { - const auto *CRD = getCXXRecordDecl(State, Reg); - if (!CRD) - return false; - - for (const auto *Method : CRD->methods()) { - if (!Method->isOverloadedOperator()) - continue; - const auto OPK = Method->getOverloadedOperator(); - if (OPK == OO_Subscript) { - return true; - } - } - return false; -} - -bool frontModifiable(ProgramStateRef State, const MemRegion *Reg) { - const auto *CRD = getCXXRecordDecl(State, Reg); - if (!CRD) - return false; - - for (const auto *Method : CRD->methods()) { - if (!Method->getDeclName().isIdentifier()) - continue; - if (Method->getName() == "push_front" || Method->getName() == "pop_front") { - return true; - } - } - return false; -} - -bool backModifiable(ProgramStateRef State, const MemRegion *Reg) { - const auto *CRD = getCXXRecordDecl(State, Reg); - if (!CRD) - return false; - - for (const auto *Method : CRD->methods()) { - if (!Method->getDeclName().isIdentifier()) - continue; - if (Method->getName() == "push_back" || Method->getName() == "pop_back") { - return true; - } - } - return false; -} - -const CXXRecordDecl *getCXXRecordDecl(ProgramStateRef State, - const MemRegion *Reg) { - auto TI = getDynamicTypeInfo(State, Reg); - if (!TI.isValid()) - return nullptr; - - auto Type = TI.getType(); - if (const auto *RefT = Type->getAs()) { - Type = RefT->getPointeeType(); - } - - return Type->getUnqualifiedDesugaredType()->getAsCXXRecordDecl(); -} - -SymbolRef getContainerBegin(ProgramStateRef State, const MemRegion *Cont) { - const auto *CDataPtr = getContainerData(State, Cont); - if (!CDataPtr) - return nullptr; - - return CDataPtr->getBegin(); -} - -SymbolRef getContainerEnd(ProgramStateRef State, const MemRegion *Cont) { - const auto *CDataPtr = getContainerData(State, Cont); - if (!CDataPtr) - return nullptr; - - return CDataPtr->getEnd(); -} - -ProgramStateRef createContainerBegin(ProgramStateRef State, - const MemRegion *Cont, const Expr *E, - QualType T, const LocationContext *LCtx, - unsigned BlockCount) { - // Only create if it does not exist - const auto *CDataPtr = getContainerData(State, Cont); - if (CDataPtr && CDataPtr->getBegin()) - return State; - - auto &SymMgr = State->getSymbolManager(); - const SymbolConjured *Sym = SymMgr.conjureSymbol(E, LCtx, T, BlockCount, - "begin"); - State = assumeNoOverflow(State, Sym, 4); - - if (CDataPtr) { - const auto CData = CDataPtr->newBegin(Sym); - return setContainerData(State, Cont, CData); - } - - const auto CData = ContainerData::fromBegin(Sym); - return setContainerData(State, Cont, CData); -} - -ProgramStateRef createContainerEnd(ProgramStateRef State, const MemRegion *Cont, - const Expr *E, QualType T, - const LocationContext *LCtx, - unsigned BlockCount) { - // Only create if it does not exist - const auto *CDataPtr = getContainerData(State, Cont); - if (CDataPtr && CDataPtr->getEnd()) - return State; - - auto &SymMgr = State->getSymbolManager(); - const SymbolConjured *Sym = SymMgr.conjureSymbol(E, LCtx, T, BlockCount, - "end"); - State = assumeNoOverflow(State, Sym, 4); - - if (CDataPtr) { - const auto CData = CDataPtr->newEnd(Sym); - return setContainerData(State, Cont, CData); - } - - const auto CData = ContainerData::fromEnd(Sym); - return setContainerData(State, Cont, CData); -} - -ProgramStateRef setContainerData(ProgramStateRef State, const MemRegion *Cont, - const ContainerData &CData) { - return State->set(Cont, CData); -} - ProgramStateRef removeIteratorPosition(ProgramStateRef State, const SVal &Val) { if (auto Reg = Val.getAsRegion()) { Reg = Reg->getMostDerivedObjectRegion(); @@ -1381,47 +543,6 @@ return nullptr; } -// This function tells the analyzer's engine that symbols produced by our -// checker, most notably iterator positions, are relatively small. -// A distance between items in the container should not be very large. -// By assuming that it is within around 1/8 of the address space, -// we can help the analyzer perform operations on these symbols -// without being afraid of integer overflows. -// FIXME: Should we provide it as an API, so that all checkers could use it? -ProgramStateRef assumeNoOverflow(ProgramStateRef State, SymbolRef Sym, - long Scale) { - SValBuilder &SVB = State->getStateManager().getSValBuilder(); - BasicValueFactory &BV = SVB.getBasicValueFactory(); - - QualType T = Sym->getType(); - assert(T->isSignedIntegerOrEnumerationType()); - APSIntType AT = BV.getAPSIntType(T); - - ProgramStateRef NewState = State; - - llvm::APSInt Max = AT.getMaxValue() / AT.getValue(Scale); - SVal IsCappedFromAbove = - SVB.evalBinOpNN(State, BO_LE, nonloc::SymbolVal(Sym), - nonloc::ConcreteInt(Max), SVB.getConditionType()); - if (auto DV = IsCappedFromAbove.getAs()) { - NewState = NewState->assume(*DV, true); - if (!NewState) - return State; - } - - llvm::APSInt Min = -Max; - SVal IsCappedFromBelow = - SVB.evalBinOpNN(State, BO_GE, nonloc::SymbolVal(Sym), - nonloc::ConcreteInt(Min), SVB.getConditionType()); - if (auto DV = IsCappedFromBelow.getAs()) { - NewState = NewState->assume(*DV, true); - if (!NewState) - return State; - } - - return NewState; -} - ProgramStateRef relateSymbols(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2, bool Equal) { auto &SVB = State->getStateManager().getSValBuilder(); @@ -1454,22 +575,6 @@ return NewState; } -bool hasLiveIterators(ProgramStateRef State, const MemRegion *Cont) { - auto RegionMap = State->get(); - for (const auto &Reg : RegionMap) { - if (Reg.second.getContainer() == Cont) - return true; - } - - auto SymbolMap = State->get(); - for (const auto &Sym : SymbolMap) { - if (Sym.second.getContainer() == Cont) - return true; - } - - return false; -} - bool isBoundThroughLazyCompoundVal(const Environment &Env, const MemRegion *Reg) { for (const auto &Binding : Env) { @@ -1482,152 +587,6 @@ return false; } -template -ProgramStateRef processIteratorPositions(ProgramStateRef State, Condition Cond, - Process Proc) { - auto &RegionMapFactory = State->get_context(); - auto RegionMap = State->get(); - bool Changed = false; - for (const auto &Reg : RegionMap) { - if (Cond(Reg.second)) { - RegionMap = RegionMapFactory.add(RegionMap, Reg.first, Proc(Reg.second)); - Changed = true; - } - } - - if (Changed) - State = State->set(RegionMap); - - auto &SymbolMapFactory = State->get_context(); - auto SymbolMap = State->get(); - Changed = false; - for (const auto &Sym : SymbolMap) { - if (Cond(Sym.second)) { - SymbolMap = SymbolMapFactory.add(SymbolMap, Sym.first, Proc(Sym.second)); - Changed = true; - } - } - - if (Changed) - State = State->set(SymbolMap); - - return State; -} - -ProgramStateRef invalidateAllIteratorPositions(ProgramStateRef State, - const MemRegion *Cont) { - auto MatchCont = [&](const IteratorPosition &Pos) { - return Pos.getContainer() == Cont; - }; - auto Invalidate = [&](const IteratorPosition &Pos) { - return Pos.invalidate(); - }; - return processIteratorPositions(State, MatchCont, Invalidate); -} - -ProgramStateRef -invalidateAllIteratorPositionsExcept(ProgramStateRef State, - const MemRegion *Cont, SymbolRef Offset, - BinaryOperator::Opcode Opc) { - auto MatchContAndCompare = [&](const IteratorPosition &Pos) { - return Pos.getContainer() == Cont && - !compare(State, Pos.getOffset(), Offset, Opc); - }; - auto Invalidate = [&](const IteratorPosition &Pos) { - return Pos.invalidate(); - }; - return processIteratorPositions(State, MatchContAndCompare, Invalidate); -} - -ProgramStateRef invalidateIteratorPositions(ProgramStateRef State, - SymbolRef Offset, - BinaryOperator::Opcode Opc) { - auto Compare = [&](const IteratorPosition &Pos) { - return compare(State, Pos.getOffset(), Offset, Opc); - }; - auto Invalidate = [&](const IteratorPosition &Pos) { - return Pos.invalidate(); - }; - return processIteratorPositions(State, Compare, Invalidate); -} - -ProgramStateRef invalidateIteratorPositions(ProgramStateRef State, - SymbolRef Offset1, - BinaryOperator::Opcode Opc1, - SymbolRef Offset2, - BinaryOperator::Opcode Opc2) { - auto Compare = [&](const IteratorPosition &Pos) { - return compare(State, Pos.getOffset(), Offset1, Opc1) && - compare(State, Pos.getOffset(), Offset2, Opc2); - }; - auto Invalidate = [&](const IteratorPosition &Pos) { - return Pos.invalidate(); - }; - return processIteratorPositions(State, Compare, Invalidate); -} - -ProgramStateRef reassignAllIteratorPositions(ProgramStateRef State, - const MemRegion *Cont, - const MemRegion *NewCont) { - auto MatchCont = [&](const IteratorPosition &Pos) { - return Pos.getContainer() == Cont; - }; - auto ReAssign = [&](const IteratorPosition &Pos) { - return Pos.reAssign(NewCont); - }; - return processIteratorPositions(State, MatchCont, ReAssign); -} - -ProgramStateRef reassignAllIteratorPositionsUnless(ProgramStateRef State, - const MemRegion *Cont, - const MemRegion *NewCont, - SymbolRef Offset, - BinaryOperator::Opcode Opc) { - auto MatchContAndCompare = [&](const IteratorPosition &Pos) { - return Pos.getContainer() == Cont && - !compare(State, Pos.getOffset(), Offset, Opc); - }; - auto ReAssign = [&](const IteratorPosition &Pos) { - return Pos.reAssign(NewCont); - }; - return processIteratorPositions(State, MatchContAndCompare, ReAssign); -} - -// This function rebases symbolic expression `OldSym + Int` to `NewSym + Int`, -// `OldSym - Int` to `NewSym - Int` and `OldSym` to `NewSym` in any iterator -// position offsets where `CondSym` is true. -ProgramStateRef rebaseSymbolInIteratorPositionsIf( - ProgramStateRef State, SValBuilder &SVB, SymbolRef OldSym, - SymbolRef NewSym, SymbolRef CondSym, BinaryOperator::Opcode Opc) { - auto LessThanEnd = [&](const IteratorPosition &Pos) { - return compare(State, Pos.getOffset(), CondSym, Opc); - }; - auto RebaseSymbol = [&](const IteratorPosition &Pos) { - return Pos.setTo(rebaseSymbol(State, SVB, Pos.getOffset(), OldSym, - NewSym)); - }; - return processIteratorPositions(State, LessThanEnd, RebaseSymbol); -} - -// This function rebases symbolic expression `OldExpr + Int` to `NewExpr + Int`, -// `OldExpr - Int` to `NewExpr - Int` and `OldExpr` to `NewExpr` in expression -// `OrigExpr`. -SymbolRef rebaseSymbol(ProgramStateRef State, SValBuilder &SVB, - SymbolRef OrigExpr, SymbolRef OldExpr, - SymbolRef NewSym) { - auto &SymMgr = SVB.getSymbolManager(); - auto Diff = SVB.evalBinOpNN(State, BO_Sub, nonloc::SymbolVal(OrigExpr), - nonloc::SymbolVal(OldExpr), - SymMgr.getType(OrigExpr)); - - const auto DiffInt = Diff.getAs(); - if (!DiffInt) - return OrigExpr; - - return SVB.evalBinOpNN(State, BO_Add, *DiffInt, nonloc::SymbolVal(NewSym), - SymMgr.getType(OrigExpr)).getAsSymbol(); -} - } // namespace void ento::registerIteratorModeling(CheckerManager &mgr) { Index: clang/test/Analysis/container-modeling.cpp =================================================================== --- /dev/null +++ clang/test/Analysis/container-modeling.cpp @@ -0,0 +1,189 @@ +// 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=true -DINLINE=1 %s -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 + +#include "Inputs/system-header-simulator-cxx.h" + +template +long clang_analyzer_container_begin(const Container&); +template +long clang_analyzer_container_end(const Container&); + +void clang_analyzer_denote(long, const char*); +void clang_analyzer_express(long); +void clang_analyzer_eval(bool); +void clang_analyzer_warnIfReached(); + +void begin(const std::vector &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()}} +} + +void end(const std::vector &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()}} +} + +//////////////////////////////////////////////////////////////////////////////// +/// +/// C O N T A I N E R A S S I G N M E N T S +/// +//////////////////////////////////////////////////////////////////////////////// + +// Move + +void move_assignment(std::vector &V1, std::vector &V2) { + V1.cbegin(); + V1.cend(); + V2.cbegin(); + V2.cend(); + long B1 = clang_analyzer_container_begin(V1); + long E1 = clang_analyzer_container_end(V1); + long B2 = clang_analyzer_container_begin(V2); + long E2 = clang_analyzer_container_end(V2); + V1 = std::move(V2); + clang_analyzer_eval(clang_analyzer_container_begin(V1) == B2); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_container_end(V2) == E2); //expected-warning{{TRUE}} +} + +//////////////////////////////////////////////////////////////////////////////// +/// +/// C O N T A I N E R M O D I F I E R S +/// +//////////////////////////////////////////////////////////////////////////////// + +/// push_back() +/// +/// Design decision: extends containers to the ->RIGHT-> (i.e. the +/// past-the-end position of the container is incremented). + +void push_back(std::vector &V, int n) { + V.cbegin(); + V.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()"); + + V.push_back(n); + + clang_analyzer_express(clang_analyzer_container_begin(V)); // expected-warning{{$V.begin()}} + clang_analyzer_express(clang_analyzer_container_end(V)); // expected-warning{{$V.end() + 1}} +} + +/// emplace_back() +/// +/// Design decision: extends containers to the ->RIGHT-> (i.e. the +/// past-the-end position of the container is incremented). + +void emplace_back(std::vector &V, int n) { + V.cbegin(); + V.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()"); + + V.emplace_back(n); + + clang_analyzer_express(clang_analyzer_container_begin(V)); // expected-warning{{$V.begin()}} + clang_analyzer_express(clang_analyzer_container_end(V)); // expected-warning{{$V.end() + 1}} +} + +/// pop_back() +/// +/// Design decision: shrinks containers to the <-LEFT<- (i.e. the +/// past-the-end position of the container is decremented). + +void pop_back(std::vector &V, int n) { + V.cbegin(); + V.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()"); + + V.pop_back(); + + clang_analyzer_express(clang_analyzer_container_begin(V)); // expected-warning{{$V.begin()}} + clang_analyzer_express(clang_analyzer_container_end(V)); // expected-warning{{$V.end() - 1}} +} + +/// push_front() +/// +/// Design decision: extends containers to the <-LEFT<- (i.e. the first +/// position of the container is decremented). + +void push_front(std::deque &D, int n) { + D.cbegin(); + D.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(D), "$D.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(D), "$D.end()"); + + D.push_front(n); + + 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_end(D)); // expected-warning{{$D.end()}} +} + +/// emplace_front() +/// +/// Design decision: extends containers to the <-LEFT<- (i.e. the first +/// position of the container is decremented). + +void deque_emplace_front(std::deque &D, int n) { + D.cbegin(); + D.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(D), "$D.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(D), "$D.end()"); + + D.emplace_front(n); + + 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_end(D)); // expected-warning{{$D.end()}} +} + +/// pop_front() +/// +/// Design decision: shrinks containers to the ->RIGHT-> (i.e. the first +/// position of the container is incremented). + +void deque_pop_front(std::deque &D, int n) { + D.cbegin(); + D.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(D), "$D.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(D), "$D.end()"); + + D.pop_front(); + + clang_analyzer_express(clang_analyzer_container_begin(D)); // expected-warning{{$D.begin() + 1}} + clang_analyzer_express(clang_analyzer_container_end(D)); // expected-warning{{$D.end()}} +} + +void clang_analyzer_printState(); + +void print_state(std::vector &V) { + V.cbegin(); + clang_analyzer_printState(); + +// CHECK: "checker_messages": [ +// CHECK-NEXT: { "checker": "alpha.cplusplus.ContainerModeling", "messages": [ +// CHECK-NEXT: "Container Data :", +// CHECK-NEXT: "SymRegion{reg_$[[#]] & V>} : [ conj_$[[#]]{long, LC[[#]], S[[#]], #[[#]]} .. ]" +// CHECK-NEXT: ]} + + V.cend(); + clang_analyzer_printState(); + +// CHECK: "checker_messages": [ +// CHECK-NEXT: { "checker": "alpha.cplusplus.ContainerModeling", "messages": [ +// CHECK-NEXT: "Container Data :", +// CHECK-NEXT: "SymRegion{reg_$[[#]] & V>} : [ conj_$[[#]]{long, LC[[#]], S[[#]], #[[#]]} .. conj_$[[#]]{long, LC[[#]], S[[#]], #[[#]]} ]" +// CHECK-NEXT: ]} +} Index: clang/test/Analysis/debug-container-modeling.cpp =================================================================== --- /dev/null +++ clang/test/Analysis/debug-container-modeling.cpp @@ -0,0 +1,31 @@ +// RUN: %clang_analyze_cc1 -std=c++11\ +// RUN: -analyzer-checker=core,cplusplus\ +// RUN: -analyzer-checker=debug.DebugContainerModeling,debug.ExprInspection\ +// RUN: -analyzer-config aggressive-binary-operation-simplification=true\ +// RUN: -analyzer-config c++-container-inlining=false %s -verify + +// RUN: %clang_analyze_cc1 -std=c++11\ +// RUN: -analyzer-checker=core,cplusplus\ +// RUN: -analyzer-checker=debug.DebugContainerModeling,debug.ExprInspection\ +// RUN: -analyzer-config aggressive-binary-operation-simplification=true\ +// RUN: -analyzer-config c++-container-inlining=true -DINLINE=1 %s -verify + +#include "Inputs/system-header-simulator-cxx.h" + +template +long clang_analyzer_container_begin(const Container&); +template +long clang_analyzer_container_end(const Container&); +void clang_analyzer_denote(long, const char*); +void clang_analyzer_express(long); + +void container_begin_end(const std::vector v0) { + v0.begin(); + v0.end(); + + clang_analyzer_denote(clang_analyzer_container_begin(v0), "$b0"); + clang_analyzer_denote(clang_analyzer_container_end(v0), "$e0"); + + clang_analyzer_express(clang_analyzer_container_begin(v0)); // expected-warning{{$b0}} + clang_analyzer_express(clang_analyzer_container_end(v0)); // expected-warning{{$e0}} +} Index: clang/test/Analysis/debug-iterator-modeling.cpp =================================================================== --- clang/test/Analysis/debug-iterator-modeling.cpp +++ clang/test/Analysis/debug-iterator-modeling.cpp @@ -30,15 +30,12 @@ void iterator_position(const std::vector v0) { auto b0 = v0.begin(), e0 = v0.end(); - clang_analyzer_denote(clang_analyzer_iterator_position(b0), "$b0"); - clang_analyzer_denote(clang_analyzer_iterator_position(e0), "$e0"); + clang_analyzer_denote(clang_analyzer_container_begin(v0), "$b0"); + clang_analyzer_denote(clang_analyzer_container_end(v0), "$e0"); clang_analyzer_express(clang_analyzer_iterator_position(b0)); // expected-warning{{$b0}} clang_analyzer_express(clang_analyzer_iterator_position(e0)); // expected-warning{{$e0}} - clang_analyzer_express(clang_analyzer_container_begin(v0)); // expected-warning{{$b0}} - clang_analyzer_express(clang_analyzer_container_end(v0)); // expected-warning{{$e0}} - ++b0; clang_analyzer_express(clang_analyzer_iterator_position(b0)); // expected-warning{{$b0 + 1}} Index: clang/test/Analysis/iterator-modelling.cpp =================================================================== --- clang/test/Analysis/iterator-modelling.cpp +++ clang/test/Analysis/iterator-modelling.cpp @@ -246,7 +246,6 @@ clang_analyzer_eval(clang_analyzer_iterator_container(i1) == &L1); // expected-warning{{TRUE}} clang_analyzer_eval(clang_analyzer_iterator_container(i2) == &L1); // expected-warning{{TRUE}} - clang_analyzer_express(clang_analyzer_container_begin(L1)); // expected-warning{{$L2.begin()}} clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$L2.begin()}} } @@ -265,7 +264,6 @@ clang_analyzer_eval(clang_analyzer_iterator_container(i1) == &V1); // expected-warning{{TRUE}} clang_analyzer_eval(clang_analyzer_iterator_container(i2) == &V1); // expected-warning{{TRUE}} - clang_analyzer_express(clang_analyzer_container_begin(V1)); // expected-warning{{$V2.begin()}} clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$V2.begin()}} } @@ -284,7 +282,6 @@ clang_analyzer_eval(clang_analyzer_iterator_container(i1) == &D1); // expected-warning{{TRUE}} clang_analyzer_eval(clang_analyzer_iterator_container(i2) == &D1); // expected-warning{{TRUE}} - clang_analyzer_express(clang_analyzer_container_begin(D1)); // expected-warning{{$D2.begin()}} clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$D2.begin()}} } @@ -302,7 +299,6 @@ clang_analyzer_eval(clang_analyzer_iterator_container(i1) == &FL1); // expected-warning{{TRUE}} - clang_analyzer_express(clang_analyzer_container_begin(FL1)); // expected-warning{{$FL2.begin()}} clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$FL2.begin()}} } @@ -400,10 +396,7 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{TRUE}} - clang_analyzer_express(clang_analyzer_container_begin(L)); // expected-warning{{$L.begin()}} clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$L.begin()}} - - clang_analyzer_express(clang_analyzer_container_end(L)); // expected-warning{{$L.end() + 1}} clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$L.end() - 1}} clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning{{$L.end()}} FIXME: Should be $L.end() + 1 } @@ -422,10 +415,7 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} - clang_analyzer_express(clang_analyzer_container_begin(V)); // expected-warning{{$V.begin()}} clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$V.begin()}} - - clang_analyzer_express(clang_analyzer_container_end(V)); // expected-warning{{$V.end() + 1}} clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$V.end() - 1}} } @@ -443,9 +433,6 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{FALSE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} - - clang_analyzer_express(clang_analyzer_container_begin(D)); // expected-warning{{$D.begin()}} - clang_analyzer_express(clang_analyzer_container_end(D)); // expected-warning{{$D.end()}} FIXME: Should be $D.end() + 1 (to correctly track the container's size) } /// emplace_back() @@ -469,10 +456,7 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{TRUE}} - clang_analyzer_express(clang_analyzer_container_begin(L)); // expected-warning{{$L.begin()}} clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$L.begin()}} - - clang_analyzer_express(clang_analyzer_container_end(L)); // expected-warning{{$L.end() + 1}} clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$L.end()}} clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning{{$L.end()}} FIXME: Should be $L.end() + 1 } @@ -491,10 +475,7 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} - clang_analyzer_express(clang_analyzer_container_begin(V)); // expected-warning{{$V.begin()}} clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$V.begin()}} - - clang_analyzer_express(clang_analyzer_container_end(V)); // expected-warning{{$V.end() + 1}} clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$V.end() - 1}} } @@ -512,9 +493,6 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{FALSE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} - - clang_analyzer_express(clang_analyzer_container_begin(D)); // expected-warning{{$D.begin()}} - clang_analyzer_express(clang_analyzer_container_end(D)); // expected-warning{{$D.end()}} FIXME: Should be $D.end() + 1 (to correctly track the container's size) } /// pop_back() @@ -538,10 +516,7 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{TRUE}} - clang_analyzer_express(clang_analyzer_container_begin(L)); // expected-warning{{$L.begin()}} clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$L.begin()}} - - clang_analyzer_express(clang_analyzer_container_end(L)); // expected-warning{{$L.end() - 1}} clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning{{$L.end()}} FIXME: Should be $L.end() - 1 } @@ -560,10 +535,7 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} - clang_analyzer_express(clang_analyzer_container_begin(V)); // expected-warning{{$V.begin()}} clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$V.begin()}} - - clang_analyzer_express(clang_analyzer_container_end(V)); // expected-warning{{$V.end() - 1}} } /// std::deque-like containers: Iterators to the last element are invalidated. @@ -582,10 +554,7 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} - clang_analyzer_express(clang_analyzer_container_begin(D)); // expected-warning{{$D.begin()}} clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$D.begin()}} - - clang_analyzer_express(clang_analyzer_container_end(D)); // expected-warning{{$D.end() - 1}} } /// push_front() @@ -608,10 +577,7 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} - clang_analyzer_express(clang_analyzer_container_begin(L)); // expected-warning{{$L.begin() - 1}} clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$L.begin()}} - - clang_analyzer_express(clang_analyzer_container_end(L)); // expected-warning{{$L.end()}} clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$L.end()}} } @@ -629,10 +595,6 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{FALSE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} - - 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_end(D)); // expected-warning{{$D.end()}} } /// std::forward_list-like containers: No iterators are invalidated. @@ -648,10 +610,7 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} - clang_analyzer_express(clang_analyzer_container_begin(FL)); // expected-warning{{$FL.begin() - 1}} clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$FL.begin()}} - - clang_analyzer_express(clang_analyzer_container_end(FL)); // expected-warning{{$FL.end()}} clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$FL.end()}} } @@ -675,10 +634,7 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} - clang_analyzer_express(clang_analyzer_container_begin(L)); // expected-warning{{$L.begin() - 1}} clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$L.begin()}} - - clang_analyzer_express(clang_analyzer_container_end(L)); // expected-warning{{$L.end()}} clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$L.end()}} } @@ -696,10 +652,6 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{FALSE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} - - 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_end(D)); // expected-warning{{$D.end()}} } /// std::forward_list-like containers: No iterators are invalidated. @@ -715,10 +667,7 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} - clang_analyzer_express(clang_analyzer_container_begin(FL)); // expected-warning{{$FL.begin() - 1}} clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$FL.begin()}} - - clang_analyzer_express(clang_analyzer_container_end(FL)); // expected-warning{{$FL.end()}} clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$FL.end()}} } @@ -743,10 +692,7 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{TRUE}} - clang_analyzer_express(clang_analyzer_container_begin(L)); // expected-warning{{$L.begin() + 1}} clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$L.begin() + 1}} - - clang_analyzer_express(clang_analyzer_container_end(L)); // expected-warning{{$L.end()}} clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning{{$L.end()}} } @@ -765,10 +711,7 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{TRUE}} - clang_analyzer_express(clang_analyzer_container_begin(D)); // expected-warning{{$D.begin() + 1}} clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$D.begin() + 1}} - - clang_analyzer_express(clang_analyzer_container_end(D)); // expected-warning{{$D.end()}} clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning{{$D.end()}} } @@ -787,10 +730,7 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{TRUE}} - clang_analyzer_express(clang_analyzer_container_begin(FL)); // expected-warning{{$FL.begin() + 1}} clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$FL.begin() + 1}} - - clang_analyzer_express(clang_analyzer_container_end(FL)); // expected-warning{{$FL.end()}} clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning{{$FL.end()}} } @@ -817,11 +757,8 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} - clang_analyzer_express(clang_analyzer_container_begin(L)); // expected-warning{{$L.begin()}} FIXME: Should be $L.begin() - 1 clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$L.begin()}} // clang_analyzer_express(clang_analyzer_iterator_position(i2)); FIXME: expect warning $L.begin() - 1 - - clang_analyzer_express(clang_analyzer_container_end(L)); // expected-warning{{$L.end()}} clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$L.end()}} } @@ -837,12 +774,9 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{TRUE}} - clang_analyzer_express(clang_analyzer_container_begin(L)); // expected-warning{{$L.begin()}} FIXME: Should be $L.begin() - 1 clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$L.begin()}} FIXME: Should be $L.begin() - 1 clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$L.begin() + 1}} // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $L.begin() - - clang_analyzer_express(clang_analyzer_container_end(L)); // expected-warning{{$L.end()}} clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning{{$L.end()}} } @@ -861,13 +795,9 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{TRUE}} - clang_analyzer_express(clang_analyzer_container_begin(L)); // expected-warning{{$L.begin()}} clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$L.begin()}} - clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$i1}} // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $i - 1 - - clang_analyzer_express(clang_analyzer_container_end(L)); // expected-warning{{$L.end()}} clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning{{$L.end()}} } @@ -883,10 +813,7 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{TRUE}} - clang_analyzer_express(clang_analyzer_container_begin(L)); // expected-warning{{$L.begin()}} clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$L.begin()}} - - clang_analyzer_express(clang_analyzer_container_end(L)); // expected-warning{{$L.end()}} clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$L.end() - 1}} clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning{{$L.end()}} // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $L.end() - 2 @@ -904,10 +831,7 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{TRUE}} - clang_analyzer_express(clang_analyzer_container_begin(L)); // expected-warning{{$L.begin()}} clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$L.begin()}} - - clang_analyzer_express(clang_analyzer_container_end(L)); // expected-warning{{$L.end()}} clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$L.end() - 1}} FIXME: should be $L.end() - 2 clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning{{$L.end()}} // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $L.end() - 1 @@ -928,10 +852,7 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{FALSE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} - clang_analyzer_express(clang_analyzer_container_begin(V)); // expected-warning{{$V.begin()}} FIXME: Should be $V.begin() - 1 // clang_analyzer_express(clang_analyzer_iterator_position(i2)); FIXME: expect warning $V.begin() - 1 - - // clang_analyzer_express(clang_analyzer_container_end(V)); // FIXME: expect warning $V.end() } void vector_insert_behind_begin(std::vector &V, int n) { @@ -946,11 +867,8 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} - clang_analyzer_express(clang_analyzer_container_begin(V)); // expected-warning{{$V.begin()}} FIXME: Should be $V.begin() - 1 clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$V.begin()}} FIXME: Should be $V.begin() - 1 // clang_analyzer_express(clang_analyzer_iterator_position(i3)); // FIXME: expect -warning $V.begin() - - // clang_analyzer_express(clang_analyzer_container_end(V)); // FIXME: expect warning $V.end() } void vector_insert_unknown(std::vector &V, int n) { @@ -966,12 +884,8 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} - clang_analyzer_express(clang_analyzer_container_begin(V)); // expected-warning{{$V.begin()}} clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$V.begin()}} - // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expecte warning $i1 - 1 - - // clang_analyzer_express(clang_analyzer_container_end(V)); FIXME expect warning $V.end() } void vector_insert_ahead_of_end(std::vector &V, int n) { @@ -986,10 +900,7 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} - clang_analyzer_express(clang_analyzer_container_begin(V)); // expected-warning{{$V.begin()}} clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$V.begin()}} - - // clang_analyzer_express(clang_analyzer_container_end(V)); FIXME: expect warning $V.end() + 1 // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $V.end() - 2 } @@ -1005,10 +916,7 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} - clang_analyzer_express(clang_analyzer_container_begin(V)); // expected-warning{{$V.begin()}} clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$V.begin()}} - - // clang_analyzer_express(clang_analyzer_container_end(V)); FIXME: expect warning $V.end() clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$V.end() - 1}} FIXME: Should be $V.end() - 2 // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $V.end() - 1 } @@ -1027,10 +935,7 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{FALSE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} - clang_analyzer_express(clang_analyzer_container_begin(D)); // expected-warning{{$D.begin()}} FIXME: Should be $D.begin() - 1 // clang_analyzer_express(clang_analyzer_iterator_position(i2)); FIXME: expect warning $D.begin() - 1 - - // clang_analyzer_express(clang_analyzer_container_end(D)); FIXME: expect warning $D.end() } void deque_insert_behind_begin(std::deque &D, int n) { @@ -1045,10 +950,7 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} - clang_analyzer_express(clang_analyzer_container_begin(D)); // expected-warning{{$D.begin()}} FIXME: Should be $D.begin - 1 // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $D.begin() - 1 - - // clang_analyzer_express(clang_analyzer_container_end(D)); FIXME: expect warning $D.end() } void deque_insert_unknown(std::deque &D, int n) { @@ -1064,11 +966,7 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} - clang_analyzer_express(clang_analyzer_container_begin(D)); // expected-warning{{$D.begin()}} - // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $i1 - 1 - - // clang_analyzer_express(clang_analyzer_container_end(D)); FIXME: expect warning $D.end() } void deque_insert_ahead_of_end(std::deque &D, int n) { @@ -1083,9 +981,6 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} - clang_analyzer_express(clang_analyzer_container_begin(D)); // expected-warning{{$D.begin()}} - - // clang_analyzer_express(clang_analyzer_container_end(D)); FIXME: expect warning $D.end() + 1 // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $D.end() - 2 } @@ -1101,9 +996,6 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} - clang_analyzer_express(clang_analyzer_container_begin(D)); // expected-warning{{$D.begin()}} - - // clang_analyzer_express(clang_analyzer_container_end(D)); FIXME: expect warning $D.end() // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $D.end() - 1 } @@ -1128,11 +1020,8 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} - clang_analyzer_express(clang_analyzer_container_begin(FL)); // expected-warning{{$FL.begin()}} clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$FL.begin()}} // clang_analyzer_express(clang_analyzer_iterator_position(i2)); FIXME: expect warning $FL.begin() + 1 - - clang_analyzer_express(clang_analyzer_container_end(FL)); // expected-warning{{$FL.end()}} clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$FL.end()}} } @@ -1148,12 +1037,9 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{TRUE}} - clang_analyzer_express(clang_analyzer_container_begin(FL)); // expected-warning{{$FL.begin()}} clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$FL.begin()}} clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$FL.begin() + 1}} // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $FL.begin() + 2 - - clang_analyzer_express(clang_analyzer_container_end(FL)); // expected-warning{{$FL.end()}} clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning{{$FL.end()}} } @@ -1170,13 +1056,9 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{TRUE}} - clang_analyzer_express(clang_analyzer_container_begin(FL)); // expected-warning{{$FL.begin()}} clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$FL.begin()}} - clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$i1}} // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $i1 + 1 - - clang_analyzer_express(clang_analyzer_container_end(FL)); // expected-warning{{$FL.end()}} clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning{{$FL.end()}} } @@ -1203,11 +1085,8 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} - clang_analyzer_express(clang_analyzer_container_begin(L)); // expected-warning{{$L.begin()}} FIXME: Should be $L.begin() - 1 clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$L.begin()}} // clang_analyzer_express(clang_analyzer_iterator_position(i2)); FIXME: expect warning $L.begin() - 1 - - clang_analyzer_express(clang_analyzer_container_end(L)); // expected-warning{{$L.end()}} clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$L.end()}} } @@ -1223,12 +1102,9 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{TRUE}} - clang_analyzer_express(clang_analyzer_container_begin(L)); // expected-warning{{$L.begin()}} FIXME: Should be $L.begin() - 1 clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$L.begin()}} FIXME: Should be $L.begin() - 1 clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$L.begin() + 1}} // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $L.begin() - - clang_analyzer_express(clang_analyzer_container_end(L)); // expected-warning{{$L.end()}} clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning{{$L.end()}} } @@ -1247,13 +1123,9 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{TRUE}} - clang_analyzer_express(clang_analyzer_container_begin(L)); // expected-warning{{$L.begin()}} clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$L.begin()}} - clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$i1}} // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $i - 1 - - clang_analyzer_express(clang_analyzer_container_end(L)); // expected-warning{{$L.end()}} clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning{{$L.end()}} } @@ -1269,10 +1141,7 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{TRUE}} - clang_analyzer_express(clang_analyzer_container_begin(L)); // expected-warning{{$L.begin()}} clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$L.begin()}} - - clang_analyzer_express(clang_analyzer_container_end(L)); // expected-warning{{$L.end()}} clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$L.end() - 1}} clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning{{$L.end()}} // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $L.end() - 2 @@ -1290,10 +1159,7 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{TRUE}} - clang_analyzer_express(clang_analyzer_container_begin(L)); // expected-warning{{$L.begin()}} clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$L.begin()}} - - clang_analyzer_express(clang_analyzer_container_end(L)); // expected-warning{{$L.end()}} clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$L.end() - 1}} FIXME: should be $L.end() - 2 clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning{{$L.end()}} // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $L.end() - 1 @@ -1313,11 +1179,7 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{FALSE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} - - clang_analyzer_express(clang_analyzer_container_begin(V)); // expected-warning{{$V.begin()}} FIXME: Should be $V.begin() - 1 // clang_analyzer_express(clang_analyzer_iterator_position(i2)); FIXME: expect warning $V.begin() - 1 - - // clang_analyzer_express(clang_analyzer_container_end(V)); // FIXME: expect warning $V.end() } void vector_emplace_behind_begin(std::vector &V, int n) { @@ -1332,11 +1194,8 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} - clang_analyzer_express(clang_analyzer_container_begin(V)); // expected-warning{{$V.begin()}} FIXME: Should be $V.begin() - 1 clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$V.begin()}} FIXME: Should be $V.begin() - 1 // clang_analyzer_express(clang_analyzer_iterator_position(i3)); // FIXME: expect -warning $V.begin() - - // clang_analyzer_express(clang_analyzer_container_end(V)); // FIXME: expect warning $V.end() } void vector_emplace_unknown(std::vector &V, int n) { @@ -1352,12 +1211,8 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} - clang_analyzer_express(clang_analyzer_container_begin(V)); // expected-warning{{$V.begin()}} clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$V.begin()}} - // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expecte warning $i1 - 1 - - // clang_analyzer_express(clang_analyzer_container_end(V)); FIXME expect warning $V.end() } void vector_emplace_ahead_of_end(std::vector &V, int n) { @@ -1372,10 +1227,7 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} - clang_analyzer_express(clang_analyzer_container_begin(V)); // expected-warning{{$V.begin()}} clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$V.begin()}} - - // clang_analyzer_express(clang_analyzer_container_end(V)); FIXME: expect warning $V.end() + 1 // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $V.end() - 2 } @@ -1391,10 +1243,7 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} - clang_analyzer_express(clang_analyzer_container_begin(V)); // expected-warning{{$V.begin()}} clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$V.begin()}} - - // clang_analyzer_express(clang_analyzer_container_end(V)); FIXME: expect warning $V.end() clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$V.end() - 1}} FIXME: Should be $V.end() - 2 // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $V.end() - 1 } @@ -1412,11 +1261,7 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{FALSE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} - - clang_analyzer_express(clang_analyzer_container_begin(D)); // expected-warning{{$D.begin()}} FIXME: Should be $D.begin() - 1 // clang_analyzer_express(clang_analyzer_iterator_position(i2)); FIXME: expect warning $D.begin() - 1 - - // clang_analyzer_express(clang_analyzer_container_end(D)); FIXME: expect warning $D.end() } void deque_emplace_behind_begin(std::deque &D, int n) { @@ -1430,11 +1275,7 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{FALSE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} - - clang_analyzer_express(clang_analyzer_container_begin(D)); // expected-warning{{$D.begin()}} FIXME: Should be $D.begin - 1 // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $D.begin() - 1 - - // clang_analyzer_express(clang_analyzer_container_end(D)); FIXME: expect warning $D.end() } void deque_emplace_unknown(std::deque &D, int n) { @@ -1450,11 +1291,7 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} - clang_analyzer_express(clang_analyzer_container_begin(D)); // expected-warning{{$D.begin()}} - // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $i1 - 1 - - // clang_analyzer_express(clang_analyzer_container_end(D)); FIXME: expect warning $D.end() } void deque_emplace_ahead_of_end(std::deque &D, int n) { @@ -1469,9 +1306,6 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} - clang_analyzer_express(clang_analyzer_container_begin(D)); // expected-warning{{$D.begin()}} - - // clang_analyzer_express(clang_analyzer_container_end(D)); FIXME: expect warning $D.end() + 1 // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $D.end() - 2 } @@ -1487,9 +1321,6 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} - clang_analyzer_express(clang_analyzer_container_begin(D)); // expected-warning{{$D.begin()}} - - // clang_analyzer_express(clang_analyzer_container_end(D)); FIXME: expect warning $D.end() // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $D.end() - 1 } @@ -1514,11 +1345,8 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} - clang_analyzer_express(clang_analyzer_container_begin(FL)); // expected-warning{{$FL.begin()}} clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$FL.begin()}} // clang_analyzer_express(clang_analyzer_iterator_position(i2)); FIXME: expect warning $FL.begin() + 1 - - clang_analyzer_express(clang_analyzer_container_end(FL)); // expected-warning{{$FL.end()}} clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$FL.end()}} } @@ -1535,12 +1363,9 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{TRUE}} - clang_analyzer_express(clang_analyzer_container_begin(FL)); // expected-warning{{$FL.begin()}} clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$FL.begin()}} clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$FL.begin() + 1}} // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $FL.begin() + 2 - - clang_analyzer_express(clang_analyzer_container_end(FL)); // expected-warning{{$FL.end()}} clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning{{$FL.end()}} } @@ -1557,13 +1382,9 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{TRUE}} - clang_analyzer_express(clang_analyzer_container_begin(FL)); // expected-warning{{$FL.begin()}} clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$FL.begin()}} - clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$i1}} // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $i1 + 1 - - clang_analyzer_express(clang_analyzer_container_end(FL)); // expected-warning{{$FL.end()}} clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning{{$FL.end()}} } @@ -1592,11 +1413,8 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{TRUE}} - clang_analyzer_express(clang_analyzer_container_begin(L)); // expected-warning{{$L.begin()}} FIXME: Should be$L.begin() + 1 clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$L.begin() + 1}} // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $L.begin() + 1 - - clang_analyzer_express(clang_analyzer_container_end(L)); // expected-warning{{$L.end()}} clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning{{$L.end()}} } @@ -1612,11 +1430,8 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{TRUE}} - clang_analyzer_express(clang_analyzer_container_begin(L)); // expected-warning{{$L.begin()}} FIXME: Should be $L.begin() + 1 clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$L.begin()}} FIXME: Should be $L.begin() + 1 // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $L.begin() + 2 - - clang_analyzer_express(clang_analyzer_container_end(L)); // expected-warning{{$L.end()}} clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning{{$L.end()}} } @@ -1633,12 +1448,8 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{TRUE}} - clang_analyzer_express(clang_analyzer_container_begin(L)); // expected-warning{{$L.begin()}} clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$L.begin()}} - // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $i1 + 1 - - clang_analyzer_express(clang_analyzer_container_end(L)); // expected-warning{{$L.end()}} clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning{{$L.end()}} } @@ -1654,10 +1465,7 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{TRUE}} - clang_analyzer_express(clang_analyzer_container_begin(L)); // expected-warning{{$L.begin()}} clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$L.begin()}} - - clang_analyzer_express(clang_analyzer_container_end(L)); // expected-warning{{$L.end()}} clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning{{$L.end()}} // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $L.end() } @@ -1677,10 +1485,7 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} - clang_analyzer_express(clang_analyzer_container_begin(V)); // expected-warning{{$V.begin()}} FIXME: Should be $V.begin() + 1 // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $V.begin() + 1 - - // clang_analyzer_express(clang_analyzer_container_end(V)); FIXME: expect warning $V.end() } void vector_erase_behind_begin(std::vector &V, int n) { @@ -1695,11 +1500,8 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} - clang_analyzer_express(clang_analyzer_container_begin(V)); // expected-warning{{$V.begin()}} FIXME: Should be $V.begin() + 1 clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$V.begin()}} FIXME: Should be $V.begin() + 1 // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $V.begin() + 2 - - // clang_analyzer_express(clang_analyzer_container_end(V)); FIXME: expect warning $V.end() } void vector_erase_unknown(std::vector &V) { @@ -1715,12 +1517,8 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} - clang_analyzer_express(clang_analyzer_container_begin(V)); // expected-warning{{$V.begin()}} clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$V.begin()}} - // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $i1 + 1 - - // clang_analyzer_express(clang_analyzer_container_end(V)); FIXME: expect warning $V.end() } void vector_erase_ahead_of_end(std::vector &V) { @@ -1735,10 +1533,7 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} - clang_analyzer_express(clang_analyzer_container_begin(V)); // expected-warning{{$V.begin()}} clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$V.begin()}} - - // clang_analyzer_express(clang_analyzer_container_end(V)); FIXME: expect warning $V.end() // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $V.end() } @@ -1762,10 +1557,7 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} - clang_analyzer_express(clang_analyzer_container_begin(D)); // expected-warning{{$D.begin()}} FIXME: Should be $D.begin() + 1 // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $D.begin() + 1 - - // clang_analyzer_express(clang_analyzer_container_end(D)); FIXME: expect warning{{$D.end() } void deque_erase_behind_begin(std::deque &D, int n) { @@ -1780,10 +1572,7 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} - clang_analyzer_express(clang_analyzer_container_begin(D)); // expected-warning{{$D.begin()}} FIXME: Should be $D.begin() + 1 // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $D.begin() + 2 - - // clang_analyzer_express(clang_analyzer_container_end(D)); FIXME: expect warning $D.end() } void deque_erase_unknown(std::deque &D) { @@ -1799,11 +1588,7 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} - clang_analyzer_express(clang_analyzer_container_begin(D)); // expected-warning{{$D.begin()}} - // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $i1 + 1 - - // clang_analyzer_express(clang_analyzer_container_end(D)); FIXME: expect warning $D.end() } void deque_erase_ahead_of_end(std::deque &D) { @@ -1818,9 +1603,6 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} - clang_analyzer_express(clang_analyzer_container_begin(D)); // expected-warning{{$D.begin()}} - - // clang_analyzer_express(clang_analyzer_container_end(D)); FIXME: expect warning $D.end() // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $D.end() } @@ -1851,12 +1633,9 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{TRUE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i3)); //expected-warning{{TRUE}} - clang_analyzer_express(clang_analyzer_container_begin(FL)); // expected-warning{{$FL.begin()}} clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$FL.begin()}} clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning{{$FL.begin() + 2}} FIXME: Should be $FL.begin() + 1 // clang_analyzer_express(clang_analyzer_iterator_position(i4)); FIXME: expect warning $FL.begin() + 1 - - clang_analyzer_express(clang_analyzer_container_end(FL)); // expected-warning{{$FL.end()}} clang_analyzer_express(clang_analyzer_iterator_position(i3)); // expected-warning{{$FL.end()}} } @@ -1879,14 +1658,10 @@ clang_analyzer_eval(clang_analyzer_iterator_validity(i3)); //expected-warning{{TRUE}} clang_analyzer_eval(clang_analyzer_iterator_validity(i4)); //expected-warning{{TRUE}} - clang_analyzer_express(clang_analyzer_container_begin(FL)); // expected-warning{{$FL.begin()}} clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$FL.begin()}} - clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$i1}} clang_analyzer_express(clang_analyzer_iterator_position(i3)); // expected-warning{{$i1 + 2}} FIXME: Should be $i1 + 1 // clang_analyzer_express(clang_analyzer_iterator_position(i5)); FIXME: expect warning $i1 + 1 - - clang_analyzer_express(clang_analyzer_container_end(FL)); // expected-warning{{$FL.end()}} clang_analyzer_express(clang_analyzer_iterator_position(i4)); // expected-warning{{$FL.end()}} } @@ -1981,9 +1756,7 @@ clang_analyzer_printState(); // CHECK: "checker_messages": [ -// CHECK-NEXT: { "checker": "alpha.cplusplus.IteratorModeling", "messages": [ -// CHECK-NEXT: "Container Data :", -// CHECK-NEXT: "SymRegion{reg_$[[#]] & V>} : [ conj_$[[#]]{long, LC[[#]], S[[#]], #[[#]]} .. ]", +// CHECK: { "checker": "alpha.cplusplus.IteratorModeling", "messages": [ // CHECK-NEXT: "Iterator Positions :", // CHECK-NEXT: "i0 : Valid ; Container == SymRegion{reg_$[[#]] & V>} ; Offset == conj_$[[#]]{long, LC[[#]], S[[#]], #[[#]]}" // CHECK-NEXT: ]} @@ -1992,9 +1765,7 @@ clang_analyzer_printState(); // CHECK: "checker_messages": [ -// CHECK-NEXT: { "checker": "alpha.cplusplus.IteratorModeling", "messages": [ -// CHECK-NEXT: "Container Data :", -// CHECK-NEXT: "SymRegion{reg_$[[#]] & V>} : [ conj_$[[#]]{long, LC[[#]], S[[#]], #[[#]]} .. conj_$[[#]]{long, LC[[#]], S[[#]], #[[#]]} ]", +// CHECK: { "checker": "alpha.cplusplus.IteratorModeling", "messages": [ // CHECK-NEXT: "Iterator Positions :", // CHECK-NEXT: "i1 : Valid ; Container == SymRegion{reg_$[[#]] & V>} ; Offset == conj_$[[#]]{long, LC[[#]], S[[#]], #[[#]]}" // CHECK-NEXT: ]}