xref: /freebsd/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp (revision 5ffd83dbcc34f10e07f6d3e968ae6365869615f4)
1*5ffd83dbSDimitry Andric //===-- ContainerModeling.cpp -------------------------------------*- C++ -*--//
2*5ffd83dbSDimitry Andric //
3*5ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*5ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*5ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*5ffd83dbSDimitry Andric //
7*5ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
8*5ffd83dbSDimitry Andric //
9*5ffd83dbSDimitry Andric // Defines a modeling-checker for modeling STL container-like containers.
10*5ffd83dbSDimitry Andric //
11*5ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
12*5ffd83dbSDimitry Andric 
13*5ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
14*5ffd83dbSDimitry Andric #include "clang/AST/DeclTemplate.h"
15*5ffd83dbSDimitry Andric #include "clang/Driver/DriverDiagnostic.h"
16*5ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
17*5ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Core/Checker.h"
18*5ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
19*5ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
20*5ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h"
21*5ffd83dbSDimitry Andric 
22*5ffd83dbSDimitry Andric #include "Iterator.h"
23*5ffd83dbSDimitry Andric 
24*5ffd83dbSDimitry Andric #include <utility>
25*5ffd83dbSDimitry Andric 
26*5ffd83dbSDimitry Andric using namespace clang;
27*5ffd83dbSDimitry Andric using namespace ento;
28*5ffd83dbSDimitry Andric using namespace iterator;
29*5ffd83dbSDimitry Andric 
30*5ffd83dbSDimitry Andric namespace {
31*5ffd83dbSDimitry Andric 
32*5ffd83dbSDimitry Andric class ContainerModeling
33*5ffd83dbSDimitry Andric   : public Checker<check::PostCall, check::LiveSymbols, check::DeadSymbols> {
34*5ffd83dbSDimitry Andric 
35*5ffd83dbSDimitry Andric   void handleBegin(CheckerContext &C, const Expr *CE, SVal RetVal,
36*5ffd83dbSDimitry Andric                    SVal Cont) const;
37*5ffd83dbSDimitry Andric   void handleEnd(CheckerContext &C, const Expr *CE, SVal RetVal,
38*5ffd83dbSDimitry Andric                  SVal Cont) const;
39*5ffd83dbSDimitry Andric   void handleAssignment(CheckerContext &C, SVal Cont, const Expr *CE = nullptr,
40*5ffd83dbSDimitry Andric                         SVal OldCont = UndefinedVal()) const;
41*5ffd83dbSDimitry Andric   void handleAssign(CheckerContext &C, SVal Cont, const Expr *ContE) const;
42*5ffd83dbSDimitry Andric   void handleClear(CheckerContext &C, SVal Cont, const Expr *ContE) const;
43*5ffd83dbSDimitry Andric   void handlePushBack(CheckerContext &C, SVal Cont, const Expr *ContE) const;
44*5ffd83dbSDimitry Andric   void handlePopBack(CheckerContext &C, SVal Cont, const Expr *ContE) const;
45*5ffd83dbSDimitry Andric   void handlePushFront(CheckerContext &C, SVal Cont, const Expr *ContE) const;
46*5ffd83dbSDimitry Andric   void handlePopFront(CheckerContext &C, SVal Cont, const Expr *ContE) const;
47*5ffd83dbSDimitry Andric   void handleInsert(CheckerContext &C, SVal Cont, SVal Iter) const;
48*5ffd83dbSDimitry Andric   void handleErase(CheckerContext &C, SVal Cont, SVal Iter) const;
49*5ffd83dbSDimitry Andric   void handleErase(CheckerContext &C, SVal Cont, SVal Iter1, SVal Iter2) const;
50*5ffd83dbSDimitry Andric   void handleEraseAfter(CheckerContext &C, SVal Cont, SVal Iter) const;
51*5ffd83dbSDimitry Andric   void handleEraseAfter(CheckerContext &C, SVal Cont, SVal Iter1,
52*5ffd83dbSDimitry Andric                         SVal Iter2) const;
53*5ffd83dbSDimitry Andric   const NoteTag *getChangeTag(CheckerContext &C, StringRef Text,
54*5ffd83dbSDimitry Andric                               const MemRegion *ContReg,
55*5ffd83dbSDimitry Andric                               const Expr *ContE) const;
56*5ffd83dbSDimitry Andric   void printState(raw_ostream &Out, ProgramStateRef State, const char *NL,
57*5ffd83dbSDimitry Andric                   const char *Sep) const override;
58*5ffd83dbSDimitry Andric 
59*5ffd83dbSDimitry Andric public:
60*5ffd83dbSDimitry Andric   ContainerModeling() = default;
61*5ffd83dbSDimitry Andric 
62*5ffd83dbSDimitry Andric   void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
63*5ffd83dbSDimitry Andric   void checkLiveSymbols(ProgramStateRef State, SymbolReaper &SR) const;
64*5ffd83dbSDimitry Andric   void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
65*5ffd83dbSDimitry Andric 
66*5ffd83dbSDimitry Andric   using NoItParamFn = void (ContainerModeling::*)(CheckerContext &, SVal,
67*5ffd83dbSDimitry Andric                                                   const Expr *) const;
68*5ffd83dbSDimitry Andric   using OneItParamFn = void (ContainerModeling::*)(CheckerContext &, SVal,
69*5ffd83dbSDimitry Andric                                                    SVal) const;
70*5ffd83dbSDimitry Andric   using TwoItParamFn = void (ContainerModeling::*)(CheckerContext &, SVal, SVal,
71*5ffd83dbSDimitry Andric                                                    SVal) const;
72*5ffd83dbSDimitry Andric 
73*5ffd83dbSDimitry Andric   CallDescriptionMap<NoItParamFn> NoIterParamFunctions = {
74*5ffd83dbSDimitry Andric     {{0, "clear", 0},
75*5ffd83dbSDimitry Andric      &ContainerModeling::handleClear},
76*5ffd83dbSDimitry Andric     {{0, "assign", 2},
77*5ffd83dbSDimitry Andric      &ContainerModeling::handleAssign},
78*5ffd83dbSDimitry Andric     {{0, "push_back", 1},
79*5ffd83dbSDimitry Andric      &ContainerModeling::handlePushBack},
80*5ffd83dbSDimitry Andric     {{0, "emplace_back", 1},
81*5ffd83dbSDimitry Andric      &ContainerModeling::handlePushBack},
82*5ffd83dbSDimitry Andric     {{0, "pop_back", 0},
83*5ffd83dbSDimitry Andric      &ContainerModeling::handlePopBack},
84*5ffd83dbSDimitry Andric     {{0, "push_front", 1},
85*5ffd83dbSDimitry Andric      &ContainerModeling::handlePushFront},
86*5ffd83dbSDimitry Andric     {{0, "emplace_front", 1},
87*5ffd83dbSDimitry Andric      &ContainerModeling::handlePushFront},
88*5ffd83dbSDimitry Andric     {{0, "pop_front", 0},
89*5ffd83dbSDimitry Andric      &ContainerModeling::handlePopFront},
90*5ffd83dbSDimitry Andric   };
91*5ffd83dbSDimitry Andric 
92*5ffd83dbSDimitry Andric   CallDescriptionMap<OneItParamFn> OneIterParamFunctions = {
93*5ffd83dbSDimitry Andric     {{0, "insert", 2},
94*5ffd83dbSDimitry Andric      &ContainerModeling::handleInsert},
95*5ffd83dbSDimitry Andric     {{0, "emplace", 2},
96*5ffd83dbSDimitry Andric      &ContainerModeling::handleInsert},
97*5ffd83dbSDimitry Andric     {{0, "erase", 1},
98*5ffd83dbSDimitry Andric      &ContainerModeling::handleErase},
99*5ffd83dbSDimitry Andric     {{0, "erase_after", 1},
100*5ffd83dbSDimitry Andric      &ContainerModeling::handleEraseAfter},
101*5ffd83dbSDimitry Andric   };
102*5ffd83dbSDimitry Andric 
103*5ffd83dbSDimitry Andric   CallDescriptionMap<TwoItParamFn> TwoIterParamFunctions = {
104*5ffd83dbSDimitry Andric     {{0, "erase", 2},
105*5ffd83dbSDimitry Andric      &ContainerModeling::handleErase},
106*5ffd83dbSDimitry Andric     {{0, "erase_after", 2},
107*5ffd83dbSDimitry Andric      &ContainerModeling::handleEraseAfter},
108*5ffd83dbSDimitry Andric   };
109*5ffd83dbSDimitry Andric 
110*5ffd83dbSDimitry Andric };
111*5ffd83dbSDimitry Andric 
112*5ffd83dbSDimitry Andric bool isBeginCall(const FunctionDecl *Func);
113*5ffd83dbSDimitry Andric bool isEndCall(const FunctionDecl *Func);
114*5ffd83dbSDimitry Andric bool hasSubscriptOperator(ProgramStateRef State, const MemRegion *Reg);
115*5ffd83dbSDimitry Andric bool frontModifiable(ProgramStateRef State, const MemRegion *Reg);
116*5ffd83dbSDimitry Andric bool backModifiable(ProgramStateRef State, const MemRegion *Reg);
117*5ffd83dbSDimitry Andric SymbolRef getContainerBegin(ProgramStateRef State, const MemRegion *Cont);
118*5ffd83dbSDimitry Andric SymbolRef getContainerEnd(ProgramStateRef State, const MemRegion *Cont);
119*5ffd83dbSDimitry Andric ProgramStateRef createContainerBegin(ProgramStateRef State,
120*5ffd83dbSDimitry Andric                                      const MemRegion *Cont, const Expr *E,
121*5ffd83dbSDimitry Andric                                      QualType T, const LocationContext *LCtx,
122*5ffd83dbSDimitry Andric                                      unsigned BlockCount);
123*5ffd83dbSDimitry Andric ProgramStateRef createContainerEnd(ProgramStateRef State, const MemRegion *Cont,
124*5ffd83dbSDimitry Andric                                    const Expr *E, QualType T,
125*5ffd83dbSDimitry Andric                                    const LocationContext *LCtx,
126*5ffd83dbSDimitry Andric                                    unsigned BlockCount);
127*5ffd83dbSDimitry Andric ProgramStateRef setContainerData(ProgramStateRef State, const MemRegion *Cont,
128*5ffd83dbSDimitry Andric                                  const ContainerData &CData);
129*5ffd83dbSDimitry Andric ProgramStateRef invalidateAllIteratorPositions(ProgramStateRef State,
130*5ffd83dbSDimitry Andric                                                const MemRegion *Cont);
131*5ffd83dbSDimitry Andric ProgramStateRef
132*5ffd83dbSDimitry Andric invalidateAllIteratorPositionsExcept(ProgramStateRef State,
133*5ffd83dbSDimitry Andric                                      const MemRegion *Cont, SymbolRef Offset,
134*5ffd83dbSDimitry Andric                                      BinaryOperator::Opcode Opc);
135*5ffd83dbSDimitry Andric ProgramStateRef invalidateIteratorPositions(ProgramStateRef State,
136*5ffd83dbSDimitry Andric                                             SymbolRef Offset,
137*5ffd83dbSDimitry Andric                                             BinaryOperator::Opcode Opc);
138*5ffd83dbSDimitry Andric ProgramStateRef invalidateIteratorPositions(ProgramStateRef State,
139*5ffd83dbSDimitry Andric                                             SymbolRef Offset1,
140*5ffd83dbSDimitry Andric                                             BinaryOperator::Opcode Opc1,
141*5ffd83dbSDimitry Andric                                             SymbolRef Offset2,
142*5ffd83dbSDimitry Andric                                             BinaryOperator::Opcode Opc2);
143*5ffd83dbSDimitry Andric ProgramStateRef reassignAllIteratorPositions(ProgramStateRef State,
144*5ffd83dbSDimitry Andric                                              const MemRegion *Cont,
145*5ffd83dbSDimitry Andric                                              const MemRegion *NewCont);
146*5ffd83dbSDimitry Andric ProgramStateRef reassignAllIteratorPositionsUnless(ProgramStateRef State,
147*5ffd83dbSDimitry Andric                                                    const MemRegion *Cont,
148*5ffd83dbSDimitry Andric                                                    const MemRegion *NewCont,
149*5ffd83dbSDimitry Andric                                                    SymbolRef Offset,
150*5ffd83dbSDimitry Andric                                                    BinaryOperator::Opcode Opc);
151*5ffd83dbSDimitry Andric ProgramStateRef rebaseSymbolInIteratorPositionsIf(
152*5ffd83dbSDimitry Andric     ProgramStateRef State, SValBuilder &SVB, SymbolRef OldSym,
153*5ffd83dbSDimitry Andric     SymbolRef NewSym, SymbolRef CondSym, BinaryOperator::Opcode Opc);
154*5ffd83dbSDimitry Andric SymbolRef rebaseSymbol(ProgramStateRef State, SValBuilder &SVB, SymbolRef Expr,
155*5ffd83dbSDimitry Andric                         SymbolRef OldSym, SymbolRef NewSym);
156*5ffd83dbSDimitry Andric bool hasLiveIterators(ProgramStateRef State, const MemRegion *Cont);
157*5ffd83dbSDimitry Andric 
158*5ffd83dbSDimitry Andric } // namespace
159*5ffd83dbSDimitry Andric 
160*5ffd83dbSDimitry Andric void ContainerModeling::checkPostCall(const CallEvent &Call,
161*5ffd83dbSDimitry Andric                                      CheckerContext &C) const {
162*5ffd83dbSDimitry Andric   const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
163*5ffd83dbSDimitry Andric   if (!Func)
164*5ffd83dbSDimitry Andric     return;
165*5ffd83dbSDimitry Andric 
166*5ffd83dbSDimitry Andric   if (Func->isOverloadedOperator()) {
167*5ffd83dbSDimitry Andric     const auto Op = Func->getOverloadedOperator();
168*5ffd83dbSDimitry Andric     if (Op == OO_Equal) {
169*5ffd83dbSDimitry Andric       // Overloaded 'operator=' must be a non-static member function.
170*5ffd83dbSDimitry Andric       const auto *InstCall = cast<CXXInstanceCall>(&Call);
171*5ffd83dbSDimitry Andric       if (cast<CXXMethodDecl>(Func)->isMoveAssignmentOperator()) {
172*5ffd83dbSDimitry Andric         handleAssignment(C, InstCall->getCXXThisVal(), Call.getOriginExpr(),
173*5ffd83dbSDimitry Andric                      Call.getArgSVal(0));
174*5ffd83dbSDimitry Andric         return;
175*5ffd83dbSDimitry Andric       }
176*5ffd83dbSDimitry Andric 
177*5ffd83dbSDimitry Andric       handleAssignment(C, InstCall->getCXXThisVal());
178*5ffd83dbSDimitry Andric       return;
179*5ffd83dbSDimitry Andric     }
180*5ffd83dbSDimitry Andric   } else {
181*5ffd83dbSDimitry Andric     if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
182*5ffd83dbSDimitry Andric       const NoItParamFn *Handler0 = NoIterParamFunctions.lookup(Call);
183*5ffd83dbSDimitry Andric       if (Handler0) {
184*5ffd83dbSDimitry Andric         (this->**Handler0)(C, InstCall->getCXXThisVal(),
185*5ffd83dbSDimitry Andric                            InstCall->getCXXThisExpr());
186*5ffd83dbSDimitry Andric         return;
187*5ffd83dbSDimitry Andric       }
188*5ffd83dbSDimitry Andric 
189*5ffd83dbSDimitry Andric       const OneItParamFn *Handler1 = OneIterParamFunctions.lookup(Call);
190*5ffd83dbSDimitry Andric       if (Handler1) {
191*5ffd83dbSDimitry Andric         (this->**Handler1)(C, InstCall->getCXXThisVal(), Call.getArgSVal(0));
192*5ffd83dbSDimitry Andric         return;
193*5ffd83dbSDimitry Andric       }
194*5ffd83dbSDimitry Andric 
195*5ffd83dbSDimitry Andric       const TwoItParamFn *Handler2 = TwoIterParamFunctions.lookup(Call);
196*5ffd83dbSDimitry Andric       if (Handler2) {
197*5ffd83dbSDimitry Andric         (this->**Handler2)(C, InstCall->getCXXThisVal(), Call.getArgSVal(0),
198*5ffd83dbSDimitry Andric                            Call.getArgSVal(1));
199*5ffd83dbSDimitry Andric         return;
200*5ffd83dbSDimitry Andric       }
201*5ffd83dbSDimitry Andric 
202*5ffd83dbSDimitry Andric       const auto *OrigExpr = Call.getOriginExpr();
203*5ffd83dbSDimitry Andric       if (!OrigExpr)
204*5ffd83dbSDimitry Andric         return;
205*5ffd83dbSDimitry Andric 
206*5ffd83dbSDimitry Andric       if (isBeginCall(Func)) {
207*5ffd83dbSDimitry Andric         handleBegin(C, OrigExpr, Call.getReturnValue(),
208*5ffd83dbSDimitry Andric                     InstCall->getCXXThisVal());
209*5ffd83dbSDimitry Andric         return;
210*5ffd83dbSDimitry Andric       }
211*5ffd83dbSDimitry Andric 
212*5ffd83dbSDimitry Andric       if (isEndCall(Func)) {
213*5ffd83dbSDimitry Andric         handleEnd(C, OrigExpr, Call.getReturnValue(),
214*5ffd83dbSDimitry Andric                   InstCall->getCXXThisVal());
215*5ffd83dbSDimitry Andric         return;
216*5ffd83dbSDimitry Andric       }
217*5ffd83dbSDimitry Andric     }
218*5ffd83dbSDimitry Andric   }
219*5ffd83dbSDimitry Andric }
220*5ffd83dbSDimitry Andric 
221*5ffd83dbSDimitry Andric void ContainerModeling::checkLiveSymbols(ProgramStateRef State,
222*5ffd83dbSDimitry Andric                                          SymbolReaper &SR) const {
223*5ffd83dbSDimitry Andric   // Keep symbolic expressions of container begins and ends alive
224*5ffd83dbSDimitry Andric   auto ContMap = State->get<ContainerMap>();
225*5ffd83dbSDimitry Andric   for (const auto &Cont : ContMap) {
226*5ffd83dbSDimitry Andric     const auto CData = Cont.second;
227*5ffd83dbSDimitry Andric     if (CData.getBegin()) {
228*5ffd83dbSDimitry Andric       SR.markLive(CData.getBegin());
229*5ffd83dbSDimitry Andric       if(const auto *SIE = dyn_cast<SymIntExpr>(CData.getBegin()))
230*5ffd83dbSDimitry Andric         SR.markLive(SIE->getLHS());
231*5ffd83dbSDimitry Andric     }
232*5ffd83dbSDimitry Andric     if (CData.getEnd()) {
233*5ffd83dbSDimitry Andric       SR.markLive(CData.getEnd());
234*5ffd83dbSDimitry Andric       if(const auto *SIE = dyn_cast<SymIntExpr>(CData.getEnd()))
235*5ffd83dbSDimitry Andric         SR.markLive(SIE->getLHS());
236*5ffd83dbSDimitry Andric     }
237*5ffd83dbSDimitry Andric   }
238*5ffd83dbSDimitry Andric }
239*5ffd83dbSDimitry Andric 
240*5ffd83dbSDimitry Andric void ContainerModeling::checkDeadSymbols(SymbolReaper &SR,
241*5ffd83dbSDimitry Andric                                          CheckerContext &C) const {
242*5ffd83dbSDimitry Andric   // Cleanup
243*5ffd83dbSDimitry Andric   auto State = C.getState();
244*5ffd83dbSDimitry Andric 
245*5ffd83dbSDimitry Andric   auto ContMap = State->get<ContainerMap>();
246*5ffd83dbSDimitry Andric   for (const auto &Cont : ContMap) {
247*5ffd83dbSDimitry Andric     if (!SR.isLiveRegion(Cont.first)) {
248*5ffd83dbSDimitry Andric       // We must keep the container data while it has live iterators to be able
249*5ffd83dbSDimitry Andric       // to compare them to the begin and the end of the container.
250*5ffd83dbSDimitry Andric       if (!hasLiveIterators(State, Cont.first)) {
251*5ffd83dbSDimitry Andric         State = State->remove<ContainerMap>(Cont.first);
252*5ffd83dbSDimitry Andric       }
253*5ffd83dbSDimitry Andric     }
254*5ffd83dbSDimitry Andric   }
255*5ffd83dbSDimitry Andric 
256*5ffd83dbSDimitry Andric   C.addTransition(State);
257*5ffd83dbSDimitry Andric }
258*5ffd83dbSDimitry Andric 
259*5ffd83dbSDimitry Andric void ContainerModeling::handleBegin(CheckerContext &C, const Expr *CE,
260*5ffd83dbSDimitry Andric                                    SVal RetVal, SVal Cont) const {
261*5ffd83dbSDimitry Andric   const auto *ContReg = Cont.getAsRegion();
262*5ffd83dbSDimitry Andric   if (!ContReg)
263*5ffd83dbSDimitry Andric     return;
264*5ffd83dbSDimitry Andric 
265*5ffd83dbSDimitry Andric   ContReg = ContReg->getMostDerivedObjectRegion();
266*5ffd83dbSDimitry Andric 
267*5ffd83dbSDimitry Andric   // If the container already has a begin symbol then use it. Otherwise first
268*5ffd83dbSDimitry Andric   // create a new one.
269*5ffd83dbSDimitry Andric   auto State = C.getState();
270*5ffd83dbSDimitry Andric   auto BeginSym = getContainerBegin(State, ContReg);
271*5ffd83dbSDimitry Andric   if (!BeginSym) {
272*5ffd83dbSDimitry Andric     State = createContainerBegin(State, ContReg, CE, C.getASTContext().LongTy,
273*5ffd83dbSDimitry Andric                                  C.getLocationContext(), C.blockCount());
274*5ffd83dbSDimitry Andric     BeginSym = getContainerBegin(State, ContReg);
275*5ffd83dbSDimitry Andric   }
276*5ffd83dbSDimitry Andric   State = setIteratorPosition(State, RetVal,
277*5ffd83dbSDimitry Andric                               IteratorPosition::getPosition(ContReg, BeginSym));
278*5ffd83dbSDimitry Andric   C.addTransition(State);
279*5ffd83dbSDimitry Andric }
280*5ffd83dbSDimitry Andric 
281*5ffd83dbSDimitry Andric void ContainerModeling::handleEnd(CheckerContext &C, const Expr *CE,
282*5ffd83dbSDimitry Andric                                  SVal RetVal, SVal Cont) const {
283*5ffd83dbSDimitry Andric   const auto *ContReg = Cont.getAsRegion();
284*5ffd83dbSDimitry Andric   if (!ContReg)
285*5ffd83dbSDimitry Andric     return;
286*5ffd83dbSDimitry Andric 
287*5ffd83dbSDimitry Andric   ContReg = ContReg->getMostDerivedObjectRegion();
288*5ffd83dbSDimitry Andric 
289*5ffd83dbSDimitry Andric   // If the container already has an end symbol then use it. Otherwise first
290*5ffd83dbSDimitry Andric   // create a new one.
291*5ffd83dbSDimitry Andric   auto State = C.getState();
292*5ffd83dbSDimitry Andric   auto EndSym = getContainerEnd(State, ContReg);
293*5ffd83dbSDimitry Andric   if (!EndSym) {
294*5ffd83dbSDimitry Andric     State = createContainerEnd(State, ContReg, CE, C.getASTContext().LongTy,
295*5ffd83dbSDimitry Andric                                C.getLocationContext(), C.blockCount());
296*5ffd83dbSDimitry Andric     EndSym = getContainerEnd(State, ContReg);
297*5ffd83dbSDimitry Andric   }
298*5ffd83dbSDimitry Andric   State = setIteratorPosition(State, RetVal,
299*5ffd83dbSDimitry Andric                               IteratorPosition::getPosition(ContReg, EndSym));
300*5ffd83dbSDimitry Andric   C.addTransition(State);
301*5ffd83dbSDimitry Andric }
302*5ffd83dbSDimitry Andric 
303*5ffd83dbSDimitry Andric void ContainerModeling::handleAssignment(CheckerContext &C, SVal Cont,
304*5ffd83dbSDimitry Andric                                          const Expr *CE, SVal OldCont) const {
305*5ffd83dbSDimitry Andric   const auto *ContReg = Cont.getAsRegion();
306*5ffd83dbSDimitry Andric   if (!ContReg)
307*5ffd83dbSDimitry Andric     return;
308*5ffd83dbSDimitry Andric 
309*5ffd83dbSDimitry Andric   ContReg = ContReg->getMostDerivedObjectRegion();
310*5ffd83dbSDimitry Andric 
311*5ffd83dbSDimitry Andric   // Assignment of a new value to a container always invalidates all its
312*5ffd83dbSDimitry Andric   // iterators
313*5ffd83dbSDimitry Andric   auto State = C.getState();
314*5ffd83dbSDimitry Andric   const auto CData = getContainerData(State, ContReg);
315*5ffd83dbSDimitry Andric   if (CData) {
316*5ffd83dbSDimitry Andric     State = invalidateAllIteratorPositions(State, ContReg);
317*5ffd83dbSDimitry Andric   }
318*5ffd83dbSDimitry Andric 
319*5ffd83dbSDimitry Andric   // In case of move, iterators of the old container (except the past-end
320*5ffd83dbSDimitry Andric   // iterators) remain valid but refer to the new container
321*5ffd83dbSDimitry Andric   if (!OldCont.isUndef()) {
322*5ffd83dbSDimitry Andric     const auto *OldContReg = OldCont.getAsRegion();
323*5ffd83dbSDimitry Andric     if (OldContReg) {
324*5ffd83dbSDimitry Andric       OldContReg = OldContReg->getMostDerivedObjectRegion();
325*5ffd83dbSDimitry Andric       const auto OldCData = getContainerData(State, OldContReg);
326*5ffd83dbSDimitry Andric       if (OldCData) {
327*5ffd83dbSDimitry Andric         if (const auto OldEndSym = OldCData->getEnd()) {
328*5ffd83dbSDimitry Andric           // If we already assigned an "end" symbol to the old container, then
329*5ffd83dbSDimitry Andric           // first reassign all iterator positions to the new container which
330*5ffd83dbSDimitry Andric           // are not past the container (thus not greater or equal to the
331*5ffd83dbSDimitry Andric           // current "end" symbol).
332*5ffd83dbSDimitry Andric           State = reassignAllIteratorPositionsUnless(State, OldContReg, ContReg,
333*5ffd83dbSDimitry Andric                                                      OldEndSym, BO_GE);
334*5ffd83dbSDimitry Andric           auto &SymMgr = C.getSymbolManager();
335*5ffd83dbSDimitry Andric           auto &SVB = C.getSValBuilder();
336*5ffd83dbSDimitry Andric           // Then generate and assign a new "end" symbol for the new container.
337*5ffd83dbSDimitry Andric           auto NewEndSym =
338*5ffd83dbSDimitry Andric               SymMgr.conjureSymbol(CE, C.getLocationContext(),
339*5ffd83dbSDimitry Andric                                    C.getASTContext().LongTy, C.blockCount());
340*5ffd83dbSDimitry Andric           State = assumeNoOverflow(State, NewEndSym, 4);
341*5ffd83dbSDimitry Andric           if (CData) {
342*5ffd83dbSDimitry Andric             State = setContainerData(State, ContReg, CData->newEnd(NewEndSym));
343*5ffd83dbSDimitry Andric           } else {
344*5ffd83dbSDimitry Andric             State = setContainerData(State, ContReg,
345*5ffd83dbSDimitry Andric                                      ContainerData::fromEnd(NewEndSym));
346*5ffd83dbSDimitry Andric           }
347*5ffd83dbSDimitry Andric           // Finally, replace the old "end" symbol in the already reassigned
348*5ffd83dbSDimitry Andric           // iterator positions with the new "end" symbol.
349*5ffd83dbSDimitry Andric           State = rebaseSymbolInIteratorPositionsIf(
350*5ffd83dbSDimitry Andric               State, SVB, OldEndSym, NewEndSym, OldEndSym, BO_LT);
351*5ffd83dbSDimitry Andric         } else {
352*5ffd83dbSDimitry Andric           // There was no "end" symbol assigned yet to the old container,
353*5ffd83dbSDimitry Andric           // so reassign all iterator positions to the new container.
354*5ffd83dbSDimitry Andric           State = reassignAllIteratorPositions(State, OldContReg, ContReg);
355*5ffd83dbSDimitry Andric         }
356*5ffd83dbSDimitry Andric         if (const auto OldBeginSym = OldCData->getBegin()) {
357*5ffd83dbSDimitry Andric           // If we already assigned a "begin" symbol to the old container, then
358*5ffd83dbSDimitry Andric           // assign it to the new container and remove it from the old one.
359*5ffd83dbSDimitry Andric           if (CData) {
360*5ffd83dbSDimitry Andric             State =
361*5ffd83dbSDimitry Andric                 setContainerData(State, ContReg, CData->newBegin(OldBeginSym));
362*5ffd83dbSDimitry Andric           } else {
363*5ffd83dbSDimitry Andric             State = setContainerData(State, ContReg,
364*5ffd83dbSDimitry Andric                                      ContainerData::fromBegin(OldBeginSym));
365*5ffd83dbSDimitry Andric           }
366*5ffd83dbSDimitry Andric           State =
367*5ffd83dbSDimitry Andric               setContainerData(State, OldContReg, OldCData->newBegin(nullptr));
368*5ffd83dbSDimitry Andric         }
369*5ffd83dbSDimitry Andric       } else {
370*5ffd83dbSDimitry Andric         // There was neither "begin" nor "end" symbol assigned yet to the old
371*5ffd83dbSDimitry Andric         // container, so reassign all iterator positions to the new container.
372*5ffd83dbSDimitry Andric         State = reassignAllIteratorPositions(State, OldContReg, ContReg);
373*5ffd83dbSDimitry Andric       }
374*5ffd83dbSDimitry Andric     }
375*5ffd83dbSDimitry Andric   }
376*5ffd83dbSDimitry Andric   C.addTransition(State);
377*5ffd83dbSDimitry Andric }
378*5ffd83dbSDimitry Andric 
379*5ffd83dbSDimitry Andric void ContainerModeling::handleAssign(CheckerContext &C, SVal Cont,
380*5ffd83dbSDimitry Andric                                      const Expr *ContE) const {
381*5ffd83dbSDimitry Andric   const auto *ContReg = Cont.getAsRegion();
382*5ffd83dbSDimitry Andric   if (!ContReg)
383*5ffd83dbSDimitry Andric     return;
384*5ffd83dbSDimitry Andric 
385*5ffd83dbSDimitry Andric   ContReg = ContReg->getMostDerivedObjectRegion();
386*5ffd83dbSDimitry Andric 
387*5ffd83dbSDimitry Andric   // The assign() operation invalidates all the iterators
388*5ffd83dbSDimitry Andric   auto State = C.getState();
389*5ffd83dbSDimitry Andric   State = invalidateAllIteratorPositions(State, ContReg);
390*5ffd83dbSDimitry Andric   C.addTransition(State);
391*5ffd83dbSDimitry Andric }
392*5ffd83dbSDimitry Andric 
393*5ffd83dbSDimitry Andric void ContainerModeling::handleClear(CheckerContext &C, SVal Cont,
394*5ffd83dbSDimitry Andric                                     const Expr *ContE) const {
395*5ffd83dbSDimitry Andric   const auto *ContReg = Cont.getAsRegion();
396*5ffd83dbSDimitry Andric   if (!ContReg)
397*5ffd83dbSDimitry Andric     return;
398*5ffd83dbSDimitry Andric 
399*5ffd83dbSDimitry Andric   ContReg = ContReg->getMostDerivedObjectRegion();
400*5ffd83dbSDimitry Andric 
401*5ffd83dbSDimitry Andric   // The clear() operation invalidates all the iterators, except the past-end
402*5ffd83dbSDimitry Andric   // iterators of list-like containers
403*5ffd83dbSDimitry Andric   auto State = C.getState();
404*5ffd83dbSDimitry Andric   if (!hasSubscriptOperator(State, ContReg) ||
405*5ffd83dbSDimitry Andric       !backModifiable(State, ContReg)) {
406*5ffd83dbSDimitry Andric     const auto CData = getContainerData(State, ContReg);
407*5ffd83dbSDimitry Andric     if (CData) {
408*5ffd83dbSDimitry Andric       if (const auto EndSym = CData->getEnd()) {
409*5ffd83dbSDimitry Andric         State =
410*5ffd83dbSDimitry Andric             invalidateAllIteratorPositionsExcept(State, ContReg, EndSym, BO_GE);
411*5ffd83dbSDimitry Andric         C.addTransition(State);
412*5ffd83dbSDimitry Andric         return;
413*5ffd83dbSDimitry Andric       }
414*5ffd83dbSDimitry Andric     }
415*5ffd83dbSDimitry Andric   }
416*5ffd83dbSDimitry Andric   const NoteTag *ChangeTag =
417*5ffd83dbSDimitry Andric     getChangeTag(C, "became empty", ContReg, ContE);
418*5ffd83dbSDimitry Andric   State = invalidateAllIteratorPositions(State, ContReg);
419*5ffd83dbSDimitry Andric   C.addTransition(State, ChangeTag);
420*5ffd83dbSDimitry Andric }
421*5ffd83dbSDimitry Andric 
422*5ffd83dbSDimitry Andric void ContainerModeling::handlePushBack(CheckerContext &C, SVal Cont,
423*5ffd83dbSDimitry Andric                                        const Expr *ContE) const {
424*5ffd83dbSDimitry Andric   const auto *ContReg = Cont.getAsRegion();
425*5ffd83dbSDimitry Andric   if (!ContReg)
426*5ffd83dbSDimitry Andric     return;
427*5ffd83dbSDimitry Andric 
428*5ffd83dbSDimitry Andric   ContReg = ContReg->getMostDerivedObjectRegion();
429*5ffd83dbSDimitry Andric 
430*5ffd83dbSDimitry Andric   // For deque-like containers invalidate all iterator positions
431*5ffd83dbSDimitry Andric   auto State = C.getState();
432*5ffd83dbSDimitry Andric   if (hasSubscriptOperator(State, ContReg) && frontModifiable(State, ContReg)) {
433*5ffd83dbSDimitry Andric     State = invalidateAllIteratorPositions(State, ContReg);
434*5ffd83dbSDimitry Andric     C.addTransition(State);
435*5ffd83dbSDimitry Andric     return;
436*5ffd83dbSDimitry Andric   }
437*5ffd83dbSDimitry Andric 
438*5ffd83dbSDimitry Andric   const auto CData = getContainerData(State, ContReg);
439*5ffd83dbSDimitry Andric   if (!CData)
440*5ffd83dbSDimitry Andric     return;
441*5ffd83dbSDimitry Andric 
442*5ffd83dbSDimitry Andric   // For vector-like containers invalidate the past-end iterator positions
443*5ffd83dbSDimitry Andric   if (const auto EndSym = CData->getEnd()) {
444*5ffd83dbSDimitry Andric     if (hasSubscriptOperator(State, ContReg)) {
445*5ffd83dbSDimitry Andric       State = invalidateIteratorPositions(State, EndSym, BO_GE);
446*5ffd83dbSDimitry Andric     }
447*5ffd83dbSDimitry Andric     auto &SymMgr = C.getSymbolManager();
448*5ffd83dbSDimitry Andric     auto &BVF = SymMgr.getBasicVals();
449*5ffd83dbSDimitry Andric     auto &SVB = C.getSValBuilder();
450*5ffd83dbSDimitry Andric     const auto newEndSym =
451*5ffd83dbSDimitry Andric       SVB.evalBinOp(State, BO_Add,
452*5ffd83dbSDimitry Andric                     nonloc::SymbolVal(EndSym),
453*5ffd83dbSDimitry Andric                     nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
454*5ffd83dbSDimitry Andric                     SymMgr.getType(EndSym)).getAsSymbol();
455*5ffd83dbSDimitry Andric     const NoteTag *ChangeTag =
456*5ffd83dbSDimitry Andric       getChangeTag(C, "extended to the back by 1 position", ContReg, ContE);
457*5ffd83dbSDimitry Andric     State = setContainerData(State, ContReg, CData->newEnd(newEndSym));
458*5ffd83dbSDimitry Andric     C.addTransition(State, ChangeTag);
459*5ffd83dbSDimitry Andric   }
460*5ffd83dbSDimitry Andric }
461*5ffd83dbSDimitry Andric 
462*5ffd83dbSDimitry Andric void ContainerModeling::handlePopBack(CheckerContext &C, SVal Cont,
463*5ffd83dbSDimitry Andric                                       const Expr *ContE) const {
464*5ffd83dbSDimitry Andric   const auto *ContReg = Cont.getAsRegion();
465*5ffd83dbSDimitry Andric   if (!ContReg)
466*5ffd83dbSDimitry Andric     return;
467*5ffd83dbSDimitry Andric 
468*5ffd83dbSDimitry Andric   ContReg = ContReg->getMostDerivedObjectRegion();
469*5ffd83dbSDimitry Andric 
470*5ffd83dbSDimitry Andric   auto State = C.getState();
471*5ffd83dbSDimitry Andric   const auto CData = getContainerData(State, ContReg);
472*5ffd83dbSDimitry Andric   if (!CData)
473*5ffd83dbSDimitry Andric     return;
474*5ffd83dbSDimitry Andric 
475*5ffd83dbSDimitry Andric   if (const auto EndSym = CData->getEnd()) {
476*5ffd83dbSDimitry Andric     auto &SymMgr = C.getSymbolManager();
477*5ffd83dbSDimitry Andric     auto &BVF = SymMgr.getBasicVals();
478*5ffd83dbSDimitry Andric     auto &SVB = C.getSValBuilder();
479*5ffd83dbSDimitry Andric     const auto BackSym =
480*5ffd83dbSDimitry Andric       SVB.evalBinOp(State, BO_Sub,
481*5ffd83dbSDimitry Andric                     nonloc::SymbolVal(EndSym),
482*5ffd83dbSDimitry Andric                     nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
483*5ffd83dbSDimitry Andric                     SymMgr.getType(EndSym)).getAsSymbol();
484*5ffd83dbSDimitry Andric     const NoteTag *ChangeTag =
485*5ffd83dbSDimitry Andric       getChangeTag(C, "shrank from the back by 1 position", ContReg, ContE);
486*5ffd83dbSDimitry Andric     // For vector-like and deque-like containers invalidate the last and the
487*5ffd83dbSDimitry Andric     // past-end iterator positions. For list-like containers only invalidate
488*5ffd83dbSDimitry Andric     // the last position
489*5ffd83dbSDimitry Andric     if (hasSubscriptOperator(State, ContReg) &&
490*5ffd83dbSDimitry Andric         backModifiable(State, ContReg)) {
491*5ffd83dbSDimitry Andric       State = invalidateIteratorPositions(State, BackSym, BO_GE);
492*5ffd83dbSDimitry Andric       State = setContainerData(State, ContReg, CData->newEnd(nullptr));
493*5ffd83dbSDimitry Andric     } else {
494*5ffd83dbSDimitry Andric       State = invalidateIteratorPositions(State, BackSym, BO_EQ);
495*5ffd83dbSDimitry Andric     }
496*5ffd83dbSDimitry Andric     auto newEndSym = BackSym;
497*5ffd83dbSDimitry Andric     State = setContainerData(State, ContReg, CData->newEnd(newEndSym));
498*5ffd83dbSDimitry Andric     C.addTransition(State, ChangeTag);
499*5ffd83dbSDimitry Andric   }
500*5ffd83dbSDimitry Andric }
501*5ffd83dbSDimitry Andric 
502*5ffd83dbSDimitry Andric void ContainerModeling::handlePushFront(CheckerContext &C, SVal Cont,
503*5ffd83dbSDimitry Andric                                         const Expr *ContE) const {
504*5ffd83dbSDimitry Andric   const auto *ContReg = Cont.getAsRegion();
505*5ffd83dbSDimitry Andric   if (!ContReg)
506*5ffd83dbSDimitry Andric     return;
507*5ffd83dbSDimitry Andric 
508*5ffd83dbSDimitry Andric   ContReg = ContReg->getMostDerivedObjectRegion();
509*5ffd83dbSDimitry Andric 
510*5ffd83dbSDimitry Andric   // For deque-like containers invalidate all iterator positions
511*5ffd83dbSDimitry Andric   auto State = C.getState();
512*5ffd83dbSDimitry Andric   if (hasSubscriptOperator(State, ContReg)) {
513*5ffd83dbSDimitry Andric     State = invalidateAllIteratorPositions(State, ContReg);
514*5ffd83dbSDimitry Andric     C.addTransition(State);
515*5ffd83dbSDimitry Andric   } else {
516*5ffd83dbSDimitry Andric     const auto CData = getContainerData(State, ContReg);
517*5ffd83dbSDimitry Andric     if (!CData)
518*5ffd83dbSDimitry Andric       return;
519*5ffd83dbSDimitry Andric 
520*5ffd83dbSDimitry Andric     if (const auto BeginSym = CData->getBegin()) {
521*5ffd83dbSDimitry Andric       auto &SymMgr = C.getSymbolManager();
522*5ffd83dbSDimitry Andric       auto &BVF = SymMgr.getBasicVals();
523*5ffd83dbSDimitry Andric       auto &SVB = C.getSValBuilder();
524*5ffd83dbSDimitry Andric       const auto newBeginSym =
525*5ffd83dbSDimitry Andric         SVB.evalBinOp(State, BO_Sub,
526*5ffd83dbSDimitry Andric                       nonloc::SymbolVal(BeginSym),
527*5ffd83dbSDimitry Andric                       nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
528*5ffd83dbSDimitry Andric                       SymMgr.getType(BeginSym)).getAsSymbol();
529*5ffd83dbSDimitry Andric       const NoteTag *ChangeTag =
530*5ffd83dbSDimitry Andric         getChangeTag(C, "extended to the front by 1 position", ContReg, ContE);
531*5ffd83dbSDimitry Andric       State = setContainerData(State, ContReg, CData->newBegin(newBeginSym));
532*5ffd83dbSDimitry Andric       C.addTransition(State, ChangeTag);
533*5ffd83dbSDimitry Andric     }
534*5ffd83dbSDimitry Andric   }
535*5ffd83dbSDimitry Andric }
536*5ffd83dbSDimitry Andric 
537*5ffd83dbSDimitry Andric void ContainerModeling::handlePopFront(CheckerContext &C, SVal Cont,
538*5ffd83dbSDimitry Andric                                        const Expr *ContE) const {
539*5ffd83dbSDimitry Andric   const auto *ContReg = Cont.getAsRegion();
540*5ffd83dbSDimitry Andric   if (!ContReg)
541*5ffd83dbSDimitry Andric     return;
542*5ffd83dbSDimitry Andric 
543*5ffd83dbSDimitry Andric   ContReg = ContReg->getMostDerivedObjectRegion();
544*5ffd83dbSDimitry Andric 
545*5ffd83dbSDimitry Andric   auto State = C.getState();
546*5ffd83dbSDimitry Andric   const auto CData = getContainerData(State, ContReg);
547*5ffd83dbSDimitry Andric   if (!CData)
548*5ffd83dbSDimitry Andric     return;
549*5ffd83dbSDimitry Andric 
550*5ffd83dbSDimitry Andric   // For deque-like containers invalidate all iterator positions. For list-like
551*5ffd83dbSDimitry Andric   // iterators only invalidate the first position
552*5ffd83dbSDimitry Andric   if (const auto BeginSym = CData->getBegin()) {
553*5ffd83dbSDimitry Andric     if (hasSubscriptOperator(State, ContReg)) {
554*5ffd83dbSDimitry Andric       State = invalidateIteratorPositions(State, BeginSym, BO_LE);
555*5ffd83dbSDimitry Andric     } else {
556*5ffd83dbSDimitry Andric       State = invalidateIteratorPositions(State, BeginSym, BO_EQ);
557*5ffd83dbSDimitry Andric     }
558*5ffd83dbSDimitry Andric     auto &SymMgr = C.getSymbolManager();
559*5ffd83dbSDimitry Andric     auto &BVF = SymMgr.getBasicVals();
560*5ffd83dbSDimitry Andric     auto &SVB = C.getSValBuilder();
561*5ffd83dbSDimitry Andric     const auto newBeginSym =
562*5ffd83dbSDimitry Andric       SVB.evalBinOp(State, BO_Add,
563*5ffd83dbSDimitry Andric                     nonloc::SymbolVal(BeginSym),
564*5ffd83dbSDimitry Andric                     nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
565*5ffd83dbSDimitry Andric                     SymMgr.getType(BeginSym)).getAsSymbol();
566*5ffd83dbSDimitry Andric     const NoteTag *ChangeTag =
567*5ffd83dbSDimitry Andric       getChangeTag(C, "shrank from the front by 1 position", ContReg, ContE);
568*5ffd83dbSDimitry Andric     State = setContainerData(State, ContReg, CData->newBegin(newBeginSym));
569*5ffd83dbSDimitry Andric     C.addTransition(State, ChangeTag);
570*5ffd83dbSDimitry Andric   }
571*5ffd83dbSDimitry Andric }
572*5ffd83dbSDimitry Andric 
573*5ffd83dbSDimitry Andric void ContainerModeling::handleInsert(CheckerContext &C, SVal Cont,
574*5ffd83dbSDimitry Andric                                      SVal Iter) const {
575*5ffd83dbSDimitry Andric   const auto *ContReg = Cont.getAsRegion();
576*5ffd83dbSDimitry Andric   if (!ContReg)
577*5ffd83dbSDimitry Andric     return;
578*5ffd83dbSDimitry Andric 
579*5ffd83dbSDimitry Andric   ContReg = ContReg->getMostDerivedObjectRegion();
580*5ffd83dbSDimitry Andric 
581*5ffd83dbSDimitry Andric   auto State = C.getState();
582*5ffd83dbSDimitry Andric   const auto *Pos = getIteratorPosition(State, Iter);
583*5ffd83dbSDimitry Andric   if (!Pos)
584*5ffd83dbSDimitry Andric     return;
585*5ffd83dbSDimitry Andric 
586*5ffd83dbSDimitry Andric   // For deque-like containers invalidate all iterator positions. For
587*5ffd83dbSDimitry Andric   // vector-like containers invalidate iterator positions after the insertion.
588*5ffd83dbSDimitry Andric   if (hasSubscriptOperator(State, ContReg) && backModifiable(State, ContReg)) {
589*5ffd83dbSDimitry Andric     if (frontModifiable(State, ContReg)) {
590*5ffd83dbSDimitry Andric       State = invalidateAllIteratorPositions(State, ContReg);
591*5ffd83dbSDimitry Andric     } else {
592*5ffd83dbSDimitry Andric       State = invalidateIteratorPositions(State, Pos->getOffset(), BO_GE);
593*5ffd83dbSDimitry Andric     }
594*5ffd83dbSDimitry Andric     if (const auto *CData = getContainerData(State, ContReg)) {
595*5ffd83dbSDimitry Andric       if (const auto EndSym = CData->getEnd()) {
596*5ffd83dbSDimitry Andric         State = invalidateIteratorPositions(State, EndSym, BO_GE);
597*5ffd83dbSDimitry Andric         State = setContainerData(State, ContReg, CData->newEnd(nullptr));
598*5ffd83dbSDimitry Andric       }
599*5ffd83dbSDimitry Andric     }
600*5ffd83dbSDimitry Andric     C.addTransition(State);
601*5ffd83dbSDimitry Andric   }
602*5ffd83dbSDimitry Andric }
603*5ffd83dbSDimitry Andric 
604*5ffd83dbSDimitry Andric void ContainerModeling::handleErase(CheckerContext &C, SVal Cont,
605*5ffd83dbSDimitry Andric                                     SVal Iter) const {
606*5ffd83dbSDimitry Andric   const auto *ContReg = Cont.getAsRegion();
607*5ffd83dbSDimitry Andric   if (!ContReg)
608*5ffd83dbSDimitry Andric     return;
609*5ffd83dbSDimitry Andric 
610*5ffd83dbSDimitry Andric   ContReg = ContReg->getMostDerivedObjectRegion();
611*5ffd83dbSDimitry Andric 
612*5ffd83dbSDimitry Andric   auto State = C.getState();
613*5ffd83dbSDimitry Andric   const auto *Pos = getIteratorPosition(State, Iter);
614*5ffd83dbSDimitry Andric   if (!Pos)
615*5ffd83dbSDimitry Andric     return;
616*5ffd83dbSDimitry Andric 
617*5ffd83dbSDimitry Andric   // For deque-like containers invalidate all iterator positions. For
618*5ffd83dbSDimitry Andric   // vector-like containers invalidate iterator positions at and after the
619*5ffd83dbSDimitry Andric   // deletion. For list-like containers only invalidate the deleted position.
620*5ffd83dbSDimitry Andric   if (hasSubscriptOperator(State, ContReg) && backModifiable(State, ContReg)) {
621*5ffd83dbSDimitry Andric     if (frontModifiable(State, ContReg)) {
622*5ffd83dbSDimitry Andric       State = invalidateAllIteratorPositions(State, ContReg);
623*5ffd83dbSDimitry Andric     } else {
624*5ffd83dbSDimitry Andric       State = invalidateIteratorPositions(State, Pos->getOffset(), BO_GE);
625*5ffd83dbSDimitry Andric     }
626*5ffd83dbSDimitry Andric     if (const auto *CData = getContainerData(State, ContReg)) {
627*5ffd83dbSDimitry Andric       if (const auto EndSym = CData->getEnd()) {
628*5ffd83dbSDimitry Andric         State = invalidateIteratorPositions(State, EndSym, BO_GE);
629*5ffd83dbSDimitry Andric         State = setContainerData(State, ContReg, CData->newEnd(nullptr));
630*5ffd83dbSDimitry Andric       }
631*5ffd83dbSDimitry Andric     }
632*5ffd83dbSDimitry Andric   } else {
633*5ffd83dbSDimitry Andric     State = invalidateIteratorPositions(State, Pos->getOffset(), BO_EQ);
634*5ffd83dbSDimitry Andric   }
635*5ffd83dbSDimitry Andric   C.addTransition(State);
636*5ffd83dbSDimitry Andric }
637*5ffd83dbSDimitry Andric 
638*5ffd83dbSDimitry Andric void ContainerModeling::handleErase(CheckerContext &C, SVal Cont, SVal Iter1,
639*5ffd83dbSDimitry Andric                                     SVal Iter2) const {
640*5ffd83dbSDimitry Andric   const auto *ContReg = Cont.getAsRegion();
641*5ffd83dbSDimitry Andric   if (!ContReg)
642*5ffd83dbSDimitry Andric     return;
643*5ffd83dbSDimitry Andric 
644*5ffd83dbSDimitry Andric   ContReg = ContReg->getMostDerivedObjectRegion();
645*5ffd83dbSDimitry Andric   auto State = C.getState();
646*5ffd83dbSDimitry Andric   const auto *Pos1 = getIteratorPosition(State, Iter1);
647*5ffd83dbSDimitry Andric   const auto *Pos2 = getIteratorPosition(State, Iter2);
648*5ffd83dbSDimitry Andric   if (!Pos1 || !Pos2)
649*5ffd83dbSDimitry Andric     return;
650*5ffd83dbSDimitry Andric 
651*5ffd83dbSDimitry Andric   // For deque-like containers invalidate all iterator positions. For
652*5ffd83dbSDimitry Andric   // vector-like containers invalidate iterator positions at and after the
653*5ffd83dbSDimitry Andric   // deletion range. For list-like containers only invalidate the deleted
654*5ffd83dbSDimitry Andric   // position range [first..last].
655*5ffd83dbSDimitry Andric   if (hasSubscriptOperator(State, ContReg) && backModifiable(State, ContReg)) {
656*5ffd83dbSDimitry Andric     if (frontModifiable(State, ContReg)) {
657*5ffd83dbSDimitry Andric       State = invalidateAllIteratorPositions(State, ContReg);
658*5ffd83dbSDimitry Andric     } else {
659*5ffd83dbSDimitry Andric       State = invalidateIteratorPositions(State, Pos1->getOffset(), BO_GE);
660*5ffd83dbSDimitry Andric     }
661*5ffd83dbSDimitry Andric     if (const auto *CData = getContainerData(State, ContReg)) {
662*5ffd83dbSDimitry Andric       if (const auto EndSym = CData->getEnd()) {
663*5ffd83dbSDimitry Andric         State = invalidateIteratorPositions(State, EndSym, BO_GE);
664*5ffd83dbSDimitry Andric         State = setContainerData(State, ContReg, CData->newEnd(nullptr));
665*5ffd83dbSDimitry Andric       }
666*5ffd83dbSDimitry Andric     }
667*5ffd83dbSDimitry Andric   } else {
668*5ffd83dbSDimitry Andric     State = invalidateIteratorPositions(State, Pos1->getOffset(), BO_GE,
669*5ffd83dbSDimitry Andric                                         Pos2->getOffset(), BO_LT);
670*5ffd83dbSDimitry Andric   }
671*5ffd83dbSDimitry Andric   C.addTransition(State);
672*5ffd83dbSDimitry Andric }
673*5ffd83dbSDimitry Andric 
674*5ffd83dbSDimitry Andric void ContainerModeling::handleEraseAfter(CheckerContext &C, SVal Cont,
675*5ffd83dbSDimitry Andric                                         SVal Iter) const {
676*5ffd83dbSDimitry Andric   auto State = C.getState();
677*5ffd83dbSDimitry Andric   const auto *Pos = getIteratorPosition(State, Iter);
678*5ffd83dbSDimitry Andric   if (!Pos)
679*5ffd83dbSDimitry Andric     return;
680*5ffd83dbSDimitry Andric 
681*5ffd83dbSDimitry Andric   // Invalidate the deleted iterator position, which is the position of the
682*5ffd83dbSDimitry Andric   // parameter plus one.
683*5ffd83dbSDimitry Andric   auto &SymMgr = C.getSymbolManager();
684*5ffd83dbSDimitry Andric   auto &BVF = SymMgr.getBasicVals();
685*5ffd83dbSDimitry Andric   auto &SVB = C.getSValBuilder();
686*5ffd83dbSDimitry Andric   const auto NextSym =
687*5ffd83dbSDimitry Andric     SVB.evalBinOp(State, BO_Add,
688*5ffd83dbSDimitry Andric                   nonloc::SymbolVal(Pos->getOffset()),
689*5ffd83dbSDimitry Andric                   nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
690*5ffd83dbSDimitry Andric                   SymMgr.getType(Pos->getOffset())).getAsSymbol();
691*5ffd83dbSDimitry Andric   State = invalidateIteratorPositions(State, NextSym, BO_EQ);
692*5ffd83dbSDimitry Andric   C.addTransition(State);
693*5ffd83dbSDimitry Andric }
694*5ffd83dbSDimitry Andric 
695*5ffd83dbSDimitry Andric void ContainerModeling::handleEraseAfter(CheckerContext &C, SVal Cont,
696*5ffd83dbSDimitry Andric                                          SVal Iter1, SVal Iter2) const {
697*5ffd83dbSDimitry Andric   auto State = C.getState();
698*5ffd83dbSDimitry Andric   const auto *Pos1 = getIteratorPosition(State, Iter1);
699*5ffd83dbSDimitry Andric   const auto *Pos2 = getIteratorPosition(State, Iter2);
700*5ffd83dbSDimitry Andric   if (!Pos1 || !Pos2)
701*5ffd83dbSDimitry Andric     return;
702*5ffd83dbSDimitry Andric 
703*5ffd83dbSDimitry Andric   // Invalidate the deleted iterator position range (first..last)
704*5ffd83dbSDimitry Andric   State = invalidateIteratorPositions(State, Pos1->getOffset(), BO_GT,
705*5ffd83dbSDimitry Andric                                       Pos2->getOffset(), BO_LT);
706*5ffd83dbSDimitry Andric   C.addTransition(State);
707*5ffd83dbSDimitry Andric }
708*5ffd83dbSDimitry Andric 
709*5ffd83dbSDimitry Andric const NoteTag *ContainerModeling::getChangeTag(CheckerContext &C,
710*5ffd83dbSDimitry Andric                                                StringRef Text,
711*5ffd83dbSDimitry Andric                                                const MemRegion *ContReg,
712*5ffd83dbSDimitry Andric                                                const Expr *ContE) const {
713*5ffd83dbSDimitry Andric   StringRef Name;
714*5ffd83dbSDimitry Andric   // First try to get the name of the variable from the region
715*5ffd83dbSDimitry Andric   if (const auto *DR = dyn_cast<DeclRegion>(ContReg)) {
716*5ffd83dbSDimitry Andric     Name = DR->getDecl()->getName();
717*5ffd83dbSDimitry Andric   // If the region is not a `DeclRegion` then use the expression instead
718*5ffd83dbSDimitry Andric   } else if (const auto *DRE =
719*5ffd83dbSDimitry Andric              dyn_cast<DeclRefExpr>(ContE->IgnoreParenCasts())) {
720*5ffd83dbSDimitry Andric     Name = DRE->getDecl()->getName();
721*5ffd83dbSDimitry Andric   }
722*5ffd83dbSDimitry Andric 
723*5ffd83dbSDimitry Andric   return C.getNoteTag(
724*5ffd83dbSDimitry Andric       [Text, Name, ContReg](PathSensitiveBugReport &BR) -> std::string {
725*5ffd83dbSDimitry Andric         if (!BR.isInteresting(ContReg))
726*5ffd83dbSDimitry Andric           return "";
727*5ffd83dbSDimitry Andric 
728*5ffd83dbSDimitry Andric         SmallString<256> Msg;
729*5ffd83dbSDimitry Andric         llvm::raw_svector_ostream Out(Msg);
730*5ffd83dbSDimitry Andric         Out << "Container " << (!Name.empty() ? ("'" + Name.str() + "' ") : "" )
731*5ffd83dbSDimitry Andric             << Text;
732*5ffd83dbSDimitry Andric         return std::string(Out.str());
733*5ffd83dbSDimitry Andric       });
734*5ffd83dbSDimitry Andric }
735*5ffd83dbSDimitry Andric 
736*5ffd83dbSDimitry Andric void ContainerModeling::printState(raw_ostream &Out, ProgramStateRef State,
737*5ffd83dbSDimitry Andric                                   const char *NL, const char *Sep) const {
738*5ffd83dbSDimitry Andric   auto ContMap = State->get<ContainerMap>();
739*5ffd83dbSDimitry Andric 
740*5ffd83dbSDimitry Andric   if (!ContMap.isEmpty()) {
741*5ffd83dbSDimitry Andric     Out << Sep << "Container Data :" << NL;
742*5ffd83dbSDimitry Andric     for (const auto &Cont : ContMap) {
743*5ffd83dbSDimitry Andric       Cont.first->dumpToStream(Out);
744*5ffd83dbSDimitry Andric       Out << " : [ ";
745*5ffd83dbSDimitry Andric       const auto CData = Cont.second;
746*5ffd83dbSDimitry Andric       if (CData.getBegin())
747*5ffd83dbSDimitry Andric         CData.getBegin()->dumpToStream(Out);
748*5ffd83dbSDimitry Andric       else
749*5ffd83dbSDimitry Andric         Out << "<Unknown>";
750*5ffd83dbSDimitry Andric       Out << " .. ";
751*5ffd83dbSDimitry Andric       if (CData.getEnd())
752*5ffd83dbSDimitry Andric         CData.getEnd()->dumpToStream(Out);
753*5ffd83dbSDimitry Andric       else
754*5ffd83dbSDimitry Andric         Out << "<Unknown>";
755*5ffd83dbSDimitry Andric       Out << " ]";
756*5ffd83dbSDimitry Andric     }
757*5ffd83dbSDimitry Andric   }
758*5ffd83dbSDimitry Andric }
759*5ffd83dbSDimitry Andric 
760*5ffd83dbSDimitry Andric namespace {
761*5ffd83dbSDimitry Andric 
762*5ffd83dbSDimitry Andric bool isBeginCall(const FunctionDecl *Func) {
763*5ffd83dbSDimitry Andric   const auto *IdInfo = Func->getIdentifier();
764*5ffd83dbSDimitry Andric   if (!IdInfo)
765*5ffd83dbSDimitry Andric     return false;
766*5ffd83dbSDimitry Andric   return IdInfo->getName().endswith_lower("begin");
767*5ffd83dbSDimitry Andric }
768*5ffd83dbSDimitry Andric 
769*5ffd83dbSDimitry Andric bool isEndCall(const FunctionDecl *Func) {
770*5ffd83dbSDimitry Andric   const auto *IdInfo = Func->getIdentifier();
771*5ffd83dbSDimitry Andric   if (!IdInfo)
772*5ffd83dbSDimitry Andric     return false;
773*5ffd83dbSDimitry Andric   return IdInfo->getName().endswith_lower("end");
774*5ffd83dbSDimitry Andric }
775*5ffd83dbSDimitry Andric 
776*5ffd83dbSDimitry Andric const CXXRecordDecl *getCXXRecordDecl(ProgramStateRef State,
777*5ffd83dbSDimitry Andric                                       const MemRegion *Reg) {
778*5ffd83dbSDimitry Andric   auto TI = getDynamicTypeInfo(State, Reg);
779*5ffd83dbSDimitry Andric   if (!TI.isValid())
780*5ffd83dbSDimitry Andric     return nullptr;
781*5ffd83dbSDimitry Andric 
782*5ffd83dbSDimitry Andric   auto Type = TI.getType();
783*5ffd83dbSDimitry Andric   if (const auto *RefT = Type->getAs<ReferenceType>()) {
784*5ffd83dbSDimitry Andric     Type = RefT->getPointeeType();
785*5ffd83dbSDimitry Andric   }
786*5ffd83dbSDimitry Andric 
787*5ffd83dbSDimitry Andric   return Type->getUnqualifiedDesugaredType()->getAsCXXRecordDecl();
788*5ffd83dbSDimitry Andric }
789*5ffd83dbSDimitry Andric 
790*5ffd83dbSDimitry Andric bool hasSubscriptOperator(ProgramStateRef State, const MemRegion *Reg) {
791*5ffd83dbSDimitry Andric   const auto *CRD = getCXXRecordDecl(State, Reg);
792*5ffd83dbSDimitry Andric   if (!CRD)
793*5ffd83dbSDimitry Andric     return false;
794*5ffd83dbSDimitry Andric 
795*5ffd83dbSDimitry Andric   for (const auto *Method : CRD->methods()) {
796*5ffd83dbSDimitry Andric     if (!Method->isOverloadedOperator())
797*5ffd83dbSDimitry Andric       continue;
798*5ffd83dbSDimitry Andric     const auto OPK = Method->getOverloadedOperator();
799*5ffd83dbSDimitry Andric     if (OPK == OO_Subscript) {
800*5ffd83dbSDimitry Andric       return true;
801*5ffd83dbSDimitry Andric     }
802*5ffd83dbSDimitry Andric   }
803*5ffd83dbSDimitry Andric   return false;
804*5ffd83dbSDimitry Andric }
805*5ffd83dbSDimitry Andric 
806*5ffd83dbSDimitry Andric bool frontModifiable(ProgramStateRef State, const MemRegion *Reg) {
807*5ffd83dbSDimitry Andric   const auto *CRD = getCXXRecordDecl(State, Reg);
808*5ffd83dbSDimitry Andric   if (!CRD)
809*5ffd83dbSDimitry Andric     return false;
810*5ffd83dbSDimitry Andric 
811*5ffd83dbSDimitry Andric   for (const auto *Method : CRD->methods()) {
812*5ffd83dbSDimitry Andric     if (!Method->getDeclName().isIdentifier())
813*5ffd83dbSDimitry Andric       continue;
814*5ffd83dbSDimitry Andric     if (Method->getName() == "push_front" || Method->getName() == "pop_front") {
815*5ffd83dbSDimitry Andric       return true;
816*5ffd83dbSDimitry Andric     }
817*5ffd83dbSDimitry Andric   }
818*5ffd83dbSDimitry Andric   return false;
819*5ffd83dbSDimitry Andric }
820*5ffd83dbSDimitry Andric 
821*5ffd83dbSDimitry Andric bool backModifiable(ProgramStateRef State, const MemRegion *Reg) {
822*5ffd83dbSDimitry Andric   const auto *CRD = getCXXRecordDecl(State, Reg);
823*5ffd83dbSDimitry Andric   if (!CRD)
824*5ffd83dbSDimitry Andric     return false;
825*5ffd83dbSDimitry Andric 
826*5ffd83dbSDimitry Andric   for (const auto *Method : CRD->methods()) {
827*5ffd83dbSDimitry Andric     if (!Method->getDeclName().isIdentifier())
828*5ffd83dbSDimitry Andric       continue;
829*5ffd83dbSDimitry Andric     if (Method->getName() == "push_back" || Method->getName() == "pop_back") {
830*5ffd83dbSDimitry Andric       return true;
831*5ffd83dbSDimitry Andric     }
832*5ffd83dbSDimitry Andric   }
833*5ffd83dbSDimitry Andric   return false;
834*5ffd83dbSDimitry Andric }
835*5ffd83dbSDimitry Andric 
836*5ffd83dbSDimitry Andric SymbolRef getContainerBegin(ProgramStateRef State, const MemRegion *Cont) {
837*5ffd83dbSDimitry Andric   const auto *CDataPtr = getContainerData(State, Cont);
838*5ffd83dbSDimitry Andric   if (!CDataPtr)
839*5ffd83dbSDimitry Andric     return nullptr;
840*5ffd83dbSDimitry Andric 
841*5ffd83dbSDimitry Andric   return CDataPtr->getBegin();
842*5ffd83dbSDimitry Andric }
843*5ffd83dbSDimitry Andric 
844*5ffd83dbSDimitry Andric SymbolRef getContainerEnd(ProgramStateRef State, const MemRegion *Cont) {
845*5ffd83dbSDimitry Andric   const auto *CDataPtr = getContainerData(State, Cont);
846*5ffd83dbSDimitry Andric   if (!CDataPtr)
847*5ffd83dbSDimitry Andric     return nullptr;
848*5ffd83dbSDimitry Andric 
849*5ffd83dbSDimitry Andric   return CDataPtr->getEnd();
850*5ffd83dbSDimitry Andric }
851*5ffd83dbSDimitry Andric 
852*5ffd83dbSDimitry Andric ProgramStateRef createContainerBegin(ProgramStateRef State,
853*5ffd83dbSDimitry Andric                                      const MemRegion *Cont, const Expr *E,
854*5ffd83dbSDimitry Andric                                      QualType T, const LocationContext *LCtx,
855*5ffd83dbSDimitry Andric                                      unsigned BlockCount) {
856*5ffd83dbSDimitry Andric   // Only create if it does not exist
857*5ffd83dbSDimitry Andric   const auto *CDataPtr = getContainerData(State, Cont);
858*5ffd83dbSDimitry Andric   if (CDataPtr && CDataPtr->getBegin())
859*5ffd83dbSDimitry Andric     return State;
860*5ffd83dbSDimitry Andric 
861*5ffd83dbSDimitry Andric   auto &SymMgr = State->getSymbolManager();
862*5ffd83dbSDimitry Andric   const SymbolConjured *Sym = SymMgr.conjureSymbol(E, LCtx, T, BlockCount,
863*5ffd83dbSDimitry Andric                                                    "begin");
864*5ffd83dbSDimitry Andric   State = assumeNoOverflow(State, Sym, 4);
865*5ffd83dbSDimitry Andric 
866*5ffd83dbSDimitry Andric   if (CDataPtr) {
867*5ffd83dbSDimitry Andric     const auto CData = CDataPtr->newBegin(Sym);
868*5ffd83dbSDimitry Andric     return setContainerData(State, Cont, CData);
869*5ffd83dbSDimitry Andric   }
870*5ffd83dbSDimitry Andric 
871*5ffd83dbSDimitry Andric   const auto CData = ContainerData::fromBegin(Sym);
872*5ffd83dbSDimitry Andric   return setContainerData(State, Cont, CData);
873*5ffd83dbSDimitry Andric }
874*5ffd83dbSDimitry Andric 
875*5ffd83dbSDimitry Andric ProgramStateRef createContainerEnd(ProgramStateRef State, const MemRegion *Cont,
876*5ffd83dbSDimitry Andric                                    const Expr *E, QualType T,
877*5ffd83dbSDimitry Andric                                    const LocationContext *LCtx,
878*5ffd83dbSDimitry Andric                                    unsigned BlockCount) {
879*5ffd83dbSDimitry Andric   // Only create if it does not exist
880*5ffd83dbSDimitry Andric   const auto *CDataPtr = getContainerData(State, Cont);
881*5ffd83dbSDimitry Andric   if (CDataPtr && CDataPtr->getEnd())
882*5ffd83dbSDimitry Andric     return State;
883*5ffd83dbSDimitry Andric 
884*5ffd83dbSDimitry Andric   auto &SymMgr = State->getSymbolManager();
885*5ffd83dbSDimitry Andric   const SymbolConjured *Sym = SymMgr.conjureSymbol(E, LCtx, T, BlockCount,
886*5ffd83dbSDimitry Andric                                                   "end");
887*5ffd83dbSDimitry Andric   State = assumeNoOverflow(State, Sym, 4);
888*5ffd83dbSDimitry Andric 
889*5ffd83dbSDimitry Andric   if (CDataPtr) {
890*5ffd83dbSDimitry Andric     const auto CData = CDataPtr->newEnd(Sym);
891*5ffd83dbSDimitry Andric     return setContainerData(State, Cont, CData);
892*5ffd83dbSDimitry Andric   }
893*5ffd83dbSDimitry Andric 
894*5ffd83dbSDimitry Andric   const auto CData = ContainerData::fromEnd(Sym);
895*5ffd83dbSDimitry Andric   return setContainerData(State, Cont, CData);
896*5ffd83dbSDimitry Andric }
897*5ffd83dbSDimitry Andric 
898*5ffd83dbSDimitry Andric ProgramStateRef setContainerData(ProgramStateRef State, const MemRegion *Cont,
899*5ffd83dbSDimitry Andric                                  const ContainerData &CData) {
900*5ffd83dbSDimitry Andric   return State->set<ContainerMap>(Cont, CData);
901*5ffd83dbSDimitry Andric }
902*5ffd83dbSDimitry Andric 
903*5ffd83dbSDimitry Andric template <typename Condition, typename Process>
904*5ffd83dbSDimitry Andric ProgramStateRef processIteratorPositions(ProgramStateRef State, Condition Cond,
905*5ffd83dbSDimitry Andric                                          Process Proc) {
906*5ffd83dbSDimitry Andric   auto &RegionMapFactory = State->get_context<IteratorRegionMap>();
907*5ffd83dbSDimitry Andric   auto RegionMap = State->get<IteratorRegionMap>();
908*5ffd83dbSDimitry Andric   bool Changed = false;
909*5ffd83dbSDimitry Andric   for (const auto &Reg : RegionMap) {
910*5ffd83dbSDimitry Andric     if (Cond(Reg.second)) {
911*5ffd83dbSDimitry Andric       RegionMap = RegionMapFactory.add(RegionMap, Reg.first, Proc(Reg.second));
912*5ffd83dbSDimitry Andric       Changed = true;
913*5ffd83dbSDimitry Andric     }
914*5ffd83dbSDimitry Andric   }
915*5ffd83dbSDimitry Andric 
916*5ffd83dbSDimitry Andric   if (Changed)
917*5ffd83dbSDimitry Andric     State = State->set<IteratorRegionMap>(RegionMap);
918*5ffd83dbSDimitry Andric 
919*5ffd83dbSDimitry Andric   auto &SymbolMapFactory = State->get_context<IteratorSymbolMap>();
920*5ffd83dbSDimitry Andric   auto SymbolMap = State->get<IteratorSymbolMap>();
921*5ffd83dbSDimitry Andric   Changed = false;
922*5ffd83dbSDimitry Andric   for (const auto &Sym : SymbolMap) {
923*5ffd83dbSDimitry Andric     if (Cond(Sym.second)) {
924*5ffd83dbSDimitry Andric       SymbolMap = SymbolMapFactory.add(SymbolMap, Sym.first, Proc(Sym.second));
925*5ffd83dbSDimitry Andric       Changed = true;
926*5ffd83dbSDimitry Andric     }
927*5ffd83dbSDimitry Andric   }
928*5ffd83dbSDimitry Andric 
929*5ffd83dbSDimitry Andric   if (Changed)
930*5ffd83dbSDimitry Andric     State = State->set<IteratorSymbolMap>(SymbolMap);
931*5ffd83dbSDimitry Andric 
932*5ffd83dbSDimitry Andric   return State;
933*5ffd83dbSDimitry Andric }
934*5ffd83dbSDimitry Andric 
935*5ffd83dbSDimitry Andric ProgramStateRef invalidateAllIteratorPositions(ProgramStateRef State,
936*5ffd83dbSDimitry Andric                                                const MemRegion *Cont) {
937*5ffd83dbSDimitry Andric   auto MatchCont = [&](const IteratorPosition &Pos) {
938*5ffd83dbSDimitry Andric     return Pos.getContainer() == Cont;
939*5ffd83dbSDimitry Andric   };
940*5ffd83dbSDimitry Andric   auto Invalidate = [&](const IteratorPosition &Pos) {
941*5ffd83dbSDimitry Andric     return Pos.invalidate();
942*5ffd83dbSDimitry Andric   };
943*5ffd83dbSDimitry Andric   return processIteratorPositions(State, MatchCont, Invalidate);
944*5ffd83dbSDimitry Andric }
945*5ffd83dbSDimitry Andric 
946*5ffd83dbSDimitry Andric ProgramStateRef
947*5ffd83dbSDimitry Andric invalidateAllIteratorPositionsExcept(ProgramStateRef State,
948*5ffd83dbSDimitry Andric                                      const MemRegion *Cont, SymbolRef Offset,
949*5ffd83dbSDimitry Andric                                      BinaryOperator::Opcode Opc) {
950*5ffd83dbSDimitry Andric   auto MatchContAndCompare = [&](const IteratorPosition &Pos) {
951*5ffd83dbSDimitry Andric     return Pos.getContainer() == Cont &&
952*5ffd83dbSDimitry Andric            !compare(State, Pos.getOffset(), Offset, Opc);
953*5ffd83dbSDimitry Andric   };
954*5ffd83dbSDimitry Andric   auto Invalidate = [&](const IteratorPosition &Pos) {
955*5ffd83dbSDimitry Andric     return Pos.invalidate();
956*5ffd83dbSDimitry Andric   };
957*5ffd83dbSDimitry Andric   return processIteratorPositions(State, MatchContAndCompare, Invalidate);
958*5ffd83dbSDimitry Andric }
959*5ffd83dbSDimitry Andric 
960*5ffd83dbSDimitry Andric ProgramStateRef invalidateIteratorPositions(ProgramStateRef State,
961*5ffd83dbSDimitry Andric                                             SymbolRef Offset,
962*5ffd83dbSDimitry Andric                                             BinaryOperator::Opcode Opc) {
963*5ffd83dbSDimitry Andric   auto Compare = [&](const IteratorPosition &Pos) {
964*5ffd83dbSDimitry Andric     return compare(State, Pos.getOffset(), Offset, Opc);
965*5ffd83dbSDimitry Andric   };
966*5ffd83dbSDimitry Andric   auto Invalidate = [&](const IteratorPosition &Pos) {
967*5ffd83dbSDimitry Andric     return Pos.invalidate();
968*5ffd83dbSDimitry Andric   };
969*5ffd83dbSDimitry Andric   return processIteratorPositions(State, Compare, Invalidate);
970*5ffd83dbSDimitry Andric }
971*5ffd83dbSDimitry Andric 
972*5ffd83dbSDimitry Andric ProgramStateRef invalidateIteratorPositions(ProgramStateRef State,
973*5ffd83dbSDimitry Andric                                             SymbolRef Offset1,
974*5ffd83dbSDimitry Andric                                             BinaryOperator::Opcode Opc1,
975*5ffd83dbSDimitry Andric                                             SymbolRef Offset2,
976*5ffd83dbSDimitry Andric                                             BinaryOperator::Opcode Opc2) {
977*5ffd83dbSDimitry Andric   auto Compare = [&](const IteratorPosition &Pos) {
978*5ffd83dbSDimitry Andric     return compare(State, Pos.getOffset(), Offset1, Opc1) &&
979*5ffd83dbSDimitry Andric            compare(State, Pos.getOffset(), Offset2, Opc2);
980*5ffd83dbSDimitry Andric   };
981*5ffd83dbSDimitry Andric   auto Invalidate = [&](const IteratorPosition &Pos) {
982*5ffd83dbSDimitry Andric     return Pos.invalidate();
983*5ffd83dbSDimitry Andric   };
984*5ffd83dbSDimitry Andric   return processIteratorPositions(State, Compare, Invalidate);
985*5ffd83dbSDimitry Andric }
986*5ffd83dbSDimitry Andric 
987*5ffd83dbSDimitry Andric ProgramStateRef reassignAllIteratorPositions(ProgramStateRef State,
988*5ffd83dbSDimitry Andric                                              const MemRegion *Cont,
989*5ffd83dbSDimitry Andric                                              const MemRegion *NewCont) {
990*5ffd83dbSDimitry Andric   auto MatchCont = [&](const IteratorPosition &Pos) {
991*5ffd83dbSDimitry Andric     return Pos.getContainer() == Cont;
992*5ffd83dbSDimitry Andric   };
993*5ffd83dbSDimitry Andric   auto ReAssign = [&](const IteratorPosition &Pos) {
994*5ffd83dbSDimitry Andric     return Pos.reAssign(NewCont);
995*5ffd83dbSDimitry Andric   };
996*5ffd83dbSDimitry Andric   return processIteratorPositions(State, MatchCont, ReAssign);
997*5ffd83dbSDimitry Andric }
998*5ffd83dbSDimitry Andric 
999*5ffd83dbSDimitry Andric ProgramStateRef reassignAllIteratorPositionsUnless(ProgramStateRef State,
1000*5ffd83dbSDimitry Andric                                                    const MemRegion *Cont,
1001*5ffd83dbSDimitry Andric                                                    const MemRegion *NewCont,
1002*5ffd83dbSDimitry Andric                                                    SymbolRef Offset,
1003*5ffd83dbSDimitry Andric                                                    BinaryOperator::Opcode Opc) {
1004*5ffd83dbSDimitry Andric   auto MatchContAndCompare = [&](const IteratorPosition &Pos) {
1005*5ffd83dbSDimitry Andric     return Pos.getContainer() == Cont &&
1006*5ffd83dbSDimitry Andric     !compare(State, Pos.getOffset(), Offset, Opc);
1007*5ffd83dbSDimitry Andric   };
1008*5ffd83dbSDimitry Andric   auto ReAssign = [&](const IteratorPosition &Pos) {
1009*5ffd83dbSDimitry Andric     return Pos.reAssign(NewCont);
1010*5ffd83dbSDimitry Andric   };
1011*5ffd83dbSDimitry Andric   return processIteratorPositions(State, MatchContAndCompare, ReAssign);
1012*5ffd83dbSDimitry Andric }
1013*5ffd83dbSDimitry Andric 
1014*5ffd83dbSDimitry Andric // This function rebases symbolic expression `OldSym + Int` to `NewSym + Int`,
1015*5ffd83dbSDimitry Andric // `OldSym - Int` to `NewSym - Int` and  `OldSym` to `NewSym` in any iterator
1016*5ffd83dbSDimitry Andric // position offsets where `CondSym` is true.
1017*5ffd83dbSDimitry Andric ProgramStateRef rebaseSymbolInIteratorPositionsIf(
1018*5ffd83dbSDimitry Andric     ProgramStateRef State, SValBuilder &SVB, SymbolRef OldSym,
1019*5ffd83dbSDimitry Andric     SymbolRef NewSym, SymbolRef CondSym, BinaryOperator::Opcode Opc) {
1020*5ffd83dbSDimitry Andric   auto LessThanEnd = [&](const IteratorPosition &Pos) {
1021*5ffd83dbSDimitry Andric     return compare(State, Pos.getOffset(), CondSym, Opc);
1022*5ffd83dbSDimitry Andric   };
1023*5ffd83dbSDimitry Andric   auto RebaseSymbol = [&](const IteratorPosition &Pos) {
1024*5ffd83dbSDimitry Andric     return Pos.setTo(rebaseSymbol(State, SVB, Pos.getOffset(), OldSym,
1025*5ffd83dbSDimitry Andric                                    NewSym));
1026*5ffd83dbSDimitry Andric   };
1027*5ffd83dbSDimitry Andric   return processIteratorPositions(State, LessThanEnd, RebaseSymbol);
1028*5ffd83dbSDimitry Andric }
1029*5ffd83dbSDimitry Andric 
1030*5ffd83dbSDimitry Andric // This function rebases symbolic expression `OldExpr + Int` to `NewExpr + Int`,
1031*5ffd83dbSDimitry Andric // `OldExpr - Int` to `NewExpr - Int` and  `OldExpr` to `NewExpr` in expression
1032*5ffd83dbSDimitry Andric // `OrigExpr`.
1033*5ffd83dbSDimitry Andric SymbolRef rebaseSymbol(ProgramStateRef State, SValBuilder &SVB,
1034*5ffd83dbSDimitry Andric                        SymbolRef OrigExpr, SymbolRef OldExpr,
1035*5ffd83dbSDimitry Andric                        SymbolRef NewSym) {
1036*5ffd83dbSDimitry Andric   auto &SymMgr = SVB.getSymbolManager();
1037*5ffd83dbSDimitry Andric   auto Diff = SVB.evalBinOpNN(State, BO_Sub, nonloc::SymbolVal(OrigExpr),
1038*5ffd83dbSDimitry Andric                               nonloc::SymbolVal(OldExpr),
1039*5ffd83dbSDimitry Andric                               SymMgr.getType(OrigExpr));
1040*5ffd83dbSDimitry Andric 
1041*5ffd83dbSDimitry Andric   const auto DiffInt = Diff.getAs<nonloc::ConcreteInt>();
1042*5ffd83dbSDimitry Andric   if (!DiffInt)
1043*5ffd83dbSDimitry Andric     return OrigExpr;
1044*5ffd83dbSDimitry Andric 
1045*5ffd83dbSDimitry Andric   return SVB.evalBinOpNN(State, BO_Add, *DiffInt, nonloc::SymbolVal(NewSym),
1046*5ffd83dbSDimitry Andric                          SymMgr.getType(OrigExpr)).getAsSymbol();
1047*5ffd83dbSDimitry Andric }
1048*5ffd83dbSDimitry Andric 
1049*5ffd83dbSDimitry Andric bool hasLiveIterators(ProgramStateRef State, const MemRegion *Cont) {
1050*5ffd83dbSDimitry Andric   auto RegionMap = State->get<IteratorRegionMap>();
1051*5ffd83dbSDimitry Andric   for (const auto &Reg : RegionMap) {
1052*5ffd83dbSDimitry Andric     if (Reg.second.getContainer() == Cont)
1053*5ffd83dbSDimitry Andric       return true;
1054*5ffd83dbSDimitry Andric   }
1055*5ffd83dbSDimitry Andric 
1056*5ffd83dbSDimitry Andric   auto SymbolMap = State->get<IteratorSymbolMap>();
1057*5ffd83dbSDimitry Andric   for (const auto &Sym : SymbolMap) {
1058*5ffd83dbSDimitry Andric     if (Sym.second.getContainer() == Cont)
1059*5ffd83dbSDimitry Andric       return true;
1060*5ffd83dbSDimitry Andric   }
1061*5ffd83dbSDimitry Andric 
1062*5ffd83dbSDimitry Andric   return false;
1063*5ffd83dbSDimitry Andric }
1064*5ffd83dbSDimitry Andric 
1065*5ffd83dbSDimitry Andric } // namespace
1066*5ffd83dbSDimitry Andric 
1067*5ffd83dbSDimitry Andric void ento::registerContainerModeling(CheckerManager &mgr) {
1068*5ffd83dbSDimitry Andric   mgr.registerChecker<ContainerModeling>();
1069*5ffd83dbSDimitry Andric }
1070*5ffd83dbSDimitry Andric 
1071*5ffd83dbSDimitry Andric bool ento::shouldRegisterContainerModeling(const CheckerManager &mgr) {
1072*5ffd83dbSDimitry Andric   if (!mgr.getLangOpts().CPlusPlus)
1073*5ffd83dbSDimitry Andric     return false;
1074*5ffd83dbSDimitry Andric 
1075*5ffd83dbSDimitry Andric   if (!mgr.getAnalyzerOptions().ShouldAggressivelySimplifyBinaryOperation) {
1076*5ffd83dbSDimitry Andric     mgr.getASTContext().getDiagnostics().Report(
1077*5ffd83dbSDimitry Andric         diag::err_analyzer_checker_incompatible_analyzer_option)
1078*5ffd83dbSDimitry Andric       << "aggressive-binary-operation-simplification" << "false";
1079*5ffd83dbSDimitry Andric     return false;
1080*5ffd83dbSDimitry Andric   }
1081*5ffd83dbSDimitry Andric 
1082*5ffd83dbSDimitry Andric   return true;
1083*5ffd83dbSDimitry Andric }
1084