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