xref: /freebsd/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp (revision fe6060f10f634930ff71b7c50291ddc610da2475)
15ffd83dbSDimitry Andric //===-- ContainerModeling.cpp -------------------------------------*- C++ -*--//
25ffd83dbSDimitry Andric //
35ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65ffd83dbSDimitry Andric //
75ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
85ffd83dbSDimitry Andric //
95ffd83dbSDimitry Andric // Defines a modeling-checker for modeling STL container-like containers.
105ffd83dbSDimitry Andric //
115ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
125ffd83dbSDimitry Andric 
135ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
145ffd83dbSDimitry Andric #include "clang/AST/DeclTemplate.h"
155ffd83dbSDimitry Andric #include "clang/Driver/DriverDiagnostic.h"
165ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
175ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Core/Checker.h"
185ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
195ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
205ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h"
215ffd83dbSDimitry Andric 
225ffd83dbSDimitry Andric #include "Iterator.h"
235ffd83dbSDimitry Andric 
245ffd83dbSDimitry Andric #include <utility>
255ffd83dbSDimitry Andric 
265ffd83dbSDimitry Andric using namespace clang;
275ffd83dbSDimitry Andric using namespace ento;
285ffd83dbSDimitry Andric using namespace iterator;
295ffd83dbSDimitry Andric 
305ffd83dbSDimitry Andric namespace {
315ffd83dbSDimitry Andric 
325ffd83dbSDimitry Andric class ContainerModeling
335ffd83dbSDimitry Andric   : public Checker<check::PostCall, check::LiveSymbols, check::DeadSymbols> {
345ffd83dbSDimitry Andric 
355ffd83dbSDimitry Andric   void handleBegin(CheckerContext &C, const Expr *CE, SVal RetVal,
365ffd83dbSDimitry Andric                    SVal Cont) const;
375ffd83dbSDimitry Andric   void handleEnd(CheckerContext &C, const Expr *CE, SVal RetVal,
385ffd83dbSDimitry Andric                  SVal Cont) const;
395ffd83dbSDimitry Andric   void handleAssignment(CheckerContext &C, SVal Cont, const Expr *CE = nullptr,
405ffd83dbSDimitry Andric                         SVal OldCont = UndefinedVal()) const;
415ffd83dbSDimitry Andric   void handleAssign(CheckerContext &C, SVal Cont, const Expr *ContE) const;
425ffd83dbSDimitry Andric   void handleClear(CheckerContext &C, SVal Cont, const Expr *ContE) const;
435ffd83dbSDimitry Andric   void handlePushBack(CheckerContext &C, SVal Cont, const Expr *ContE) const;
445ffd83dbSDimitry Andric   void handlePopBack(CheckerContext &C, SVal Cont, const Expr *ContE) const;
455ffd83dbSDimitry Andric   void handlePushFront(CheckerContext &C, SVal Cont, const Expr *ContE) const;
465ffd83dbSDimitry Andric   void handlePopFront(CheckerContext &C, SVal Cont, const Expr *ContE) const;
475ffd83dbSDimitry Andric   void handleInsert(CheckerContext &C, SVal Cont, SVal Iter) const;
485ffd83dbSDimitry Andric   void handleErase(CheckerContext &C, SVal Cont, SVal Iter) const;
495ffd83dbSDimitry Andric   void handleErase(CheckerContext &C, SVal Cont, SVal Iter1, SVal Iter2) const;
505ffd83dbSDimitry Andric   void handleEraseAfter(CheckerContext &C, SVal Cont, SVal Iter) const;
515ffd83dbSDimitry Andric   void handleEraseAfter(CheckerContext &C, SVal Cont, SVal Iter1,
525ffd83dbSDimitry Andric                         SVal Iter2) const;
535ffd83dbSDimitry Andric   const NoteTag *getChangeTag(CheckerContext &C, StringRef Text,
545ffd83dbSDimitry Andric                               const MemRegion *ContReg,
555ffd83dbSDimitry Andric                               const Expr *ContE) const;
565ffd83dbSDimitry Andric   void printState(raw_ostream &Out, ProgramStateRef State, const char *NL,
575ffd83dbSDimitry Andric                   const char *Sep) const override;
585ffd83dbSDimitry Andric 
595ffd83dbSDimitry Andric public:
605ffd83dbSDimitry Andric   ContainerModeling() = default;
615ffd83dbSDimitry Andric 
625ffd83dbSDimitry Andric   void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
635ffd83dbSDimitry Andric   void checkLiveSymbols(ProgramStateRef State, SymbolReaper &SR) const;
645ffd83dbSDimitry Andric   void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
655ffd83dbSDimitry Andric 
665ffd83dbSDimitry Andric   using NoItParamFn = void (ContainerModeling::*)(CheckerContext &, SVal,
675ffd83dbSDimitry Andric                                                   const Expr *) const;
685ffd83dbSDimitry Andric   using OneItParamFn = void (ContainerModeling::*)(CheckerContext &, SVal,
695ffd83dbSDimitry Andric                                                    SVal) const;
705ffd83dbSDimitry Andric   using TwoItParamFn = void (ContainerModeling::*)(CheckerContext &, SVal, SVal,
715ffd83dbSDimitry Andric                                                    SVal) const;
725ffd83dbSDimitry Andric 
735ffd83dbSDimitry Andric   CallDescriptionMap<NoItParamFn> NoIterParamFunctions = {
745ffd83dbSDimitry Andric     {{0, "clear", 0},
755ffd83dbSDimitry Andric      &ContainerModeling::handleClear},
765ffd83dbSDimitry Andric     {{0, "assign", 2},
775ffd83dbSDimitry Andric      &ContainerModeling::handleAssign},
785ffd83dbSDimitry Andric     {{0, "push_back", 1},
795ffd83dbSDimitry Andric      &ContainerModeling::handlePushBack},
805ffd83dbSDimitry Andric     {{0, "emplace_back", 1},
815ffd83dbSDimitry Andric      &ContainerModeling::handlePushBack},
825ffd83dbSDimitry Andric     {{0, "pop_back", 0},
835ffd83dbSDimitry Andric      &ContainerModeling::handlePopBack},
845ffd83dbSDimitry Andric     {{0, "push_front", 1},
855ffd83dbSDimitry Andric      &ContainerModeling::handlePushFront},
865ffd83dbSDimitry Andric     {{0, "emplace_front", 1},
875ffd83dbSDimitry Andric      &ContainerModeling::handlePushFront},
885ffd83dbSDimitry Andric     {{0, "pop_front", 0},
895ffd83dbSDimitry Andric      &ContainerModeling::handlePopFront},
905ffd83dbSDimitry Andric   };
915ffd83dbSDimitry Andric 
925ffd83dbSDimitry Andric   CallDescriptionMap<OneItParamFn> OneIterParamFunctions = {
935ffd83dbSDimitry Andric     {{0, "insert", 2},
945ffd83dbSDimitry Andric      &ContainerModeling::handleInsert},
955ffd83dbSDimitry Andric     {{0, "emplace", 2},
965ffd83dbSDimitry Andric      &ContainerModeling::handleInsert},
975ffd83dbSDimitry Andric     {{0, "erase", 1},
985ffd83dbSDimitry Andric      &ContainerModeling::handleErase},
995ffd83dbSDimitry Andric     {{0, "erase_after", 1},
1005ffd83dbSDimitry Andric      &ContainerModeling::handleEraseAfter},
1015ffd83dbSDimitry Andric   };
1025ffd83dbSDimitry Andric 
1035ffd83dbSDimitry Andric   CallDescriptionMap<TwoItParamFn> TwoIterParamFunctions = {
1045ffd83dbSDimitry Andric     {{0, "erase", 2},
1055ffd83dbSDimitry Andric      &ContainerModeling::handleErase},
1065ffd83dbSDimitry Andric     {{0, "erase_after", 2},
1075ffd83dbSDimitry Andric      &ContainerModeling::handleEraseAfter},
1085ffd83dbSDimitry Andric   };
1095ffd83dbSDimitry Andric 
1105ffd83dbSDimitry Andric };
1115ffd83dbSDimitry Andric 
1125ffd83dbSDimitry Andric bool isBeginCall(const FunctionDecl *Func);
1135ffd83dbSDimitry Andric bool isEndCall(const FunctionDecl *Func);
1145ffd83dbSDimitry Andric bool hasSubscriptOperator(ProgramStateRef State, const MemRegion *Reg);
1155ffd83dbSDimitry Andric bool frontModifiable(ProgramStateRef State, const MemRegion *Reg);
1165ffd83dbSDimitry Andric bool backModifiable(ProgramStateRef State, const MemRegion *Reg);
1175ffd83dbSDimitry Andric SymbolRef getContainerBegin(ProgramStateRef State, const MemRegion *Cont);
1185ffd83dbSDimitry Andric SymbolRef getContainerEnd(ProgramStateRef State, const MemRegion *Cont);
1195ffd83dbSDimitry Andric ProgramStateRef createContainerBegin(ProgramStateRef State,
1205ffd83dbSDimitry Andric                                      const MemRegion *Cont, const Expr *E,
1215ffd83dbSDimitry Andric                                      QualType T, const LocationContext *LCtx,
1225ffd83dbSDimitry Andric                                      unsigned BlockCount);
1235ffd83dbSDimitry Andric ProgramStateRef createContainerEnd(ProgramStateRef State, const MemRegion *Cont,
1245ffd83dbSDimitry Andric                                    const Expr *E, QualType T,
1255ffd83dbSDimitry Andric                                    const LocationContext *LCtx,
1265ffd83dbSDimitry Andric                                    unsigned BlockCount);
1275ffd83dbSDimitry Andric ProgramStateRef setContainerData(ProgramStateRef State, const MemRegion *Cont,
1285ffd83dbSDimitry Andric                                  const ContainerData &CData);
1295ffd83dbSDimitry Andric ProgramStateRef invalidateAllIteratorPositions(ProgramStateRef State,
1305ffd83dbSDimitry Andric                                                const MemRegion *Cont);
1315ffd83dbSDimitry Andric ProgramStateRef
1325ffd83dbSDimitry Andric invalidateAllIteratorPositionsExcept(ProgramStateRef State,
1335ffd83dbSDimitry Andric                                      const MemRegion *Cont, SymbolRef Offset,
1345ffd83dbSDimitry Andric                                      BinaryOperator::Opcode Opc);
1355ffd83dbSDimitry Andric ProgramStateRef invalidateIteratorPositions(ProgramStateRef State,
1365ffd83dbSDimitry Andric                                             SymbolRef Offset,
1375ffd83dbSDimitry Andric                                             BinaryOperator::Opcode Opc);
1385ffd83dbSDimitry Andric ProgramStateRef invalidateIteratorPositions(ProgramStateRef State,
1395ffd83dbSDimitry Andric                                             SymbolRef Offset1,
1405ffd83dbSDimitry Andric                                             BinaryOperator::Opcode Opc1,
1415ffd83dbSDimitry Andric                                             SymbolRef Offset2,
1425ffd83dbSDimitry Andric                                             BinaryOperator::Opcode Opc2);
1435ffd83dbSDimitry Andric ProgramStateRef reassignAllIteratorPositions(ProgramStateRef State,
1445ffd83dbSDimitry Andric                                              const MemRegion *Cont,
1455ffd83dbSDimitry Andric                                              const MemRegion *NewCont);
1465ffd83dbSDimitry Andric ProgramStateRef reassignAllIteratorPositionsUnless(ProgramStateRef State,
1475ffd83dbSDimitry Andric                                                    const MemRegion *Cont,
1485ffd83dbSDimitry Andric                                                    const MemRegion *NewCont,
1495ffd83dbSDimitry Andric                                                    SymbolRef Offset,
1505ffd83dbSDimitry Andric                                                    BinaryOperator::Opcode Opc);
1515ffd83dbSDimitry Andric ProgramStateRef rebaseSymbolInIteratorPositionsIf(
1525ffd83dbSDimitry Andric     ProgramStateRef State, SValBuilder &SVB, SymbolRef OldSym,
1535ffd83dbSDimitry Andric     SymbolRef NewSym, SymbolRef CondSym, BinaryOperator::Opcode Opc);
1545ffd83dbSDimitry Andric SymbolRef rebaseSymbol(ProgramStateRef State, SValBuilder &SVB, SymbolRef Expr,
1555ffd83dbSDimitry Andric                         SymbolRef OldSym, SymbolRef NewSym);
1565ffd83dbSDimitry Andric bool hasLiveIterators(ProgramStateRef State, const MemRegion *Cont);
1575ffd83dbSDimitry Andric 
1585ffd83dbSDimitry Andric } // namespace
1595ffd83dbSDimitry Andric 
1605ffd83dbSDimitry Andric void ContainerModeling::checkPostCall(const CallEvent &Call,
1615ffd83dbSDimitry Andric                                      CheckerContext &C) const {
1625ffd83dbSDimitry Andric   const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
1635ffd83dbSDimitry Andric   if (!Func)
1645ffd83dbSDimitry Andric     return;
1655ffd83dbSDimitry Andric 
1665ffd83dbSDimitry Andric   if (Func->isOverloadedOperator()) {
1675ffd83dbSDimitry Andric     const auto Op = Func->getOverloadedOperator();
1685ffd83dbSDimitry Andric     if (Op == OO_Equal) {
1695ffd83dbSDimitry Andric       // Overloaded 'operator=' must be a non-static member function.
1705ffd83dbSDimitry Andric       const auto *InstCall = cast<CXXInstanceCall>(&Call);
1715ffd83dbSDimitry Andric       if (cast<CXXMethodDecl>(Func)->isMoveAssignmentOperator()) {
1725ffd83dbSDimitry Andric         handleAssignment(C, InstCall->getCXXThisVal(), Call.getOriginExpr(),
1735ffd83dbSDimitry Andric                      Call.getArgSVal(0));
1745ffd83dbSDimitry Andric         return;
1755ffd83dbSDimitry Andric       }
1765ffd83dbSDimitry Andric 
1775ffd83dbSDimitry Andric       handleAssignment(C, InstCall->getCXXThisVal());
1785ffd83dbSDimitry Andric       return;
1795ffd83dbSDimitry Andric     }
1805ffd83dbSDimitry Andric   } else {
1815ffd83dbSDimitry Andric     if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
1825ffd83dbSDimitry Andric       const NoItParamFn *Handler0 = NoIterParamFunctions.lookup(Call);
1835ffd83dbSDimitry Andric       if (Handler0) {
1845ffd83dbSDimitry Andric         (this->**Handler0)(C, InstCall->getCXXThisVal(),
1855ffd83dbSDimitry Andric                            InstCall->getCXXThisExpr());
1865ffd83dbSDimitry Andric         return;
1875ffd83dbSDimitry Andric       }
1885ffd83dbSDimitry Andric 
1895ffd83dbSDimitry Andric       const OneItParamFn *Handler1 = OneIterParamFunctions.lookup(Call);
1905ffd83dbSDimitry Andric       if (Handler1) {
1915ffd83dbSDimitry Andric         (this->**Handler1)(C, InstCall->getCXXThisVal(), Call.getArgSVal(0));
1925ffd83dbSDimitry Andric         return;
1935ffd83dbSDimitry Andric       }
1945ffd83dbSDimitry Andric 
1955ffd83dbSDimitry Andric       const TwoItParamFn *Handler2 = TwoIterParamFunctions.lookup(Call);
1965ffd83dbSDimitry Andric       if (Handler2) {
1975ffd83dbSDimitry Andric         (this->**Handler2)(C, InstCall->getCXXThisVal(), Call.getArgSVal(0),
1985ffd83dbSDimitry Andric                            Call.getArgSVal(1));
1995ffd83dbSDimitry Andric         return;
2005ffd83dbSDimitry Andric       }
2015ffd83dbSDimitry Andric 
2025ffd83dbSDimitry Andric       const auto *OrigExpr = Call.getOriginExpr();
2035ffd83dbSDimitry Andric       if (!OrigExpr)
2045ffd83dbSDimitry Andric         return;
2055ffd83dbSDimitry Andric 
2065ffd83dbSDimitry Andric       if (isBeginCall(Func)) {
2075ffd83dbSDimitry Andric         handleBegin(C, OrigExpr, Call.getReturnValue(),
2085ffd83dbSDimitry Andric                     InstCall->getCXXThisVal());
2095ffd83dbSDimitry Andric         return;
2105ffd83dbSDimitry Andric       }
2115ffd83dbSDimitry Andric 
2125ffd83dbSDimitry Andric       if (isEndCall(Func)) {
2135ffd83dbSDimitry Andric         handleEnd(C, OrigExpr, Call.getReturnValue(),
2145ffd83dbSDimitry Andric                   InstCall->getCXXThisVal());
2155ffd83dbSDimitry Andric         return;
2165ffd83dbSDimitry Andric       }
2175ffd83dbSDimitry Andric     }
2185ffd83dbSDimitry Andric   }
2195ffd83dbSDimitry Andric }
2205ffd83dbSDimitry Andric 
2215ffd83dbSDimitry Andric void ContainerModeling::checkLiveSymbols(ProgramStateRef State,
2225ffd83dbSDimitry Andric                                          SymbolReaper &SR) const {
2235ffd83dbSDimitry Andric   // Keep symbolic expressions of container begins and ends alive
2245ffd83dbSDimitry Andric   auto ContMap = State->get<ContainerMap>();
2255ffd83dbSDimitry Andric   for (const auto &Cont : ContMap) {
2265ffd83dbSDimitry Andric     const auto CData = Cont.second;
2275ffd83dbSDimitry Andric     if (CData.getBegin()) {
2285ffd83dbSDimitry Andric       SR.markLive(CData.getBegin());
2295ffd83dbSDimitry Andric       if(const auto *SIE = dyn_cast<SymIntExpr>(CData.getBegin()))
2305ffd83dbSDimitry Andric         SR.markLive(SIE->getLHS());
2315ffd83dbSDimitry Andric     }
2325ffd83dbSDimitry Andric     if (CData.getEnd()) {
2335ffd83dbSDimitry Andric       SR.markLive(CData.getEnd());
2345ffd83dbSDimitry Andric       if(const auto *SIE = dyn_cast<SymIntExpr>(CData.getEnd()))
2355ffd83dbSDimitry Andric         SR.markLive(SIE->getLHS());
2365ffd83dbSDimitry Andric     }
2375ffd83dbSDimitry Andric   }
2385ffd83dbSDimitry Andric }
2395ffd83dbSDimitry Andric 
2405ffd83dbSDimitry Andric void ContainerModeling::checkDeadSymbols(SymbolReaper &SR,
2415ffd83dbSDimitry Andric                                          CheckerContext &C) const {
2425ffd83dbSDimitry Andric   // Cleanup
2435ffd83dbSDimitry Andric   auto State = C.getState();
2445ffd83dbSDimitry Andric 
2455ffd83dbSDimitry Andric   auto ContMap = State->get<ContainerMap>();
2465ffd83dbSDimitry Andric   for (const auto &Cont : ContMap) {
2475ffd83dbSDimitry Andric     if (!SR.isLiveRegion(Cont.first)) {
2485ffd83dbSDimitry Andric       // We must keep the container data while it has live iterators to be able
2495ffd83dbSDimitry Andric       // to compare them to the begin and the end of the container.
2505ffd83dbSDimitry Andric       if (!hasLiveIterators(State, Cont.first)) {
2515ffd83dbSDimitry Andric         State = State->remove<ContainerMap>(Cont.first);
2525ffd83dbSDimitry Andric       }
2535ffd83dbSDimitry Andric     }
2545ffd83dbSDimitry Andric   }
2555ffd83dbSDimitry Andric 
2565ffd83dbSDimitry Andric   C.addTransition(State);
2575ffd83dbSDimitry Andric }
2585ffd83dbSDimitry Andric 
2595ffd83dbSDimitry Andric void ContainerModeling::handleBegin(CheckerContext &C, const Expr *CE,
2605ffd83dbSDimitry Andric                                    SVal RetVal, SVal Cont) const {
2615ffd83dbSDimitry Andric   const auto *ContReg = Cont.getAsRegion();
2625ffd83dbSDimitry Andric   if (!ContReg)
2635ffd83dbSDimitry Andric     return;
2645ffd83dbSDimitry Andric 
2655ffd83dbSDimitry Andric   ContReg = ContReg->getMostDerivedObjectRegion();
2665ffd83dbSDimitry Andric 
2675ffd83dbSDimitry Andric   // If the container already has a begin symbol then use it. Otherwise first
2685ffd83dbSDimitry Andric   // create a new one.
2695ffd83dbSDimitry Andric   auto State = C.getState();
2705ffd83dbSDimitry Andric   auto BeginSym = getContainerBegin(State, ContReg);
2715ffd83dbSDimitry Andric   if (!BeginSym) {
2725ffd83dbSDimitry Andric     State = createContainerBegin(State, ContReg, CE, C.getASTContext().LongTy,
2735ffd83dbSDimitry Andric                                  C.getLocationContext(), C.blockCount());
2745ffd83dbSDimitry Andric     BeginSym = getContainerBegin(State, ContReg);
2755ffd83dbSDimitry Andric   }
2765ffd83dbSDimitry Andric   State = setIteratorPosition(State, RetVal,
2775ffd83dbSDimitry Andric                               IteratorPosition::getPosition(ContReg, BeginSym));
2785ffd83dbSDimitry Andric   C.addTransition(State);
2795ffd83dbSDimitry Andric }
2805ffd83dbSDimitry Andric 
2815ffd83dbSDimitry Andric void ContainerModeling::handleEnd(CheckerContext &C, const Expr *CE,
2825ffd83dbSDimitry Andric                                  SVal RetVal, SVal Cont) const {
2835ffd83dbSDimitry Andric   const auto *ContReg = Cont.getAsRegion();
2845ffd83dbSDimitry Andric   if (!ContReg)
2855ffd83dbSDimitry Andric     return;
2865ffd83dbSDimitry Andric 
2875ffd83dbSDimitry Andric   ContReg = ContReg->getMostDerivedObjectRegion();
2885ffd83dbSDimitry Andric 
2895ffd83dbSDimitry Andric   // If the container already has an end symbol then use it. Otherwise first
2905ffd83dbSDimitry Andric   // create a new one.
2915ffd83dbSDimitry Andric   auto State = C.getState();
2925ffd83dbSDimitry Andric   auto EndSym = getContainerEnd(State, ContReg);
2935ffd83dbSDimitry Andric   if (!EndSym) {
2945ffd83dbSDimitry Andric     State = createContainerEnd(State, ContReg, CE, C.getASTContext().LongTy,
2955ffd83dbSDimitry Andric                                C.getLocationContext(), C.blockCount());
2965ffd83dbSDimitry Andric     EndSym = getContainerEnd(State, ContReg);
2975ffd83dbSDimitry Andric   }
2985ffd83dbSDimitry Andric   State = setIteratorPosition(State, RetVal,
2995ffd83dbSDimitry Andric                               IteratorPosition::getPosition(ContReg, EndSym));
3005ffd83dbSDimitry Andric   C.addTransition(State);
3015ffd83dbSDimitry Andric }
3025ffd83dbSDimitry Andric 
3035ffd83dbSDimitry Andric void ContainerModeling::handleAssignment(CheckerContext &C, SVal Cont,
3045ffd83dbSDimitry Andric                                          const Expr *CE, SVal OldCont) const {
3055ffd83dbSDimitry Andric   const auto *ContReg = Cont.getAsRegion();
3065ffd83dbSDimitry Andric   if (!ContReg)
3075ffd83dbSDimitry Andric     return;
3085ffd83dbSDimitry Andric 
3095ffd83dbSDimitry Andric   ContReg = ContReg->getMostDerivedObjectRegion();
3105ffd83dbSDimitry Andric 
3115ffd83dbSDimitry Andric   // Assignment of a new value to a container always invalidates all its
3125ffd83dbSDimitry Andric   // iterators
3135ffd83dbSDimitry Andric   auto State = C.getState();
3145ffd83dbSDimitry Andric   const auto CData = getContainerData(State, ContReg);
3155ffd83dbSDimitry Andric   if (CData) {
3165ffd83dbSDimitry Andric     State = invalidateAllIteratorPositions(State, ContReg);
3175ffd83dbSDimitry Andric   }
3185ffd83dbSDimitry Andric 
3195ffd83dbSDimitry Andric   // In case of move, iterators of the old container (except the past-end
3205ffd83dbSDimitry Andric   // iterators) remain valid but refer to the new container
3215ffd83dbSDimitry Andric   if (!OldCont.isUndef()) {
3225ffd83dbSDimitry Andric     const auto *OldContReg = OldCont.getAsRegion();
3235ffd83dbSDimitry Andric     if (OldContReg) {
3245ffd83dbSDimitry Andric       OldContReg = OldContReg->getMostDerivedObjectRegion();
3255ffd83dbSDimitry Andric       const auto OldCData = getContainerData(State, OldContReg);
3265ffd83dbSDimitry Andric       if (OldCData) {
3275ffd83dbSDimitry Andric         if (const auto OldEndSym = OldCData->getEnd()) {
3285ffd83dbSDimitry Andric           // If we already assigned an "end" symbol to the old container, then
3295ffd83dbSDimitry Andric           // first reassign all iterator positions to the new container which
3305ffd83dbSDimitry Andric           // are not past the container (thus not greater or equal to the
3315ffd83dbSDimitry Andric           // current "end" symbol).
3325ffd83dbSDimitry Andric           State = reassignAllIteratorPositionsUnless(State, OldContReg, ContReg,
3335ffd83dbSDimitry Andric                                                      OldEndSym, BO_GE);
3345ffd83dbSDimitry Andric           auto &SymMgr = C.getSymbolManager();
3355ffd83dbSDimitry Andric           auto &SVB = C.getSValBuilder();
3365ffd83dbSDimitry Andric           // Then generate and assign a new "end" symbol for the new container.
3375ffd83dbSDimitry Andric           auto NewEndSym =
3385ffd83dbSDimitry Andric               SymMgr.conjureSymbol(CE, C.getLocationContext(),
3395ffd83dbSDimitry Andric                                    C.getASTContext().LongTy, C.blockCount());
3405ffd83dbSDimitry Andric           State = assumeNoOverflow(State, NewEndSym, 4);
3415ffd83dbSDimitry Andric           if (CData) {
3425ffd83dbSDimitry Andric             State = setContainerData(State, ContReg, CData->newEnd(NewEndSym));
3435ffd83dbSDimitry Andric           } else {
3445ffd83dbSDimitry Andric             State = setContainerData(State, ContReg,
3455ffd83dbSDimitry Andric                                      ContainerData::fromEnd(NewEndSym));
3465ffd83dbSDimitry Andric           }
3475ffd83dbSDimitry Andric           // Finally, replace the old "end" symbol in the already reassigned
3485ffd83dbSDimitry Andric           // iterator positions with the new "end" symbol.
3495ffd83dbSDimitry Andric           State = rebaseSymbolInIteratorPositionsIf(
3505ffd83dbSDimitry Andric               State, SVB, OldEndSym, NewEndSym, OldEndSym, BO_LT);
3515ffd83dbSDimitry Andric         } else {
3525ffd83dbSDimitry Andric           // There was no "end" symbol assigned yet to the old container,
3535ffd83dbSDimitry Andric           // so reassign all iterator positions to the new container.
3545ffd83dbSDimitry Andric           State = reassignAllIteratorPositions(State, OldContReg, ContReg);
3555ffd83dbSDimitry Andric         }
3565ffd83dbSDimitry Andric         if (const auto OldBeginSym = OldCData->getBegin()) {
3575ffd83dbSDimitry Andric           // If we already assigned a "begin" symbol to the old container, then
3585ffd83dbSDimitry Andric           // assign it to the new container and remove it from the old one.
3595ffd83dbSDimitry Andric           if (CData) {
3605ffd83dbSDimitry Andric             State =
3615ffd83dbSDimitry Andric                 setContainerData(State, ContReg, CData->newBegin(OldBeginSym));
3625ffd83dbSDimitry Andric           } else {
3635ffd83dbSDimitry Andric             State = setContainerData(State, ContReg,
3645ffd83dbSDimitry Andric                                      ContainerData::fromBegin(OldBeginSym));
3655ffd83dbSDimitry Andric           }
3665ffd83dbSDimitry Andric           State =
3675ffd83dbSDimitry Andric               setContainerData(State, OldContReg, OldCData->newBegin(nullptr));
3685ffd83dbSDimitry Andric         }
3695ffd83dbSDimitry Andric       } else {
3705ffd83dbSDimitry Andric         // There was neither "begin" nor "end" symbol assigned yet to the old
3715ffd83dbSDimitry Andric         // container, so reassign all iterator positions to the new container.
3725ffd83dbSDimitry Andric         State = reassignAllIteratorPositions(State, OldContReg, ContReg);
3735ffd83dbSDimitry Andric       }
3745ffd83dbSDimitry Andric     }
3755ffd83dbSDimitry Andric   }
3765ffd83dbSDimitry Andric   C.addTransition(State);
3775ffd83dbSDimitry Andric }
3785ffd83dbSDimitry Andric 
3795ffd83dbSDimitry Andric void ContainerModeling::handleAssign(CheckerContext &C, SVal Cont,
3805ffd83dbSDimitry Andric                                      const Expr *ContE) const {
3815ffd83dbSDimitry Andric   const auto *ContReg = Cont.getAsRegion();
3825ffd83dbSDimitry Andric   if (!ContReg)
3835ffd83dbSDimitry Andric     return;
3845ffd83dbSDimitry Andric 
3855ffd83dbSDimitry Andric   ContReg = ContReg->getMostDerivedObjectRegion();
3865ffd83dbSDimitry Andric 
3875ffd83dbSDimitry Andric   // The assign() operation invalidates all the iterators
3885ffd83dbSDimitry Andric   auto State = C.getState();
3895ffd83dbSDimitry Andric   State = invalidateAllIteratorPositions(State, ContReg);
3905ffd83dbSDimitry Andric   C.addTransition(State);
3915ffd83dbSDimitry Andric }
3925ffd83dbSDimitry Andric 
3935ffd83dbSDimitry Andric void ContainerModeling::handleClear(CheckerContext &C, SVal Cont,
3945ffd83dbSDimitry Andric                                     const Expr *ContE) const {
3955ffd83dbSDimitry Andric   const auto *ContReg = Cont.getAsRegion();
3965ffd83dbSDimitry Andric   if (!ContReg)
3975ffd83dbSDimitry Andric     return;
3985ffd83dbSDimitry Andric 
3995ffd83dbSDimitry Andric   ContReg = ContReg->getMostDerivedObjectRegion();
4005ffd83dbSDimitry Andric 
4015ffd83dbSDimitry Andric   // The clear() operation invalidates all the iterators, except the past-end
4025ffd83dbSDimitry Andric   // iterators of list-like containers
4035ffd83dbSDimitry Andric   auto State = C.getState();
4045ffd83dbSDimitry Andric   if (!hasSubscriptOperator(State, ContReg) ||
4055ffd83dbSDimitry Andric       !backModifiable(State, ContReg)) {
4065ffd83dbSDimitry Andric     const auto CData = getContainerData(State, ContReg);
4075ffd83dbSDimitry Andric     if (CData) {
4085ffd83dbSDimitry Andric       if (const auto EndSym = CData->getEnd()) {
4095ffd83dbSDimitry Andric         State =
4105ffd83dbSDimitry Andric             invalidateAllIteratorPositionsExcept(State, ContReg, EndSym, BO_GE);
4115ffd83dbSDimitry Andric         C.addTransition(State);
4125ffd83dbSDimitry Andric         return;
4135ffd83dbSDimitry Andric       }
4145ffd83dbSDimitry Andric     }
4155ffd83dbSDimitry Andric   }
4165ffd83dbSDimitry Andric   const NoteTag *ChangeTag =
4175ffd83dbSDimitry Andric     getChangeTag(C, "became empty", ContReg, ContE);
4185ffd83dbSDimitry Andric   State = invalidateAllIteratorPositions(State, ContReg);
4195ffd83dbSDimitry Andric   C.addTransition(State, ChangeTag);
4205ffd83dbSDimitry Andric }
4215ffd83dbSDimitry Andric 
4225ffd83dbSDimitry Andric void ContainerModeling::handlePushBack(CheckerContext &C, SVal Cont,
4235ffd83dbSDimitry Andric                                        const Expr *ContE) const {
4245ffd83dbSDimitry Andric   const auto *ContReg = Cont.getAsRegion();
4255ffd83dbSDimitry Andric   if (!ContReg)
4265ffd83dbSDimitry Andric     return;
4275ffd83dbSDimitry Andric 
4285ffd83dbSDimitry Andric   ContReg = ContReg->getMostDerivedObjectRegion();
4295ffd83dbSDimitry Andric 
4305ffd83dbSDimitry Andric   // For deque-like containers invalidate all iterator positions
4315ffd83dbSDimitry Andric   auto State = C.getState();
4325ffd83dbSDimitry Andric   if (hasSubscriptOperator(State, ContReg) && frontModifiable(State, ContReg)) {
4335ffd83dbSDimitry Andric     State = invalidateAllIteratorPositions(State, ContReg);
4345ffd83dbSDimitry Andric     C.addTransition(State);
4355ffd83dbSDimitry Andric     return;
4365ffd83dbSDimitry Andric   }
4375ffd83dbSDimitry Andric 
4385ffd83dbSDimitry Andric   const auto CData = getContainerData(State, ContReg);
4395ffd83dbSDimitry Andric   if (!CData)
4405ffd83dbSDimitry Andric     return;
4415ffd83dbSDimitry Andric 
4425ffd83dbSDimitry Andric   // For vector-like containers invalidate the past-end iterator positions
4435ffd83dbSDimitry Andric   if (const auto EndSym = CData->getEnd()) {
4445ffd83dbSDimitry Andric     if (hasSubscriptOperator(State, ContReg)) {
4455ffd83dbSDimitry Andric       State = invalidateIteratorPositions(State, EndSym, BO_GE);
4465ffd83dbSDimitry Andric     }
4475ffd83dbSDimitry Andric     auto &SymMgr = C.getSymbolManager();
4485ffd83dbSDimitry Andric     auto &BVF = SymMgr.getBasicVals();
4495ffd83dbSDimitry Andric     auto &SVB = C.getSValBuilder();
4505ffd83dbSDimitry Andric     const auto newEndSym =
4515ffd83dbSDimitry Andric       SVB.evalBinOp(State, BO_Add,
4525ffd83dbSDimitry Andric                     nonloc::SymbolVal(EndSym),
4535ffd83dbSDimitry Andric                     nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
4545ffd83dbSDimitry Andric                     SymMgr.getType(EndSym)).getAsSymbol();
4555ffd83dbSDimitry Andric     const NoteTag *ChangeTag =
4565ffd83dbSDimitry Andric       getChangeTag(C, "extended to the back by 1 position", ContReg, ContE);
4575ffd83dbSDimitry Andric     State = setContainerData(State, ContReg, CData->newEnd(newEndSym));
4585ffd83dbSDimitry Andric     C.addTransition(State, ChangeTag);
4595ffd83dbSDimitry Andric   }
4605ffd83dbSDimitry Andric }
4615ffd83dbSDimitry Andric 
4625ffd83dbSDimitry Andric void ContainerModeling::handlePopBack(CheckerContext &C, SVal Cont,
4635ffd83dbSDimitry Andric                                       const Expr *ContE) const {
4645ffd83dbSDimitry Andric   const auto *ContReg = Cont.getAsRegion();
4655ffd83dbSDimitry Andric   if (!ContReg)
4665ffd83dbSDimitry Andric     return;
4675ffd83dbSDimitry Andric 
4685ffd83dbSDimitry Andric   ContReg = ContReg->getMostDerivedObjectRegion();
4695ffd83dbSDimitry Andric 
4705ffd83dbSDimitry Andric   auto State = C.getState();
4715ffd83dbSDimitry Andric   const auto CData = getContainerData(State, ContReg);
4725ffd83dbSDimitry Andric   if (!CData)
4735ffd83dbSDimitry Andric     return;
4745ffd83dbSDimitry Andric 
4755ffd83dbSDimitry Andric   if (const auto EndSym = CData->getEnd()) {
4765ffd83dbSDimitry Andric     auto &SymMgr = C.getSymbolManager();
4775ffd83dbSDimitry Andric     auto &BVF = SymMgr.getBasicVals();
4785ffd83dbSDimitry Andric     auto &SVB = C.getSValBuilder();
4795ffd83dbSDimitry Andric     const auto BackSym =
4805ffd83dbSDimitry Andric       SVB.evalBinOp(State, BO_Sub,
4815ffd83dbSDimitry Andric                     nonloc::SymbolVal(EndSym),
4825ffd83dbSDimitry Andric                     nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
4835ffd83dbSDimitry Andric                     SymMgr.getType(EndSym)).getAsSymbol();
4845ffd83dbSDimitry Andric     const NoteTag *ChangeTag =
4855ffd83dbSDimitry Andric       getChangeTag(C, "shrank from the back by 1 position", ContReg, ContE);
4865ffd83dbSDimitry Andric     // For vector-like and deque-like containers invalidate the last and the
4875ffd83dbSDimitry Andric     // past-end iterator positions. For list-like containers only invalidate
4885ffd83dbSDimitry Andric     // the last position
4895ffd83dbSDimitry Andric     if (hasSubscriptOperator(State, ContReg) &&
4905ffd83dbSDimitry Andric         backModifiable(State, ContReg)) {
4915ffd83dbSDimitry Andric       State = invalidateIteratorPositions(State, BackSym, BO_GE);
4925ffd83dbSDimitry Andric       State = setContainerData(State, ContReg, CData->newEnd(nullptr));
4935ffd83dbSDimitry Andric     } else {
4945ffd83dbSDimitry Andric       State = invalidateIteratorPositions(State, BackSym, BO_EQ);
4955ffd83dbSDimitry Andric     }
4965ffd83dbSDimitry Andric     auto newEndSym = BackSym;
4975ffd83dbSDimitry Andric     State = setContainerData(State, ContReg, CData->newEnd(newEndSym));
4985ffd83dbSDimitry Andric     C.addTransition(State, ChangeTag);
4995ffd83dbSDimitry Andric   }
5005ffd83dbSDimitry Andric }
5015ffd83dbSDimitry Andric 
5025ffd83dbSDimitry Andric void ContainerModeling::handlePushFront(CheckerContext &C, SVal Cont,
5035ffd83dbSDimitry Andric                                         const Expr *ContE) const {
5045ffd83dbSDimitry Andric   const auto *ContReg = Cont.getAsRegion();
5055ffd83dbSDimitry Andric   if (!ContReg)
5065ffd83dbSDimitry Andric     return;
5075ffd83dbSDimitry Andric 
5085ffd83dbSDimitry Andric   ContReg = ContReg->getMostDerivedObjectRegion();
5095ffd83dbSDimitry Andric 
5105ffd83dbSDimitry Andric   // For deque-like containers invalidate all iterator positions
5115ffd83dbSDimitry Andric   auto State = C.getState();
5125ffd83dbSDimitry Andric   if (hasSubscriptOperator(State, ContReg)) {
5135ffd83dbSDimitry Andric     State = invalidateAllIteratorPositions(State, ContReg);
5145ffd83dbSDimitry Andric     C.addTransition(State);
5155ffd83dbSDimitry Andric   } else {
5165ffd83dbSDimitry Andric     const auto CData = getContainerData(State, ContReg);
5175ffd83dbSDimitry Andric     if (!CData)
5185ffd83dbSDimitry Andric       return;
5195ffd83dbSDimitry Andric 
5205ffd83dbSDimitry Andric     if (const auto BeginSym = CData->getBegin()) {
5215ffd83dbSDimitry Andric       auto &SymMgr = C.getSymbolManager();
5225ffd83dbSDimitry Andric       auto &BVF = SymMgr.getBasicVals();
5235ffd83dbSDimitry Andric       auto &SVB = C.getSValBuilder();
5245ffd83dbSDimitry Andric       const auto newBeginSym =
5255ffd83dbSDimitry Andric         SVB.evalBinOp(State, BO_Sub,
5265ffd83dbSDimitry Andric                       nonloc::SymbolVal(BeginSym),
5275ffd83dbSDimitry Andric                       nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
5285ffd83dbSDimitry Andric                       SymMgr.getType(BeginSym)).getAsSymbol();
5295ffd83dbSDimitry Andric       const NoteTag *ChangeTag =
5305ffd83dbSDimitry Andric         getChangeTag(C, "extended to the front by 1 position", ContReg, ContE);
5315ffd83dbSDimitry Andric       State = setContainerData(State, ContReg, CData->newBegin(newBeginSym));
5325ffd83dbSDimitry Andric       C.addTransition(State, ChangeTag);
5335ffd83dbSDimitry Andric     }
5345ffd83dbSDimitry Andric   }
5355ffd83dbSDimitry Andric }
5365ffd83dbSDimitry Andric 
5375ffd83dbSDimitry Andric void ContainerModeling::handlePopFront(CheckerContext &C, SVal Cont,
5385ffd83dbSDimitry Andric                                        const Expr *ContE) const {
5395ffd83dbSDimitry Andric   const auto *ContReg = Cont.getAsRegion();
5405ffd83dbSDimitry Andric   if (!ContReg)
5415ffd83dbSDimitry Andric     return;
5425ffd83dbSDimitry Andric 
5435ffd83dbSDimitry Andric   ContReg = ContReg->getMostDerivedObjectRegion();
5445ffd83dbSDimitry Andric 
5455ffd83dbSDimitry Andric   auto State = C.getState();
5465ffd83dbSDimitry Andric   const auto CData = getContainerData(State, ContReg);
5475ffd83dbSDimitry Andric   if (!CData)
5485ffd83dbSDimitry Andric     return;
5495ffd83dbSDimitry Andric 
5505ffd83dbSDimitry Andric   // For deque-like containers invalidate all iterator positions. For list-like
5515ffd83dbSDimitry Andric   // iterators only invalidate the first position
5525ffd83dbSDimitry Andric   if (const auto BeginSym = CData->getBegin()) {
5535ffd83dbSDimitry Andric     if (hasSubscriptOperator(State, ContReg)) {
5545ffd83dbSDimitry Andric       State = invalidateIteratorPositions(State, BeginSym, BO_LE);
5555ffd83dbSDimitry Andric     } else {
5565ffd83dbSDimitry Andric       State = invalidateIteratorPositions(State, BeginSym, BO_EQ);
5575ffd83dbSDimitry Andric     }
5585ffd83dbSDimitry Andric     auto &SymMgr = C.getSymbolManager();
5595ffd83dbSDimitry Andric     auto &BVF = SymMgr.getBasicVals();
5605ffd83dbSDimitry Andric     auto &SVB = C.getSValBuilder();
5615ffd83dbSDimitry Andric     const auto newBeginSym =
5625ffd83dbSDimitry Andric       SVB.evalBinOp(State, BO_Add,
5635ffd83dbSDimitry Andric                     nonloc::SymbolVal(BeginSym),
5645ffd83dbSDimitry Andric                     nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
5655ffd83dbSDimitry Andric                     SymMgr.getType(BeginSym)).getAsSymbol();
5665ffd83dbSDimitry Andric     const NoteTag *ChangeTag =
5675ffd83dbSDimitry Andric       getChangeTag(C, "shrank from the front by 1 position", ContReg, ContE);
5685ffd83dbSDimitry Andric     State = setContainerData(State, ContReg, CData->newBegin(newBeginSym));
5695ffd83dbSDimitry Andric     C.addTransition(State, ChangeTag);
5705ffd83dbSDimitry Andric   }
5715ffd83dbSDimitry Andric }
5725ffd83dbSDimitry Andric 
5735ffd83dbSDimitry Andric void ContainerModeling::handleInsert(CheckerContext &C, SVal Cont,
5745ffd83dbSDimitry Andric                                      SVal Iter) const {
5755ffd83dbSDimitry Andric   const auto *ContReg = Cont.getAsRegion();
5765ffd83dbSDimitry Andric   if (!ContReg)
5775ffd83dbSDimitry Andric     return;
5785ffd83dbSDimitry Andric 
5795ffd83dbSDimitry Andric   ContReg = ContReg->getMostDerivedObjectRegion();
5805ffd83dbSDimitry Andric 
5815ffd83dbSDimitry Andric   auto State = C.getState();
5825ffd83dbSDimitry Andric   const auto *Pos = getIteratorPosition(State, Iter);
5835ffd83dbSDimitry Andric   if (!Pos)
5845ffd83dbSDimitry Andric     return;
5855ffd83dbSDimitry Andric 
5865ffd83dbSDimitry Andric   // For deque-like containers invalidate all iterator positions. For
5875ffd83dbSDimitry Andric   // vector-like containers invalidate iterator positions after the insertion.
5885ffd83dbSDimitry Andric   if (hasSubscriptOperator(State, ContReg) && backModifiable(State, ContReg)) {
5895ffd83dbSDimitry Andric     if (frontModifiable(State, ContReg)) {
5905ffd83dbSDimitry Andric       State = invalidateAllIteratorPositions(State, ContReg);
5915ffd83dbSDimitry Andric     } else {
5925ffd83dbSDimitry Andric       State = invalidateIteratorPositions(State, Pos->getOffset(), BO_GE);
5935ffd83dbSDimitry Andric     }
5945ffd83dbSDimitry Andric     if (const auto *CData = getContainerData(State, ContReg)) {
5955ffd83dbSDimitry Andric       if (const auto EndSym = CData->getEnd()) {
5965ffd83dbSDimitry Andric         State = invalidateIteratorPositions(State, EndSym, BO_GE);
5975ffd83dbSDimitry Andric         State = setContainerData(State, ContReg, CData->newEnd(nullptr));
5985ffd83dbSDimitry Andric       }
5995ffd83dbSDimitry Andric     }
6005ffd83dbSDimitry Andric     C.addTransition(State);
6015ffd83dbSDimitry Andric   }
6025ffd83dbSDimitry Andric }
6035ffd83dbSDimitry Andric 
6045ffd83dbSDimitry Andric void ContainerModeling::handleErase(CheckerContext &C, SVal Cont,
6055ffd83dbSDimitry Andric                                     SVal Iter) const {
6065ffd83dbSDimitry Andric   const auto *ContReg = Cont.getAsRegion();
6075ffd83dbSDimitry Andric   if (!ContReg)
6085ffd83dbSDimitry Andric     return;
6095ffd83dbSDimitry Andric 
6105ffd83dbSDimitry Andric   ContReg = ContReg->getMostDerivedObjectRegion();
6115ffd83dbSDimitry Andric 
6125ffd83dbSDimitry Andric   auto State = C.getState();
6135ffd83dbSDimitry Andric   const auto *Pos = getIteratorPosition(State, Iter);
6145ffd83dbSDimitry Andric   if (!Pos)
6155ffd83dbSDimitry Andric     return;
6165ffd83dbSDimitry Andric 
6175ffd83dbSDimitry Andric   // For deque-like containers invalidate all iterator positions. For
6185ffd83dbSDimitry Andric   // vector-like containers invalidate iterator positions at and after the
6195ffd83dbSDimitry Andric   // deletion. For list-like containers only invalidate the deleted position.
6205ffd83dbSDimitry Andric   if (hasSubscriptOperator(State, ContReg) && backModifiable(State, ContReg)) {
6215ffd83dbSDimitry Andric     if (frontModifiable(State, ContReg)) {
6225ffd83dbSDimitry Andric       State = invalidateAllIteratorPositions(State, ContReg);
6235ffd83dbSDimitry Andric     } else {
6245ffd83dbSDimitry Andric       State = invalidateIteratorPositions(State, Pos->getOffset(), BO_GE);
6255ffd83dbSDimitry Andric     }
6265ffd83dbSDimitry Andric     if (const auto *CData = getContainerData(State, ContReg)) {
6275ffd83dbSDimitry Andric       if (const auto EndSym = CData->getEnd()) {
6285ffd83dbSDimitry Andric         State = invalidateIteratorPositions(State, EndSym, BO_GE);
6295ffd83dbSDimitry Andric         State = setContainerData(State, ContReg, CData->newEnd(nullptr));
6305ffd83dbSDimitry Andric       }
6315ffd83dbSDimitry Andric     }
6325ffd83dbSDimitry Andric   } else {
6335ffd83dbSDimitry Andric     State = invalidateIteratorPositions(State, Pos->getOffset(), BO_EQ);
6345ffd83dbSDimitry Andric   }
6355ffd83dbSDimitry Andric   C.addTransition(State);
6365ffd83dbSDimitry Andric }
6375ffd83dbSDimitry Andric 
6385ffd83dbSDimitry Andric void ContainerModeling::handleErase(CheckerContext &C, SVal Cont, SVal Iter1,
6395ffd83dbSDimitry Andric                                     SVal Iter2) const {
6405ffd83dbSDimitry Andric   const auto *ContReg = Cont.getAsRegion();
6415ffd83dbSDimitry Andric   if (!ContReg)
6425ffd83dbSDimitry Andric     return;
6435ffd83dbSDimitry Andric 
6445ffd83dbSDimitry Andric   ContReg = ContReg->getMostDerivedObjectRegion();
6455ffd83dbSDimitry Andric   auto State = C.getState();
6465ffd83dbSDimitry Andric   const auto *Pos1 = getIteratorPosition(State, Iter1);
6475ffd83dbSDimitry Andric   const auto *Pos2 = getIteratorPosition(State, Iter2);
6485ffd83dbSDimitry Andric   if (!Pos1 || !Pos2)
6495ffd83dbSDimitry Andric     return;
6505ffd83dbSDimitry Andric 
6515ffd83dbSDimitry Andric   // For deque-like containers invalidate all iterator positions. For
6525ffd83dbSDimitry Andric   // vector-like containers invalidate iterator positions at and after the
6535ffd83dbSDimitry Andric   // deletion range. For list-like containers only invalidate the deleted
6545ffd83dbSDimitry Andric   // position range [first..last].
6555ffd83dbSDimitry Andric   if (hasSubscriptOperator(State, ContReg) && backModifiable(State, ContReg)) {
6565ffd83dbSDimitry Andric     if (frontModifiable(State, ContReg)) {
6575ffd83dbSDimitry Andric       State = invalidateAllIteratorPositions(State, ContReg);
6585ffd83dbSDimitry Andric     } else {
6595ffd83dbSDimitry Andric       State = invalidateIteratorPositions(State, Pos1->getOffset(), BO_GE);
6605ffd83dbSDimitry Andric     }
6615ffd83dbSDimitry Andric     if (const auto *CData = getContainerData(State, ContReg)) {
6625ffd83dbSDimitry Andric       if (const auto EndSym = CData->getEnd()) {
6635ffd83dbSDimitry Andric         State = invalidateIteratorPositions(State, EndSym, BO_GE);
6645ffd83dbSDimitry Andric         State = setContainerData(State, ContReg, CData->newEnd(nullptr));
6655ffd83dbSDimitry Andric       }
6665ffd83dbSDimitry Andric     }
6675ffd83dbSDimitry Andric   } else {
6685ffd83dbSDimitry Andric     State = invalidateIteratorPositions(State, Pos1->getOffset(), BO_GE,
6695ffd83dbSDimitry Andric                                         Pos2->getOffset(), BO_LT);
6705ffd83dbSDimitry Andric   }
6715ffd83dbSDimitry Andric   C.addTransition(State);
6725ffd83dbSDimitry Andric }
6735ffd83dbSDimitry Andric 
6745ffd83dbSDimitry Andric void ContainerModeling::handleEraseAfter(CheckerContext &C, SVal Cont,
6755ffd83dbSDimitry Andric                                         SVal Iter) const {
6765ffd83dbSDimitry Andric   auto State = C.getState();
6775ffd83dbSDimitry Andric   const auto *Pos = getIteratorPosition(State, Iter);
6785ffd83dbSDimitry Andric   if (!Pos)
6795ffd83dbSDimitry Andric     return;
6805ffd83dbSDimitry Andric 
6815ffd83dbSDimitry Andric   // Invalidate the deleted iterator position, which is the position of the
6825ffd83dbSDimitry Andric   // parameter plus one.
6835ffd83dbSDimitry Andric   auto &SymMgr = C.getSymbolManager();
6845ffd83dbSDimitry Andric   auto &BVF = SymMgr.getBasicVals();
6855ffd83dbSDimitry Andric   auto &SVB = C.getSValBuilder();
6865ffd83dbSDimitry Andric   const auto NextSym =
6875ffd83dbSDimitry Andric     SVB.evalBinOp(State, BO_Add,
6885ffd83dbSDimitry Andric                   nonloc::SymbolVal(Pos->getOffset()),
6895ffd83dbSDimitry Andric                   nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
6905ffd83dbSDimitry Andric                   SymMgr.getType(Pos->getOffset())).getAsSymbol();
6915ffd83dbSDimitry Andric   State = invalidateIteratorPositions(State, NextSym, BO_EQ);
6925ffd83dbSDimitry Andric   C.addTransition(State);
6935ffd83dbSDimitry Andric }
6945ffd83dbSDimitry Andric 
6955ffd83dbSDimitry Andric void ContainerModeling::handleEraseAfter(CheckerContext &C, SVal Cont,
6965ffd83dbSDimitry Andric                                          SVal Iter1, SVal Iter2) const {
6975ffd83dbSDimitry Andric   auto State = C.getState();
6985ffd83dbSDimitry Andric   const auto *Pos1 = getIteratorPosition(State, Iter1);
6995ffd83dbSDimitry Andric   const auto *Pos2 = getIteratorPosition(State, Iter2);
7005ffd83dbSDimitry Andric   if (!Pos1 || !Pos2)
7015ffd83dbSDimitry Andric     return;
7025ffd83dbSDimitry Andric 
7035ffd83dbSDimitry Andric   // Invalidate the deleted iterator position range (first..last)
7045ffd83dbSDimitry Andric   State = invalidateIteratorPositions(State, Pos1->getOffset(), BO_GT,
7055ffd83dbSDimitry Andric                                       Pos2->getOffset(), BO_LT);
7065ffd83dbSDimitry Andric   C.addTransition(State);
7075ffd83dbSDimitry Andric }
7085ffd83dbSDimitry Andric 
7095ffd83dbSDimitry Andric const NoteTag *ContainerModeling::getChangeTag(CheckerContext &C,
7105ffd83dbSDimitry Andric                                                StringRef Text,
7115ffd83dbSDimitry Andric                                                const MemRegion *ContReg,
7125ffd83dbSDimitry Andric                                                const Expr *ContE) const {
7135ffd83dbSDimitry Andric   StringRef Name;
7145ffd83dbSDimitry Andric   // First try to get the name of the variable from the region
7155ffd83dbSDimitry Andric   if (const auto *DR = dyn_cast<DeclRegion>(ContReg)) {
7165ffd83dbSDimitry Andric     Name = DR->getDecl()->getName();
7175ffd83dbSDimitry Andric   // If the region is not a `DeclRegion` then use the expression instead
7185ffd83dbSDimitry Andric   } else if (const auto *DRE =
7195ffd83dbSDimitry Andric              dyn_cast<DeclRefExpr>(ContE->IgnoreParenCasts())) {
7205ffd83dbSDimitry Andric     Name = DRE->getDecl()->getName();
7215ffd83dbSDimitry Andric   }
7225ffd83dbSDimitry Andric 
7235ffd83dbSDimitry Andric   return C.getNoteTag(
7245ffd83dbSDimitry Andric       [Text, Name, ContReg](PathSensitiveBugReport &BR) -> std::string {
7255ffd83dbSDimitry Andric         if (!BR.isInteresting(ContReg))
7265ffd83dbSDimitry Andric           return "";
7275ffd83dbSDimitry Andric 
7285ffd83dbSDimitry Andric         SmallString<256> Msg;
7295ffd83dbSDimitry Andric         llvm::raw_svector_ostream Out(Msg);
7305ffd83dbSDimitry Andric         Out << "Container " << (!Name.empty() ? ("'" + Name.str() + "' ") : "" )
7315ffd83dbSDimitry Andric             << Text;
7325ffd83dbSDimitry Andric         return std::string(Out.str());
7335ffd83dbSDimitry Andric       });
7345ffd83dbSDimitry Andric }
7355ffd83dbSDimitry Andric 
7365ffd83dbSDimitry Andric void ContainerModeling::printState(raw_ostream &Out, ProgramStateRef State,
7375ffd83dbSDimitry Andric                                   const char *NL, const char *Sep) const {
7385ffd83dbSDimitry Andric   auto ContMap = State->get<ContainerMap>();
7395ffd83dbSDimitry Andric 
7405ffd83dbSDimitry Andric   if (!ContMap.isEmpty()) {
7415ffd83dbSDimitry Andric     Out << Sep << "Container Data :" << NL;
7425ffd83dbSDimitry Andric     for (const auto &Cont : ContMap) {
7435ffd83dbSDimitry Andric       Cont.first->dumpToStream(Out);
7445ffd83dbSDimitry Andric       Out << " : [ ";
7455ffd83dbSDimitry Andric       const auto CData = Cont.second;
7465ffd83dbSDimitry Andric       if (CData.getBegin())
7475ffd83dbSDimitry Andric         CData.getBegin()->dumpToStream(Out);
7485ffd83dbSDimitry Andric       else
7495ffd83dbSDimitry Andric         Out << "<Unknown>";
7505ffd83dbSDimitry Andric       Out << " .. ";
7515ffd83dbSDimitry Andric       if (CData.getEnd())
7525ffd83dbSDimitry Andric         CData.getEnd()->dumpToStream(Out);
7535ffd83dbSDimitry Andric       else
7545ffd83dbSDimitry Andric         Out << "<Unknown>";
7555ffd83dbSDimitry Andric       Out << " ]";
7565ffd83dbSDimitry Andric     }
7575ffd83dbSDimitry Andric   }
7585ffd83dbSDimitry Andric }
7595ffd83dbSDimitry Andric 
7605ffd83dbSDimitry Andric namespace {
7615ffd83dbSDimitry Andric 
7625ffd83dbSDimitry Andric bool isBeginCall(const FunctionDecl *Func) {
7635ffd83dbSDimitry Andric   const auto *IdInfo = Func->getIdentifier();
7645ffd83dbSDimitry Andric   if (!IdInfo)
7655ffd83dbSDimitry Andric     return false;
766*fe6060f1SDimitry Andric   return IdInfo->getName().endswith_insensitive("begin");
7675ffd83dbSDimitry Andric }
7685ffd83dbSDimitry Andric 
7695ffd83dbSDimitry Andric bool isEndCall(const FunctionDecl *Func) {
7705ffd83dbSDimitry Andric   const auto *IdInfo = Func->getIdentifier();
7715ffd83dbSDimitry Andric   if (!IdInfo)
7725ffd83dbSDimitry Andric     return false;
773*fe6060f1SDimitry Andric   return IdInfo->getName().endswith_insensitive("end");
7745ffd83dbSDimitry Andric }
7755ffd83dbSDimitry Andric 
7765ffd83dbSDimitry Andric const CXXRecordDecl *getCXXRecordDecl(ProgramStateRef State,
7775ffd83dbSDimitry Andric                                       const MemRegion *Reg) {
7785ffd83dbSDimitry Andric   auto TI = getDynamicTypeInfo(State, Reg);
7795ffd83dbSDimitry Andric   if (!TI.isValid())
7805ffd83dbSDimitry Andric     return nullptr;
7815ffd83dbSDimitry Andric 
7825ffd83dbSDimitry Andric   auto Type = TI.getType();
7835ffd83dbSDimitry Andric   if (const auto *RefT = Type->getAs<ReferenceType>()) {
7845ffd83dbSDimitry Andric     Type = RefT->getPointeeType();
7855ffd83dbSDimitry Andric   }
7865ffd83dbSDimitry Andric 
7875ffd83dbSDimitry Andric   return Type->getUnqualifiedDesugaredType()->getAsCXXRecordDecl();
7885ffd83dbSDimitry Andric }
7895ffd83dbSDimitry Andric 
7905ffd83dbSDimitry Andric bool hasSubscriptOperator(ProgramStateRef State, const MemRegion *Reg) {
7915ffd83dbSDimitry Andric   const auto *CRD = getCXXRecordDecl(State, Reg);
7925ffd83dbSDimitry Andric   if (!CRD)
7935ffd83dbSDimitry Andric     return false;
7945ffd83dbSDimitry Andric 
7955ffd83dbSDimitry Andric   for (const auto *Method : CRD->methods()) {
7965ffd83dbSDimitry Andric     if (!Method->isOverloadedOperator())
7975ffd83dbSDimitry Andric       continue;
7985ffd83dbSDimitry Andric     const auto OPK = Method->getOverloadedOperator();
7995ffd83dbSDimitry Andric     if (OPK == OO_Subscript) {
8005ffd83dbSDimitry Andric       return true;
8015ffd83dbSDimitry Andric     }
8025ffd83dbSDimitry Andric   }
8035ffd83dbSDimitry Andric   return false;
8045ffd83dbSDimitry Andric }
8055ffd83dbSDimitry Andric 
8065ffd83dbSDimitry Andric bool frontModifiable(ProgramStateRef State, const MemRegion *Reg) {
8075ffd83dbSDimitry Andric   const auto *CRD = getCXXRecordDecl(State, Reg);
8085ffd83dbSDimitry Andric   if (!CRD)
8095ffd83dbSDimitry Andric     return false;
8105ffd83dbSDimitry Andric 
8115ffd83dbSDimitry Andric   for (const auto *Method : CRD->methods()) {
8125ffd83dbSDimitry Andric     if (!Method->getDeclName().isIdentifier())
8135ffd83dbSDimitry Andric       continue;
8145ffd83dbSDimitry Andric     if (Method->getName() == "push_front" || Method->getName() == "pop_front") {
8155ffd83dbSDimitry Andric       return true;
8165ffd83dbSDimitry Andric     }
8175ffd83dbSDimitry Andric   }
8185ffd83dbSDimitry Andric   return false;
8195ffd83dbSDimitry Andric }
8205ffd83dbSDimitry Andric 
8215ffd83dbSDimitry Andric bool backModifiable(ProgramStateRef State, const MemRegion *Reg) {
8225ffd83dbSDimitry Andric   const auto *CRD = getCXXRecordDecl(State, Reg);
8235ffd83dbSDimitry Andric   if (!CRD)
8245ffd83dbSDimitry Andric     return false;
8255ffd83dbSDimitry Andric 
8265ffd83dbSDimitry Andric   for (const auto *Method : CRD->methods()) {
8275ffd83dbSDimitry Andric     if (!Method->getDeclName().isIdentifier())
8285ffd83dbSDimitry Andric       continue;
8295ffd83dbSDimitry Andric     if (Method->getName() == "push_back" || Method->getName() == "pop_back") {
8305ffd83dbSDimitry Andric       return true;
8315ffd83dbSDimitry Andric     }
8325ffd83dbSDimitry Andric   }
8335ffd83dbSDimitry Andric   return false;
8345ffd83dbSDimitry Andric }
8355ffd83dbSDimitry Andric 
8365ffd83dbSDimitry Andric SymbolRef getContainerBegin(ProgramStateRef State, const MemRegion *Cont) {
8375ffd83dbSDimitry Andric   const auto *CDataPtr = getContainerData(State, Cont);
8385ffd83dbSDimitry Andric   if (!CDataPtr)
8395ffd83dbSDimitry Andric     return nullptr;
8405ffd83dbSDimitry Andric 
8415ffd83dbSDimitry Andric   return CDataPtr->getBegin();
8425ffd83dbSDimitry Andric }
8435ffd83dbSDimitry Andric 
8445ffd83dbSDimitry Andric SymbolRef getContainerEnd(ProgramStateRef State, const MemRegion *Cont) {
8455ffd83dbSDimitry Andric   const auto *CDataPtr = getContainerData(State, Cont);
8465ffd83dbSDimitry Andric   if (!CDataPtr)
8475ffd83dbSDimitry Andric     return nullptr;
8485ffd83dbSDimitry Andric 
8495ffd83dbSDimitry Andric   return CDataPtr->getEnd();
8505ffd83dbSDimitry Andric }
8515ffd83dbSDimitry Andric 
8525ffd83dbSDimitry Andric ProgramStateRef createContainerBegin(ProgramStateRef State,
8535ffd83dbSDimitry Andric                                      const MemRegion *Cont, const Expr *E,
8545ffd83dbSDimitry Andric                                      QualType T, const LocationContext *LCtx,
8555ffd83dbSDimitry Andric                                      unsigned BlockCount) {
8565ffd83dbSDimitry Andric   // Only create if it does not exist
8575ffd83dbSDimitry Andric   const auto *CDataPtr = getContainerData(State, Cont);
8585ffd83dbSDimitry Andric   if (CDataPtr && CDataPtr->getBegin())
8595ffd83dbSDimitry Andric     return State;
8605ffd83dbSDimitry Andric 
8615ffd83dbSDimitry Andric   auto &SymMgr = State->getSymbolManager();
8625ffd83dbSDimitry Andric   const SymbolConjured *Sym = SymMgr.conjureSymbol(E, LCtx, T, BlockCount,
8635ffd83dbSDimitry Andric                                                    "begin");
8645ffd83dbSDimitry Andric   State = assumeNoOverflow(State, Sym, 4);
8655ffd83dbSDimitry Andric 
8665ffd83dbSDimitry Andric   if (CDataPtr) {
8675ffd83dbSDimitry Andric     const auto CData = CDataPtr->newBegin(Sym);
8685ffd83dbSDimitry Andric     return setContainerData(State, Cont, CData);
8695ffd83dbSDimitry Andric   }
8705ffd83dbSDimitry Andric 
8715ffd83dbSDimitry Andric   const auto CData = ContainerData::fromBegin(Sym);
8725ffd83dbSDimitry Andric   return setContainerData(State, Cont, CData);
8735ffd83dbSDimitry Andric }
8745ffd83dbSDimitry Andric 
8755ffd83dbSDimitry Andric ProgramStateRef createContainerEnd(ProgramStateRef State, const MemRegion *Cont,
8765ffd83dbSDimitry Andric                                    const Expr *E, QualType T,
8775ffd83dbSDimitry Andric                                    const LocationContext *LCtx,
8785ffd83dbSDimitry Andric                                    unsigned BlockCount) {
8795ffd83dbSDimitry Andric   // Only create if it does not exist
8805ffd83dbSDimitry Andric   const auto *CDataPtr = getContainerData(State, Cont);
8815ffd83dbSDimitry Andric   if (CDataPtr && CDataPtr->getEnd())
8825ffd83dbSDimitry Andric     return State;
8835ffd83dbSDimitry Andric 
8845ffd83dbSDimitry Andric   auto &SymMgr = State->getSymbolManager();
8855ffd83dbSDimitry Andric   const SymbolConjured *Sym = SymMgr.conjureSymbol(E, LCtx, T, BlockCount,
8865ffd83dbSDimitry Andric                                                   "end");
8875ffd83dbSDimitry Andric   State = assumeNoOverflow(State, Sym, 4);
8885ffd83dbSDimitry Andric 
8895ffd83dbSDimitry Andric   if (CDataPtr) {
8905ffd83dbSDimitry Andric     const auto CData = CDataPtr->newEnd(Sym);
8915ffd83dbSDimitry Andric     return setContainerData(State, Cont, CData);
8925ffd83dbSDimitry Andric   }
8935ffd83dbSDimitry Andric 
8945ffd83dbSDimitry Andric   const auto CData = ContainerData::fromEnd(Sym);
8955ffd83dbSDimitry Andric   return setContainerData(State, Cont, CData);
8965ffd83dbSDimitry Andric }
8975ffd83dbSDimitry Andric 
8985ffd83dbSDimitry Andric ProgramStateRef setContainerData(ProgramStateRef State, const MemRegion *Cont,
8995ffd83dbSDimitry Andric                                  const ContainerData &CData) {
9005ffd83dbSDimitry Andric   return State->set<ContainerMap>(Cont, CData);
9015ffd83dbSDimitry Andric }
9025ffd83dbSDimitry Andric 
9035ffd83dbSDimitry Andric template <typename Condition, typename Process>
9045ffd83dbSDimitry Andric ProgramStateRef processIteratorPositions(ProgramStateRef State, Condition Cond,
9055ffd83dbSDimitry Andric                                          Process Proc) {
9065ffd83dbSDimitry Andric   auto &RegionMapFactory = State->get_context<IteratorRegionMap>();
9075ffd83dbSDimitry Andric   auto RegionMap = State->get<IteratorRegionMap>();
9085ffd83dbSDimitry Andric   bool Changed = false;
9095ffd83dbSDimitry Andric   for (const auto &Reg : RegionMap) {
9105ffd83dbSDimitry Andric     if (Cond(Reg.second)) {
9115ffd83dbSDimitry Andric       RegionMap = RegionMapFactory.add(RegionMap, Reg.first, Proc(Reg.second));
9125ffd83dbSDimitry Andric       Changed = true;
9135ffd83dbSDimitry Andric     }
9145ffd83dbSDimitry Andric   }
9155ffd83dbSDimitry Andric 
9165ffd83dbSDimitry Andric   if (Changed)
9175ffd83dbSDimitry Andric     State = State->set<IteratorRegionMap>(RegionMap);
9185ffd83dbSDimitry Andric 
9195ffd83dbSDimitry Andric   auto &SymbolMapFactory = State->get_context<IteratorSymbolMap>();
9205ffd83dbSDimitry Andric   auto SymbolMap = State->get<IteratorSymbolMap>();
9215ffd83dbSDimitry Andric   Changed = false;
9225ffd83dbSDimitry Andric   for (const auto &Sym : SymbolMap) {
9235ffd83dbSDimitry Andric     if (Cond(Sym.second)) {
9245ffd83dbSDimitry Andric       SymbolMap = SymbolMapFactory.add(SymbolMap, Sym.first, Proc(Sym.second));
9255ffd83dbSDimitry Andric       Changed = true;
9265ffd83dbSDimitry Andric     }
9275ffd83dbSDimitry Andric   }
9285ffd83dbSDimitry Andric 
9295ffd83dbSDimitry Andric   if (Changed)
9305ffd83dbSDimitry Andric     State = State->set<IteratorSymbolMap>(SymbolMap);
9315ffd83dbSDimitry Andric 
9325ffd83dbSDimitry Andric   return State;
9335ffd83dbSDimitry Andric }
9345ffd83dbSDimitry Andric 
9355ffd83dbSDimitry Andric ProgramStateRef invalidateAllIteratorPositions(ProgramStateRef State,
9365ffd83dbSDimitry Andric                                                const MemRegion *Cont) {
9375ffd83dbSDimitry Andric   auto MatchCont = [&](const IteratorPosition &Pos) {
9385ffd83dbSDimitry Andric     return Pos.getContainer() == Cont;
9395ffd83dbSDimitry Andric   };
9405ffd83dbSDimitry Andric   auto Invalidate = [&](const IteratorPosition &Pos) {
9415ffd83dbSDimitry Andric     return Pos.invalidate();
9425ffd83dbSDimitry Andric   };
9435ffd83dbSDimitry Andric   return processIteratorPositions(State, MatchCont, Invalidate);
9445ffd83dbSDimitry Andric }
9455ffd83dbSDimitry Andric 
9465ffd83dbSDimitry Andric ProgramStateRef
9475ffd83dbSDimitry Andric invalidateAllIteratorPositionsExcept(ProgramStateRef State,
9485ffd83dbSDimitry Andric                                      const MemRegion *Cont, SymbolRef Offset,
9495ffd83dbSDimitry Andric                                      BinaryOperator::Opcode Opc) {
9505ffd83dbSDimitry Andric   auto MatchContAndCompare = [&](const IteratorPosition &Pos) {
9515ffd83dbSDimitry Andric     return Pos.getContainer() == Cont &&
9525ffd83dbSDimitry Andric            !compare(State, Pos.getOffset(), Offset, Opc);
9535ffd83dbSDimitry Andric   };
9545ffd83dbSDimitry Andric   auto Invalidate = [&](const IteratorPosition &Pos) {
9555ffd83dbSDimitry Andric     return Pos.invalidate();
9565ffd83dbSDimitry Andric   };
9575ffd83dbSDimitry Andric   return processIteratorPositions(State, MatchContAndCompare, Invalidate);
9585ffd83dbSDimitry Andric }
9595ffd83dbSDimitry Andric 
9605ffd83dbSDimitry Andric ProgramStateRef invalidateIteratorPositions(ProgramStateRef State,
9615ffd83dbSDimitry Andric                                             SymbolRef Offset,
9625ffd83dbSDimitry Andric                                             BinaryOperator::Opcode Opc) {
9635ffd83dbSDimitry Andric   auto Compare = [&](const IteratorPosition &Pos) {
9645ffd83dbSDimitry Andric     return compare(State, Pos.getOffset(), Offset, Opc);
9655ffd83dbSDimitry Andric   };
9665ffd83dbSDimitry Andric   auto Invalidate = [&](const IteratorPosition &Pos) {
9675ffd83dbSDimitry Andric     return Pos.invalidate();
9685ffd83dbSDimitry Andric   };
9695ffd83dbSDimitry Andric   return processIteratorPositions(State, Compare, Invalidate);
9705ffd83dbSDimitry Andric }
9715ffd83dbSDimitry Andric 
9725ffd83dbSDimitry Andric ProgramStateRef invalidateIteratorPositions(ProgramStateRef State,
9735ffd83dbSDimitry Andric                                             SymbolRef Offset1,
9745ffd83dbSDimitry Andric                                             BinaryOperator::Opcode Opc1,
9755ffd83dbSDimitry Andric                                             SymbolRef Offset2,
9765ffd83dbSDimitry Andric                                             BinaryOperator::Opcode Opc2) {
9775ffd83dbSDimitry Andric   auto Compare = [&](const IteratorPosition &Pos) {
9785ffd83dbSDimitry Andric     return compare(State, Pos.getOffset(), Offset1, Opc1) &&
9795ffd83dbSDimitry Andric            compare(State, Pos.getOffset(), Offset2, Opc2);
9805ffd83dbSDimitry Andric   };
9815ffd83dbSDimitry Andric   auto Invalidate = [&](const IteratorPosition &Pos) {
9825ffd83dbSDimitry Andric     return Pos.invalidate();
9835ffd83dbSDimitry Andric   };
9845ffd83dbSDimitry Andric   return processIteratorPositions(State, Compare, Invalidate);
9855ffd83dbSDimitry Andric }
9865ffd83dbSDimitry Andric 
9875ffd83dbSDimitry Andric ProgramStateRef reassignAllIteratorPositions(ProgramStateRef State,
9885ffd83dbSDimitry Andric                                              const MemRegion *Cont,
9895ffd83dbSDimitry Andric                                              const MemRegion *NewCont) {
9905ffd83dbSDimitry Andric   auto MatchCont = [&](const IteratorPosition &Pos) {
9915ffd83dbSDimitry Andric     return Pos.getContainer() == Cont;
9925ffd83dbSDimitry Andric   };
9935ffd83dbSDimitry Andric   auto ReAssign = [&](const IteratorPosition &Pos) {
9945ffd83dbSDimitry Andric     return Pos.reAssign(NewCont);
9955ffd83dbSDimitry Andric   };
9965ffd83dbSDimitry Andric   return processIteratorPositions(State, MatchCont, ReAssign);
9975ffd83dbSDimitry Andric }
9985ffd83dbSDimitry Andric 
9995ffd83dbSDimitry Andric ProgramStateRef reassignAllIteratorPositionsUnless(ProgramStateRef State,
10005ffd83dbSDimitry Andric                                                    const MemRegion *Cont,
10015ffd83dbSDimitry Andric                                                    const MemRegion *NewCont,
10025ffd83dbSDimitry Andric                                                    SymbolRef Offset,
10035ffd83dbSDimitry Andric                                                    BinaryOperator::Opcode Opc) {
10045ffd83dbSDimitry Andric   auto MatchContAndCompare = [&](const IteratorPosition &Pos) {
10055ffd83dbSDimitry Andric     return Pos.getContainer() == Cont &&
10065ffd83dbSDimitry Andric     !compare(State, Pos.getOffset(), Offset, Opc);
10075ffd83dbSDimitry Andric   };
10085ffd83dbSDimitry Andric   auto ReAssign = [&](const IteratorPosition &Pos) {
10095ffd83dbSDimitry Andric     return Pos.reAssign(NewCont);
10105ffd83dbSDimitry Andric   };
10115ffd83dbSDimitry Andric   return processIteratorPositions(State, MatchContAndCompare, ReAssign);
10125ffd83dbSDimitry Andric }
10135ffd83dbSDimitry Andric 
10145ffd83dbSDimitry Andric // This function rebases symbolic expression `OldSym + Int` to `NewSym + Int`,
10155ffd83dbSDimitry Andric // `OldSym - Int` to `NewSym - Int` and  `OldSym` to `NewSym` in any iterator
10165ffd83dbSDimitry Andric // position offsets where `CondSym` is true.
10175ffd83dbSDimitry Andric ProgramStateRef rebaseSymbolInIteratorPositionsIf(
10185ffd83dbSDimitry Andric     ProgramStateRef State, SValBuilder &SVB, SymbolRef OldSym,
10195ffd83dbSDimitry Andric     SymbolRef NewSym, SymbolRef CondSym, BinaryOperator::Opcode Opc) {
10205ffd83dbSDimitry Andric   auto LessThanEnd = [&](const IteratorPosition &Pos) {
10215ffd83dbSDimitry Andric     return compare(State, Pos.getOffset(), CondSym, Opc);
10225ffd83dbSDimitry Andric   };
10235ffd83dbSDimitry Andric   auto RebaseSymbol = [&](const IteratorPosition &Pos) {
10245ffd83dbSDimitry Andric     return Pos.setTo(rebaseSymbol(State, SVB, Pos.getOffset(), OldSym,
10255ffd83dbSDimitry Andric                                    NewSym));
10265ffd83dbSDimitry Andric   };
10275ffd83dbSDimitry Andric   return processIteratorPositions(State, LessThanEnd, RebaseSymbol);
10285ffd83dbSDimitry Andric }
10295ffd83dbSDimitry Andric 
10305ffd83dbSDimitry Andric // This function rebases symbolic expression `OldExpr + Int` to `NewExpr + Int`,
10315ffd83dbSDimitry Andric // `OldExpr - Int` to `NewExpr - Int` and  `OldExpr` to `NewExpr` in expression
10325ffd83dbSDimitry Andric // `OrigExpr`.
10335ffd83dbSDimitry Andric SymbolRef rebaseSymbol(ProgramStateRef State, SValBuilder &SVB,
10345ffd83dbSDimitry Andric                        SymbolRef OrigExpr, SymbolRef OldExpr,
10355ffd83dbSDimitry Andric                        SymbolRef NewSym) {
10365ffd83dbSDimitry Andric   auto &SymMgr = SVB.getSymbolManager();
10375ffd83dbSDimitry Andric   auto Diff = SVB.evalBinOpNN(State, BO_Sub, nonloc::SymbolVal(OrigExpr),
10385ffd83dbSDimitry Andric                               nonloc::SymbolVal(OldExpr),
10395ffd83dbSDimitry Andric                               SymMgr.getType(OrigExpr));
10405ffd83dbSDimitry Andric 
10415ffd83dbSDimitry Andric   const auto DiffInt = Diff.getAs<nonloc::ConcreteInt>();
10425ffd83dbSDimitry Andric   if (!DiffInt)
10435ffd83dbSDimitry Andric     return OrigExpr;
10445ffd83dbSDimitry Andric 
10455ffd83dbSDimitry Andric   return SVB.evalBinOpNN(State, BO_Add, *DiffInt, nonloc::SymbolVal(NewSym),
10465ffd83dbSDimitry Andric                          SymMgr.getType(OrigExpr)).getAsSymbol();
10475ffd83dbSDimitry Andric }
10485ffd83dbSDimitry Andric 
10495ffd83dbSDimitry Andric bool hasLiveIterators(ProgramStateRef State, const MemRegion *Cont) {
10505ffd83dbSDimitry Andric   auto RegionMap = State->get<IteratorRegionMap>();
10515ffd83dbSDimitry Andric   for (const auto &Reg : RegionMap) {
10525ffd83dbSDimitry Andric     if (Reg.second.getContainer() == Cont)
10535ffd83dbSDimitry Andric       return true;
10545ffd83dbSDimitry Andric   }
10555ffd83dbSDimitry Andric 
10565ffd83dbSDimitry Andric   auto SymbolMap = State->get<IteratorSymbolMap>();
10575ffd83dbSDimitry Andric   for (const auto &Sym : SymbolMap) {
10585ffd83dbSDimitry Andric     if (Sym.second.getContainer() == Cont)
10595ffd83dbSDimitry Andric       return true;
10605ffd83dbSDimitry Andric   }
10615ffd83dbSDimitry Andric 
10625ffd83dbSDimitry Andric   return false;
10635ffd83dbSDimitry Andric }
10645ffd83dbSDimitry Andric 
10655ffd83dbSDimitry Andric } // namespace
10665ffd83dbSDimitry Andric 
10675ffd83dbSDimitry Andric void ento::registerContainerModeling(CheckerManager &mgr) {
10685ffd83dbSDimitry Andric   mgr.registerChecker<ContainerModeling>();
10695ffd83dbSDimitry Andric }
10705ffd83dbSDimitry Andric 
10715ffd83dbSDimitry Andric bool ento::shouldRegisterContainerModeling(const CheckerManager &mgr) {
10725ffd83dbSDimitry Andric   if (!mgr.getLangOpts().CPlusPlus)
10735ffd83dbSDimitry Andric     return false;
10745ffd83dbSDimitry Andric 
10755ffd83dbSDimitry Andric   if (!mgr.getAnalyzerOptions().ShouldAggressivelySimplifyBinaryOperation) {
10765ffd83dbSDimitry Andric     mgr.getASTContext().getDiagnostics().Report(
10775ffd83dbSDimitry Andric         diag::err_analyzer_checker_incompatible_analyzer_option)
10785ffd83dbSDimitry Andric       << "aggressive-binary-operation-simplification" << "false";
10795ffd83dbSDimitry Andric     return false;
10805ffd83dbSDimitry Andric   }
10815ffd83dbSDimitry Andric 
10825ffd83dbSDimitry Andric   return true;
10835ffd83dbSDimitry Andric }
1084