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