xref: /freebsd-src/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp (revision 480093f4440d54b30b3025afeac24b48f2ba7a2e)
1*480093f4SDimitry Andric //===-- IteratorModeling.cpp --------------------------------------*- C++ -*--//
2*480093f4SDimitry Andric //
3*480093f4SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*480093f4SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*480093f4SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*480093f4SDimitry Andric //
7*480093f4SDimitry Andric //===----------------------------------------------------------------------===//
8*480093f4SDimitry Andric //
9*480093f4SDimitry Andric // Defines a checker for using iterators outside their range (past end). Usage
10*480093f4SDimitry Andric // means here dereferencing, incrementing etc.
11*480093f4SDimitry Andric //
12*480093f4SDimitry Andric //===----------------------------------------------------------------------===//
13*480093f4SDimitry Andric //
14*480093f4SDimitry Andric // In the code, iterator can be represented as a:
15*480093f4SDimitry Andric // * type-I: typedef-ed pointer. Operations over such iterator, such as
16*480093f4SDimitry Andric //           comparisons or increments, are modeled straightforwardly by the
17*480093f4SDimitry Andric //           analyzer.
18*480093f4SDimitry Andric // * type-II: structure with its method bodies available.  Operations over such
19*480093f4SDimitry Andric //            iterator are inlined by the analyzer, and results of modeling
20*480093f4SDimitry Andric //            these operations are exposing implementation details of the
21*480093f4SDimitry Andric //            iterators, which is not necessarily helping.
22*480093f4SDimitry Andric // * type-III: completely opaque structure. Operations over such iterator are
23*480093f4SDimitry Andric //             modeled conservatively, producing conjured symbols everywhere.
24*480093f4SDimitry Andric //
25*480093f4SDimitry Andric // To handle all these types in a common way we introduce a structure called
26*480093f4SDimitry Andric // IteratorPosition which is an abstraction of the position the iterator
27*480093f4SDimitry Andric // represents using symbolic expressions. The checker handles all the
28*480093f4SDimitry Andric // operations on this structure.
29*480093f4SDimitry Andric //
30*480093f4SDimitry Andric // Additionally, depending on the circumstances, operators of types II and III
31*480093f4SDimitry Andric // can be represented as:
32*480093f4SDimitry Andric // * type-IIa, type-IIIa: conjured structure symbols - when returned by value
33*480093f4SDimitry Andric //                        from conservatively evaluated methods such as
34*480093f4SDimitry Andric //                        `.begin()`.
35*480093f4SDimitry Andric // * type-IIb, type-IIIb: memory regions of iterator-typed objects, such as
36*480093f4SDimitry Andric //                        variables or temporaries, when the iterator object is
37*480093f4SDimitry Andric //                        currently treated as an lvalue.
38*480093f4SDimitry Andric // * type-IIc, type-IIIc: compound values of iterator-typed objects, when the
39*480093f4SDimitry Andric //                        iterator object is treated as an rvalue taken of a
40*480093f4SDimitry Andric //                        particular lvalue, eg. a copy of "type-a" iterator
41*480093f4SDimitry Andric //                        object, or an iterator that existed before the
42*480093f4SDimitry Andric //                        analysis has started.
43*480093f4SDimitry Andric //
44*480093f4SDimitry Andric // To handle any of these three different representations stored in an SVal we
45*480093f4SDimitry Andric // use setter and getters functions which separate the three cases. To store
46*480093f4SDimitry Andric // them we use a pointer union of symbol and memory region.
47*480093f4SDimitry Andric //
48*480093f4SDimitry Andric // The checker works the following way: We record the begin and the
49*480093f4SDimitry Andric // past-end iterator for all containers whenever their `.begin()` and `.end()`
50*480093f4SDimitry Andric // are called. Since the Constraint Manager cannot handle such SVals we need
51*480093f4SDimitry Andric // to take over its role. We post-check equality and non-equality comparisons
52*480093f4SDimitry Andric // and record that the two sides are equal if we are in the 'equal' branch
53*480093f4SDimitry Andric // (true-branch for `==` and false-branch for `!=`).
54*480093f4SDimitry Andric //
55*480093f4SDimitry Andric // In case of type-I or type-II iterators we get a concrete integer as a result
56*480093f4SDimitry Andric // of the comparison (1 or 0) but in case of type-III we only get a Symbol. In
57*480093f4SDimitry Andric // this latter case we record the symbol and reload it in evalAssume() and do
58*480093f4SDimitry Andric // the propagation there. We also handle (maybe double) negated comparisons
59*480093f4SDimitry Andric // which are represented in the form of (x == 0 or x != 0) where x is the
60*480093f4SDimitry Andric // comparison itself.
61*480093f4SDimitry Andric //
62*480093f4SDimitry Andric // Since `SimpleConstraintManager` cannot handle complex symbolic expressions
63*480093f4SDimitry Andric // we only use expressions of the format S, S+n or S-n for iterator positions
64*480093f4SDimitry Andric // where S is a conjured symbol and n is an unsigned concrete integer. When
65*480093f4SDimitry Andric // making an assumption e.g. `S1 + n == S2 + m` we store `S1 - S2 == m - n` as
66*480093f4SDimitry Andric // a constraint which we later retrieve when doing an actual comparison.
67*480093f4SDimitry Andric 
68*480093f4SDimitry Andric #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
69*480093f4SDimitry Andric #include "clang/AST/DeclTemplate.h"
70*480093f4SDimitry Andric #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
71*480093f4SDimitry Andric #include "clang/StaticAnalyzer/Core/Checker.h"
72*480093f4SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
73*480093f4SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
74*480093f4SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h"
75*480093f4SDimitry Andric 
76*480093f4SDimitry Andric #include "Iterator.h"
77*480093f4SDimitry Andric 
78*480093f4SDimitry Andric #include <utility>
79*480093f4SDimitry Andric 
80*480093f4SDimitry Andric using namespace clang;
81*480093f4SDimitry Andric using namespace ento;
82*480093f4SDimitry Andric using namespace iterator;
83*480093f4SDimitry Andric 
84*480093f4SDimitry Andric namespace {
85*480093f4SDimitry Andric 
86*480093f4SDimitry Andric class IteratorModeling
87*480093f4SDimitry Andric     : public Checker<check::PostCall, check::PostStmt<MaterializeTemporaryExpr>,
88*480093f4SDimitry Andric                      check::Bind, check::LiveSymbols, check::DeadSymbols> {
89*480093f4SDimitry Andric 
90*480093f4SDimitry Andric   void handleComparison(CheckerContext &C, const Expr *CE, SVal RetVal,
91*480093f4SDimitry Andric                         const SVal &LVal, const SVal &RVal,
92*480093f4SDimitry Andric                         OverloadedOperatorKind Op) const;
93*480093f4SDimitry Andric   void processComparison(CheckerContext &C, ProgramStateRef State,
94*480093f4SDimitry Andric                          SymbolRef Sym1, SymbolRef Sym2, const SVal &RetVal,
95*480093f4SDimitry Andric                          OverloadedOperatorKind Op) const;
96*480093f4SDimitry Andric   void handleIncrement(CheckerContext &C, const SVal &RetVal, const SVal &Iter,
97*480093f4SDimitry Andric                        bool Postfix) const;
98*480093f4SDimitry Andric   void handleDecrement(CheckerContext &C, const SVal &RetVal, const SVal &Iter,
99*480093f4SDimitry Andric                        bool Postfix) const;
100*480093f4SDimitry Andric   void handleRandomIncrOrDecr(CheckerContext &C, const Expr *CE,
101*480093f4SDimitry Andric                               OverloadedOperatorKind Op, const SVal &RetVal,
102*480093f4SDimitry Andric                               const SVal &LHS, const SVal &RHS) const;
103*480093f4SDimitry Andric   void handleBegin(CheckerContext &C, const Expr *CE, const SVal &RetVal,
104*480093f4SDimitry Andric                    const SVal &Cont) const;
105*480093f4SDimitry Andric   void handleEnd(CheckerContext &C, const Expr *CE, const SVal &RetVal,
106*480093f4SDimitry Andric                  const SVal &Cont) const;
107*480093f4SDimitry Andric   void assignToContainer(CheckerContext &C, const Expr *CE, const SVal &RetVal,
108*480093f4SDimitry Andric                          const MemRegion *Cont) const;
109*480093f4SDimitry Andric   void handleAssign(CheckerContext &C, const SVal &Cont,
110*480093f4SDimitry Andric                     const Expr *CE = nullptr,
111*480093f4SDimitry Andric                     const SVal &OldCont = UndefinedVal()) const;
112*480093f4SDimitry Andric   void handleClear(CheckerContext &C, const SVal &Cont) const;
113*480093f4SDimitry Andric   void handlePushBack(CheckerContext &C, const SVal &Cont) const;
114*480093f4SDimitry Andric   void handlePopBack(CheckerContext &C, const SVal &Cont) const;
115*480093f4SDimitry Andric   void handlePushFront(CheckerContext &C, const SVal &Cont) const;
116*480093f4SDimitry Andric   void handlePopFront(CheckerContext &C, const SVal &Cont) const;
117*480093f4SDimitry Andric   void handleInsert(CheckerContext &C, const SVal &Iter) const;
118*480093f4SDimitry Andric   void handleErase(CheckerContext &C, const SVal &Iter) const;
119*480093f4SDimitry Andric   void handleErase(CheckerContext &C, const SVal &Iter1,
120*480093f4SDimitry Andric                    const SVal &Iter2) const;
121*480093f4SDimitry Andric   void handleEraseAfter(CheckerContext &C, const SVal &Iter) const;
122*480093f4SDimitry Andric   void handleEraseAfter(CheckerContext &C, const SVal &Iter1,
123*480093f4SDimitry Andric                         const SVal &Iter2) const;
124*480093f4SDimitry Andric   void printState(raw_ostream &Out, ProgramStateRef State, const char *NL,
125*480093f4SDimitry Andric                   const char *Sep) const override;
126*480093f4SDimitry Andric 
127*480093f4SDimitry Andric public:
128*480093f4SDimitry Andric   IteratorModeling() {}
129*480093f4SDimitry Andric 
130*480093f4SDimitry Andric   void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
131*480093f4SDimitry Andric   void checkBind(SVal Loc, SVal Val, const Stmt *S, CheckerContext &C) const;
132*480093f4SDimitry Andric   void checkPostStmt(const CXXConstructExpr *CCE, CheckerContext &C) const;
133*480093f4SDimitry Andric   void checkPostStmt(const DeclStmt *DS, CheckerContext &C) const;
134*480093f4SDimitry Andric   void checkPostStmt(const MaterializeTemporaryExpr *MTE,
135*480093f4SDimitry Andric                      CheckerContext &C) const;
136*480093f4SDimitry Andric   void checkLiveSymbols(ProgramStateRef State, SymbolReaper &SR) const;
137*480093f4SDimitry Andric   void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
138*480093f4SDimitry Andric };
139*480093f4SDimitry Andric 
140*480093f4SDimitry Andric bool isBeginCall(const FunctionDecl *Func);
141*480093f4SDimitry Andric bool isEndCall(const FunctionDecl *Func);
142*480093f4SDimitry Andric bool isAssignCall(const FunctionDecl *Func);
143*480093f4SDimitry Andric bool isClearCall(const FunctionDecl *Func);
144*480093f4SDimitry Andric bool isPushBackCall(const FunctionDecl *Func);
145*480093f4SDimitry Andric bool isEmplaceBackCall(const FunctionDecl *Func);
146*480093f4SDimitry Andric bool isPopBackCall(const FunctionDecl *Func);
147*480093f4SDimitry Andric bool isPushFrontCall(const FunctionDecl *Func);
148*480093f4SDimitry Andric bool isEmplaceFrontCall(const FunctionDecl *Func);
149*480093f4SDimitry Andric bool isPopFrontCall(const FunctionDecl *Func);
150*480093f4SDimitry Andric bool isAssignmentOperator(OverloadedOperatorKind OK);
151*480093f4SDimitry Andric bool isSimpleComparisonOperator(OverloadedOperatorKind OK);
152*480093f4SDimitry Andric bool hasSubscriptOperator(ProgramStateRef State, const MemRegion *Reg);
153*480093f4SDimitry Andric bool frontModifiable(ProgramStateRef State, const MemRegion *Reg);
154*480093f4SDimitry Andric bool backModifiable(ProgramStateRef State, const MemRegion *Reg);
155*480093f4SDimitry Andric SymbolRef getContainerBegin(ProgramStateRef State, const MemRegion *Cont);
156*480093f4SDimitry Andric SymbolRef getContainerEnd(ProgramStateRef State, const MemRegion *Cont);
157*480093f4SDimitry Andric ProgramStateRef createContainerBegin(ProgramStateRef State,
158*480093f4SDimitry Andric                                      const MemRegion *Cont, const Expr *E,
159*480093f4SDimitry Andric                                      QualType T, const LocationContext *LCtx,
160*480093f4SDimitry Andric                                      unsigned BlockCount);
161*480093f4SDimitry Andric ProgramStateRef createContainerEnd(ProgramStateRef State, const MemRegion *Cont,
162*480093f4SDimitry Andric                                    const Expr *E, QualType T,
163*480093f4SDimitry Andric                                    const LocationContext *LCtx,
164*480093f4SDimitry Andric                                    unsigned BlockCount);
165*480093f4SDimitry Andric ProgramStateRef setContainerData(ProgramStateRef State, const MemRegion *Cont,
166*480093f4SDimitry Andric                                  const ContainerData &CData);
167*480093f4SDimitry Andric ProgramStateRef removeIteratorPosition(ProgramStateRef State, const SVal &Val);
168*480093f4SDimitry Andric ProgramStateRef assumeNoOverflow(ProgramStateRef State, SymbolRef Sym,
169*480093f4SDimitry Andric                                  long Scale);
170*480093f4SDimitry Andric ProgramStateRef invalidateAllIteratorPositions(ProgramStateRef State,
171*480093f4SDimitry Andric                                                const MemRegion *Cont);
172*480093f4SDimitry Andric ProgramStateRef
173*480093f4SDimitry Andric invalidateAllIteratorPositionsExcept(ProgramStateRef State,
174*480093f4SDimitry Andric                                      const MemRegion *Cont, SymbolRef Offset,
175*480093f4SDimitry Andric                                      BinaryOperator::Opcode Opc);
176*480093f4SDimitry Andric ProgramStateRef invalidateIteratorPositions(ProgramStateRef State,
177*480093f4SDimitry Andric                                             SymbolRef Offset,
178*480093f4SDimitry Andric                                             BinaryOperator::Opcode Opc);
179*480093f4SDimitry Andric ProgramStateRef invalidateIteratorPositions(ProgramStateRef State,
180*480093f4SDimitry Andric                                             SymbolRef Offset1,
181*480093f4SDimitry Andric                                             BinaryOperator::Opcode Opc1,
182*480093f4SDimitry Andric                                             SymbolRef Offset2,
183*480093f4SDimitry Andric                                             BinaryOperator::Opcode Opc2);
184*480093f4SDimitry Andric ProgramStateRef reassignAllIteratorPositions(ProgramStateRef State,
185*480093f4SDimitry Andric                                              const MemRegion *Cont,
186*480093f4SDimitry Andric                                              const MemRegion *NewCont);
187*480093f4SDimitry Andric ProgramStateRef reassignAllIteratorPositionsUnless(ProgramStateRef State,
188*480093f4SDimitry Andric                                                    const MemRegion *Cont,
189*480093f4SDimitry Andric                                                    const MemRegion *NewCont,
190*480093f4SDimitry Andric                                                    SymbolRef Offset,
191*480093f4SDimitry Andric                                                    BinaryOperator::Opcode Opc);
192*480093f4SDimitry Andric ProgramStateRef rebaseSymbolInIteratorPositionsIf(
193*480093f4SDimitry Andric     ProgramStateRef State, SValBuilder &SVB, SymbolRef OldSym,
194*480093f4SDimitry Andric     SymbolRef NewSym, SymbolRef CondSym, BinaryOperator::Opcode Opc);
195*480093f4SDimitry Andric ProgramStateRef relateSymbols(ProgramStateRef State, SymbolRef Sym1,
196*480093f4SDimitry Andric                               SymbolRef Sym2, bool Equal);
197*480093f4SDimitry Andric SymbolRef rebaseSymbol(ProgramStateRef State, SValBuilder &SVB, SymbolRef Expr,
198*480093f4SDimitry Andric                         SymbolRef OldSym, SymbolRef NewSym);
199*480093f4SDimitry Andric bool hasLiveIterators(ProgramStateRef State, const MemRegion *Cont);
200*480093f4SDimitry Andric bool isBoundThroughLazyCompoundVal(const Environment &Env,
201*480093f4SDimitry Andric                                    const MemRegion *Reg);
202*480093f4SDimitry Andric 
203*480093f4SDimitry Andric } // namespace
204*480093f4SDimitry Andric 
205*480093f4SDimitry Andric void IteratorModeling::checkPostCall(const CallEvent &Call,
206*480093f4SDimitry Andric                                      CheckerContext &C) const {
207*480093f4SDimitry Andric   // Record new iterator positions and iterator position changes
208*480093f4SDimitry Andric   const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
209*480093f4SDimitry Andric   if (!Func)
210*480093f4SDimitry Andric     return;
211*480093f4SDimitry Andric 
212*480093f4SDimitry Andric   if (Func->isOverloadedOperator()) {
213*480093f4SDimitry Andric     const auto Op = Func->getOverloadedOperator();
214*480093f4SDimitry Andric     if (isAssignmentOperator(Op)) {
215*480093f4SDimitry Andric       // Overloaded 'operator=' must be a non-static member function.
216*480093f4SDimitry Andric       const auto *InstCall = cast<CXXInstanceCall>(&Call);
217*480093f4SDimitry Andric       if (cast<CXXMethodDecl>(Func)->isMoveAssignmentOperator()) {
218*480093f4SDimitry Andric         handleAssign(C, InstCall->getCXXThisVal(), Call.getOriginExpr(),
219*480093f4SDimitry Andric                      Call.getArgSVal(0));
220*480093f4SDimitry Andric         return;
221*480093f4SDimitry Andric       }
222*480093f4SDimitry Andric 
223*480093f4SDimitry Andric       handleAssign(C, InstCall->getCXXThisVal());
224*480093f4SDimitry Andric       return;
225*480093f4SDimitry Andric     } else if (isSimpleComparisonOperator(Op)) {
226*480093f4SDimitry Andric       const auto *OrigExpr = Call.getOriginExpr();
227*480093f4SDimitry Andric       if (!OrigExpr)
228*480093f4SDimitry Andric         return;
229*480093f4SDimitry Andric 
230*480093f4SDimitry Andric       if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
231*480093f4SDimitry Andric         handleComparison(C, OrigExpr, Call.getReturnValue(),
232*480093f4SDimitry Andric                          InstCall->getCXXThisVal(), Call.getArgSVal(0), Op);
233*480093f4SDimitry Andric         return;
234*480093f4SDimitry Andric       }
235*480093f4SDimitry Andric 
236*480093f4SDimitry Andric       handleComparison(C, OrigExpr, Call.getReturnValue(), Call.getArgSVal(0),
237*480093f4SDimitry Andric                          Call.getArgSVal(1), Op);
238*480093f4SDimitry Andric       return;
239*480093f4SDimitry Andric     } else if (isRandomIncrOrDecrOperator(Func->getOverloadedOperator())) {
240*480093f4SDimitry Andric       const auto *OrigExpr = Call.getOriginExpr();
241*480093f4SDimitry Andric       if (!OrigExpr)
242*480093f4SDimitry Andric         return;
243*480093f4SDimitry Andric 
244*480093f4SDimitry Andric       if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
245*480093f4SDimitry Andric         if (Call.getNumArgs() >= 1 &&
246*480093f4SDimitry Andric               Call.getArgExpr(0)->getType()->isIntegralOrEnumerationType()) {
247*480093f4SDimitry Andric           handleRandomIncrOrDecr(C, OrigExpr, Func->getOverloadedOperator(),
248*480093f4SDimitry Andric                                  Call.getReturnValue(),
249*480093f4SDimitry Andric                                  InstCall->getCXXThisVal(), Call.getArgSVal(0));
250*480093f4SDimitry Andric           return;
251*480093f4SDimitry Andric         }
252*480093f4SDimitry Andric       } else {
253*480093f4SDimitry Andric         if (Call.getNumArgs() >= 2 &&
254*480093f4SDimitry Andric               Call.getArgExpr(1)->getType()->isIntegralOrEnumerationType()) {
255*480093f4SDimitry Andric           handleRandomIncrOrDecr(C, OrigExpr, Func->getOverloadedOperator(),
256*480093f4SDimitry Andric                                  Call.getReturnValue(), Call.getArgSVal(0),
257*480093f4SDimitry Andric                                  Call.getArgSVal(1));
258*480093f4SDimitry Andric           return;
259*480093f4SDimitry Andric         }
260*480093f4SDimitry Andric       }
261*480093f4SDimitry Andric     } else if (isIncrementOperator(Func->getOverloadedOperator())) {
262*480093f4SDimitry Andric       if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
263*480093f4SDimitry Andric         handleIncrement(C, Call.getReturnValue(), InstCall->getCXXThisVal(),
264*480093f4SDimitry Andric                         Call.getNumArgs());
265*480093f4SDimitry Andric         return;
266*480093f4SDimitry Andric       }
267*480093f4SDimitry Andric 
268*480093f4SDimitry Andric       handleIncrement(C, Call.getReturnValue(), Call.getArgSVal(0),
269*480093f4SDimitry Andric                       Call.getNumArgs());
270*480093f4SDimitry Andric       return;
271*480093f4SDimitry Andric     } else if (isDecrementOperator(Func->getOverloadedOperator())) {
272*480093f4SDimitry Andric       if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
273*480093f4SDimitry Andric         handleDecrement(C, Call.getReturnValue(), InstCall->getCXXThisVal(),
274*480093f4SDimitry Andric                         Call.getNumArgs());
275*480093f4SDimitry Andric         return;
276*480093f4SDimitry Andric       }
277*480093f4SDimitry Andric 
278*480093f4SDimitry Andric       handleDecrement(C, Call.getReturnValue(), Call.getArgSVal(0),
279*480093f4SDimitry Andric                         Call.getNumArgs());
280*480093f4SDimitry Andric       return;
281*480093f4SDimitry Andric     }
282*480093f4SDimitry Andric   } else {
283*480093f4SDimitry Andric     if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
284*480093f4SDimitry Andric       if (isAssignCall(Func)) {
285*480093f4SDimitry Andric         handleAssign(C, InstCall->getCXXThisVal());
286*480093f4SDimitry Andric         return;
287*480093f4SDimitry Andric       }
288*480093f4SDimitry Andric 
289*480093f4SDimitry Andric       if (isClearCall(Func)) {
290*480093f4SDimitry Andric         handleClear(C, InstCall->getCXXThisVal());
291*480093f4SDimitry Andric         return;
292*480093f4SDimitry Andric       }
293*480093f4SDimitry Andric 
294*480093f4SDimitry Andric       if (isPushBackCall(Func) || isEmplaceBackCall(Func)) {
295*480093f4SDimitry Andric         handlePushBack(C, InstCall->getCXXThisVal());
296*480093f4SDimitry Andric         return;
297*480093f4SDimitry Andric       }
298*480093f4SDimitry Andric 
299*480093f4SDimitry Andric       if (isPopBackCall(Func)) {
300*480093f4SDimitry Andric         handlePopBack(C, InstCall->getCXXThisVal());
301*480093f4SDimitry Andric         return;
302*480093f4SDimitry Andric       }
303*480093f4SDimitry Andric 
304*480093f4SDimitry Andric       if (isPushFrontCall(Func) || isEmplaceFrontCall(Func)) {
305*480093f4SDimitry Andric         handlePushFront(C, InstCall->getCXXThisVal());
306*480093f4SDimitry Andric         return;
307*480093f4SDimitry Andric       }
308*480093f4SDimitry Andric 
309*480093f4SDimitry Andric       if (isPopFrontCall(Func)) {
310*480093f4SDimitry Andric         handlePopFront(C, InstCall->getCXXThisVal());
311*480093f4SDimitry Andric         return;
312*480093f4SDimitry Andric       }
313*480093f4SDimitry Andric 
314*480093f4SDimitry Andric       if (isInsertCall(Func) || isEmplaceCall(Func)) {
315*480093f4SDimitry Andric         handleInsert(C, Call.getArgSVal(0));
316*480093f4SDimitry Andric         return;
317*480093f4SDimitry Andric       }
318*480093f4SDimitry Andric 
319*480093f4SDimitry Andric       if (isEraseCall(Func)) {
320*480093f4SDimitry Andric         if (Call.getNumArgs() == 1) {
321*480093f4SDimitry Andric           handleErase(C, Call.getArgSVal(0));
322*480093f4SDimitry Andric           return;
323*480093f4SDimitry Andric         }
324*480093f4SDimitry Andric 
325*480093f4SDimitry Andric         if (Call.getNumArgs() == 2) {
326*480093f4SDimitry Andric           handleErase(C, Call.getArgSVal(0), Call.getArgSVal(1));
327*480093f4SDimitry Andric           return;
328*480093f4SDimitry Andric         }
329*480093f4SDimitry Andric       }
330*480093f4SDimitry Andric 
331*480093f4SDimitry Andric       if (isEraseAfterCall(Func)) {
332*480093f4SDimitry Andric         if (Call.getNumArgs() == 1) {
333*480093f4SDimitry Andric           handleEraseAfter(C, Call.getArgSVal(0));
334*480093f4SDimitry Andric           return;
335*480093f4SDimitry Andric         }
336*480093f4SDimitry Andric 
337*480093f4SDimitry Andric         if (Call.getNumArgs() == 2) {
338*480093f4SDimitry Andric           handleEraseAfter(C, Call.getArgSVal(0), Call.getArgSVal(1));
339*480093f4SDimitry Andric           return;
340*480093f4SDimitry Andric         }
341*480093f4SDimitry Andric       }
342*480093f4SDimitry Andric     }
343*480093f4SDimitry Andric 
344*480093f4SDimitry Andric     const auto *OrigExpr = Call.getOriginExpr();
345*480093f4SDimitry Andric     if (!OrigExpr)
346*480093f4SDimitry Andric       return;
347*480093f4SDimitry Andric 
348*480093f4SDimitry Andric     if (!isIteratorType(Call.getResultType()))
349*480093f4SDimitry Andric       return;
350*480093f4SDimitry Andric 
351*480093f4SDimitry Andric     auto State = C.getState();
352*480093f4SDimitry Andric 
353*480093f4SDimitry Andric     if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
354*480093f4SDimitry Andric       if (isBeginCall(Func)) {
355*480093f4SDimitry Andric         handleBegin(C, OrigExpr, Call.getReturnValue(),
356*480093f4SDimitry Andric                     InstCall->getCXXThisVal());
357*480093f4SDimitry Andric         return;
358*480093f4SDimitry Andric       }
359*480093f4SDimitry Andric 
360*480093f4SDimitry Andric       if (isEndCall(Func)) {
361*480093f4SDimitry Andric         handleEnd(C, OrigExpr, Call.getReturnValue(),
362*480093f4SDimitry Andric                   InstCall->getCXXThisVal());
363*480093f4SDimitry Andric         return;
364*480093f4SDimitry Andric       }
365*480093f4SDimitry Andric     }
366*480093f4SDimitry Andric 
367*480093f4SDimitry Andric     // Already bound to container?
368*480093f4SDimitry Andric     if (getIteratorPosition(State, Call.getReturnValue()))
369*480093f4SDimitry Andric       return;
370*480093f4SDimitry Andric 
371*480093f4SDimitry Andric     // Copy-like and move constructors
372*480093f4SDimitry Andric     if (isa<CXXConstructorCall>(&Call) && Call.getNumArgs() == 1) {
373*480093f4SDimitry Andric       if (const auto *Pos = getIteratorPosition(State, Call.getArgSVal(0))) {
374*480093f4SDimitry Andric         State = setIteratorPosition(State, Call.getReturnValue(), *Pos);
375*480093f4SDimitry Andric         if (cast<CXXConstructorDecl>(Func)->isMoveConstructor()) {
376*480093f4SDimitry Andric           State = removeIteratorPosition(State, Call.getArgSVal(0));
377*480093f4SDimitry Andric         }
378*480093f4SDimitry Andric         C.addTransition(State);
379*480093f4SDimitry Andric         return;
380*480093f4SDimitry Andric       }
381*480093f4SDimitry Andric     }
382*480093f4SDimitry Andric 
383*480093f4SDimitry Andric     // Assumption: if return value is an iterator which is not yet bound to a
384*480093f4SDimitry Andric     //             container, then look for the first iterator argument, and
385*480093f4SDimitry Andric     //             bind the return value to the same container. This approach
386*480093f4SDimitry Andric     //             works for STL algorithms.
387*480093f4SDimitry Andric     // FIXME: Add a more conservative mode
388*480093f4SDimitry Andric     for (unsigned i = 0; i < Call.getNumArgs(); ++i) {
389*480093f4SDimitry Andric       if (isIteratorType(Call.getArgExpr(i)->getType())) {
390*480093f4SDimitry Andric         if (const auto *Pos = getIteratorPosition(State, Call.getArgSVal(i))) {
391*480093f4SDimitry Andric           assignToContainer(C, OrigExpr, Call.getReturnValue(),
392*480093f4SDimitry Andric                             Pos->getContainer());
393*480093f4SDimitry Andric           return;
394*480093f4SDimitry Andric         }
395*480093f4SDimitry Andric       }
396*480093f4SDimitry Andric     }
397*480093f4SDimitry Andric   }
398*480093f4SDimitry Andric }
399*480093f4SDimitry Andric 
400*480093f4SDimitry Andric void IteratorModeling::checkBind(SVal Loc, SVal Val, const Stmt *S,
401*480093f4SDimitry Andric                                  CheckerContext &C) const {
402*480093f4SDimitry Andric   auto State = C.getState();
403*480093f4SDimitry Andric   const auto *Pos = getIteratorPosition(State, Val);
404*480093f4SDimitry Andric   if (Pos) {
405*480093f4SDimitry Andric     State = setIteratorPosition(State, Loc, *Pos);
406*480093f4SDimitry Andric     C.addTransition(State);
407*480093f4SDimitry Andric   } else {
408*480093f4SDimitry Andric     const auto *OldPos = getIteratorPosition(State, Loc);
409*480093f4SDimitry Andric     if (OldPos) {
410*480093f4SDimitry Andric       State = removeIteratorPosition(State, Loc);
411*480093f4SDimitry Andric       C.addTransition(State);
412*480093f4SDimitry Andric     }
413*480093f4SDimitry Andric   }
414*480093f4SDimitry Andric }
415*480093f4SDimitry Andric 
416*480093f4SDimitry Andric void IteratorModeling::checkPostStmt(const MaterializeTemporaryExpr *MTE,
417*480093f4SDimitry Andric                                      CheckerContext &C) const {
418*480093f4SDimitry Andric   /* Transfer iterator state to temporary objects */
419*480093f4SDimitry Andric   auto State = C.getState();
420*480093f4SDimitry Andric   const auto *Pos = getIteratorPosition(State, C.getSVal(MTE->getSubExpr()));
421*480093f4SDimitry Andric   if (!Pos)
422*480093f4SDimitry Andric     return;
423*480093f4SDimitry Andric   State = setIteratorPosition(State, C.getSVal(MTE), *Pos);
424*480093f4SDimitry Andric   C.addTransition(State);
425*480093f4SDimitry Andric }
426*480093f4SDimitry Andric 
427*480093f4SDimitry Andric void IteratorModeling::checkLiveSymbols(ProgramStateRef State,
428*480093f4SDimitry Andric                                         SymbolReaper &SR) const {
429*480093f4SDimitry Andric   // Keep symbolic expressions of iterator positions, container begins and ends
430*480093f4SDimitry Andric   // alive
431*480093f4SDimitry Andric   auto RegionMap = State->get<IteratorRegionMap>();
432*480093f4SDimitry Andric   for (const auto &Reg : RegionMap) {
433*480093f4SDimitry Andric     const auto Offset = Reg.second.getOffset();
434*480093f4SDimitry Andric     for (auto i = Offset->symbol_begin(); i != Offset->symbol_end(); ++i)
435*480093f4SDimitry Andric       if (isa<SymbolData>(*i))
436*480093f4SDimitry Andric         SR.markLive(*i);
437*480093f4SDimitry Andric   }
438*480093f4SDimitry Andric 
439*480093f4SDimitry Andric   auto SymbolMap = State->get<IteratorSymbolMap>();
440*480093f4SDimitry Andric   for (const auto &Sym : SymbolMap) {
441*480093f4SDimitry Andric     const auto Offset = Sym.second.getOffset();
442*480093f4SDimitry Andric     for (auto i = Offset->symbol_begin(); i != Offset->symbol_end(); ++i)
443*480093f4SDimitry Andric       if (isa<SymbolData>(*i))
444*480093f4SDimitry Andric         SR.markLive(*i);
445*480093f4SDimitry Andric   }
446*480093f4SDimitry Andric 
447*480093f4SDimitry Andric   auto ContMap = State->get<ContainerMap>();
448*480093f4SDimitry Andric   for (const auto &Cont : ContMap) {
449*480093f4SDimitry Andric     const auto CData = Cont.second;
450*480093f4SDimitry Andric     if (CData.getBegin()) {
451*480093f4SDimitry Andric       SR.markLive(CData.getBegin());
452*480093f4SDimitry Andric       if(const auto *SIE = dyn_cast<SymIntExpr>(CData.getBegin()))
453*480093f4SDimitry Andric         SR.markLive(SIE->getLHS());
454*480093f4SDimitry Andric     }
455*480093f4SDimitry Andric     if (CData.getEnd()) {
456*480093f4SDimitry Andric       SR.markLive(CData.getEnd());
457*480093f4SDimitry Andric       if(const auto *SIE = dyn_cast<SymIntExpr>(CData.getEnd()))
458*480093f4SDimitry Andric         SR.markLive(SIE->getLHS());
459*480093f4SDimitry Andric     }
460*480093f4SDimitry Andric   }
461*480093f4SDimitry Andric }
462*480093f4SDimitry Andric 
463*480093f4SDimitry Andric void IteratorModeling::checkDeadSymbols(SymbolReaper &SR,
464*480093f4SDimitry Andric                                         CheckerContext &C) const {
465*480093f4SDimitry Andric   // Cleanup
466*480093f4SDimitry Andric   auto State = C.getState();
467*480093f4SDimitry Andric 
468*480093f4SDimitry Andric   auto RegionMap = State->get<IteratorRegionMap>();
469*480093f4SDimitry Andric   for (const auto &Reg : RegionMap) {
470*480093f4SDimitry Andric     if (!SR.isLiveRegion(Reg.first)) {
471*480093f4SDimitry Andric       // The region behind the `LazyCompoundVal` is often cleaned up before
472*480093f4SDimitry Andric       // the `LazyCompoundVal` itself. If there are iterator positions keyed
473*480093f4SDimitry Andric       // by these regions their cleanup must be deferred.
474*480093f4SDimitry Andric       if (!isBoundThroughLazyCompoundVal(State->getEnvironment(), Reg.first)) {
475*480093f4SDimitry Andric         State = State->remove<IteratorRegionMap>(Reg.first);
476*480093f4SDimitry Andric       }
477*480093f4SDimitry Andric     }
478*480093f4SDimitry Andric   }
479*480093f4SDimitry Andric 
480*480093f4SDimitry Andric   auto SymbolMap = State->get<IteratorSymbolMap>();
481*480093f4SDimitry Andric   for (const auto &Sym : SymbolMap) {
482*480093f4SDimitry Andric     if (!SR.isLive(Sym.first)) {
483*480093f4SDimitry Andric       State = State->remove<IteratorSymbolMap>(Sym.first);
484*480093f4SDimitry Andric     }
485*480093f4SDimitry Andric   }
486*480093f4SDimitry Andric 
487*480093f4SDimitry Andric   auto ContMap = State->get<ContainerMap>();
488*480093f4SDimitry Andric   for (const auto &Cont : ContMap) {
489*480093f4SDimitry Andric     if (!SR.isLiveRegion(Cont.first)) {
490*480093f4SDimitry Andric       // We must keep the container data while it has live iterators to be able
491*480093f4SDimitry Andric       // to compare them to the begin and the end of the container.
492*480093f4SDimitry Andric       if (!hasLiveIterators(State, Cont.first)) {
493*480093f4SDimitry Andric         State = State->remove<ContainerMap>(Cont.first);
494*480093f4SDimitry Andric       }
495*480093f4SDimitry Andric     }
496*480093f4SDimitry Andric   }
497*480093f4SDimitry Andric 
498*480093f4SDimitry Andric   C.addTransition(State);
499*480093f4SDimitry Andric }
500*480093f4SDimitry Andric 
501*480093f4SDimitry Andric void IteratorModeling::handleComparison(CheckerContext &C, const Expr *CE,
502*480093f4SDimitry Andric                                        SVal RetVal, const SVal &LVal,
503*480093f4SDimitry Andric                                        const SVal &RVal,
504*480093f4SDimitry Andric                                        OverloadedOperatorKind Op) const {
505*480093f4SDimitry Andric   // Record the operands and the operator of the comparison for the next
506*480093f4SDimitry Andric   // evalAssume, if the result is a symbolic expression. If it is a concrete
507*480093f4SDimitry Andric   // value (only one branch is possible), then transfer the state between
508*480093f4SDimitry Andric   // the operands according to the operator and the result
509*480093f4SDimitry Andric    auto State = C.getState();
510*480093f4SDimitry Andric   const auto *LPos = getIteratorPosition(State, LVal);
511*480093f4SDimitry Andric   const auto *RPos = getIteratorPosition(State, RVal);
512*480093f4SDimitry Andric   const MemRegion *Cont = nullptr;
513*480093f4SDimitry Andric   if (LPos) {
514*480093f4SDimitry Andric     Cont = LPos->getContainer();
515*480093f4SDimitry Andric   } else if (RPos) {
516*480093f4SDimitry Andric     Cont = RPos->getContainer();
517*480093f4SDimitry Andric   }
518*480093f4SDimitry Andric   if (!Cont)
519*480093f4SDimitry Andric     return;
520*480093f4SDimitry Andric 
521*480093f4SDimitry Andric   // At least one of the iterators have recorded positions. If one of them has
522*480093f4SDimitry Andric   // not then create a new symbol for the offset.
523*480093f4SDimitry Andric   SymbolRef Sym;
524*480093f4SDimitry Andric   if (!LPos || !RPos) {
525*480093f4SDimitry Andric     auto &SymMgr = C.getSymbolManager();
526*480093f4SDimitry Andric     Sym = SymMgr.conjureSymbol(CE, C.getLocationContext(),
527*480093f4SDimitry Andric                                C.getASTContext().LongTy, C.blockCount());
528*480093f4SDimitry Andric     State = assumeNoOverflow(State, Sym, 4);
529*480093f4SDimitry Andric   }
530*480093f4SDimitry Andric 
531*480093f4SDimitry Andric   if (!LPos) {
532*480093f4SDimitry Andric     State = setIteratorPosition(State, LVal,
533*480093f4SDimitry Andric                                 IteratorPosition::getPosition(Cont, Sym));
534*480093f4SDimitry Andric     LPos = getIteratorPosition(State, LVal);
535*480093f4SDimitry Andric   } else if (!RPos) {
536*480093f4SDimitry Andric     State = setIteratorPosition(State, RVal,
537*480093f4SDimitry Andric                                 IteratorPosition::getPosition(Cont, Sym));
538*480093f4SDimitry Andric     RPos = getIteratorPosition(State, RVal);
539*480093f4SDimitry Andric   }
540*480093f4SDimitry Andric 
541*480093f4SDimitry Andric   // We cannot make assumpotions on `UnknownVal`. Let us conjure a symbol
542*480093f4SDimitry Andric   // instead.
543*480093f4SDimitry Andric   if (RetVal.isUnknown()) {
544*480093f4SDimitry Andric     auto &SymMgr = C.getSymbolManager();
545*480093f4SDimitry Andric     auto *LCtx = C.getLocationContext();
546*480093f4SDimitry Andric     RetVal = nonloc::SymbolVal(SymMgr.conjureSymbol(
547*480093f4SDimitry Andric         CE, LCtx, C.getASTContext().BoolTy, C.blockCount()));
548*480093f4SDimitry Andric     State = State->BindExpr(CE, LCtx, RetVal);
549*480093f4SDimitry Andric   }
550*480093f4SDimitry Andric 
551*480093f4SDimitry Andric   processComparison(C, State, LPos->getOffset(), RPos->getOffset(), RetVal, Op);
552*480093f4SDimitry Andric }
553*480093f4SDimitry Andric 
554*480093f4SDimitry Andric void IteratorModeling::processComparison(CheckerContext &C,
555*480093f4SDimitry Andric                                          ProgramStateRef State, SymbolRef Sym1,
556*480093f4SDimitry Andric                                          SymbolRef Sym2, const SVal &RetVal,
557*480093f4SDimitry Andric                                          OverloadedOperatorKind Op) const {
558*480093f4SDimitry Andric   if (const auto TruthVal = RetVal.getAs<nonloc::ConcreteInt>()) {
559*480093f4SDimitry Andric     if ((State = relateSymbols(State, Sym1, Sym2,
560*480093f4SDimitry Andric                               (Op == OO_EqualEqual) ==
561*480093f4SDimitry Andric                                (TruthVal->getValue() != 0)))) {
562*480093f4SDimitry Andric       C.addTransition(State);
563*480093f4SDimitry Andric     } else {
564*480093f4SDimitry Andric       C.generateSink(State, C.getPredecessor());
565*480093f4SDimitry Andric     }
566*480093f4SDimitry Andric     return;
567*480093f4SDimitry Andric   }
568*480093f4SDimitry Andric 
569*480093f4SDimitry Andric   const auto ConditionVal = RetVal.getAs<DefinedSVal>();
570*480093f4SDimitry Andric   if (!ConditionVal)
571*480093f4SDimitry Andric     return;
572*480093f4SDimitry Andric 
573*480093f4SDimitry Andric   if (auto StateTrue = relateSymbols(State, Sym1, Sym2, Op == OO_EqualEqual)) {
574*480093f4SDimitry Andric     StateTrue = StateTrue->assume(*ConditionVal, true);
575*480093f4SDimitry Andric     C.addTransition(StateTrue);
576*480093f4SDimitry Andric   }
577*480093f4SDimitry Andric 
578*480093f4SDimitry Andric   if (auto StateFalse = relateSymbols(State, Sym1, Sym2, Op != OO_EqualEqual)) {
579*480093f4SDimitry Andric     StateFalse = StateFalse->assume(*ConditionVal, false);
580*480093f4SDimitry Andric     C.addTransition(StateFalse);
581*480093f4SDimitry Andric   }
582*480093f4SDimitry Andric }
583*480093f4SDimitry Andric 
584*480093f4SDimitry Andric void IteratorModeling::handleIncrement(CheckerContext &C, const SVal &RetVal,
585*480093f4SDimitry Andric                                        const SVal &Iter, bool Postfix) const {
586*480093f4SDimitry Andric   // Increment the symbolic expressions which represents the position of the
587*480093f4SDimitry Andric   // iterator
588*480093f4SDimitry Andric   auto State = C.getState();
589*480093f4SDimitry Andric   auto &BVF = C.getSymbolManager().getBasicVals();
590*480093f4SDimitry Andric 
591*480093f4SDimitry Andric   const auto *Pos = getIteratorPosition(State, Iter);
592*480093f4SDimitry Andric   if (!Pos)
593*480093f4SDimitry Andric     return;
594*480093f4SDimitry Andric 
595*480093f4SDimitry Andric   auto NewState =
596*480093f4SDimitry Andric     advancePosition(State, Iter, OO_Plus,
597*480093f4SDimitry Andric                     nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
598*480093f4SDimitry Andric   assert(NewState &&
599*480093f4SDimitry Andric          "Advancing position by concrete int should always be successful");
600*480093f4SDimitry Andric 
601*480093f4SDimitry Andric   const auto *NewPos = getIteratorPosition(NewState, Iter);
602*480093f4SDimitry Andric   assert(NewPos &&
603*480093f4SDimitry Andric          "Iterator should have position after successful advancement");
604*480093f4SDimitry Andric 
605*480093f4SDimitry Andric   State = setIteratorPosition(State, Iter, *NewPos);
606*480093f4SDimitry Andric   State = setIteratorPosition(State, RetVal, Postfix ? *Pos : *NewPos);
607*480093f4SDimitry Andric   C.addTransition(State);
608*480093f4SDimitry Andric }
609*480093f4SDimitry Andric 
610*480093f4SDimitry Andric void IteratorModeling::handleDecrement(CheckerContext &C, const SVal &RetVal,
611*480093f4SDimitry Andric                                        const SVal &Iter, bool Postfix) const {
612*480093f4SDimitry Andric   // Decrement the symbolic expressions which represents the position of the
613*480093f4SDimitry Andric   // iterator
614*480093f4SDimitry Andric   auto State = C.getState();
615*480093f4SDimitry Andric   auto &BVF = C.getSymbolManager().getBasicVals();
616*480093f4SDimitry Andric 
617*480093f4SDimitry Andric   const auto *Pos = getIteratorPosition(State, Iter);
618*480093f4SDimitry Andric   if (!Pos)
619*480093f4SDimitry Andric     return;
620*480093f4SDimitry Andric 
621*480093f4SDimitry Andric   auto NewState =
622*480093f4SDimitry Andric     advancePosition(State, Iter, OO_Minus,
623*480093f4SDimitry Andric                     nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
624*480093f4SDimitry Andric   assert(NewState &&
625*480093f4SDimitry Andric          "Advancing position by concrete int should always be successful");
626*480093f4SDimitry Andric 
627*480093f4SDimitry Andric   const auto *NewPos = getIteratorPosition(NewState, Iter);
628*480093f4SDimitry Andric   assert(NewPos &&
629*480093f4SDimitry Andric          "Iterator should have position after successful advancement");
630*480093f4SDimitry Andric 
631*480093f4SDimitry Andric   State = setIteratorPosition(State, Iter, *NewPos);
632*480093f4SDimitry Andric   State = setIteratorPosition(State, RetVal, Postfix ? *Pos : *NewPos);
633*480093f4SDimitry Andric   C.addTransition(State);
634*480093f4SDimitry Andric }
635*480093f4SDimitry Andric 
636*480093f4SDimitry Andric void IteratorModeling::handleRandomIncrOrDecr(CheckerContext &C,
637*480093f4SDimitry Andric                                               const Expr *CE,
638*480093f4SDimitry Andric                                               OverloadedOperatorKind Op,
639*480093f4SDimitry Andric                                               const SVal &RetVal,
640*480093f4SDimitry Andric                                               const SVal &LHS,
641*480093f4SDimitry Andric                                               const SVal &RHS) const {
642*480093f4SDimitry Andric   // Increment or decrement the symbolic expressions which represents the
643*480093f4SDimitry Andric   // position of the iterator
644*480093f4SDimitry Andric   auto State = C.getState();
645*480093f4SDimitry Andric 
646*480093f4SDimitry Andric   const auto *Pos = getIteratorPosition(State, LHS);
647*480093f4SDimitry Andric   if (!Pos)
648*480093f4SDimitry Andric     return;
649*480093f4SDimitry Andric 
650*480093f4SDimitry Andric   const auto *value = &RHS;
651*480093f4SDimitry Andric   if (auto loc = RHS.getAs<Loc>()) {
652*480093f4SDimitry Andric     const auto val = State->getRawSVal(*loc);
653*480093f4SDimitry Andric     value = &val;
654*480093f4SDimitry Andric   }
655*480093f4SDimitry Andric 
656*480093f4SDimitry Andric   auto &TgtVal = (Op == OO_PlusEqual || Op == OO_MinusEqual) ? LHS : RetVal;
657*480093f4SDimitry Andric 
658*480093f4SDimitry Andric   auto NewState =
659*480093f4SDimitry Andric     advancePosition(State, LHS, Op, *value);
660*480093f4SDimitry Andric   if (NewState) {
661*480093f4SDimitry Andric     const auto *NewPos = getIteratorPosition(NewState, LHS);
662*480093f4SDimitry Andric     assert(NewPos &&
663*480093f4SDimitry Andric            "Iterator should have position after successful advancement");
664*480093f4SDimitry Andric 
665*480093f4SDimitry Andric     State = setIteratorPosition(NewState, TgtVal, *NewPos);
666*480093f4SDimitry Andric     C.addTransition(State);
667*480093f4SDimitry Andric   } else {
668*480093f4SDimitry Andric     assignToContainer(C, CE, TgtVal, Pos->getContainer());
669*480093f4SDimitry Andric   }
670*480093f4SDimitry Andric }
671*480093f4SDimitry Andric 
672*480093f4SDimitry Andric void IteratorModeling::handleBegin(CheckerContext &C, const Expr *CE,
673*480093f4SDimitry Andric                                    const SVal &RetVal, const SVal &Cont) const {
674*480093f4SDimitry Andric   const auto *ContReg = Cont.getAsRegion();
675*480093f4SDimitry Andric   if (!ContReg)
676*480093f4SDimitry Andric     return;
677*480093f4SDimitry Andric 
678*480093f4SDimitry Andric   ContReg = ContReg->getMostDerivedObjectRegion();
679*480093f4SDimitry Andric 
680*480093f4SDimitry Andric   // If the container already has a begin symbol then use it. Otherwise first
681*480093f4SDimitry Andric   // create a new one.
682*480093f4SDimitry Andric   auto State = C.getState();
683*480093f4SDimitry Andric   auto BeginSym = getContainerBegin(State, ContReg);
684*480093f4SDimitry Andric   if (!BeginSym) {
685*480093f4SDimitry Andric     State = createContainerBegin(State, ContReg, CE, C.getASTContext().LongTy,
686*480093f4SDimitry Andric                                  C.getLocationContext(), C.blockCount());
687*480093f4SDimitry Andric     BeginSym = getContainerBegin(State, ContReg);
688*480093f4SDimitry Andric   }
689*480093f4SDimitry Andric   State = setIteratorPosition(State, RetVal,
690*480093f4SDimitry Andric                               IteratorPosition::getPosition(ContReg, BeginSym));
691*480093f4SDimitry Andric   C.addTransition(State);
692*480093f4SDimitry Andric }
693*480093f4SDimitry Andric 
694*480093f4SDimitry Andric void IteratorModeling::handleEnd(CheckerContext &C, const Expr *CE,
695*480093f4SDimitry Andric                                  const SVal &RetVal, const SVal &Cont) const {
696*480093f4SDimitry Andric   const auto *ContReg = Cont.getAsRegion();
697*480093f4SDimitry Andric   if (!ContReg)
698*480093f4SDimitry Andric     return;
699*480093f4SDimitry Andric 
700*480093f4SDimitry Andric   ContReg = ContReg->getMostDerivedObjectRegion();
701*480093f4SDimitry Andric 
702*480093f4SDimitry Andric   // If the container already has an end symbol then use it. Otherwise first
703*480093f4SDimitry Andric   // create a new one.
704*480093f4SDimitry Andric   auto State = C.getState();
705*480093f4SDimitry Andric   auto EndSym = getContainerEnd(State, ContReg);
706*480093f4SDimitry Andric   if (!EndSym) {
707*480093f4SDimitry Andric     State = createContainerEnd(State, ContReg, CE, C.getASTContext().LongTy,
708*480093f4SDimitry Andric                                C.getLocationContext(), C.blockCount());
709*480093f4SDimitry Andric     EndSym = getContainerEnd(State, ContReg);
710*480093f4SDimitry Andric   }
711*480093f4SDimitry Andric   State = setIteratorPosition(State, RetVal,
712*480093f4SDimitry Andric                               IteratorPosition::getPosition(ContReg, EndSym));
713*480093f4SDimitry Andric   C.addTransition(State);
714*480093f4SDimitry Andric }
715*480093f4SDimitry Andric 
716*480093f4SDimitry Andric void IteratorModeling::assignToContainer(CheckerContext &C, const Expr *CE,
717*480093f4SDimitry Andric                                          const SVal &RetVal,
718*480093f4SDimitry Andric                                          const MemRegion *Cont) const {
719*480093f4SDimitry Andric   Cont = Cont->getMostDerivedObjectRegion();
720*480093f4SDimitry Andric 
721*480093f4SDimitry Andric   auto State = C.getState();
722*480093f4SDimitry Andric   auto &SymMgr = C.getSymbolManager();
723*480093f4SDimitry Andric   auto Sym = SymMgr.conjureSymbol(CE, C.getLocationContext(),
724*480093f4SDimitry Andric                                   C.getASTContext().LongTy, C.blockCount());
725*480093f4SDimitry Andric   State = assumeNoOverflow(State, Sym, 4);
726*480093f4SDimitry Andric   State = setIteratorPosition(State, RetVal,
727*480093f4SDimitry Andric                               IteratorPosition::getPosition(Cont, Sym));
728*480093f4SDimitry Andric   C.addTransition(State);
729*480093f4SDimitry Andric }
730*480093f4SDimitry Andric 
731*480093f4SDimitry Andric void IteratorModeling::handleAssign(CheckerContext &C, const SVal &Cont,
732*480093f4SDimitry Andric                                     const Expr *CE, const SVal &OldCont) const {
733*480093f4SDimitry Andric   const auto *ContReg = Cont.getAsRegion();
734*480093f4SDimitry Andric   if (!ContReg)
735*480093f4SDimitry Andric     return;
736*480093f4SDimitry Andric 
737*480093f4SDimitry Andric   ContReg = ContReg->getMostDerivedObjectRegion();
738*480093f4SDimitry Andric 
739*480093f4SDimitry Andric   // Assignment of a new value to a container always invalidates all its
740*480093f4SDimitry Andric   // iterators
741*480093f4SDimitry Andric   auto State = C.getState();
742*480093f4SDimitry Andric   const auto CData = getContainerData(State, ContReg);
743*480093f4SDimitry Andric   if (CData) {
744*480093f4SDimitry Andric     State = invalidateAllIteratorPositions(State, ContReg);
745*480093f4SDimitry Andric   }
746*480093f4SDimitry Andric 
747*480093f4SDimitry Andric   // In case of move, iterators of the old container (except the past-end
748*480093f4SDimitry Andric   // iterators) remain valid but refer to the new container
749*480093f4SDimitry Andric   if (!OldCont.isUndef()) {
750*480093f4SDimitry Andric     const auto *OldContReg = OldCont.getAsRegion();
751*480093f4SDimitry Andric     if (OldContReg) {
752*480093f4SDimitry Andric       OldContReg = OldContReg->getMostDerivedObjectRegion();
753*480093f4SDimitry Andric       const auto OldCData = getContainerData(State, OldContReg);
754*480093f4SDimitry Andric       if (OldCData) {
755*480093f4SDimitry Andric         if (const auto OldEndSym = OldCData->getEnd()) {
756*480093f4SDimitry Andric           // If we already assigned an "end" symbol to the old container, then
757*480093f4SDimitry Andric           // first reassign all iterator positions to the new container which
758*480093f4SDimitry Andric           // are not past the container (thus not greater or equal to the
759*480093f4SDimitry Andric           // current "end" symbol).
760*480093f4SDimitry Andric           State = reassignAllIteratorPositionsUnless(State, OldContReg, ContReg,
761*480093f4SDimitry Andric                                                      OldEndSym, BO_GE);
762*480093f4SDimitry Andric           auto &SymMgr = C.getSymbolManager();
763*480093f4SDimitry Andric           auto &SVB = C.getSValBuilder();
764*480093f4SDimitry Andric           // Then generate and assign a new "end" symbol for the new container.
765*480093f4SDimitry Andric           auto NewEndSym =
766*480093f4SDimitry Andric               SymMgr.conjureSymbol(CE, C.getLocationContext(),
767*480093f4SDimitry Andric                                    C.getASTContext().LongTy, C.blockCount());
768*480093f4SDimitry Andric           State = assumeNoOverflow(State, NewEndSym, 4);
769*480093f4SDimitry Andric           if (CData) {
770*480093f4SDimitry Andric             State = setContainerData(State, ContReg, CData->newEnd(NewEndSym));
771*480093f4SDimitry Andric           } else {
772*480093f4SDimitry Andric             State = setContainerData(State, ContReg,
773*480093f4SDimitry Andric                                      ContainerData::fromEnd(NewEndSym));
774*480093f4SDimitry Andric           }
775*480093f4SDimitry Andric           // Finally, replace the old "end" symbol in the already reassigned
776*480093f4SDimitry Andric           // iterator positions with the new "end" symbol.
777*480093f4SDimitry Andric           State = rebaseSymbolInIteratorPositionsIf(
778*480093f4SDimitry Andric               State, SVB, OldEndSym, NewEndSym, OldEndSym, BO_LT);
779*480093f4SDimitry Andric         } else {
780*480093f4SDimitry Andric           // There was no "end" symbol assigned yet to the old container,
781*480093f4SDimitry Andric           // so reassign all iterator positions to the new container.
782*480093f4SDimitry Andric           State = reassignAllIteratorPositions(State, OldContReg, ContReg);
783*480093f4SDimitry Andric         }
784*480093f4SDimitry Andric         if (const auto OldBeginSym = OldCData->getBegin()) {
785*480093f4SDimitry Andric           // If we already assigned a "begin" symbol to the old container, then
786*480093f4SDimitry Andric           // assign it to the new container and remove it from the old one.
787*480093f4SDimitry Andric           if (CData) {
788*480093f4SDimitry Andric             State =
789*480093f4SDimitry Andric                 setContainerData(State, ContReg, CData->newBegin(OldBeginSym));
790*480093f4SDimitry Andric           } else {
791*480093f4SDimitry Andric             State = setContainerData(State, ContReg,
792*480093f4SDimitry Andric                                      ContainerData::fromBegin(OldBeginSym));
793*480093f4SDimitry Andric           }
794*480093f4SDimitry Andric           State =
795*480093f4SDimitry Andric               setContainerData(State, OldContReg, OldCData->newEnd(nullptr));
796*480093f4SDimitry Andric         }
797*480093f4SDimitry Andric       } else {
798*480093f4SDimitry Andric         // There was neither "begin" nor "end" symbol assigned yet to the old
799*480093f4SDimitry Andric         // container, so reassign all iterator positions to the new container.
800*480093f4SDimitry Andric         State = reassignAllIteratorPositions(State, OldContReg, ContReg);
801*480093f4SDimitry Andric       }
802*480093f4SDimitry Andric     }
803*480093f4SDimitry Andric   }
804*480093f4SDimitry Andric   C.addTransition(State);
805*480093f4SDimitry Andric }
806*480093f4SDimitry Andric 
807*480093f4SDimitry Andric void IteratorModeling::handleClear(CheckerContext &C, const SVal &Cont) const {
808*480093f4SDimitry Andric   const auto *ContReg = Cont.getAsRegion();
809*480093f4SDimitry Andric   if (!ContReg)
810*480093f4SDimitry Andric     return;
811*480093f4SDimitry Andric 
812*480093f4SDimitry Andric   ContReg = ContReg->getMostDerivedObjectRegion();
813*480093f4SDimitry Andric 
814*480093f4SDimitry Andric   // The clear() operation invalidates all the iterators, except the past-end
815*480093f4SDimitry Andric   // iterators of list-like containers
816*480093f4SDimitry Andric   auto State = C.getState();
817*480093f4SDimitry Andric   if (!hasSubscriptOperator(State, ContReg) ||
818*480093f4SDimitry Andric       !backModifiable(State, ContReg)) {
819*480093f4SDimitry Andric     const auto CData = getContainerData(State, ContReg);
820*480093f4SDimitry Andric     if (CData) {
821*480093f4SDimitry Andric       if (const auto EndSym = CData->getEnd()) {
822*480093f4SDimitry Andric         State =
823*480093f4SDimitry Andric             invalidateAllIteratorPositionsExcept(State, ContReg, EndSym, BO_GE);
824*480093f4SDimitry Andric         C.addTransition(State);
825*480093f4SDimitry Andric         return;
826*480093f4SDimitry Andric       }
827*480093f4SDimitry Andric     }
828*480093f4SDimitry Andric   }
829*480093f4SDimitry Andric   State = invalidateAllIteratorPositions(State, ContReg);
830*480093f4SDimitry Andric   C.addTransition(State);
831*480093f4SDimitry Andric }
832*480093f4SDimitry Andric 
833*480093f4SDimitry Andric void IteratorModeling::handlePushBack(CheckerContext &C,
834*480093f4SDimitry Andric                                       const SVal &Cont) const {
835*480093f4SDimitry Andric   const auto *ContReg = Cont.getAsRegion();
836*480093f4SDimitry Andric   if (!ContReg)
837*480093f4SDimitry Andric     return;
838*480093f4SDimitry Andric 
839*480093f4SDimitry Andric   ContReg = ContReg->getMostDerivedObjectRegion();
840*480093f4SDimitry Andric 
841*480093f4SDimitry Andric   // For deque-like containers invalidate all iterator positions
842*480093f4SDimitry Andric   auto State = C.getState();
843*480093f4SDimitry Andric   if (hasSubscriptOperator(State, ContReg) && frontModifiable(State, ContReg)) {
844*480093f4SDimitry Andric     State = invalidateAllIteratorPositions(State, ContReg);
845*480093f4SDimitry Andric     C.addTransition(State);
846*480093f4SDimitry Andric     return;
847*480093f4SDimitry Andric   }
848*480093f4SDimitry Andric 
849*480093f4SDimitry Andric   const auto CData = getContainerData(State, ContReg);
850*480093f4SDimitry Andric   if (!CData)
851*480093f4SDimitry Andric     return;
852*480093f4SDimitry Andric 
853*480093f4SDimitry Andric   // For vector-like containers invalidate the past-end iterator positions
854*480093f4SDimitry Andric   if (const auto EndSym = CData->getEnd()) {
855*480093f4SDimitry Andric     if (hasSubscriptOperator(State, ContReg)) {
856*480093f4SDimitry Andric       State = invalidateIteratorPositions(State, EndSym, BO_GE);
857*480093f4SDimitry Andric     }
858*480093f4SDimitry Andric     auto &SymMgr = C.getSymbolManager();
859*480093f4SDimitry Andric     auto &BVF = SymMgr.getBasicVals();
860*480093f4SDimitry Andric     auto &SVB = C.getSValBuilder();
861*480093f4SDimitry Andric     const auto newEndSym =
862*480093f4SDimitry Andric       SVB.evalBinOp(State, BO_Add,
863*480093f4SDimitry Andric                     nonloc::SymbolVal(EndSym),
864*480093f4SDimitry Andric                     nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
865*480093f4SDimitry Andric                     SymMgr.getType(EndSym)).getAsSymbol();
866*480093f4SDimitry Andric     State = setContainerData(State, ContReg, CData->newEnd(newEndSym));
867*480093f4SDimitry Andric   }
868*480093f4SDimitry Andric   C.addTransition(State);
869*480093f4SDimitry Andric }
870*480093f4SDimitry Andric 
871*480093f4SDimitry Andric void IteratorModeling::handlePopBack(CheckerContext &C,
872*480093f4SDimitry Andric                                      const SVal &Cont) const {
873*480093f4SDimitry Andric   const auto *ContReg = Cont.getAsRegion();
874*480093f4SDimitry Andric   if (!ContReg)
875*480093f4SDimitry Andric     return;
876*480093f4SDimitry Andric 
877*480093f4SDimitry Andric   ContReg = ContReg->getMostDerivedObjectRegion();
878*480093f4SDimitry Andric 
879*480093f4SDimitry Andric   auto State = C.getState();
880*480093f4SDimitry Andric   const auto CData = getContainerData(State, ContReg);
881*480093f4SDimitry Andric   if (!CData)
882*480093f4SDimitry Andric     return;
883*480093f4SDimitry Andric 
884*480093f4SDimitry Andric   if (const auto EndSym = CData->getEnd()) {
885*480093f4SDimitry Andric     auto &SymMgr = C.getSymbolManager();
886*480093f4SDimitry Andric     auto &BVF = SymMgr.getBasicVals();
887*480093f4SDimitry Andric     auto &SVB = C.getSValBuilder();
888*480093f4SDimitry Andric     const auto BackSym =
889*480093f4SDimitry Andric       SVB.evalBinOp(State, BO_Sub,
890*480093f4SDimitry Andric                     nonloc::SymbolVal(EndSym),
891*480093f4SDimitry Andric                     nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
892*480093f4SDimitry Andric                     SymMgr.getType(EndSym)).getAsSymbol();
893*480093f4SDimitry Andric     // For vector-like and deque-like containers invalidate the last and the
894*480093f4SDimitry Andric     // past-end iterator positions. For list-like containers only invalidate
895*480093f4SDimitry Andric     // the last position
896*480093f4SDimitry Andric     if (hasSubscriptOperator(State, ContReg) &&
897*480093f4SDimitry Andric         backModifiable(State, ContReg)) {
898*480093f4SDimitry Andric       State = invalidateIteratorPositions(State, BackSym, BO_GE);
899*480093f4SDimitry Andric       State = setContainerData(State, ContReg, CData->newEnd(nullptr));
900*480093f4SDimitry Andric     } else {
901*480093f4SDimitry Andric       State = invalidateIteratorPositions(State, BackSym, BO_EQ);
902*480093f4SDimitry Andric     }
903*480093f4SDimitry Andric     auto newEndSym = BackSym;
904*480093f4SDimitry Andric     State = setContainerData(State, ContReg, CData->newEnd(newEndSym));
905*480093f4SDimitry Andric     C.addTransition(State);
906*480093f4SDimitry Andric   }
907*480093f4SDimitry Andric }
908*480093f4SDimitry Andric 
909*480093f4SDimitry Andric void IteratorModeling::handlePushFront(CheckerContext &C,
910*480093f4SDimitry Andric                                        const SVal &Cont) const {
911*480093f4SDimitry Andric   const auto *ContReg = Cont.getAsRegion();
912*480093f4SDimitry Andric   if (!ContReg)
913*480093f4SDimitry Andric     return;
914*480093f4SDimitry Andric 
915*480093f4SDimitry Andric   ContReg = ContReg->getMostDerivedObjectRegion();
916*480093f4SDimitry Andric 
917*480093f4SDimitry Andric   // For deque-like containers invalidate all iterator positions
918*480093f4SDimitry Andric   auto State = C.getState();
919*480093f4SDimitry Andric   if (hasSubscriptOperator(State, ContReg)) {
920*480093f4SDimitry Andric     State = invalidateAllIteratorPositions(State, ContReg);
921*480093f4SDimitry Andric     C.addTransition(State);
922*480093f4SDimitry Andric   } else {
923*480093f4SDimitry Andric     const auto CData = getContainerData(State, ContReg);
924*480093f4SDimitry Andric     if (!CData)
925*480093f4SDimitry Andric       return;
926*480093f4SDimitry Andric 
927*480093f4SDimitry Andric     if (const auto BeginSym = CData->getBegin()) {
928*480093f4SDimitry Andric       auto &SymMgr = C.getSymbolManager();
929*480093f4SDimitry Andric       auto &BVF = SymMgr.getBasicVals();
930*480093f4SDimitry Andric       auto &SVB = C.getSValBuilder();
931*480093f4SDimitry Andric       const auto newBeginSym =
932*480093f4SDimitry Andric         SVB.evalBinOp(State, BO_Sub,
933*480093f4SDimitry Andric                       nonloc::SymbolVal(BeginSym),
934*480093f4SDimitry Andric                       nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
935*480093f4SDimitry Andric                       SymMgr.getType(BeginSym)).getAsSymbol();
936*480093f4SDimitry Andric       State = setContainerData(State, ContReg, CData->newBegin(newBeginSym));
937*480093f4SDimitry Andric       C.addTransition(State);
938*480093f4SDimitry Andric     }
939*480093f4SDimitry Andric   }
940*480093f4SDimitry Andric }
941*480093f4SDimitry Andric 
942*480093f4SDimitry Andric void IteratorModeling::handlePopFront(CheckerContext &C,
943*480093f4SDimitry Andric                                       const SVal &Cont) const {
944*480093f4SDimitry Andric   const auto *ContReg = Cont.getAsRegion();
945*480093f4SDimitry Andric   if (!ContReg)
946*480093f4SDimitry Andric     return;
947*480093f4SDimitry Andric 
948*480093f4SDimitry Andric   ContReg = ContReg->getMostDerivedObjectRegion();
949*480093f4SDimitry Andric 
950*480093f4SDimitry Andric   auto State = C.getState();
951*480093f4SDimitry Andric   const auto CData = getContainerData(State, ContReg);
952*480093f4SDimitry Andric   if (!CData)
953*480093f4SDimitry Andric     return;
954*480093f4SDimitry Andric 
955*480093f4SDimitry Andric   // For deque-like containers invalidate all iterator positions. For list-like
956*480093f4SDimitry Andric   // iterators only invalidate the first position
957*480093f4SDimitry Andric   if (const auto BeginSym = CData->getBegin()) {
958*480093f4SDimitry Andric     if (hasSubscriptOperator(State, ContReg)) {
959*480093f4SDimitry Andric       State = invalidateIteratorPositions(State, BeginSym, BO_LE);
960*480093f4SDimitry Andric     } else {
961*480093f4SDimitry Andric       State = invalidateIteratorPositions(State, BeginSym, BO_EQ);
962*480093f4SDimitry Andric     }
963*480093f4SDimitry Andric     auto &SymMgr = C.getSymbolManager();
964*480093f4SDimitry Andric     auto &BVF = SymMgr.getBasicVals();
965*480093f4SDimitry Andric     auto &SVB = C.getSValBuilder();
966*480093f4SDimitry Andric     const auto newBeginSym =
967*480093f4SDimitry Andric       SVB.evalBinOp(State, BO_Add,
968*480093f4SDimitry Andric                     nonloc::SymbolVal(BeginSym),
969*480093f4SDimitry Andric                     nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
970*480093f4SDimitry Andric                     SymMgr.getType(BeginSym)).getAsSymbol();
971*480093f4SDimitry Andric     State = setContainerData(State, ContReg, CData->newBegin(newBeginSym));
972*480093f4SDimitry Andric     C.addTransition(State);
973*480093f4SDimitry Andric   }
974*480093f4SDimitry Andric }
975*480093f4SDimitry Andric 
976*480093f4SDimitry Andric void IteratorModeling::handleInsert(CheckerContext &C, const SVal &Iter) const {
977*480093f4SDimitry Andric   auto State = C.getState();
978*480093f4SDimitry Andric   const auto *Pos = getIteratorPosition(State, Iter);
979*480093f4SDimitry Andric   if (!Pos)
980*480093f4SDimitry Andric     return;
981*480093f4SDimitry Andric 
982*480093f4SDimitry Andric   // For deque-like containers invalidate all iterator positions. For
983*480093f4SDimitry Andric   // vector-like containers invalidate iterator positions after the insertion.
984*480093f4SDimitry Andric   const auto *Cont = Pos->getContainer();
985*480093f4SDimitry Andric   if (hasSubscriptOperator(State, Cont) && backModifiable(State, Cont)) {
986*480093f4SDimitry Andric     if (frontModifiable(State, Cont)) {
987*480093f4SDimitry Andric       State = invalidateAllIteratorPositions(State, Cont);
988*480093f4SDimitry Andric     } else {
989*480093f4SDimitry Andric       State = invalidateIteratorPositions(State, Pos->getOffset(), BO_GE);
990*480093f4SDimitry Andric     }
991*480093f4SDimitry Andric     if (const auto *CData = getContainerData(State, Cont)) {
992*480093f4SDimitry Andric       if (const auto EndSym = CData->getEnd()) {
993*480093f4SDimitry Andric         State = invalidateIteratorPositions(State, EndSym, BO_GE);
994*480093f4SDimitry Andric         State = setContainerData(State, Cont, CData->newEnd(nullptr));
995*480093f4SDimitry Andric       }
996*480093f4SDimitry Andric     }
997*480093f4SDimitry Andric     C.addTransition(State);
998*480093f4SDimitry Andric   }
999*480093f4SDimitry Andric }
1000*480093f4SDimitry Andric 
1001*480093f4SDimitry Andric void IteratorModeling::handleErase(CheckerContext &C, const SVal &Iter) const {
1002*480093f4SDimitry Andric   auto State = C.getState();
1003*480093f4SDimitry Andric   const auto *Pos = getIteratorPosition(State, Iter);
1004*480093f4SDimitry Andric   if (!Pos)
1005*480093f4SDimitry Andric     return;
1006*480093f4SDimitry Andric 
1007*480093f4SDimitry Andric   // For deque-like containers invalidate all iterator positions. For
1008*480093f4SDimitry Andric   // vector-like containers invalidate iterator positions at and after the
1009*480093f4SDimitry Andric   // deletion. For list-like containers only invalidate the deleted position.
1010*480093f4SDimitry Andric   const auto *Cont = Pos->getContainer();
1011*480093f4SDimitry Andric   if (hasSubscriptOperator(State, Cont) && backModifiable(State, Cont)) {
1012*480093f4SDimitry Andric     if (frontModifiable(State, Cont)) {
1013*480093f4SDimitry Andric       State = invalidateAllIteratorPositions(State, Cont);
1014*480093f4SDimitry Andric     } else {
1015*480093f4SDimitry Andric       State = invalidateIteratorPositions(State, Pos->getOffset(), BO_GE);
1016*480093f4SDimitry Andric     }
1017*480093f4SDimitry Andric     if (const auto *CData = getContainerData(State, Cont)) {
1018*480093f4SDimitry Andric       if (const auto EndSym = CData->getEnd()) {
1019*480093f4SDimitry Andric         State = invalidateIteratorPositions(State, EndSym, BO_GE);
1020*480093f4SDimitry Andric         State = setContainerData(State, Cont, CData->newEnd(nullptr));
1021*480093f4SDimitry Andric       }
1022*480093f4SDimitry Andric     }
1023*480093f4SDimitry Andric   } else {
1024*480093f4SDimitry Andric     State = invalidateIteratorPositions(State, Pos->getOffset(), BO_EQ);
1025*480093f4SDimitry Andric   }
1026*480093f4SDimitry Andric   C.addTransition(State);
1027*480093f4SDimitry Andric }
1028*480093f4SDimitry Andric 
1029*480093f4SDimitry Andric void IteratorModeling::handleErase(CheckerContext &C, const SVal &Iter1,
1030*480093f4SDimitry Andric                                    const SVal &Iter2) const {
1031*480093f4SDimitry Andric   auto State = C.getState();
1032*480093f4SDimitry Andric   const auto *Pos1 = getIteratorPosition(State, Iter1);
1033*480093f4SDimitry Andric   const auto *Pos2 = getIteratorPosition(State, Iter2);
1034*480093f4SDimitry Andric   if (!Pos1 || !Pos2)
1035*480093f4SDimitry Andric     return;
1036*480093f4SDimitry Andric 
1037*480093f4SDimitry Andric   // For deque-like containers invalidate all iterator positions. For
1038*480093f4SDimitry Andric   // vector-like containers invalidate iterator positions at and after the
1039*480093f4SDimitry Andric   // deletion range. For list-like containers only invalidate the deleted
1040*480093f4SDimitry Andric   // position range [first..last].
1041*480093f4SDimitry Andric   const auto *Cont = Pos1->getContainer();
1042*480093f4SDimitry Andric   if (hasSubscriptOperator(State, Cont) && backModifiable(State, Cont)) {
1043*480093f4SDimitry Andric     if (frontModifiable(State, Cont)) {
1044*480093f4SDimitry Andric       State = invalidateAllIteratorPositions(State, Cont);
1045*480093f4SDimitry Andric     } else {
1046*480093f4SDimitry Andric       State = invalidateIteratorPositions(State, Pos1->getOffset(), BO_GE);
1047*480093f4SDimitry Andric     }
1048*480093f4SDimitry Andric     if (const auto *CData = getContainerData(State, Cont)) {
1049*480093f4SDimitry Andric       if (const auto EndSym = CData->getEnd()) {
1050*480093f4SDimitry Andric         State = invalidateIteratorPositions(State, EndSym, BO_GE);
1051*480093f4SDimitry Andric         State = setContainerData(State, Cont, CData->newEnd(nullptr));
1052*480093f4SDimitry Andric       }
1053*480093f4SDimitry Andric     }
1054*480093f4SDimitry Andric   } else {
1055*480093f4SDimitry Andric     State = invalidateIteratorPositions(State, Pos1->getOffset(), BO_GE,
1056*480093f4SDimitry Andric                                         Pos2->getOffset(), BO_LT);
1057*480093f4SDimitry Andric   }
1058*480093f4SDimitry Andric   C.addTransition(State);
1059*480093f4SDimitry Andric }
1060*480093f4SDimitry Andric 
1061*480093f4SDimitry Andric void IteratorModeling::handleEraseAfter(CheckerContext &C,
1062*480093f4SDimitry Andric                                         const SVal &Iter) const {
1063*480093f4SDimitry Andric   auto State = C.getState();
1064*480093f4SDimitry Andric   const auto *Pos = getIteratorPosition(State, Iter);
1065*480093f4SDimitry Andric   if (!Pos)
1066*480093f4SDimitry Andric     return;
1067*480093f4SDimitry Andric 
1068*480093f4SDimitry Andric   // Invalidate the deleted iterator position, which is the position of the
1069*480093f4SDimitry Andric   // parameter plus one.
1070*480093f4SDimitry Andric   auto &SymMgr = C.getSymbolManager();
1071*480093f4SDimitry Andric   auto &BVF = SymMgr.getBasicVals();
1072*480093f4SDimitry Andric   auto &SVB = C.getSValBuilder();
1073*480093f4SDimitry Andric   const auto NextSym =
1074*480093f4SDimitry Andric     SVB.evalBinOp(State, BO_Add,
1075*480093f4SDimitry Andric                   nonloc::SymbolVal(Pos->getOffset()),
1076*480093f4SDimitry Andric                   nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
1077*480093f4SDimitry Andric                   SymMgr.getType(Pos->getOffset())).getAsSymbol();
1078*480093f4SDimitry Andric   State = invalidateIteratorPositions(State, NextSym, BO_EQ);
1079*480093f4SDimitry Andric   C.addTransition(State);
1080*480093f4SDimitry Andric }
1081*480093f4SDimitry Andric 
1082*480093f4SDimitry Andric void IteratorModeling::handleEraseAfter(CheckerContext &C, const SVal &Iter1,
1083*480093f4SDimitry Andric                                         const SVal &Iter2) const {
1084*480093f4SDimitry Andric   auto State = C.getState();
1085*480093f4SDimitry Andric   const auto *Pos1 = getIteratorPosition(State, Iter1);
1086*480093f4SDimitry Andric   const auto *Pos2 = getIteratorPosition(State, Iter2);
1087*480093f4SDimitry Andric   if (!Pos1 || !Pos2)
1088*480093f4SDimitry Andric     return;
1089*480093f4SDimitry Andric 
1090*480093f4SDimitry Andric   // Invalidate the deleted iterator position range (first..last)
1091*480093f4SDimitry Andric   State = invalidateIteratorPositions(State, Pos1->getOffset(), BO_GT,
1092*480093f4SDimitry Andric                                       Pos2->getOffset(), BO_LT);
1093*480093f4SDimitry Andric   C.addTransition(State);
1094*480093f4SDimitry Andric }
1095*480093f4SDimitry Andric 
1096*480093f4SDimitry Andric void IteratorModeling::printState(raw_ostream &Out, ProgramStateRef State,
1097*480093f4SDimitry Andric                                   const char *NL, const char *Sep) const {
1098*480093f4SDimitry Andric 
1099*480093f4SDimitry Andric   auto ContMap = State->get<ContainerMap>();
1100*480093f4SDimitry Andric 
1101*480093f4SDimitry Andric   if (!ContMap.isEmpty()) {
1102*480093f4SDimitry Andric     Out << Sep << "Container Data :" << NL;
1103*480093f4SDimitry Andric     for (const auto &Cont : ContMap) {
1104*480093f4SDimitry Andric       Cont.first->dumpToStream(Out);
1105*480093f4SDimitry Andric       Out << " : [ ";
1106*480093f4SDimitry Andric       const auto CData = Cont.second;
1107*480093f4SDimitry Andric       if (CData.getBegin())
1108*480093f4SDimitry Andric         CData.getBegin()->dumpToStream(Out);
1109*480093f4SDimitry Andric       else
1110*480093f4SDimitry Andric         Out << "<Unknown>";
1111*480093f4SDimitry Andric       Out << " .. ";
1112*480093f4SDimitry Andric       if (CData.getEnd())
1113*480093f4SDimitry Andric         CData.getEnd()->dumpToStream(Out);
1114*480093f4SDimitry Andric       else
1115*480093f4SDimitry Andric         Out << "<Unknown>";
1116*480093f4SDimitry Andric       Out << " ]" << NL;
1117*480093f4SDimitry Andric     }
1118*480093f4SDimitry Andric   }
1119*480093f4SDimitry Andric 
1120*480093f4SDimitry Andric   auto SymbolMap = State->get<IteratorSymbolMap>();
1121*480093f4SDimitry Andric   auto RegionMap = State->get<IteratorRegionMap>();
1122*480093f4SDimitry Andric 
1123*480093f4SDimitry Andric   if (!SymbolMap.isEmpty() || !RegionMap.isEmpty()) {
1124*480093f4SDimitry Andric     Out << Sep << "Iterator Positions :" << NL;
1125*480093f4SDimitry Andric     for (const auto &Sym : SymbolMap) {
1126*480093f4SDimitry Andric       Sym.first->dumpToStream(Out);
1127*480093f4SDimitry Andric       Out << " : ";
1128*480093f4SDimitry Andric       const auto Pos = Sym.second;
1129*480093f4SDimitry Andric       Out << (Pos.isValid() ? "Valid" : "Invalid") << " ; Container == ";
1130*480093f4SDimitry Andric       Pos.getContainer()->dumpToStream(Out);
1131*480093f4SDimitry Andric       Out<<" ; Offset == ";
1132*480093f4SDimitry Andric       Pos.getOffset()->dumpToStream(Out);
1133*480093f4SDimitry Andric     }
1134*480093f4SDimitry Andric 
1135*480093f4SDimitry Andric     for (const auto &Reg : RegionMap) {
1136*480093f4SDimitry Andric       Reg.first->dumpToStream(Out);
1137*480093f4SDimitry Andric       Out << " : ";
1138*480093f4SDimitry Andric       const auto Pos = Reg.second;
1139*480093f4SDimitry Andric       Out << (Pos.isValid() ? "Valid" : "Invalid") << " ; Container == ";
1140*480093f4SDimitry Andric       Pos.getContainer()->dumpToStream(Out);
1141*480093f4SDimitry Andric       Out<<" ; Offset == ";
1142*480093f4SDimitry Andric       Pos.getOffset()->dumpToStream(Out);
1143*480093f4SDimitry Andric     }
1144*480093f4SDimitry Andric   }
1145*480093f4SDimitry Andric }
1146*480093f4SDimitry Andric 
1147*480093f4SDimitry Andric 
1148*480093f4SDimitry Andric namespace {
1149*480093f4SDimitry Andric 
1150*480093f4SDimitry Andric const CXXRecordDecl *getCXXRecordDecl(ProgramStateRef State,
1151*480093f4SDimitry Andric                                       const MemRegion *Reg);
1152*480093f4SDimitry Andric 
1153*480093f4SDimitry Andric bool isBeginCall(const FunctionDecl *Func) {
1154*480093f4SDimitry Andric   const auto *IdInfo = Func->getIdentifier();
1155*480093f4SDimitry Andric   if (!IdInfo)
1156*480093f4SDimitry Andric     return false;
1157*480093f4SDimitry Andric   return IdInfo->getName().endswith_lower("begin");
1158*480093f4SDimitry Andric }
1159*480093f4SDimitry Andric 
1160*480093f4SDimitry Andric bool isEndCall(const FunctionDecl *Func) {
1161*480093f4SDimitry Andric   const auto *IdInfo = Func->getIdentifier();
1162*480093f4SDimitry Andric   if (!IdInfo)
1163*480093f4SDimitry Andric     return false;
1164*480093f4SDimitry Andric   return IdInfo->getName().endswith_lower("end");
1165*480093f4SDimitry Andric }
1166*480093f4SDimitry Andric 
1167*480093f4SDimitry Andric bool isAssignCall(const FunctionDecl *Func) {
1168*480093f4SDimitry Andric   const auto *IdInfo = Func->getIdentifier();
1169*480093f4SDimitry Andric   if (!IdInfo)
1170*480093f4SDimitry Andric     return false;
1171*480093f4SDimitry Andric   if (Func->getNumParams() > 2)
1172*480093f4SDimitry Andric     return false;
1173*480093f4SDimitry Andric   return IdInfo->getName() == "assign";
1174*480093f4SDimitry Andric }
1175*480093f4SDimitry Andric 
1176*480093f4SDimitry Andric bool isClearCall(const FunctionDecl *Func) {
1177*480093f4SDimitry Andric   const auto *IdInfo = Func->getIdentifier();
1178*480093f4SDimitry Andric   if (!IdInfo)
1179*480093f4SDimitry Andric     return false;
1180*480093f4SDimitry Andric   if (Func->getNumParams() > 0)
1181*480093f4SDimitry Andric     return false;
1182*480093f4SDimitry Andric   return IdInfo->getName() == "clear";
1183*480093f4SDimitry Andric }
1184*480093f4SDimitry Andric 
1185*480093f4SDimitry Andric bool isPushBackCall(const FunctionDecl *Func) {
1186*480093f4SDimitry Andric   const auto *IdInfo = Func->getIdentifier();
1187*480093f4SDimitry Andric   if (!IdInfo)
1188*480093f4SDimitry Andric     return false;
1189*480093f4SDimitry Andric   if (Func->getNumParams() != 1)
1190*480093f4SDimitry Andric     return false;
1191*480093f4SDimitry Andric   return IdInfo->getName() == "push_back";
1192*480093f4SDimitry Andric }
1193*480093f4SDimitry Andric 
1194*480093f4SDimitry Andric bool isEmplaceBackCall(const FunctionDecl *Func) {
1195*480093f4SDimitry Andric   const auto *IdInfo = Func->getIdentifier();
1196*480093f4SDimitry Andric   if (!IdInfo)
1197*480093f4SDimitry Andric     return false;
1198*480093f4SDimitry Andric   if (Func->getNumParams() < 1)
1199*480093f4SDimitry Andric     return false;
1200*480093f4SDimitry Andric   return IdInfo->getName() == "emplace_back";
1201*480093f4SDimitry Andric }
1202*480093f4SDimitry Andric 
1203*480093f4SDimitry Andric bool isPopBackCall(const FunctionDecl *Func) {
1204*480093f4SDimitry Andric   const auto *IdInfo = Func->getIdentifier();
1205*480093f4SDimitry Andric   if (!IdInfo)
1206*480093f4SDimitry Andric     return false;
1207*480093f4SDimitry Andric   if (Func->getNumParams() > 0)
1208*480093f4SDimitry Andric     return false;
1209*480093f4SDimitry Andric   return IdInfo->getName() == "pop_back";
1210*480093f4SDimitry Andric }
1211*480093f4SDimitry Andric 
1212*480093f4SDimitry Andric bool isPushFrontCall(const FunctionDecl *Func) {
1213*480093f4SDimitry Andric   const auto *IdInfo = Func->getIdentifier();
1214*480093f4SDimitry Andric   if (!IdInfo)
1215*480093f4SDimitry Andric     return false;
1216*480093f4SDimitry Andric   if (Func->getNumParams() != 1)
1217*480093f4SDimitry Andric     return false;
1218*480093f4SDimitry Andric   return IdInfo->getName() == "push_front";
1219*480093f4SDimitry Andric }
1220*480093f4SDimitry Andric 
1221*480093f4SDimitry Andric bool isEmplaceFrontCall(const FunctionDecl *Func) {
1222*480093f4SDimitry Andric   const auto *IdInfo = Func->getIdentifier();
1223*480093f4SDimitry Andric   if (!IdInfo)
1224*480093f4SDimitry Andric     return false;
1225*480093f4SDimitry Andric   if (Func->getNumParams() < 1)
1226*480093f4SDimitry Andric     return false;
1227*480093f4SDimitry Andric   return IdInfo->getName() == "emplace_front";
1228*480093f4SDimitry Andric }
1229*480093f4SDimitry Andric 
1230*480093f4SDimitry Andric bool isPopFrontCall(const FunctionDecl *Func) {
1231*480093f4SDimitry Andric   const auto *IdInfo = Func->getIdentifier();
1232*480093f4SDimitry Andric   if (!IdInfo)
1233*480093f4SDimitry Andric     return false;
1234*480093f4SDimitry Andric   if (Func->getNumParams() > 0)
1235*480093f4SDimitry Andric     return false;
1236*480093f4SDimitry Andric   return IdInfo->getName() == "pop_front";
1237*480093f4SDimitry Andric }
1238*480093f4SDimitry Andric 
1239*480093f4SDimitry Andric bool isAssignmentOperator(OverloadedOperatorKind OK) { return OK == OO_Equal; }
1240*480093f4SDimitry Andric 
1241*480093f4SDimitry Andric bool isSimpleComparisonOperator(OverloadedOperatorKind OK) {
1242*480093f4SDimitry Andric   return OK == OO_EqualEqual || OK == OO_ExclaimEqual;
1243*480093f4SDimitry Andric }
1244*480093f4SDimitry Andric 
1245*480093f4SDimitry Andric bool hasSubscriptOperator(ProgramStateRef State, const MemRegion *Reg) {
1246*480093f4SDimitry Andric   const auto *CRD = getCXXRecordDecl(State, Reg);
1247*480093f4SDimitry Andric   if (!CRD)
1248*480093f4SDimitry Andric     return false;
1249*480093f4SDimitry Andric 
1250*480093f4SDimitry Andric   for (const auto *Method : CRD->methods()) {
1251*480093f4SDimitry Andric     if (!Method->isOverloadedOperator())
1252*480093f4SDimitry Andric       continue;
1253*480093f4SDimitry Andric     const auto OPK = Method->getOverloadedOperator();
1254*480093f4SDimitry Andric     if (OPK == OO_Subscript) {
1255*480093f4SDimitry Andric       return true;
1256*480093f4SDimitry Andric     }
1257*480093f4SDimitry Andric   }
1258*480093f4SDimitry Andric   return false;
1259*480093f4SDimitry Andric }
1260*480093f4SDimitry Andric 
1261*480093f4SDimitry Andric bool frontModifiable(ProgramStateRef State, const MemRegion *Reg) {
1262*480093f4SDimitry Andric   const auto *CRD = getCXXRecordDecl(State, Reg);
1263*480093f4SDimitry Andric   if (!CRD)
1264*480093f4SDimitry Andric     return false;
1265*480093f4SDimitry Andric 
1266*480093f4SDimitry Andric   for (const auto *Method : CRD->methods()) {
1267*480093f4SDimitry Andric     if (!Method->getDeclName().isIdentifier())
1268*480093f4SDimitry Andric       continue;
1269*480093f4SDimitry Andric     if (Method->getName() == "push_front" || Method->getName() == "pop_front") {
1270*480093f4SDimitry Andric       return true;
1271*480093f4SDimitry Andric     }
1272*480093f4SDimitry Andric   }
1273*480093f4SDimitry Andric   return false;
1274*480093f4SDimitry Andric }
1275*480093f4SDimitry Andric 
1276*480093f4SDimitry Andric bool backModifiable(ProgramStateRef State, const MemRegion *Reg) {
1277*480093f4SDimitry Andric   const auto *CRD = getCXXRecordDecl(State, Reg);
1278*480093f4SDimitry Andric   if (!CRD)
1279*480093f4SDimitry Andric     return false;
1280*480093f4SDimitry Andric 
1281*480093f4SDimitry Andric   for (const auto *Method : CRD->methods()) {
1282*480093f4SDimitry Andric     if (!Method->getDeclName().isIdentifier())
1283*480093f4SDimitry Andric       continue;
1284*480093f4SDimitry Andric     if (Method->getName() == "push_back" || Method->getName() == "pop_back") {
1285*480093f4SDimitry Andric       return true;
1286*480093f4SDimitry Andric     }
1287*480093f4SDimitry Andric   }
1288*480093f4SDimitry Andric   return false;
1289*480093f4SDimitry Andric }
1290*480093f4SDimitry Andric 
1291*480093f4SDimitry Andric const CXXRecordDecl *getCXXRecordDecl(ProgramStateRef State,
1292*480093f4SDimitry Andric                                       const MemRegion *Reg) {
1293*480093f4SDimitry Andric   auto TI = getDynamicTypeInfo(State, Reg);
1294*480093f4SDimitry Andric   if (!TI.isValid())
1295*480093f4SDimitry Andric     return nullptr;
1296*480093f4SDimitry Andric 
1297*480093f4SDimitry Andric   auto Type = TI.getType();
1298*480093f4SDimitry Andric   if (const auto *RefT = Type->getAs<ReferenceType>()) {
1299*480093f4SDimitry Andric     Type = RefT->getPointeeType();
1300*480093f4SDimitry Andric   }
1301*480093f4SDimitry Andric 
1302*480093f4SDimitry Andric   return Type->getUnqualifiedDesugaredType()->getAsCXXRecordDecl();
1303*480093f4SDimitry Andric }
1304*480093f4SDimitry Andric 
1305*480093f4SDimitry Andric SymbolRef getContainerBegin(ProgramStateRef State, const MemRegion *Cont) {
1306*480093f4SDimitry Andric   const auto *CDataPtr = getContainerData(State, Cont);
1307*480093f4SDimitry Andric   if (!CDataPtr)
1308*480093f4SDimitry Andric     return nullptr;
1309*480093f4SDimitry Andric 
1310*480093f4SDimitry Andric   return CDataPtr->getBegin();
1311*480093f4SDimitry Andric }
1312*480093f4SDimitry Andric 
1313*480093f4SDimitry Andric SymbolRef getContainerEnd(ProgramStateRef State, const MemRegion *Cont) {
1314*480093f4SDimitry Andric   const auto *CDataPtr = getContainerData(State, Cont);
1315*480093f4SDimitry Andric   if (!CDataPtr)
1316*480093f4SDimitry Andric     return nullptr;
1317*480093f4SDimitry Andric 
1318*480093f4SDimitry Andric   return CDataPtr->getEnd();
1319*480093f4SDimitry Andric }
1320*480093f4SDimitry Andric 
1321*480093f4SDimitry Andric ProgramStateRef createContainerBegin(ProgramStateRef State,
1322*480093f4SDimitry Andric                                      const MemRegion *Cont, const Expr *E,
1323*480093f4SDimitry Andric                                      QualType T, const LocationContext *LCtx,
1324*480093f4SDimitry Andric                                      unsigned BlockCount) {
1325*480093f4SDimitry Andric   // Only create if it does not exist
1326*480093f4SDimitry Andric   const auto *CDataPtr = getContainerData(State, Cont);
1327*480093f4SDimitry Andric   if (CDataPtr && CDataPtr->getBegin())
1328*480093f4SDimitry Andric     return State;
1329*480093f4SDimitry Andric 
1330*480093f4SDimitry Andric   auto &SymMgr = State->getSymbolManager();
1331*480093f4SDimitry Andric   const SymbolConjured *Sym = SymMgr.conjureSymbol(E, LCtx, T, BlockCount,
1332*480093f4SDimitry Andric                                                    "begin");
1333*480093f4SDimitry Andric   State = assumeNoOverflow(State, Sym, 4);
1334*480093f4SDimitry Andric 
1335*480093f4SDimitry Andric   if (CDataPtr) {
1336*480093f4SDimitry Andric     const auto CData = CDataPtr->newBegin(Sym);
1337*480093f4SDimitry Andric     return setContainerData(State, Cont, CData);
1338*480093f4SDimitry Andric   }
1339*480093f4SDimitry Andric 
1340*480093f4SDimitry Andric   const auto CData = ContainerData::fromBegin(Sym);
1341*480093f4SDimitry Andric   return setContainerData(State, Cont, CData);
1342*480093f4SDimitry Andric }
1343*480093f4SDimitry Andric 
1344*480093f4SDimitry Andric ProgramStateRef createContainerEnd(ProgramStateRef State, const MemRegion *Cont,
1345*480093f4SDimitry Andric                                    const Expr *E, QualType T,
1346*480093f4SDimitry Andric                                    const LocationContext *LCtx,
1347*480093f4SDimitry Andric                                    unsigned BlockCount) {
1348*480093f4SDimitry Andric   // Only create if it does not exist
1349*480093f4SDimitry Andric   const auto *CDataPtr = getContainerData(State, Cont);
1350*480093f4SDimitry Andric   if (CDataPtr && CDataPtr->getEnd())
1351*480093f4SDimitry Andric     return State;
1352*480093f4SDimitry Andric 
1353*480093f4SDimitry Andric   auto &SymMgr = State->getSymbolManager();
1354*480093f4SDimitry Andric   const SymbolConjured *Sym = SymMgr.conjureSymbol(E, LCtx, T, BlockCount,
1355*480093f4SDimitry Andric                                                   "end");
1356*480093f4SDimitry Andric   State = assumeNoOverflow(State, Sym, 4);
1357*480093f4SDimitry Andric 
1358*480093f4SDimitry Andric   if (CDataPtr) {
1359*480093f4SDimitry Andric     const auto CData = CDataPtr->newEnd(Sym);
1360*480093f4SDimitry Andric     return setContainerData(State, Cont, CData);
1361*480093f4SDimitry Andric   }
1362*480093f4SDimitry Andric 
1363*480093f4SDimitry Andric   const auto CData = ContainerData::fromEnd(Sym);
1364*480093f4SDimitry Andric   return setContainerData(State, Cont, CData);
1365*480093f4SDimitry Andric }
1366*480093f4SDimitry Andric 
1367*480093f4SDimitry Andric ProgramStateRef setContainerData(ProgramStateRef State, const MemRegion *Cont,
1368*480093f4SDimitry Andric                                  const ContainerData &CData) {
1369*480093f4SDimitry Andric   return State->set<ContainerMap>(Cont, CData);
1370*480093f4SDimitry Andric }
1371*480093f4SDimitry Andric 
1372*480093f4SDimitry Andric ProgramStateRef removeIteratorPosition(ProgramStateRef State, const SVal &Val) {
1373*480093f4SDimitry Andric   if (auto Reg = Val.getAsRegion()) {
1374*480093f4SDimitry Andric     Reg = Reg->getMostDerivedObjectRegion();
1375*480093f4SDimitry Andric     return State->remove<IteratorRegionMap>(Reg);
1376*480093f4SDimitry Andric   } else if (const auto Sym = Val.getAsSymbol()) {
1377*480093f4SDimitry Andric     return State->remove<IteratorSymbolMap>(Sym);
1378*480093f4SDimitry Andric   } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
1379*480093f4SDimitry Andric     return State->remove<IteratorRegionMap>(LCVal->getRegion());
1380*480093f4SDimitry Andric   }
1381*480093f4SDimitry Andric   return nullptr;
1382*480093f4SDimitry Andric }
1383*480093f4SDimitry Andric 
1384*480093f4SDimitry Andric // This function tells the analyzer's engine that symbols produced by our
1385*480093f4SDimitry Andric // checker, most notably iterator positions, are relatively small.
1386*480093f4SDimitry Andric // A distance between items in the container should not be very large.
1387*480093f4SDimitry Andric // By assuming that it is within around 1/8 of the address space,
1388*480093f4SDimitry Andric // we can help the analyzer perform operations on these symbols
1389*480093f4SDimitry Andric // without being afraid of integer overflows.
1390*480093f4SDimitry Andric // FIXME: Should we provide it as an API, so that all checkers could use it?
1391*480093f4SDimitry Andric ProgramStateRef assumeNoOverflow(ProgramStateRef State, SymbolRef Sym,
1392*480093f4SDimitry Andric                                  long Scale) {
1393*480093f4SDimitry Andric   SValBuilder &SVB = State->getStateManager().getSValBuilder();
1394*480093f4SDimitry Andric   BasicValueFactory &BV = SVB.getBasicValueFactory();
1395*480093f4SDimitry Andric 
1396*480093f4SDimitry Andric   QualType T = Sym->getType();
1397*480093f4SDimitry Andric   assert(T->isSignedIntegerOrEnumerationType());
1398*480093f4SDimitry Andric   APSIntType AT = BV.getAPSIntType(T);
1399*480093f4SDimitry Andric 
1400*480093f4SDimitry Andric   ProgramStateRef NewState = State;
1401*480093f4SDimitry Andric 
1402*480093f4SDimitry Andric   llvm::APSInt Max = AT.getMaxValue() / AT.getValue(Scale);
1403*480093f4SDimitry Andric   SVal IsCappedFromAbove =
1404*480093f4SDimitry Andric       SVB.evalBinOpNN(State, BO_LE, nonloc::SymbolVal(Sym),
1405*480093f4SDimitry Andric                       nonloc::ConcreteInt(Max), SVB.getConditionType());
1406*480093f4SDimitry Andric   if (auto DV = IsCappedFromAbove.getAs<DefinedSVal>()) {
1407*480093f4SDimitry Andric     NewState = NewState->assume(*DV, true);
1408*480093f4SDimitry Andric     if (!NewState)
1409*480093f4SDimitry Andric       return State;
1410*480093f4SDimitry Andric   }
1411*480093f4SDimitry Andric 
1412*480093f4SDimitry Andric   llvm::APSInt Min = -Max;
1413*480093f4SDimitry Andric   SVal IsCappedFromBelow =
1414*480093f4SDimitry Andric       SVB.evalBinOpNN(State, BO_GE, nonloc::SymbolVal(Sym),
1415*480093f4SDimitry Andric                       nonloc::ConcreteInt(Min), SVB.getConditionType());
1416*480093f4SDimitry Andric   if (auto DV = IsCappedFromBelow.getAs<DefinedSVal>()) {
1417*480093f4SDimitry Andric     NewState = NewState->assume(*DV, true);
1418*480093f4SDimitry Andric     if (!NewState)
1419*480093f4SDimitry Andric       return State;
1420*480093f4SDimitry Andric   }
1421*480093f4SDimitry Andric 
1422*480093f4SDimitry Andric   return NewState;
1423*480093f4SDimitry Andric }
1424*480093f4SDimitry Andric 
1425*480093f4SDimitry Andric ProgramStateRef relateSymbols(ProgramStateRef State, SymbolRef Sym1,
1426*480093f4SDimitry Andric                               SymbolRef Sym2, bool Equal) {
1427*480093f4SDimitry Andric   auto &SVB = State->getStateManager().getSValBuilder();
1428*480093f4SDimitry Andric 
1429*480093f4SDimitry Andric   // FIXME: This code should be reworked as follows:
1430*480093f4SDimitry Andric   // 1. Subtract the operands using evalBinOp().
1431*480093f4SDimitry Andric   // 2. Assume that the result doesn't overflow.
1432*480093f4SDimitry Andric   // 3. Compare the result to 0.
1433*480093f4SDimitry Andric   // 4. Assume the result of the comparison.
1434*480093f4SDimitry Andric   const auto comparison =
1435*480093f4SDimitry Andric     SVB.evalBinOp(State, BO_EQ, nonloc::SymbolVal(Sym1),
1436*480093f4SDimitry Andric                   nonloc::SymbolVal(Sym2), SVB.getConditionType());
1437*480093f4SDimitry Andric 
1438*480093f4SDimitry Andric   assert(comparison.getAs<DefinedSVal>() &&
1439*480093f4SDimitry Andric     "Symbol comparison must be a `DefinedSVal`");
1440*480093f4SDimitry Andric 
1441*480093f4SDimitry Andric   auto NewState = State->assume(comparison.castAs<DefinedSVal>(), Equal);
1442*480093f4SDimitry Andric   if (!NewState)
1443*480093f4SDimitry Andric     return nullptr;
1444*480093f4SDimitry Andric 
1445*480093f4SDimitry Andric   if (const auto CompSym = comparison.getAsSymbol()) {
1446*480093f4SDimitry Andric     assert(isa<SymIntExpr>(CompSym) &&
1447*480093f4SDimitry Andric            "Symbol comparison must be a `SymIntExpr`");
1448*480093f4SDimitry Andric     assert(BinaryOperator::isComparisonOp(
1449*480093f4SDimitry Andric                cast<SymIntExpr>(CompSym)->getOpcode()) &&
1450*480093f4SDimitry Andric            "Symbol comparison must be a comparison");
1451*480093f4SDimitry Andric     return assumeNoOverflow(NewState, cast<SymIntExpr>(CompSym)->getLHS(), 2);
1452*480093f4SDimitry Andric   }
1453*480093f4SDimitry Andric 
1454*480093f4SDimitry Andric   return NewState;
1455*480093f4SDimitry Andric }
1456*480093f4SDimitry Andric 
1457*480093f4SDimitry Andric bool hasLiveIterators(ProgramStateRef State, const MemRegion *Cont) {
1458*480093f4SDimitry Andric   auto RegionMap = State->get<IteratorRegionMap>();
1459*480093f4SDimitry Andric   for (const auto &Reg : RegionMap) {
1460*480093f4SDimitry Andric     if (Reg.second.getContainer() == Cont)
1461*480093f4SDimitry Andric       return true;
1462*480093f4SDimitry Andric   }
1463*480093f4SDimitry Andric 
1464*480093f4SDimitry Andric   auto SymbolMap = State->get<IteratorSymbolMap>();
1465*480093f4SDimitry Andric   for (const auto &Sym : SymbolMap) {
1466*480093f4SDimitry Andric     if (Sym.second.getContainer() == Cont)
1467*480093f4SDimitry Andric       return true;
1468*480093f4SDimitry Andric   }
1469*480093f4SDimitry Andric 
1470*480093f4SDimitry Andric   return false;
1471*480093f4SDimitry Andric }
1472*480093f4SDimitry Andric 
1473*480093f4SDimitry Andric bool isBoundThroughLazyCompoundVal(const Environment &Env,
1474*480093f4SDimitry Andric                                    const MemRegion *Reg) {
1475*480093f4SDimitry Andric   for (const auto &Binding : Env) {
1476*480093f4SDimitry Andric     if (const auto LCVal = Binding.second.getAs<nonloc::LazyCompoundVal>()) {
1477*480093f4SDimitry Andric       if (LCVal->getRegion() == Reg)
1478*480093f4SDimitry Andric         return true;
1479*480093f4SDimitry Andric     }
1480*480093f4SDimitry Andric   }
1481*480093f4SDimitry Andric 
1482*480093f4SDimitry Andric   return false;
1483*480093f4SDimitry Andric }
1484*480093f4SDimitry Andric 
1485*480093f4SDimitry Andric template <typename Condition, typename Process>
1486*480093f4SDimitry Andric ProgramStateRef processIteratorPositions(ProgramStateRef State, Condition Cond,
1487*480093f4SDimitry Andric                                          Process Proc) {
1488*480093f4SDimitry Andric   auto &RegionMapFactory = State->get_context<IteratorRegionMap>();
1489*480093f4SDimitry Andric   auto RegionMap = State->get<IteratorRegionMap>();
1490*480093f4SDimitry Andric   bool Changed = false;
1491*480093f4SDimitry Andric   for (const auto &Reg : RegionMap) {
1492*480093f4SDimitry Andric     if (Cond(Reg.second)) {
1493*480093f4SDimitry Andric       RegionMap = RegionMapFactory.add(RegionMap, Reg.first, Proc(Reg.second));
1494*480093f4SDimitry Andric       Changed = true;
1495*480093f4SDimitry Andric     }
1496*480093f4SDimitry Andric   }
1497*480093f4SDimitry Andric 
1498*480093f4SDimitry Andric   if (Changed)
1499*480093f4SDimitry Andric     State = State->set<IteratorRegionMap>(RegionMap);
1500*480093f4SDimitry Andric 
1501*480093f4SDimitry Andric   auto &SymbolMapFactory = State->get_context<IteratorSymbolMap>();
1502*480093f4SDimitry Andric   auto SymbolMap = State->get<IteratorSymbolMap>();
1503*480093f4SDimitry Andric   Changed = false;
1504*480093f4SDimitry Andric   for (const auto &Sym : SymbolMap) {
1505*480093f4SDimitry Andric     if (Cond(Sym.second)) {
1506*480093f4SDimitry Andric       SymbolMap = SymbolMapFactory.add(SymbolMap, Sym.first, Proc(Sym.second));
1507*480093f4SDimitry Andric       Changed = true;
1508*480093f4SDimitry Andric     }
1509*480093f4SDimitry Andric   }
1510*480093f4SDimitry Andric 
1511*480093f4SDimitry Andric   if (Changed)
1512*480093f4SDimitry Andric     State = State->set<IteratorSymbolMap>(SymbolMap);
1513*480093f4SDimitry Andric 
1514*480093f4SDimitry Andric   return State;
1515*480093f4SDimitry Andric }
1516*480093f4SDimitry Andric 
1517*480093f4SDimitry Andric ProgramStateRef invalidateAllIteratorPositions(ProgramStateRef State,
1518*480093f4SDimitry Andric                                                const MemRegion *Cont) {
1519*480093f4SDimitry Andric   auto MatchCont = [&](const IteratorPosition &Pos) {
1520*480093f4SDimitry Andric     return Pos.getContainer() == Cont;
1521*480093f4SDimitry Andric   };
1522*480093f4SDimitry Andric   auto Invalidate = [&](const IteratorPosition &Pos) {
1523*480093f4SDimitry Andric     return Pos.invalidate();
1524*480093f4SDimitry Andric   };
1525*480093f4SDimitry Andric   return processIteratorPositions(State, MatchCont, Invalidate);
1526*480093f4SDimitry Andric }
1527*480093f4SDimitry Andric 
1528*480093f4SDimitry Andric ProgramStateRef
1529*480093f4SDimitry Andric invalidateAllIteratorPositionsExcept(ProgramStateRef State,
1530*480093f4SDimitry Andric                                      const MemRegion *Cont, SymbolRef Offset,
1531*480093f4SDimitry Andric                                      BinaryOperator::Opcode Opc) {
1532*480093f4SDimitry Andric   auto MatchContAndCompare = [&](const IteratorPosition &Pos) {
1533*480093f4SDimitry Andric     return Pos.getContainer() == Cont &&
1534*480093f4SDimitry Andric            !compare(State, Pos.getOffset(), Offset, Opc);
1535*480093f4SDimitry Andric   };
1536*480093f4SDimitry Andric   auto Invalidate = [&](const IteratorPosition &Pos) {
1537*480093f4SDimitry Andric     return Pos.invalidate();
1538*480093f4SDimitry Andric   };
1539*480093f4SDimitry Andric   return processIteratorPositions(State, MatchContAndCompare, Invalidate);
1540*480093f4SDimitry Andric }
1541*480093f4SDimitry Andric 
1542*480093f4SDimitry Andric ProgramStateRef invalidateIteratorPositions(ProgramStateRef State,
1543*480093f4SDimitry Andric                                             SymbolRef Offset,
1544*480093f4SDimitry Andric                                             BinaryOperator::Opcode Opc) {
1545*480093f4SDimitry Andric   auto Compare = [&](const IteratorPosition &Pos) {
1546*480093f4SDimitry Andric     return compare(State, Pos.getOffset(), Offset, Opc);
1547*480093f4SDimitry Andric   };
1548*480093f4SDimitry Andric   auto Invalidate = [&](const IteratorPosition &Pos) {
1549*480093f4SDimitry Andric     return Pos.invalidate();
1550*480093f4SDimitry Andric   };
1551*480093f4SDimitry Andric   return processIteratorPositions(State, Compare, Invalidate);
1552*480093f4SDimitry Andric }
1553*480093f4SDimitry Andric 
1554*480093f4SDimitry Andric ProgramStateRef invalidateIteratorPositions(ProgramStateRef State,
1555*480093f4SDimitry Andric                                             SymbolRef Offset1,
1556*480093f4SDimitry Andric                                             BinaryOperator::Opcode Opc1,
1557*480093f4SDimitry Andric                                             SymbolRef Offset2,
1558*480093f4SDimitry Andric                                             BinaryOperator::Opcode Opc2) {
1559*480093f4SDimitry Andric   auto Compare = [&](const IteratorPosition &Pos) {
1560*480093f4SDimitry Andric     return compare(State, Pos.getOffset(), Offset1, Opc1) &&
1561*480093f4SDimitry Andric            compare(State, Pos.getOffset(), Offset2, Opc2);
1562*480093f4SDimitry Andric   };
1563*480093f4SDimitry Andric   auto Invalidate = [&](const IteratorPosition &Pos) {
1564*480093f4SDimitry Andric     return Pos.invalidate();
1565*480093f4SDimitry Andric   };
1566*480093f4SDimitry Andric   return processIteratorPositions(State, Compare, Invalidate);
1567*480093f4SDimitry Andric }
1568*480093f4SDimitry Andric 
1569*480093f4SDimitry Andric ProgramStateRef reassignAllIteratorPositions(ProgramStateRef State,
1570*480093f4SDimitry Andric                                              const MemRegion *Cont,
1571*480093f4SDimitry Andric                                              const MemRegion *NewCont) {
1572*480093f4SDimitry Andric   auto MatchCont = [&](const IteratorPosition &Pos) {
1573*480093f4SDimitry Andric     return Pos.getContainer() == Cont;
1574*480093f4SDimitry Andric   };
1575*480093f4SDimitry Andric   auto ReAssign = [&](const IteratorPosition &Pos) {
1576*480093f4SDimitry Andric     return Pos.reAssign(NewCont);
1577*480093f4SDimitry Andric   };
1578*480093f4SDimitry Andric   return processIteratorPositions(State, MatchCont, ReAssign);
1579*480093f4SDimitry Andric }
1580*480093f4SDimitry Andric 
1581*480093f4SDimitry Andric ProgramStateRef reassignAllIteratorPositionsUnless(ProgramStateRef State,
1582*480093f4SDimitry Andric                                                    const MemRegion *Cont,
1583*480093f4SDimitry Andric                                                    const MemRegion *NewCont,
1584*480093f4SDimitry Andric                                                    SymbolRef Offset,
1585*480093f4SDimitry Andric                                                    BinaryOperator::Opcode Opc) {
1586*480093f4SDimitry Andric   auto MatchContAndCompare = [&](const IteratorPosition &Pos) {
1587*480093f4SDimitry Andric     return Pos.getContainer() == Cont &&
1588*480093f4SDimitry Andric     !compare(State, Pos.getOffset(), Offset, Opc);
1589*480093f4SDimitry Andric   };
1590*480093f4SDimitry Andric   auto ReAssign = [&](const IteratorPosition &Pos) {
1591*480093f4SDimitry Andric     return Pos.reAssign(NewCont);
1592*480093f4SDimitry Andric   };
1593*480093f4SDimitry Andric   return processIteratorPositions(State, MatchContAndCompare, ReAssign);
1594*480093f4SDimitry Andric }
1595*480093f4SDimitry Andric 
1596*480093f4SDimitry Andric // This function rebases symbolic expression `OldSym + Int` to `NewSym + Int`,
1597*480093f4SDimitry Andric // `OldSym - Int` to `NewSym - Int` and  `OldSym` to `NewSym` in any iterator
1598*480093f4SDimitry Andric // position offsets where `CondSym` is true.
1599*480093f4SDimitry Andric ProgramStateRef rebaseSymbolInIteratorPositionsIf(
1600*480093f4SDimitry Andric     ProgramStateRef State, SValBuilder &SVB, SymbolRef OldSym,
1601*480093f4SDimitry Andric     SymbolRef NewSym, SymbolRef CondSym, BinaryOperator::Opcode Opc) {
1602*480093f4SDimitry Andric   auto LessThanEnd = [&](const IteratorPosition &Pos) {
1603*480093f4SDimitry Andric     return compare(State, Pos.getOffset(), CondSym, Opc);
1604*480093f4SDimitry Andric   };
1605*480093f4SDimitry Andric   auto RebaseSymbol = [&](const IteratorPosition &Pos) {
1606*480093f4SDimitry Andric     return Pos.setTo(rebaseSymbol(State, SVB, Pos.getOffset(), OldSym,
1607*480093f4SDimitry Andric                                    NewSym));
1608*480093f4SDimitry Andric   };
1609*480093f4SDimitry Andric   return processIteratorPositions(State, LessThanEnd, RebaseSymbol);
1610*480093f4SDimitry Andric }
1611*480093f4SDimitry Andric 
1612*480093f4SDimitry Andric // This function rebases symbolic expression `OldExpr + Int` to `NewExpr + Int`,
1613*480093f4SDimitry Andric // `OldExpr - Int` to `NewExpr - Int` and  `OldExpr` to `NewExpr` in expression
1614*480093f4SDimitry Andric // `OrigExpr`.
1615*480093f4SDimitry Andric SymbolRef rebaseSymbol(ProgramStateRef State, SValBuilder &SVB,
1616*480093f4SDimitry Andric                        SymbolRef OrigExpr, SymbolRef OldExpr,
1617*480093f4SDimitry Andric                        SymbolRef NewSym) {
1618*480093f4SDimitry Andric   auto &SymMgr = SVB.getSymbolManager();
1619*480093f4SDimitry Andric   auto Diff = SVB.evalBinOpNN(State, BO_Sub, nonloc::SymbolVal(OrigExpr),
1620*480093f4SDimitry Andric                               nonloc::SymbolVal(OldExpr),
1621*480093f4SDimitry Andric                               SymMgr.getType(OrigExpr));
1622*480093f4SDimitry Andric 
1623*480093f4SDimitry Andric   const auto DiffInt = Diff.getAs<nonloc::ConcreteInt>();
1624*480093f4SDimitry Andric   if (!DiffInt)
1625*480093f4SDimitry Andric     return OrigExpr;
1626*480093f4SDimitry Andric 
1627*480093f4SDimitry Andric   return SVB.evalBinOpNN(State, BO_Add, *DiffInt, nonloc::SymbolVal(NewSym),
1628*480093f4SDimitry Andric                          SymMgr.getType(OrigExpr)).getAsSymbol();
1629*480093f4SDimitry Andric }
1630*480093f4SDimitry Andric 
1631*480093f4SDimitry Andric } // namespace
1632*480093f4SDimitry Andric 
1633*480093f4SDimitry Andric void ento::registerIteratorModeling(CheckerManager &mgr) {
1634*480093f4SDimitry Andric   mgr.registerChecker<IteratorModeling>();
1635*480093f4SDimitry Andric }
1636*480093f4SDimitry Andric 
1637*480093f4SDimitry Andric bool ento::shouldRegisterIteratorModeling(const LangOptions &LO) {
1638*480093f4SDimitry Andric   return true;
1639*480093f4SDimitry Andric }
1640