]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/IteratorChecker.cpp
Merge llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / clang / lib / StaticAnalyzer / Checkers / IteratorChecker.cpp
1 //===-- IteratorChecker.cpp ---------------------------------------*- C++ -*--//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // Defines a checker for using iterators outside their range (past end). Usage
11 // means here dereferencing, incrementing etc.
12 //
13 //===----------------------------------------------------------------------===//
14 //
15 // In the code, iterator can be represented as a:
16 // * type-I: typedef-ed pointer. Operations over such iterator, such as
17 //           comparisons or increments, are modeled straightforwardly by the
18 //           analyzer.
19 // * type-II: structure with its method bodies available.  Operations over such
20 //            iterator are inlined by the analyzer, and results of modeling
21 //            these operations are exposing implementation details of the
22 //            iterators, which is not necessarily helping.
23 // * type-III: completely opaque structure. Operations over such iterator are
24 //             modeled conservatively, producing conjured symbols everywhere.
25 //
26 // To handle all these types in a common way we introduce a structure called
27 // IteratorPosition which is an abstraction of the position the iterator
28 // represents using symbolic expressions. The checker handles all the
29 // operations on this structure.
30 //
31 // Additionally, depending on the circumstances, operators of types II and III
32 // can be represented as:
33 // * type-IIa, type-IIIa: conjured structure symbols - when returned by value
34 //                        from conservatively evaluated methods such as
35 //                        `.begin()`.
36 // * type-IIb, type-IIIb: memory regions of iterator-typed objects, such as
37 //                        variables or temporaries, when the iterator object is
38 //                        currently treated as an lvalue.
39 // * type-IIc, type-IIIc: compound values of iterator-typed objects, when the
40 //                        iterator object is treated as an rvalue taken of a
41 //                        particular lvalue, eg. a copy of "type-a" iterator
42 //                        object, or an iterator that existed before the
43 //                        analysis has started.
44 //
45 // To handle any of these three different representations stored in an SVal we
46 // use setter and getters functions which separate the three cases. To store
47 // them we use a pointer union of symbol and memory region.
48 //
49 // The checker works the following way: We record the begin and the
50 // past-end iterator for all containers whenever their `.begin()` and `.end()`
51 // are called. Since the Constraint Manager cannot handle such SVals we need
52 // to take over its role. We post-check equality and non-equality comparisons
53 // and record that the two sides are equal if we are in the 'equal' branch
54 // (true-branch for `==` and false-branch for `!=`).
55 //
56 // In case of type-I or type-II iterators we get a concrete integer as a result
57 // of the comparison (1 or 0) but in case of type-III we only get a Symbol. In
58 // this latter case we record the symbol and reload it in evalAssume() and do
59 // the propagation there. We also handle (maybe double) negated comparisons
60 // which are represented in the form of (x == 0 or x != 0) where x is the
61 // comparison itself.
62 //
63 // Since `SimpleConstraintManager` cannot handle complex symbolic expressions
64 // we only use expressions of the format S, S+n or S-n for iterator positions
65 // where S is a conjured symbol and n is an unsigned concrete integer. When
66 // making an assumption e.g. `S1 + n == S2 + m` we store `S1 - S2 == m - n` as
67 // a constraint which we later retrieve when doing an actual comparison.
68
69 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
70 #include "clang/AST/DeclTemplate.h"
71 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
72 #include "clang/StaticAnalyzer/Core/Checker.h"
73 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
74 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
75 #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h"
76
77 #include <utility>
78
79 using namespace clang;
80 using namespace ento;
81
82 namespace {
83
84 // Abstract position of an iterator. This helps to handle all three kinds
85 // of operators in a common way by using a symbolic position.
86 struct IteratorPosition {
87 private:
88
89   // Container the iterator belongs to
90   const MemRegion *Cont;
91
92   // Whether iterator is valid
93   const bool Valid;
94
95   // Abstract offset
96   const SymbolRef Offset;
97
98   IteratorPosition(const MemRegion *C, bool V, SymbolRef Of)
99       : Cont(C), Valid(V), Offset(Of) {}
100
101 public:
102   const MemRegion *getContainer() const { return Cont; }
103   bool isValid() const { return Valid; }
104   SymbolRef getOffset() const { return Offset; }
105
106   IteratorPosition invalidate() const {
107     return IteratorPosition(Cont, false, Offset);
108   }
109
110   static IteratorPosition getPosition(const MemRegion *C, SymbolRef Of) {
111     return IteratorPosition(C, true, Of);
112   }
113
114   IteratorPosition setTo(SymbolRef NewOf) const {
115     return IteratorPosition(Cont, Valid, NewOf);
116   }
117
118   IteratorPosition reAssign(const MemRegion *NewCont) const {
119     return IteratorPosition(NewCont, Valid, Offset);
120   }
121
122   bool operator==(const IteratorPosition &X) const {
123     return Cont == X.Cont && Valid == X.Valid && Offset == X.Offset;
124   }
125
126   bool operator!=(const IteratorPosition &X) const {
127     return Cont != X.Cont || Valid != X.Valid || Offset != X.Offset;
128   }
129
130   void Profile(llvm::FoldingSetNodeID &ID) const {
131     ID.AddPointer(Cont);
132     ID.AddInteger(Valid);
133     ID.Add(Offset);
134   }
135 };
136
137 typedef llvm::PointerUnion<const MemRegion *, SymbolRef> RegionOrSymbol;
138
139 // Structure to record the symbolic begin and end position of a container
140 struct ContainerData {
141 private:
142   const SymbolRef Begin, End;
143
144   ContainerData(SymbolRef B, SymbolRef E) : Begin(B), End(E) {}
145
146 public:
147   static ContainerData fromBegin(SymbolRef B) {
148     return ContainerData(B, nullptr);
149   }
150
151   static ContainerData fromEnd(SymbolRef E) {
152     return ContainerData(nullptr, E);
153   }
154
155   SymbolRef getBegin() const { return Begin; }
156   SymbolRef getEnd() const { return End; }
157
158   ContainerData newBegin(SymbolRef B) const { return ContainerData(B, End); }
159
160   ContainerData newEnd(SymbolRef E) const { return ContainerData(Begin, E); }
161
162   bool operator==(const ContainerData &X) const {
163     return Begin == X.Begin && End == X.End;
164   }
165
166   bool operator!=(const ContainerData &X) const {
167     return Begin != X.Begin || End != X.End;
168   }
169
170   void Profile(llvm::FoldingSetNodeID &ID) const {
171     ID.Add(Begin);
172     ID.Add(End);
173   }
174 };
175
176 // Structure fo recording iterator comparisons. We needed to retrieve the
177 // original comparison expression in assumptions.
178 struct IteratorComparison {
179 private:
180   RegionOrSymbol Left, Right;
181   bool Equality;
182
183 public:
184   IteratorComparison(RegionOrSymbol L, RegionOrSymbol R, bool Eq)
185       : Left(L), Right(R), Equality(Eq) {}
186
187   RegionOrSymbol getLeft() const { return Left; }
188   RegionOrSymbol getRight() const { return Right; }
189   bool isEquality() const { return Equality; }
190   bool operator==(const IteratorComparison &X) const {
191     return Left == X.Left && Right == X.Right && Equality == X.Equality;
192   }
193   bool operator!=(const IteratorComparison &X) const {
194     return Left != X.Left || Right != X.Right || Equality != X.Equality;
195   }
196   void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(Equality); }
197 };
198
199 class IteratorChecker
200     : public Checker<check::PreCall, check::PostCall,
201                      check::PostStmt<MaterializeTemporaryExpr>, check::Bind,
202                      check::LiveSymbols, check::DeadSymbols,
203                      eval::Assume> {
204
205   std::unique_ptr<BugType> OutOfRangeBugType;
206   std::unique_ptr<BugType> MismatchedBugType;
207   std::unique_ptr<BugType> InvalidatedBugType;
208
209   void handleComparison(CheckerContext &C, const SVal &RetVal, const SVal &LVal,
210                         const SVal &RVal, OverloadedOperatorKind Op) const;
211   void verifyAccess(CheckerContext &C, const SVal &Val) const;
212   void verifyDereference(CheckerContext &C, const SVal &Val) const;
213   void handleIncrement(CheckerContext &C, const SVal &RetVal, const SVal &Iter,
214                        bool Postfix) const;
215   void handleDecrement(CheckerContext &C, const SVal &RetVal, const SVal &Iter,
216                        bool Postfix) const;
217   void handleRandomIncrOrDecr(CheckerContext &C, OverloadedOperatorKind Op,
218                               const SVal &RetVal, const SVal &LHS,
219                               const SVal &RHS) const;
220   void handleBegin(CheckerContext &C, const Expr *CE, const SVal &RetVal,
221                    const SVal &Cont) const;
222   void handleEnd(CheckerContext &C, const Expr *CE, const SVal &RetVal,
223                  const SVal &Cont) const;
224   void assignToContainer(CheckerContext &C, const Expr *CE, const SVal &RetVal,
225                          const MemRegion *Cont) const;
226   void handleAssign(CheckerContext &C, const SVal &Cont,
227                     const Expr *CE = nullptr,
228                     const SVal &OldCont = UndefinedVal()) const;
229   void handleClear(CheckerContext &C, const SVal &Cont) const;
230   void handlePushBack(CheckerContext &C, const SVal &Cont) const;
231   void handlePopBack(CheckerContext &C, const SVal &Cont) const;
232   void handlePushFront(CheckerContext &C, const SVal &Cont) const;
233   void handlePopFront(CheckerContext &C, const SVal &Cont) const;
234   void handleInsert(CheckerContext &C, const SVal &Iter) const;
235   void handleErase(CheckerContext &C, const SVal &Iter) const;
236   void handleErase(CheckerContext &C, const SVal &Iter1,
237                    const SVal &Iter2) const;
238   void handleEraseAfter(CheckerContext &C, const SVal &Iter) const;
239   void handleEraseAfter(CheckerContext &C, const SVal &Iter1,
240                         const SVal &Iter2) const;
241   void verifyIncrement(CheckerContext &C, const SVal &Iter) const;
242   void verifyDecrement(CheckerContext &C, const SVal &Iter) const;
243   void verifyRandomIncrOrDecr(CheckerContext &C, OverloadedOperatorKind Op,
244                               const SVal &LHS, const SVal &RHS) const;
245   void verifyMatch(CheckerContext &C, const SVal &Iter,
246                    const MemRegion *Cont) const;
247   void verifyMatch(CheckerContext &C, const SVal &Iter1,
248                    const SVal &Iter2) const;
249   IteratorPosition advancePosition(CheckerContext &C, OverloadedOperatorKind Op,
250                                    const IteratorPosition &Pos,
251                                    const SVal &Distance) const;
252   void reportOutOfRangeBug(const StringRef &Message, const SVal &Val,
253                            CheckerContext &C, ExplodedNode *ErrNode) const;
254   void reportMismatchedBug(const StringRef &Message, const SVal &Val1,
255                            const SVal &Val2, CheckerContext &C,
256                            ExplodedNode *ErrNode) const;
257   void reportMismatchedBug(const StringRef &Message, const SVal &Val,
258                            const MemRegion *Reg, CheckerContext &C,
259                            ExplodedNode *ErrNode) const;
260   void reportInvalidatedBug(const StringRef &Message, const SVal &Val,
261                             CheckerContext &C, ExplodedNode *ErrNode) const;
262
263 public:
264   IteratorChecker();
265
266   enum CheckKind {
267     CK_IteratorRangeChecker,
268     CK_MismatchedIteratorChecker,
269     CK_InvalidatedIteratorChecker,
270     CK_NumCheckKinds
271   };
272
273   DefaultBool ChecksEnabled[CK_NumCheckKinds];
274   CheckName CheckNames[CK_NumCheckKinds];
275
276   void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
277   void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
278   void checkBind(SVal Loc, SVal Val, const Stmt *S, CheckerContext &C) const;
279   void checkPostStmt(const CXXConstructExpr *CCE, CheckerContext &C) const;
280   void checkPostStmt(const DeclStmt *DS, CheckerContext &C) const;
281   void checkPostStmt(const MaterializeTemporaryExpr *MTE,
282                      CheckerContext &C) const;
283   void checkLiveSymbols(ProgramStateRef State, SymbolReaper &SR) const;
284   void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
285   ProgramStateRef evalAssume(ProgramStateRef State, SVal Cond,
286                              bool Assumption) const;
287 };
288 } // namespace
289
290 REGISTER_MAP_WITH_PROGRAMSTATE(IteratorSymbolMap, SymbolRef, IteratorPosition)
291 REGISTER_MAP_WITH_PROGRAMSTATE(IteratorRegionMap, const MemRegion *,
292                                IteratorPosition)
293
294 REGISTER_MAP_WITH_PROGRAMSTATE(ContainerMap, const MemRegion *, ContainerData)
295
296 REGISTER_MAP_WITH_PROGRAMSTATE(IteratorComparisonMap, const SymExpr *,
297                                IteratorComparison)
298
299 namespace {
300
301 bool isIteratorType(const QualType &Type);
302 bool isIterator(const CXXRecordDecl *CRD);
303 bool isComparisonOperator(OverloadedOperatorKind OK);
304 bool isBeginCall(const FunctionDecl *Func);
305 bool isEndCall(const FunctionDecl *Func);
306 bool isAssignCall(const FunctionDecl *Func);
307 bool isClearCall(const FunctionDecl *Func);
308 bool isPushBackCall(const FunctionDecl *Func);
309 bool isEmplaceBackCall(const FunctionDecl *Func);
310 bool isPopBackCall(const FunctionDecl *Func);
311 bool isPushFrontCall(const FunctionDecl *Func);
312 bool isEmplaceFrontCall(const FunctionDecl *Func);
313 bool isPopFrontCall(const FunctionDecl *Func);
314 bool isInsertCall(const FunctionDecl *Func);
315 bool isEraseCall(const FunctionDecl *Func);
316 bool isEraseAfterCall(const FunctionDecl *Func);
317 bool isEmplaceCall(const FunctionDecl *Func);
318 bool isAssignmentOperator(OverloadedOperatorKind OK);
319 bool isSimpleComparisonOperator(OverloadedOperatorKind OK);
320 bool isAccessOperator(OverloadedOperatorKind OK);
321 bool isDereferenceOperator(OverloadedOperatorKind OK);
322 bool isIncrementOperator(OverloadedOperatorKind OK);
323 bool isDecrementOperator(OverloadedOperatorKind OK);
324 bool isRandomIncrOrDecrOperator(OverloadedOperatorKind OK);
325 bool hasSubscriptOperator(ProgramStateRef State, const MemRegion *Reg);
326 bool frontModifiable(ProgramStateRef State, const MemRegion *Reg);
327 bool backModifiable(ProgramStateRef State, const MemRegion *Reg);
328 BinaryOperator::Opcode getOpcode(const SymExpr *SE);
329 const RegionOrSymbol getRegionOrSymbol(const SVal &Val);
330 const ProgramStateRef processComparison(ProgramStateRef State,
331                                         RegionOrSymbol LVal,
332                                         RegionOrSymbol RVal, bool Equal);
333 const ProgramStateRef saveComparison(ProgramStateRef State,
334                                      const SymExpr *Condition, const SVal &LVal,
335                                      const SVal &RVal, bool Eq);
336 const IteratorComparison *loadComparison(ProgramStateRef State,
337                                          const SymExpr *Condition);
338 SymbolRef getContainerBegin(ProgramStateRef State, const MemRegion *Cont);
339 SymbolRef getContainerEnd(ProgramStateRef State, const MemRegion *Cont);
340 ProgramStateRef createContainerBegin(ProgramStateRef State,
341                                      const MemRegion *Cont,
342                                      const SymbolRef Sym);
343 ProgramStateRef createContainerEnd(ProgramStateRef State, const MemRegion *Cont,
344                                    const SymbolRef Sym);
345 const IteratorPosition *getIteratorPosition(ProgramStateRef State,
346                                             const SVal &Val);
347 const IteratorPosition *getIteratorPosition(ProgramStateRef State,
348                                             RegionOrSymbol RegOrSym);
349 ProgramStateRef setIteratorPosition(ProgramStateRef State, const SVal &Val,
350                                     const IteratorPosition &Pos);
351 ProgramStateRef setIteratorPosition(ProgramStateRef State,
352                                     RegionOrSymbol RegOrSym,
353                                     const IteratorPosition &Pos);
354 ProgramStateRef removeIteratorPosition(ProgramStateRef State, const SVal &Val);
355 ProgramStateRef adjustIteratorPosition(ProgramStateRef State,
356                                        RegionOrSymbol RegOrSym,
357                                        const IteratorPosition &Pos, bool Equal);
358 ProgramStateRef relateIteratorPositions(ProgramStateRef State,
359                                         const IteratorPosition &Pos1,
360                                         const IteratorPosition &Pos2,
361                                         bool Equal);
362 ProgramStateRef invalidateAllIteratorPositions(ProgramStateRef State,
363                                                const MemRegion *Cont);
364 ProgramStateRef
365 invalidateAllIteratorPositionsExcept(ProgramStateRef State,
366                                      const MemRegion *Cont, SymbolRef Offset,
367                                      BinaryOperator::Opcode Opc);
368 ProgramStateRef invalidateIteratorPositions(ProgramStateRef State,
369                                             SymbolRef Offset,
370                                             BinaryOperator::Opcode Opc);
371 ProgramStateRef invalidateIteratorPositions(ProgramStateRef State,
372                                             SymbolRef Offset1,
373                                             BinaryOperator::Opcode Opc1,
374                                             SymbolRef Offset2,
375                                             BinaryOperator::Opcode Opc2);
376 ProgramStateRef reassignAllIteratorPositions(ProgramStateRef State,
377                                              const MemRegion *Cont,
378                                              const MemRegion *NewCont);
379 ProgramStateRef reassignAllIteratorPositionsUnless(ProgramStateRef State,
380                                                    const MemRegion *Cont,
381                                                    const MemRegion *NewCont,
382                                                    SymbolRef Offset,
383                                                    BinaryOperator::Opcode Opc);
384 ProgramStateRef rebaseSymbolInIteratorPositionsIf(
385     ProgramStateRef State, SValBuilder &SVB, SymbolRef OldSym,
386     SymbolRef NewSym, SymbolRef CondSym, BinaryOperator::Opcode Opc);
387 const ContainerData *getContainerData(ProgramStateRef State,
388                                       const MemRegion *Cont);
389 ProgramStateRef setContainerData(ProgramStateRef State, const MemRegion *Cont,
390                                  const ContainerData &CData);
391 bool hasLiveIterators(ProgramStateRef State, const MemRegion *Cont);
392 bool isBoundThroughLazyCompoundVal(const Environment &Env,
393                                    const MemRegion *Reg);
394 bool isPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos);
395 bool isAheadOfRange(ProgramStateRef State, const IteratorPosition &Pos);
396 bool isBehindPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos);
397 bool isZero(ProgramStateRef State, const NonLoc &Val);
398 } // namespace
399
400 IteratorChecker::IteratorChecker() {
401   OutOfRangeBugType.reset(
402       new BugType(this, "Iterator out of range", "Misuse of STL APIs"));
403   OutOfRangeBugType->setSuppressOnSink(true);
404   MismatchedBugType.reset(
405       new BugType(this, "Iterator(s) mismatched", "Misuse of STL APIs"));
406   MismatchedBugType->setSuppressOnSink(true);
407   InvalidatedBugType.reset(
408       new BugType(this, "Iterator invalidated", "Misuse of STL APIs"));
409   InvalidatedBugType->setSuppressOnSink(true);
410 }
411
412 void IteratorChecker::checkPreCall(const CallEvent &Call,
413                                    CheckerContext &C) const {
414   // Check for out of range access or access of invalidated position and
415   // iterator mismatches
416   const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
417   if (!Func)
418     return;
419
420   if (Func->isOverloadedOperator()) {
421     if (ChecksEnabled[CK_InvalidatedIteratorChecker] &&
422         isAccessOperator(Func->getOverloadedOperator())) {
423       // Check for any kind of access of invalidated iterator positions
424       if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
425         verifyAccess(C, InstCall->getCXXThisVal());
426       } else {
427         verifyAccess(C, Call.getArgSVal(0));
428       }
429     }
430     if (ChecksEnabled[CK_IteratorRangeChecker]) {
431       if (isIncrementOperator(Func->getOverloadedOperator())) {
432         // Check for out-of-range incrementions
433         if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
434           verifyIncrement(C, InstCall->getCXXThisVal());
435         } else {
436           if (Call.getNumArgs() >= 1) {
437             verifyIncrement(C, Call.getArgSVal(0));
438           }
439         }
440       } else if (isDecrementOperator(Func->getOverloadedOperator())) {
441         // Check for out-of-range decrementions
442         if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
443           verifyDecrement(C, InstCall->getCXXThisVal());
444         } else {
445           if (Call.getNumArgs() >= 1) {
446             verifyDecrement(C, Call.getArgSVal(0));
447           }
448         }
449       } else if (isRandomIncrOrDecrOperator(Func->getOverloadedOperator())) {
450         if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
451           // Check for out-of-range incrementions and decrementions
452           if (Call.getNumArgs() >= 1) {
453             verifyRandomIncrOrDecr(C, Func->getOverloadedOperator(),
454                                    InstCall->getCXXThisVal(),
455                                    Call.getArgSVal(0));
456           }
457         } else {
458           if (Call.getNumArgs() >= 2) {
459             verifyRandomIncrOrDecr(C, Func->getOverloadedOperator(),
460                                    Call.getArgSVal(0), Call.getArgSVal(1));
461           }
462         }
463       } else if (isDereferenceOperator(Func->getOverloadedOperator())) {
464         // Check for dereference of out-of-range iterators
465         if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
466           verifyDereference(C, InstCall->getCXXThisVal());
467         } else {
468           verifyDereference(C, Call.getArgSVal(0));
469         }
470       }
471     } else if (ChecksEnabled[CK_MismatchedIteratorChecker] &&
472                isComparisonOperator(Func->getOverloadedOperator())) {
473       // Check for comparisons of iterators of different containers
474       if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
475         if (Call.getNumArgs() < 1)
476           return;
477
478         if (!isIteratorType(InstCall->getCXXThisExpr()->getType()) ||
479             !isIteratorType(Call.getArgExpr(0)->getType()))
480           return;
481
482         verifyMatch(C, InstCall->getCXXThisVal(), Call.getArgSVal(0));
483       } else {
484         if (Call.getNumArgs() < 2)
485           return;
486
487         if (!isIteratorType(Call.getArgExpr(0)->getType()) ||
488             !isIteratorType(Call.getArgExpr(1)->getType()))
489           return;
490
491         verifyMatch(C, Call.getArgSVal(0), Call.getArgSVal(1));
492       }
493     }
494   } else if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
495     if (!ChecksEnabled[CK_MismatchedIteratorChecker])
496       return;
497
498     const auto *ContReg = InstCall->getCXXThisVal().getAsRegion();
499     if (!ContReg)
500       return;
501     // Check for erase, insert and emplace using iterator of another container
502     if (isEraseCall(Func) || isEraseAfterCall(Func)) {
503       verifyMatch(C, Call.getArgSVal(0),
504                   InstCall->getCXXThisVal().getAsRegion());
505       if (Call.getNumArgs() == 2) {
506         verifyMatch(C, Call.getArgSVal(1),
507                     InstCall->getCXXThisVal().getAsRegion());
508       }
509     } else if (isInsertCall(Func)) {
510       verifyMatch(C, Call.getArgSVal(0),
511                   InstCall->getCXXThisVal().getAsRegion());
512       if (Call.getNumArgs() == 3 &&
513           isIteratorType(Call.getArgExpr(1)->getType()) &&
514           isIteratorType(Call.getArgExpr(2)->getType())) {
515         verifyMatch(C, Call.getArgSVal(1), Call.getArgSVal(2));
516       }
517     } else if (isEmplaceCall(Func)) {
518       verifyMatch(C, Call.getArgSVal(0),
519                   InstCall->getCXXThisVal().getAsRegion());
520     }
521   } else if (isa<CXXConstructorCall>(&Call)) {
522     // Check match of first-last iterator pair in a constructor of a container
523     if (Call.getNumArgs() < 2)
524       return;
525
526     const auto *Ctr = cast<CXXConstructorDecl>(Call.getDecl());
527     if (Ctr->getNumParams() < 2)
528       return;
529
530     if (Ctr->getParamDecl(0)->getName() != "first" ||
531         Ctr->getParamDecl(1)->getName() != "last")
532       return;
533
534     if (!isIteratorType(Call.getArgExpr(0)->getType()) ||
535         !isIteratorType(Call.getArgExpr(1)->getType()))
536       return;
537
538     verifyMatch(C, Call.getArgSVal(0), Call.getArgSVal(1));
539   } else {
540     // The main purpose of iterators is to abstract away from different
541     // containers and provide a (maybe limited) uniform access to them.
542     // This implies that any correctly written template function that
543     // works on multiple containers using iterators takes different
544     // template parameters for different containers. So we can safely
545     // assume that passing iterators of different containers as arguments
546     // whose type replaces the same template parameter is a bug.
547     //
548     // Example:
549     // template<typename I1, typename I2>
550     // void f(I1 first1, I1 last1, I2 first2, I2 last2);
551     // 
552     // In this case the first two arguments to f() must be iterators must belong
553     // to the same container and the last to also to the same container but
554     // not necessarily to the same as the first two.
555
556     if (!ChecksEnabled[CK_MismatchedIteratorChecker])
557       return;
558
559     const auto *Templ = Func->getPrimaryTemplate();
560     if (!Templ)
561       return;
562
563     const auto *TParams = Templ->getTemplateParameters();
564     const auto *TArgs = Func->getTemplateSpecializationArgs();
565
566     // Iterate over all the template parameters
567     for (size_t I = 0; I < TParams->size(); ++I) {
568       const auto *TPDecl = dyn_cast<TemplateTypeParmDecl>(TParams->getParam(I));
569       if (!TPDecl)
570         continue;
571
572       if (TPDecl->isParameterPack())
573         continue;
574
575       const auto TAType = TArgs->get(I).getAsType();
576       if (!isIteratorType(TAType))
577         continue;
578
579       SVal LHS = UndefinedVal();
580
581       // For every template parameter which is an iterator type in the
582       // instantiation look for all functions' parameters' type by it and
583       // check whether they belong to the same container
584       for (auto J = 0U; J < Func->getNumParams(); ++J) {
585         const auto *Param = Func->getParamDecl(J);
586         const auto *ParamType =
587             Param->getType()->getAs<SubstTemplateTypeParmType>();
588         if (!ParamType ||
589             ParamType->getReplacedParameter()->getDecl() != TPDecl)
590           continue;
591         if (LHS.isUndef()) {
592           LHS = Call.getArgSVal(J);
593         } else {
594           verifyMatch(C, LHS, Call.getArgSVal(J));
595         }
596       }
597     }
598   }
599 }
600
601 void IteratorChecker::checkPostCall(const CallEvent &Call,
602                                     CheckerContext &C) const {
603   // Record new iterator positions and iterator position changes
604   const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
605   if (!Func)
606     return;
607
608   if (Func->isOverloadedOperator()) {
609     const auto Op = Func->getOverloadedOperator();
610     if (isAssignmentOperator(Op)) {
611       const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call);
612       if (Func->getParamDecl(0)->getType()->isRValueReferenceType()) {
613         handleAssign(C, InstCall->getCXXThisVal(), Call.getOriginExpr(),
614                      Call.getArgSVal(0));
615       } else {
616         handleAssign(C, InstCall->getCXXThisVal());
617       }
618     } else if (isSimpleComparisonOperator(Op)) {
619       if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
620         handleComparison(C, Call.getReturnValue(), InstCall->getCXXThisVal(),
621                          Call.getArgSVal(0), Op);
622       } else {
623         handleComparison(C, Call.getReturnValue(), Call.getArgSVal(0),
624                          Call.getArgSVal(1), Op);
625       }
626     } else if (isRandomIncrOrDecrOperator(Func->getOverloadedOperator())) {
627       if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
628         if (Call.getNumArgs() >= 1) {
629           handleRandomIncrOrDecr(C, Func->getOverloadedOperator(),
630                                  Call.getReturnValue(),
631                                  InstCall->getCXXThisVal(), Call.getArgSVal(0));
632         }
633       } else {
634         if (Call.getNumArgs() >= 2) {
635           handleRandomIncrOrDecr(C, Func->getOverloadedOperator(),
636                                  Call.getReturnValue(), Call.getArgSVal(0),
637                                  Call.getArgSVal(1));
638         }
639       }
640     } else if (isIncrementOperator(Func->getOverloadedOperator())) {
641       if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
642         handleIncrement(C, Call.getReturnValue(), InstCall->getCXXThisVal(),
643                         Call.getNumArgs());
644       } else {
645         handleIncrement(C, Call.getReturnValue(), Call.getArgSVal(0),
646                         Call.getNumArgs());
647       }
648     } else if (isDecrementOperator(Func->getOverloadedOperator())) {
649       if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
650         handleDecrement(C, Call.getReturnValue(), InstCall->getCXXThisVal(),
651                         Call.getNumArgs());
652       } else {
653         handleDecrement(C, Call.getReturnValue(), Call.getArgSVal(0),
654                         Call.getNumArgs());
655       }
656     }
657   } else {
658     if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
659       if (isAssignCall(Func)) {
660         handleAssign(C, InstCall->getCXXThisVal());
661       } else if (isClearCall(Func)) {
662         handleClear(C, InstCall->getCXXThisVal());
663       } else if (isPushBackCall(Func) || isEmplaceBackCall(Func)) {
664         handlePushBack(C, InstCall->getCXXThisVal());
665       } else if (isPopBackCall(Func)) {
666         handlePopBack(C, InstCall->getCXXThisVal());
667       } else if (isPushFrontCall(Func) || isEmplaceFrontCall(Func)) {
668         handlePushFront(C, InstCall->getCXXThisVal());
669       } else if (isPopFrontCall(Func)) {
670         handlePopFront(C, InstCall->getCXXThisVal());
671       } else if (isInsertCall(Func) || isEmplaceCall(Func)) {
672         handleInsert(C, Call.getArgSVal(0));
673       } else if (isEraseCall(Func)) {
674         if (Call.getNumArgs() == 1) {
675           handleErase(C, Call.getArgSVal(0));
676         } else if (Call.getNumArgs() == 2) {
677           handleErase(C, Call.getArgSVal(0), Call.getArgSVal(1));
678         }
679       } else if (isEraseAfterCall(Func)) {
680         if (Call.getNumArgs() == 1) {
681           handleEraseAfter(C, Call.getArgSVal(0));
682         } else if (Call.getNumArgs() == 2) {
683           handleEraseAfter(C, Call.getArgSVal(0), Call.getArgSVal(1));
684         }
685       }
686     }
687
688     const auto *OrigExpr = Call.getOriginExpr();
689     if (!OrigExpr)
690       return;
691
692     if (!isIteratorType(Call.getResultType()))
693       return;
694
695     auto State = C.getState();
696
697     if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
698       if (isBeginCall(Func)) {
699         handleBegin(C, OrigExpr, Call.getReturnValue(),
700                     InstCall->getCXXThisVal());
701         return;
702       }
703       if (isEndCall(Func)) {
704         handleEnd(C, OrigExpr, Call.getReturnValue(),
705                   InstCall->getCXXThisVal());
706         return;
707       }
708     }
709
710     // Already bound to container?
711     if (getIteratorPosition(State, Call.getReturnValue()))
712       return;
713
714     // Copy-like and move constructors
715     if (isa<CXXConstructorCall>(&Call) && Call.getNumArgs() == 1) {
716       if (const auto *Pos = getIteratorPosition(State, Call.getArgSVal(0))) {
717         State = setIteratorPosition(State, Call.getReturnValue(), *Pos);
718         if (cast<CXXConstructorDecl>(Func)->isMoveConstructor()) {
719           State = removeIteratorPosition(State, Call.getArgSVal(0));
720         }
721         C.addTransition(State);
722         return;
723       }
724     }
725
726     // Assumption: if return value is an iterator which is not yet bound to a
727     //             container, then look for the first iterator argument, and
728     //             bind the return value to the same container. This approach
729     //             works for STL algorithms.
730     // FIXME: Add a more conservative mode
731     for (unsigned i = 0; i < Call.getNumArgs(); ++i) {
732       if (isIteratorType(Call.getArgExpr(i)->getType())) {
733         if (const auto *Pos = getIteratorPosition(State, Call.getArgSVal(i))) {
734           assignToContainer(C, OrigExpr, Call.getReturnValue(),
735                             Pos->getContainer());
736           return;
737         }
738       }
739     }
740   }
741 }
742
743 void IteratorChecker::checkBind(SVal Loc, SVal Val, const Stmt *S,
744                                 CheckerContext &C) const {
745   auto State = C.getState();
746   const auto *Pos = getIteratorPosition(State, Val);
747   if (Pos) {
748     State = setIteratorPosition(State, Loc, *Pos);
749     C.addTransition(State);
750   } else {
751     const auto *OldPos = getIteratorPosition(State, Loc);
752     if (OldPos) {
753       State = removeIteratorPosition(State, Loc);
754       C.addTransition(State);
755     }
756   }
757 }
758
759 void IteratorChecker::checkPostStmt(const MaterializeTemporaryExpr *MTE,
760                                     CheckerContext &C) const {
761   /* Transfer iterator state to temporary objects */
762   auto State = C.getState();
763   const auto *Pos =
764       getIteratorPosition(State, C.getSVal(MTE->GetTemporaryExpr()));
765   if (!Pos)
766     return;
767   State = setIteratorPosition(State, C.getSVal(MTE), *Pos);
768   C.addTransition(State);
769 }
770
771 void IteratorChecker::checkLiveSymbols(ProgramStateRef State,
772                                        SymbolReaper &SR) const {
773   // Keep symbolic expressions of iterator positions, container begins and ends
774   // alive
775   auto RegionMap = State->get<IteratorRegionMap>();
776   for (const auto Reg : RegionMap) {
777     const auto Offset = Reg.second.getOffset();
778     for (auto i = Offset->symbol_begin(); i != Offset->symbol_end(); ++i)
779       if (isa<SymbolData>(*i))
780         SR.markLive(*i);
781   }
782
783   auto SymbolMap = State->get<IteratorSymbolMap>();
784   for (const auto Sym : SymbolMap) {
785     const auto Offset = Sym.second.getOffset();
786     for (auto i = Offset->symbol_begin(); i != Offset->symbol_end(); ++i)
787       if (isa<SymbolData>(*i))
788         SR.markLive(*i);
789   }
790
791   auto ContMap = State->get<ContainerMap>();
792   for (const auto Cont : ContMap) {
793     const auto CData = Cont.second;
794     if (CData.getBegin()) {
795       SR.markLive(CData.getBegin());
796       if(const auto *SIE = dyn_cast<SymIntExpr>(CData.getBegin()))
797         SR.markLive(SIE->getLHS());
798     }
799     if (CData.getEnd()) {
800       SR.markLive(CData.getEnd());
801       if(const auto *SIE = dyn_cast<SymIntExpr>(CData.getEnd()))
802         SR.markLive(SIE->getLHS());
803     }
804   }
805 }
806
807 void IteratorChecker::checkDeadSymbols(SymbolReaper &SR,
808                                        CheckerContext &C) const {
809   // Cleanup
810   auto State = C.getState();
811
812   auto RegionMap = State->get<IteratorRegionMap>();
813   for (const auto Reg : RegionMap) {
814     if (!SR.isLiveRegion(Reg.first)) {
815       // The region behind the `LazyCompoundVal` is often cleaned up before
816       // the `LazyCompoundVal` itself. If there are iterator positions keyed
817       // by these regions their cleanup must be deferred.
818       if (!isBoundThroughLazyCompoundVal(State->getEnvironment(), Reg.first)) {
819         State = State->remove<IteratorRegionMap>(Reg.first);
820       }
821     }
822   }
823
824   auto SymbolMap = State->get<IteratorSymbolMap>();
825   for (const auto Sym : SymbolMap) {
826     if (!SR.isLive(Sym.first)) {
827       State = State->remove<IteratorSymbolMap>(Sym.first);
828     }
829   }
830
831   auto ContMap = State->get<ContainerMap>();
832   for (const auto Cont : ContMap) {
833     if (!SR.isLiveRegion(Cont.first)) {
834       // We must keep the container data while it has live iterators to be able
835       // to compare them to the begin and the end of the container.
836       if (!hasLiveIterators(State, Cont.first)) {
837         State = State->remove<ContainerMap>(Cont.first);
838       }
839     }
840   }
841
842   auto ComparisonMap = State->get<IteratorComparisonMap>();
843   for (const auto Comp : ComparisonMap) {
844     if (!SR.isLive(Comp.first)) {
845       State = State->remove<IteratorComparisonMap>(Comp.first);
846     }
847   }
848
849   C.addTransition(State);
850 }
851
852 ProgramStateRef IteratorChecker::evalAssume(ProgramStateRef State, SVal Cond,
853                                             bool Assumption) const {
854   // Load recorded comparison and transfer iterator state between sides
855   // according to comparison operator and assumption
856   const auto *SE = Cond.getAsSymExpr();
857   if (!SE)
858     return State;
859
860   auto Opc = getOpcode(SE);
861   if (Opc != BO_EQ && Opc != BO_NE)
862     return State;
863
864   bool Negated = false;
865   const auto *Comp = loadComparison(State, SE);
866   if (!Comp) {
867     // Try negated comparison, which is a SymExpr to 0 integer comparison
868     const auto *SIE = dyn_cast<SymIntExpr>(SE);
869     if (!SIE)
870       return State;
871
872     if (SIE->getRHS() != 0)
873       return State;
874
875     SE = SIE->getLHS();
876     Negated = SIE->getOpcode() == BO_EQ; // Equal to zero means negation
877     Opc = getOpcode(SE);
878     if (Opc != BO_EQ && Opc != BO_NE)
879       return State;
880
881     Comp = loadComparison(State, SE);
882     if (!Comp)
883       return State;
884   }
885
886   return processComparison(State, Comp->getLeft(), Comp->getRight(),
887                            (Comp->isEquality() == Assumption) != Negated);
888 }
889
890 void IteratorChecker::handleComparison(CheckerContext &C, const SVal &RetVal,
891                                        const SVal &LVal, const SVal &RVal,
892                                        OverloadedOperatorKind Op) const {
893   // Record the operands and the operator of the comparison for the next
894   // evalAssume, if the result is a symbolic expression. If it is a concrete
895   // value (only one branch is possible), then transfer the state between
896   // the operands according to the operator and the result
897   auto State = C.getState();
898   if (const auto *Condition = RetVal.getAsSymbolicExpression()) {
899     const auto *LPos = getIteratorPosition(State, LVal);
900     const auto *RPos = getIteratorPosition(State, RVal);
901     if (!LPos && !RPos)
902       return;
903     State = saveComparison(State, Condition, LVal, RVal, Op == OO_EqualEqual);
904     C.addTransition(State);
905   } else if (const auto TruthVal = RetVal.getAs<nonloc::ConcreteInt>()) {
906     if ((State = processComparison(
907              State, getRegionOrSymbol(LVal), getRegionOrSymbol(RVal),
908              (Op == OO_EqualEqual) == (TruthVal->getValue() != 0)))) {
909       C.addTransition(State);
910     } else {
911       C.generateSink(State, C.getPredecessor());
912     }
913   }
914 }
915
916 void IteratorChecker::verifyDereference(CheckerContext &C,
917                                         const SVal &Val) const {
918   auto State = C.getState();
919   const auto *Pos = getIteratorPosition(State, Val);
920   if (Pos && isPastTheEnd(State, *Pos)) {
921     auto *N = C.generateNonFatalErrorNode(State);
922     if (!N)
923       return;
924     reportOutOfRangeBug("Past-the-end iterator dereferenced.", Val, C, N);
925     return;
926   }
927 }
928
929 void IteratorChecker::verifyAccess(CheckerContext &C, const SVal &Val) const {
930   auto State = C.getState();
931   const auto *Pos = getIteratorPosition(State, Val);
932   if (Pos && !Pos->isValid()) {
933     auto *N = C.generateNonFatalErrorNode(State);
934     if (!N) {
935       return;
936     }
937     reportInvalidatedBug("Invalidated iterator accessed.", Val, C, N);
938   }
939 }
940
941 void IteratorChecker::handleIncrement(CheckerContext &C, const SVal &RetVal,
942                                       const SVal &Iter, bool Postfix) const {
943   // Increment the symbolic expressions which represents the position of the
944   // iterator
945   auto State = C.getState();
946   const auto *Pos = getIteratorPosition(State, Iter);
947   if (Pos) {
948     auto &SymMgr = C.getSymbolManager();
949     auto &BVF = SymMgr.getBasicVals();
950     const auto NewPos =
951       advancePosition(C, OO_Plus, *Pos,
952                     nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
953     State = setIteratorPosition(State, Iter, NewPos);
954     State = setIteratorPosition(State, RetVal, Postfix ? *Pos : NewPos);
955     C.addTransition(State);
956   }
957 }
958
959 void IteratorChecker::handleDecrement(CheckerContext &C, const SVal &RetVal,
960                                       const SVal &Iter, bool Postfix) const {
961   // Decrement the symbolic expressions which represents the position of the
962   // iterator
963   auto State = C.getState();
964   const auto *Pos = getIteratorPosition(State, Iter);
965   if (Pos) {
966     auto &SymMgr = C.getSymbolManager();
967     auto &BVF = SymMgr.getBasicVals();
968     const auto NewPos =
969       advancePosition(C, OO_Minus, *Pos,
970                     nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
971     State = setIteratorPosition(State, Iter, NewPos);
972     State = setIteratorPosition(State, RetVal, Postfix ? *Pos : NewPos);
973     C.addTransition(State);
974   }
975 }
976
977 // This function tells the analyzer's engine that symbols produced by our
978 // checker, most notably iterator positions, are relatively small.
979 // A distance between items in the container should not be very large.
980 // By assuming that it is within around 1/8 of the address space,
981 // we can help the analyzer perform operations on these symbols
982 // without being afraid of integer overflows.
983 // FIXME: Should we provide it as an API, so that all checkers could use it?
984 static ProgramStateRef assumeNoOverflow(ProgramStateRef State, SymbolRef Sym,
985                                         long Scale) {
986   SValBuilder &SVB = State->getStateManager().getSValBuilder();
987   BasicValueFactory &BV = SVB.getBasicValueFactory();
988
989   QualType T = Sym->getType();
990   assert(T->isSignedIntegerOrEnumerationType());
991   APSIntType AT = BV.getAPSIntType(T);
992
993   ProgramStateRef NewState = State;
994
995   llvm::APSInt Max = AT.getMaxValue() / AT.getValue(Scale);
996   SVal IsCappedFromAbove =
997       SVB.evalBinOpNN(State, BO_LE, nonloc::SymbolVal(Sym),
998                       nonloc::ConcreteInt(Max), SVB.getConditionType());
999   if (auto DV = IsCappedFromAbove.getAs<DefinedSVal>()) {
1000     NewState = NewState->assume(*DV, true);
1001     if (!NewState)
1002       return State;
1003   }
1004
1005   llvm::APSInt Min = -Max;
1006   SVal IsCappedFromBelow =
1007       SVB.evalBinOpNN(State, BO_GE, nonloc::SymbolVal(Sym),
1008                       nonloc::ConcreteInt(Min), SVB.getConditionType());
1009   if (auto DV = IsCappedFromBelow.getAs<DefinedSVal>()) {
1010     NewState = NewState->assume(*DV, true);
1011     if (!NewState)
1012       return State;
1013   }
1014
1015   return NewState;
1016 }
1017
1018 void IteratorChecker::handleRandomIncrOrDecr(CheckerContext &C,
1019                                              OverloadedOperatorKind Op,
1020                                              const SVal &RetVal,
1021                                              const SVal &LHS,
1022                                              const SVal &RHS) const {
1023   // Increment or decrement the symbolic expressions which represents the
1024   // position of the iterator
1025   auto State = C.getState();
1026   const auto *Pos = getIteratorPosition(State, LHS);
1027   if (!Pos)
1028     return;
1029
1030   const auto *value = &RHS;
1031   if (auto loc = RHS.getAs<Loc>()) {
1032     const auto val = State->getRawSVal(*loc);
1033     value = &val;
1034   }
1035
1036   auto &TgtVal = (Op == OO_PlusEqual || Op == OO_MinusEqual) ? LHS : RetVal;
1037   State =
1038       setIteratorPosition(State, TgtVal, advancePosition(C, Op, *Pos, *value));
1039   C.addTransition(State);
1040 }
1041
1042 void IteratorChecker::verifyIncrement(CheckerContext &C,
1043                                       const SVal &Iter) const {
1044   auto &BVF = C.getSValBuilder().getBasicValueFactory();
1045   verifyRandomIncrOrDecr(C, OO_Plus, Iter,
1046                      nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
1047 }
1048
1049 void IteratorChecker::verifyDecrement(CheckerContext &C,
1050                                       const SVal &Iter) const {
1051   auto &BVF = C.getSValBuilder().getBasicValueFactory();
1052   verifyRandomIncrOrDecr(C, OO_Minus, Iter,
1053                      nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
1054 }
1055
1056 void IteratorChecker::verifyRandomIncrOrDecr(CheckerContext &C,
1057                                              OverloadedOperatorKind Op,
1058                                              const SVal &LHS,
1059                                              const SVal &RHS) const {
1060   auto State = C.getState();
1061
1062   // If the iterator is initially inside its range, then the operation is valid
1063   const auto *Pos = getIteratorPosition(State, LHS);
1064   if (!Pos)
1065     return;
1066
1067   auto Value = RHS;
1068   if (auto ValAsLoc = RHS.getAs<Loc>()) {
1069     Value = State->getRawSVal(*ValAsLoc);
1070   }
1071
1072   if (Value.isUnknown())
1073     return;
1074
1075   // Incremention or decremention by 0 is never a bug.
1076   if (isZero(State, Value.castAs<NonLoc>()))
1077     return;
1078
1079   // The result may be the past-end iterator of the container, but any other
1080   // out of range position is undefined behaviour
1081   if (isAheadOfRange(State, advancePosition(C, Op, *Pos, Value))) {
1082     auto *N = C.generateNonFatalErrorNode(State);
1083     if (!N)
1084       return;
1085     reportOutOfRangeBug("Iterator decremented ahead of its valid range.", LHS,
1086                         C, N);
1087   }
1088   if (isBehindPastTheEnd(State, advancePosition(C, Op, *Pos, Value))) {
1089     auto *N = C.generateNonFatalErrorNode(State);
1090     if (!N)
1091       return;
1092     reportOutOfRangeBug("Iterator incremented behind the past-the-end "
1093                         "iterator.", LHS, C, N);
1094   }
1095 }
1096
1097 void IteratorChecker::verifyMatch(CheckerContext &C, const SVal &Iter,
1098                                   const MemRegion *Cont) const {
1099   // Verify match between a container and the container of an iterator
1100   Cont = Cont->getMostDerivedObjectRegion();
1101
1102   auto State = C.getState();
1103   const auto *Pos = getIteratorPosition(State, Iter);
1104   if (Pos && Pos->getContainer() != Cont) {
1105     auto *N = C.generateNonFatalErrorNode(State);
1106     if (!N) {
1107       return;
1108     }
1109     reportMismatchedBug("Container accessed using foreign iterator argument.", Iter, Cont, C, N);
1110   }
1111 }
1112
1113 void IteratorChecker::verifyMatch(CheckerContext &C, const SVal &Iter1,
1114                                   const SVal &Iter2) const {
1115   // Verify match between the containers of two iterators
1116   auto State = C.getState();
1117   const auto *Pos1 = getIteratorPosition(State, Iter1);
1118   const auto *Pos2 = getIteratorPosition(State, Iter2);
1119   if (Pos1 && Pos2 && Pos1->getContainer() != Pos2->getContainer()) {
1120     auto *N = C.generateNonFatalErrorNode(State);
1121     if (!N)
1122       return;
1123     reportMismatchedBug("Iterators of different containers used where the "
1124                         "same container is expected.", Iter1, Iter2, C, N);
1125   }
1126 }
1127
1128 void IteratorChecker::handleBegin(CheckerContext &C, const Expr *CE,
1129                                   const SVal &RetVal, const SVal &Cont) const {
1130   const auto *ContReg = Cont.getAsRegion();
1131   if (!ContReg)
1132     return;
1133
1134   ContReg = ContReg->getMostDerivedObjectRegion();
1135
1136   // If the container already has a begin symbol then use it. Otherwise first
1137   // create a new one.
1138   auto State = C.getState();
1139   auto BeginSym = getContainerBegin(State, ContReg);
1140   if (!BeginSym) {
1141     auto &SymMgr = C.getSymbolManager();
1142     BeginSym = SymMgr.conjureSymbol(CE, C.getLocationContext(),
1143                                     C.getASTContext().LongTy, C.blockCount());
1144     State = assumeNoOverflow(State, BeginSym, 4);
1145     State = createContainerBegin(State, ContReg, BeginSym);
1146   }
1147   State = setIteratorPosition(State, RetVal,
1148                               IteratorPosition::getPosition(ContReg, BeginSym));
1149   C.addTransition(State);
1150 }
1151
1152 void IteratorChecker::handleEnd(CheckerContext &C, const Expr *CE,
1153                                 const SVal &RetVal, const SVal &Cont) const {
1154   const auto *ContReg = Cont.getAsRegion();
1155   if (!ContReg)
1156     return;
1157
1158   ContReg = ContReg->getMostDerivedObjectRegion();
1159
1160   // If the container already has an end symbol then use it. Otherwise first
1161   // create a new one.
1162   auto State = C.getState();
1163   auto EndSym = getContainerEnd(State, ContReg);
1164   if (!EndSym) {
1165     auto &SymMgr = C.getSymbolManager();
1166     EndSym = SymMgr.conjureSymbol(CE, C.getLocationContext(),
1167                                   C.getASTContext().LongTy, C.blockCount());
1168     State = assumeNoOverflow(State, EndSym, 4);
1169     State = createContainerEnd(State, ContReg, EndSym);
1170   }
1171   State = setIteratorPosition(State, RetVal,
1172                               IteratorPosition::getPosition(ContReg, EndSym));
1173   C.addTransition(State);
1174 }
1175
1176 void IteratorChecker::assignToContainer(CheckerContext &C, const Expr *CE,
1177                                         const SVal &RetVal,
1178                                         const MemRegion *Cont) const {
1179   Cont = Cont->getMostDerivedObjectRegion();
1180
1181   auto State = C.getState();
1182   auto &SymMgr = C.getSymbolManager();
1183   auto Sym = SymMgr.conjureSymbol(CE, C.getLocationContext(),
1184                                   C.getASTContext().LongTy, C.blockCount());
1185   State = assumeNoOverflow(State, Sym, 4);
1186   State = setIteratorPosition(State, RetVal,
1187                               IteratorPosition::getPosition(Cont, Sym));
1188   C.addTransition(State);
1189 }
1190
1191 void IteratorChecker::handleAssign(CheckerContext &C, const SVal &Cont,
1192                                    const Expr *CE, const SVal &OldCont) const {
1193   const auto *ContReg = Cont.getAsRegion();
1194   if (!ContReg)
1195     return;
1196
1197   ContReg = ContReg->getMostDerivedObjectRegion();
1198
1199   // Assignment of a new value to a container always invalidates all its
1200   // iterators
1201   auto State = C.getState();
1202   const auto CData = getContainerData(State, ContReg);
1203   if (CData) {
1204     State = invalidateAllIteratorPositions(State, ContReg);
1205   }
1206
1207   // In case of move, iterators of the old container (except the past-end
1208   // iterators) remain valid but refer to the new container
1209   if (!OldCont.isUndef()) {
1210     const auto *OldContReg = OldCont.getAsRegion();
1211     if (OldContReg) {
1212       OldContReg = OldContReg->getMostDerivedObjectRegion();
1213       const auto OldCData = getContainerData(State, OldContReg);
1214       if (OldCData) {
1215         if (const auto OldEndSym = OldCData->getEnd()) {
1216           // If we already assigned an "end" symbol to the old container, then
1217           // first reassign all iterator positions to the new container which
1218           // are not past the container (thus not greater or equal to the
1219           // current "end" symbol).
1220           State = reassignAllIteratorPositionsUnless(State, OldContReg, ContReg,
1221                                                      OldEndSym, BO_GE);
1222           auto &SymMgr = C.getSymbolManager();
1223           auto &SVB = C.getSValBuilder();
1224           // Then generate and assign a new "end" symbol for the new container.
1225           auto NewEndSym =
1226               SymMgr.conjureSymbol(CE, C.getLocationContext(),
1227                                    C.getASTContext().LongTy, C.blockCount());
1228           State = assumeNoOverflow(State, NewEndSym, 4);
1229           if (CData) {
1230             State = setContainerData(State, ContReg, CData->newEnd(NewEndSym));
1231           } else {
1232             State = setContainerData(State, ContReg,
1233                                      ContainerData::fromEnd(NewEndSym));
1234           }
1235           // Finally, replace the old "end" symbol in the already reassigned
1236           // iterator positions with the new "end" symbol.
1237           State = rebaseSymbolInIteratorPositionsIf(
1238               State, SVB, OldEndSym, NewEndSym, OldEndSym, BO_LT);
1239         } else {
1240           // There was no "end" symbol assigned yet to the old container,
1241           // so reassign all iterator positions to the new container.
1242           State = reassignAllIteratorPositions(State, OldContReg, ContReg);
1243         }
1244         if (const auto OldBeginSym = OldCData->getBegin()) {
1245           // If we already assigned a "begin" symbol to the old container, then
1246           // assign it to the new container and remove it from the old one.
1247           if (CData) {
1248             State =
1249                 setContainerData(State, ContReg, CData->newBegin(OldBeginSym));
1250           } else {
1251             State = setContainerData(State, ContReg,
1252                                      ContainerData::fromBegin(OldBeginSym));
1253           }
1254           State =
1255               setContainerData(State, OldContReg, OldCData->newEnd(nullptr));
1256         }
1257       } else {
1258         // There was neither "begin" nor "end" symbol assigned yet to the old
1259         // container, so reassign all iterator positions to the new container.
1260         State = reassignAllIteratorPositions(State, OldContReg, ContReg);
1261       }
1262     }
1263   }
1264   C.addTransition(State);
1265 }
1266
1267 void IteratorChecker::handleClear(CheckerContext &C, const SVal &Cont) const {
1268   const auto *ContReg = Cont.getAsRegion();
1269   if (!ContReg)
1270     return;
1271
1272   ContReg = ContReg->getMostDerivedObjectRegion();
1273
1274   // The clear() operation invalidates all the iterators, except the past-end
1275   // iterators of list-like containers
1276   auto State = C.getState();
1277   if (!hasSubscriptOperator(State, ContReg) ||
1278       !backModifiable(State, ContReg)) {
1279     const auto CData = getContainerData(State, ContReg);
1280     if (CData) {
1281       if (const auto EndSym = CData->getEnd()) {
1282         State =
1283             invalidateAllIteratorPositionsExcept(State, ContReg, EndSym, BO_GE);
1284         C.addTransition(State);
1285         return;
1286       }
1287     }
1288   }
1289   State = invalidateAllIteratorPositions(State, ContReg);
1290   C.addTransition(State);
1291 }
1292
1293 void IteratorChecker::handlePushBack(CheckerContext &C,
1294                                      const SVal &Cont) const {
1295   const auto *ContReg = Cont.getAsRegion();
1296   if (!ContReg)
1297     return;
1298
1299   ContReg = ContReg->getMostDerivedObjectRegion();
1300
1301   // For deque-like containers invalidate all iterator positions
1302   auto State = C.getState();
1303   if (hasSubscriptOperator(State, ContReg) && frontModifiable(State, ContReg)) {
1304     State = invalidateAllIteratorPositions(State, ContReg);
1305     C.addTransition(State);
1306     return;
1307   }
1308
1309   const auto CData = getContainerData(State, ContReg);
1310   if (!CData)
1311     return;
1312
1313   // For vector-like containers invalidate the past-end iterator positions
1314   if (const auto EndSym = CData->getEnd()) {
1315     if (hasSubscriptOperator(State, ContReg)) {
1316       State = invalidateIteratorPositions(State, EndSym, BO_GE);
1317     }
1318     auto &SymMgr = C.getSymbolManager();
1319     auto &BVF = SymMgr.getBasicVals();
1320     auto &SVB = C.getSValBuilder();
1321     const auto newEndSym =
1322       SVB.evalBinOp(State, BO_Add,
1323                     nonloc::SymbolVal(EndSym),
1324                     nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
1325                     SymMgr.getType(EndSym)).getAsSymbol();
1326     State = setContainerData(State, ContReg, CData->newEnd(newEndSym));
1327   }
1328   C.addTransition(State);
1329 }
1330
1331 void IteratorChecker::handlePopBack(CheckerContext &C, const SVal &Cont) const {
1332   const auto *ContReg = Cont.getAsRegion();
1333   if (!ContReg)
1334     return;
1335
1336   ContReg = ContReg->getMostDerivedObjectRegion();
1337
1338   auto State = C.getState();
1339   const auto CData = getContainerData(State, ContReg);
1340   if (!CData)
1341     return;
1342
1343   if (const auto EndSym = CData->getEnd()) {
1344     auto &SymMgr = C.getSymbolManager();
1345     auto &BVF = SymMgr.getBasicVals();
1346     auto &SVB = C.getSValBuilder();
1347     const auto BackSym =
1348       SVB.evalBinOp(State, BO_Sub,
1349                     nonloc::SymbolVal(EndSym),
1350                     nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
1351                     SymMgr.getType(EndSym)).getAsSymbol();
1352     // For vector-like and deque-like containers invalidate the last and the
1353     // past-end iterator positions. For list-like containers only invalidate
1354     // the last position
1355     if (hasSubscriptOperator(State, ContReg) &&
1356         backModifiable(State, ContReg)) {
1357       State = invalidateIteratorPositions(State, BackSym, BO_GE);
1358       State = setContainerData(State, ContReg, CData->newEnd(nullptr));
1359     } else {
1360       State = invalidateIteratorPositions(State, BackSym, BO_EQ);
1361     }
1362     auto newEndSym = BackSym;
1363     State = setContainerData(State, ContReg, CData->newEnd(newEndSym));
1364     C.addTransition(State);
1365   }
1366 }
1367
1368 void IteratorChecker::handlePushFront(CheckerContext &C,
1369                                       const SVal &Cont) const {
1370   const auto *ContReg = Cont.getAsRegion();
1371   if (!ContReg)
1372     return;
1373
1374   ContReg = ContReg->getMostDerivedObjectRegion();
1375
1376   // For deque-like containers invalidate all iterator positions
1377   auto State = C.getState();
1378   if (hasSubscriptOperator(State, ContReg)) {
1379     State = invalidateAllIteratorPositions(State, ContReg);
1380     C.addTransition(State);
1381   } else {
1382     const auto CData = getContainerData(State, ContReg);
1383     if (!CData)
1384       return;
1385
1386     if (const auto BeginSym = CData->getBegin()) {
1387       auto &SymMgr = C.getSymbolManager();
1388       auto &BVF = SymMgr.getBasicVals();
1389       auto &SVB = C.getSValBuilder();
1390       const auto newBeginSym =
1391         SVB.evalBinOp(State, BO_Sub,
1392                       nonloc::SymbolVal(BeginSym),
1393                       nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
1394                       SymMgr.getType(BeginSym)).getAsSymbol();
1395       State = setContainerData(State, ContReg, CData->newBegin(newBeginSym));
1396       C.addTransition(State);
1397     }
1398   }
1399 }
1400
1401 void IteratorChecker::handlePopFront(CheckerContext &C,
1402                                      const SVal &Cont) const {
1403   const auto *ContReg = Cont.getAsRegion();
1404   if (!ContReg)
1405     return;
1406
1407   ContReg = ContReg->getMostDerivedObjectRegion();
1408
1409   auto State = C.getState();
1410   const auto CData = getContainerData(State, ContReg);
1411   if (!CData)
1412     return;
1413
1414   // For deque-like containers invalidate all iterator positions. For list-like
1415   // iterators only invalidate the first position
1416   if (const auto BeginSym = CData->getBegin()) {
1417     if (hasSubscriptOperator(State, ContReg)) {
1418       State = invalidateIteratorPositions(State, BeginSym, BO_LE);
1419     } else {
1420       State = invalidateIteratorPositions(State, BeginSym, BO_EQ);
1421     }
1422     auto &SymMgr = C.getSymbolManager();
1423     auto &BVF = SymMgr.getBasicVals();
1424     auto &SVB = C.getSValBuilder();
1425     const auto newBeginSym =
1426       SVB.evalBinOp(State, BO_Add,
1427                     nonloc::SymbolVal(BeginSym),
1428                     nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
1429                     SymMgr.getType(BeginSym)).getAsSymbol();
1430     State = setContainerData(State, ContReg, CData->newBegin(newBeginSym));
1431     C.addTransition(State);
1432   }
1433 }
1434
1435 void IteratorChecker::handleInsert(CheckerContext &C, const SVal &Iter) const {
1436   auto State = C.getState();
1437   const auto *Pos = getIteratorPosition(State, Iter);
1438   if (!Pos)
1439     return;
1440
1441   // For deque-like containers invalidate all iterator positions. For
1442   // vector-like containers invalidate iterator positions after the insertion.
1443   const auto *Cont = Pos->getContainer();
1444   if (hasSubscriptOperator(State, Cont) && backModifiable(State, Cont)) {
1445     if (frontModifiable(State, Cont)) {
1446       State = invalidateAllIteratorPositions(State, Cont);
1447     } else {
1448       State = invalidateIteratorPositions(State, Pos->getOffset(), BO_GE);
1449     }
1450     if (const auto *CData = getContainerData(State, Cont)) {
1451       if (const auto EndSym = CData->getEnd()) {
1452         State = invalidateIteratorPositions(State, EndSym, BO_GE);
1453         State = setContainerData(State, Cont, CData->newEnd(nullptr));
1454       }
1455     }
1456     C.addTransition(State);
1457   }
1458 }
1459
1460 void IteratorChecker::handleErase(CheckerContext &C, const SVal &Iter) const {
1461   auto State = C.getState();
1462   const auto *Pos = getIteratorPosition(State, Iter);
1463   if (!Pos)
1464     return;
1465
1466   // For deque-like containers invalidate all iterator positions. For
1467   // vector-like containers invalidate iterator positions at and after the
1468   // deletion. For list-like containers only invalidate the deleted position.
1469   const auto *Cont = Pos->getContainer();
1470   if (hasSubscriptOperator(State, Cont) && backModifiable(State, Cont)) {
1471     if (frontModifiable(State, Cont)) {
1472       State = invalidateAllIteratorPositions(State, Cont);
1473     } else {
1474       State = invalidateIteratorPositions(State, Pos->getOffset(), BO_GE);
1475     }
1476     if (const auto *CData = getContainerData(State, Cont)) {
1477       if (const auto EndSym = CData->getEnd()) {
1478         State = invalidateIteratorPositions(State, EndSym, BO_GE);
1479         State = setContainerData(State, Cont, CData->newEnd(nullptr));
1480       }
1481     }
1482   } else {
1483     State = invalidateIteratorPositions(State, Pos->getOffset(), BO_EQ);
1484   }
1485   C.addTransition(State);
1486 }
1487
1488 void IteratorChecker::handleErase(CheckerContext &C, const SVal &Iter1,
1489                                   const SVal &Iter2) const {
1490   auto State = C.getState();
1491   const auto *Pos1 = getIteratorPosition(State, Iter1);
1492   const auto *Pos2 = getIteratorPosition(State, Iter2);
1493   if (!Pos1 || !Pos2)
1494     return;
1495
1496   // For deque-like containers invalidate all iterator positions. For
1497   // vector-like containers invalidate iterator positions at and after the
1498   // deletion range. For list-like containers only invalidate the deleted
1499   // position range [first..last].
1500   const auto *Cont = Pos1->getContainer();
1501   if (hasSubscriptOperator(State, Cont) && backModifiable(State, Cont)) {
1502     if (frontModifiable(State, Cont)) {
1503       State = invalidateAllIteratorPositions(State, Cont);
1504     } else {
1505       State = invalidateIteratorPositions(State, Pos1->getOffset(), BO_GE);
1506     }
1507     if (const auto *CData = getContainerData(State, Cont)) {
1508       if (const auto EndSym = CData->getEnd()) {
1509         State = invalidateIteratorPositions(State, EndSym, BO_GE);
1510         State = setContainerData(State, Cont, CData->newEnd(nullptr));
1511       }
1512     }
1513   } else {
1514     State = invalidateIteratorPositions(State, Pos1->getOffset(), BO_GE,
1515                                         Pos2->getOffset(), BO_LT);
1516   }
1517   C.addTransition(State);
1518 }
1519
1520 void IteratorChecker::handleEraseAfter(CheckerContext &C,
1521                                        const SVal &Iter) const {
1522   auto State = C.getState();
1523   const auto *Pos = getIteratorPosition(State, Iter);
1524   if (!Pos)
1525     return;
1526
1527   // Invalidate the deleted iterator position, which is the position of the
1528   // parameter plus one.
1529   auto &SymMgr = C.getSymbolManager();
1530   auto &BVF = SymMgr.getBasicVals();
1531   auto &SVB = C.getSValBuilder();
1532   const auto NextSym =
1533     SVB.evalBinOp(State, BO_Add,
1534                   nonloc::SymbolVal(Pos->getOffset()),
1535                   nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
1536                   SymMgr.getType(Pos->getOffset())).getAsSymbol();
1537   State = invalidateIteratorPositions(State, NextSym, BO_EQ);
1538   C.addTransition(State);
1539 }
1540
1541 void IteratorChecker::handleEraseAfter(CheckerContext &C, const SVal &Iter1,
1542                                        const SVal &Iter2) const {
1543   auto State = C.getState();
1544   const auto *Pos1 = getIteratorPosition(State, Iter1);
1545   const auto *Pos2 = getIteratorPosition(State, Iter2);
1546   if (!Pos1 || !Pos2)
1547     return;
1548
1549   // Invalidate the deleted iterator position range (first..last)
1550   State = invalidateIteratorPositions(State, Pos1->getOffset(), BO_GT,
1551                                       Pos2->getOffset(), BO_LT);
1552   C.addTransition(State);
1553 }
1554
1555 IteratorPosition IteratorChecker::advancePosition(CheckerContext &C,
1556                                                   OverloadedOperatorKind Op,
1557                                                   const IteratorPosition &Pos,
1558                                                   const SVal &Distance) const {
1559   auto State = C.getState();
1560   auto &SymMgr = C.getSymbolManager();
1561   auto &SVB = C.getSValBuilder();
1562
1563   assert ((Op == OO_Plus || Op == OO_PlusEqual ||
1564            Op == OO_Minus || Op == OO_MinusEqual) &&
1565           "Advance operator must be one of +, -, += and -=.");
1566   auto BinOp = (Op == OO_Plus || Op == OO_PlusEqual) ? BO_Add : BO_Sub;
1567   if (const auto IntDist = Distance.getAs<nonloc::ConcreteInt>()) {
1568     // For concrete integers we can calculate the new position
1569     return Pos.setTo(SVB.evalBinOp(State, BinOp,
1570                                    nonloc::SymbolVal(Pos.getOffset()), *IntDist,
1571                                    SymMgr.getType(Pos.getOffset()))
1572                          .getAsSymbol());
1573   } else {
1574     // For other symbols create a new symbol to keep expressions simple
1575     const auto &LCtx = C.getLocationContext();
1576     const auto NewPosSym = SymMgr.conjureSymbol(nullptr, LCtx,
1577                                              SymMgr.getType(Pos.getOffset()),
1578                                              C.blockCount());
1579     State = assumeNoOverflow(State, NewPosSym, 4);
1580     return Pos.setTo(NewPosSym);
1581   }
1582 }
1583
1584 void IteratorChecker::reportOutOfRangeBug(const StringRef &Message,
1585                                           const SVal &Val, CheckerContext &C,
1586                                           ExplodedNode *ErrNode) const {
1587   auto R = llvm::make_unique<BugReport>(*OutOfRangeBugType, Message, ErrNode);
1588   R->markInteresting(Val);
1589   C.emitReport(std::move(R));
1590 }
1591
1592 void IteratorChecker::reportMismatchedBug(const StringRef &Message,
1593                                           const SVal &Val1, const SVal &Val2,
1594                                           CheckerContext &C,
1595                                           ExplodedNode *ErrNode) const {
1596   auto R = llvm::make_unique<BugReport>(*MismatchedBugType, Message, ErrNode);
1597   R->markInteresting(Val1);
1598   R->markInteresting(Val2);
1599   C.emitReport(std::move(R));
1600 }
1601
1602 void IteratorChecker::reportMismatchedBug(const StringRef &Message,
1603                                           const SVal &Val, const MemRegion *Reg,
1604                                           CheckerContext &C,
1605                                           ExplodedNode *ErrNode) const {
1606   auto R = llvm::make_unique<BugReport>(*MismatchedBugType, Message, ErrNode);
1607   R->markInteresting(Val);
1608   R->markInteresting(Reg);
1609   C.emitReport(std::move(R));
1610 }
1611
1612 void IteratorChecker::reportInvalidatedBug(const StringRef &Message,
1613                                            const SVal &Val, CheckerContext &C,
1614                                            ExplodedNode *ErrNode) const {
1615   auto R = llvm::make_unique<BugReport>(*InvalidatedBugType, Message, ErrNode);
1616   R->markInteresting(Val);
1617   C.emitReport(std::move(R));
1618 }
1619
1620 namespace {
1621
1622 bool isLess(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2);
1623 bool isGreater(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2);
1624 bool isEqual(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2);
1625 bool compare(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2,
1626              BinaryOperator::Opcode Opc);
1627 bool compare(ProgramStateRef State, NonLoc NL1, NonLoc NL2,
1628              BinaryOperator::Opcode Opc);
1629 const CXXRecordDecl *getCXXRecordDecl(ProgramStateRef State,
1630                                       const MemRegion *Reg);
1631 SymbolRef rebaseSymbol(ProgramStateRef State, SValBuilder &SVB, SymbolRef Expr,
1632                         SymbolRef OldSym, SymbolRef NewSym);
1633
1634 bool isIteratorType(const QualType &Type) {
1635   if (Type->isPointerType())
1636     return true;
1637
1638   const auto *CRD = Type->getUnqualifiedDesugaredType()->getAsCXXRecordDecl();
1639   return isIterator(CRD);
1640 }
1641
1642 bool isIterator(const CXXRecordDecl *CRD) {
1643   if (!CRD)
1644     return false;
1645
1646   const auto Name = CRD->getName();
1647   if (!(Name.endswith_lower("iterator") || Name.endswith_lower("iter") ||
1648         Name.endswith_lower("it")))
1649     return false;
1650
1651   bool HasCopyCtor = false, HasCopyAssign = true, HasDtor = false,
1652        HasPreIncrOp = false, HasPostIncrOp = false, HasDerefOp = false;
1653   for (const auto *Method : CRD->methods()) {
1654     if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(Method)) {
1655       if (Ctor->isCopyConstructor()) {
1656         HasCopyCtor = !Ctor->isDeleted() && Ctor->getAccess() == AS_public;
1657       }
1658       continue;
1659     }
1660     if (const auto *Dtor = dyn_cast<CXXDestructorDecl>(Method)) {
1661       HasDtor = !Dtor->isDeleted() && Dtor->getAccess() == AS_public;
1662       continue;
1663     }
1664     if (Method->isCopyAssignmentOperator()) {
1665       HasCopyAssign = !Method->isDeleted() && Method->getAccess() == AS_public;
1666       continue;
1667     }
1668     if (!Method->isOverloadedOperator())
1669       continue;
1670     const auto OPK = Method->getOverloadedOperator();
1671     if (OPK == OO_PlusPlus) {
1672       HasPreIncrOp = HasPreIncrOp || (Method->getNumParams() == 0);
1673       HasPostIncrOp = HasPostIncrOp || (Method->getNumParams() == 1);
1674       continue;
1675     }
1676     if (OPK == OO_Star) {
1677       HasDerefOp = (Method->getNumParams() == 0);
1678       continue;
1679     }
1680   }
1681
1682   return HasCopyCtor && HasCopyAssign && HasDtor && HasPreIncrOp &&
1683          HasPostIncrOp && HasDerefOp;
1684 }
1685
1686 bool isComparisonOperator(OverloadedOperatorKind OK) {
1687   return OK == OO_EqualEqual || OK == OO_ExclaimEqual || OK == OO_Less ||
1688          OK == OO_LessEqual || OK == OO_Greater || OK == OO_GreaterEqual;
1689 }
1690
1691 bool isBeginCall(const FunctionDecl *Func) {
1692   const auto *IdInfo = Func->getIdentifier();
1693   if (!IdInfo)
1694     return false;
1695   return IdInfo->getName().endswith_lower("begin");
1696 }
1697
1698 bool isEndCall(const FunctionDecl *Func) {
1699   const auto *IdInfo = Func->getIdentifier();
1700   if (!IdInfo)
1701     return false;
1702   return IdInfo->getName().endswith_lower("end");
1703 }
1704
1705 bool isAssignCall(const FunctionDecl *Func) {
1706   const auto *IdInfo = Func->getIdentifier();
1707   if (!IdInfo)
1708     return false;
1709   if (Func->getNumParams() > 2)
1710     return false;
1711   return IdInfo->getName() == "assign";
1712 }
1713
1714 bool isClearCall(const FunctionDecl *Func) {
1715   const auto *IdInfo = Func->getIdentifier();
1716   if (!IdInfo)
1717     return false;
1718   if (Func->getNumParams() > 0)
1719     return false;
1720   return IdInfo->getName() == "clear";
1721 }
1722
1723 bool isPushBackCall(const FunctionDecl *Func) {
1724   const auto *IdInfo = Func->getIdentifier();
1725   if (!IdInfo)
1726     return false;
1727   if (Func->getNumParams() != 1)
1728     return false;
1729   return IdInfo->getName() == "push_back";
1730 }
1731
1732 bool isEmplaceBackCall(const FunctionDecl *Func) {
1733   const auto *IdInfo = Func->getIdentifier();
1734   if (!IdInfo)
1735     return false;
1736   if (Func->getNumParams() < 1)
1737     return false;
1738   return IdInfo->getName() == "emplace_back";
1739 }
1740
1741 bool isPopBackCall(const FunctionDecl *Func) {
1742   const auto *IdInfo = Func->getIdentifier();
1743   if (!IdInfo)
1744     return false;
1745   if (Func->getNumParams() > 0)
1746     return false;
1747   return IdInfo->getName() == "pop_back";
1748 }
1749
1750 bool isPushFrontCall(const FunctionDecl *Func) {
1751   const auto *IdInfo = Func->getIdentifier();
1752   if (!IdInfo)
1753     return false;
1754   if (Func->getNumParams() != 1)
1755     return false;
1756   return IdInfo->getName() == "push_front";
1757 }
1758
1759 bool isEmplaceFrontCall(const FunctionDecl *Func) {
1760   const auto *IdInfo = Func->getIdentifier();
1761   if (!IdInfo)
1762     return false;
1763   if (Func->getNumParams() < 1)
1764     return false;
1765   return IdInfo->getName() == "emplace_front";
1766 }
1767
1768 bool isPopFrontCall(const FunctionDecl *Func) {
1769   const auto *IdInfo = Func->getIdentifier();
1770   if (!IdInfo)
1771     return false;
1772   if (Func->getNumParams() > 0)
1773     return false;
1774   return IdInfo->getName() == "pop_front";
1775 }
1776
1777 bool isInsertCall(const FunctionDecl *Func) {
1778   const auto *IdInfo = Func->getIdentifier();
1779   if (!IdInfo)
1780     return false;
1781   if (Func->getNumParams() < 2 || Func->getNumParams() > 3)
1782     return false;
1783   if (!isIteratorType(Func->getParamDecl(0)->getType()))
1784     return false;
1785   return IdInfo->getName() == "insert";
1786 }
1787
1788 bool isEmplaceCall(const FunctionDecl *Func) {
1789   const auto *IdInfo = Func->getIdentifier();
1790   if (!IdInfo)
1791     return false;
1792   if (Func->getNumParams() < 2)
1793     return false;
1794   if (!isIteratorType(Func->getParamDecl(0)->getType()))
1795     return false;
1796   return IdInfo->getName() == "emplace";
1797 }
1798
1799 bool isEraseCall(const FunctionDecl *Func) {
1800   const auto *IdInfo = Func->getIdentifier();
1801   if (!IdInfo)
1802     return false;
1803   if (Func->getNumParams() < 1 || Func->getNumParams() > 2)
1804     return false;
1805   if (!isIteratorType(Func->getParamDecl(0)->getType()))
1806     return false;
1807   if (Func->getNumParams() == 2 &&
1808       !isIteratorType(Func->getParamDecl(1)->getType()))
1809     return false;
1810   return IdInfo->getName() == "erase";
1811 }
1812
1813 bool isEraseAfterCall(const FunctionDecl *Func) {
1814   const auto *IdInfo = Func->getIdentifier();
1815   if (!IdInfo)
1816     return false;
1817   if (Func->getNumParams() < 1 || Func->getNumParams() > 2)
1818     return false;
1819   if (!isIteratorType(Func->getParamDecl(0)->getType()))
1820     return false;
1821   if (Func->getNumParams() == 2 &&
1822       !isIteratorType(Func->getParamDecl(1)->getType()))
1823     return false;
1824   return IdInfo->getName() == "erase_after";
1825 }
1826
1827 bool isAssignmentOperator(OverloadedOperatorKind OK) { return OK == OO_Equal; }
1828
1829 bool isSimpleComparisonOperator(OverloadedOperatorKind OK) {
1830   return OK == OO_EqualEqual || OK == OO_ExclaimEqual;
1831 }
1832
1833 bool isAccessOperator(OverloadedOperatorKind OK) {
1834   return isDereferenceOperator(OK) || isIncrementOperator(OK) ||
1835          isDecrementOperator(OK) || isRandomIncrOrDecrOperator(OK);
1836 }
1837
1838 bool isDereferenceOperator(OverloadedOperatorKind OK) {
1839   return OK == OO_Star || OK == OO_Arrow || OK == OO_ArrowStar ||
1840          OK == OO_Subscript;
1841 }
1842
1843 bool isIncrementOperator(OverloadedOperatorKind OK) {
1844   return OK == OO_PlusPlus;
1845 }
1846
1847 bool isDecrementOperator(OverloadedOperatorKind OK) {
1848   return OK == OO_MinusMinus;
1849 }
1850
1851 bool isRandomIncrOrDecrOperator(OverloadedOperatorKind OK) {
1852   return OK == OO_Plus || OK == OO_PlusEqual || OK == OO_Minus ||
1853          OK == OO_MinusEqual;
1854 }
1855
1856 BinaryOperator::Opcode getOpcode(const SymExpr *SE) {
1857   if (const auto *BSE = dyn_cast<BinarySymExpr>(SE)) {
1858     return BSE->getOpcode();
1859   } else if (const auto *SC = dyn_cast<SymbolConjured>(SE)) {
1860     const auto *COE = dyn_cast_or_null<CXXOperatorCallExpr>(SC->getStmt());
1861     if (!COE)
1862       return BO_Comma; // Extremal value, neither EQ nor NE
1863     if (COE->getOperator() == OO_EqualEqual) {
1864       return BO_EQ;
1865     } else if (COE->getOperator() == OO_ExclaimEqual) {
1866       return BO_NE;
1867     }
1868     return BO_Comma; // Extremal value, neither EQ nor NE
1869   }
1870   return BO_Comma; // Extremal value, neither EQ nor NE
1871 }
1872
1873 bool hasSubscriptOperator(ProgramStateRef State, const MemRegion *Reg) {
1874   const auto *CRD = getCXXRecordDecl(State, Reg);
1875   if (!CRD)
1876     return false;
1877
1878   for (const auto *Method : CRD->methods()) {
1879     if (!Method->isOverloadedOperator())
1880       continue;
1881     const auto OPK = Method->getOverloadedOperator();
1882     if (OPK == OO_Subscript) {
1883       return true;
1884     }
1885   }
1886   return false;
1887 }
1888
1889 bool frontModifiable(ProgramStateRef State, const MemRegion *Reg) {
1890   const auto *CRD = getCXXRecordDecl(State, Reg);
1891   if (!CRD)
1892     return false;
1893
1894   for (const auto *Method : CRD->methods()) {
1895     if (!Method->getDeclName().isIdentifier())
1896       continue;
1897     if (Method->getName() == "push_front" || Method->getName() == "pop_front") {
1898       return true;
1899     }
1900   }
1901   return false;
1902 }
1903
1904 bool backModifiable(ProgramStateRef State, const MemRegion *Reg) {
1905   const auto *CRD = getCXXRecordDecl(State, Reg);
1906   if (!CRD)
1907     return false;
1908
1909   for (const auto *Method : CRD->methods()) {
1910     if (!Method->getDeclName().isIdentifier())
1911       continue;
1912     if (Method->getName() == "push_back" || Method->getName() == "pop_back") {
1913       return true;
1914     }
1915   }
1916   return false;
1917 }
1918
1919 const CXXRecordDecl *getCXXRecordDecl(ProgramStateRef State,
1920                                       const MemRegion *Reg) {
1921   auto TI = getDynamicTypeInfo(State, Reg);
1922   if (!TI.isValid())
1923     return nullptr;
1924
1925   auto Type = TI.getType();
1926   if (const auto *RefT = Type->getAs<ReferenceType>()) {
1927     Type = RefT->getPointeeType();
1928   }
1929
1930   return Type->getUnqualifiedDesugaredType()->getAsCXXRecordDecl();
1931 }
1932
1933 const RegionOrSymbol getRegionOrSymbol(const SVal &Val) {
1934   if (const auto Reg = Val.getAsRegion()) {
1935     return Reg;
1936   } else if (const auto Sym = Val.getAsSymbol()) {
1937     return Sym;
1938   } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
1939     return LCVal->getRegion();
1940   }
1941   return RegionOrSymbol();
1942 }
1943
1944 const ProgramStateRef processComparison(ProgramStateRef State,
1945                                         RegionOrSymbol LVal,
1946                                         RegionOrSymbol RVal, bool Equal) {
1947   const auto *LPos = getIteratorPosition(State, LVal);
1948   const auto *RPos = getIteratorPosition(State, RVal);
1949   if (LPos && !RPos) {
1950     State = adjustIteratorPosition(State, RVal, *LPos, Equal);
1951   } else if (!LPos && RPos) {
1952     State = adjustIteratorPosition(State, LVal, *RPos, Equal);
1953   } else if (LPos && RPos) {
1954     State = relateIteratorPositions(State, *LPos, *RPos, Equal);
1955   }
1956   return State;
1957 }
1958
1959 const ProgramStateRef saveComparison(ProgramStateRef State,
1960                                      const SymExpr *Condition, const SVal &LVal,
1961                                      const SVal &RVal, bool Eq) {
1962   const auto Left = getRegionOrSymbol(LVal);
1963   const auto Right = getRegionOrSymbol(RVal);
1964   if (!Left || !Right)
1965     return State;
1966   return State->set<IteratorComparisonMap>(Condition,
1967                                            IteratorComparison(Left, Right, Eq));
1968 }
1969
1970 const IteratorComparison *loadComparison(ProgramStateRef State,
1971                                          const SymExpr *Condition) {
1972   return State->get<IteratorComparisonMap>(Condition);
1973 }
1974
1975 SymbolRef getContainerBegin(ProgramStateRef State, const MemRegion *Cont) {
1976   const auto *CDataPtr = getContainerData(State, Cont);
1977   if (!CDataPtr)
1978     return nullptr;
1979
1980   return CDataPtr->getBegin();
1981 }
1982
1983 SymbolRef getContainerEnd(ProgramStateRef State, const MemRegion *Cont) {
1984   const auto *CDataPtr = getContainerData(State, Cont);
1985   if (!CDataPtr)
1986     return nullptr;
1987
1988   return CDataPtr->getEnd();
1989 }
1990
1991 ProgramStateRef createContainerBegin(ProgramStateRef State,
1992                                      const MemRegion *Cont,
1993                                      const SymbolRef Sym) {
1994   // Only create if it does not exist
1995   const auto *CDataPtr = getContainerData(State, Cont);
1996   if (CDataPtr) {
1997     if (CDataPtr->getBegin()) {
1998       return State;
1999     }
2000     const auto CData = CDataPtr->newBegin(Sym);
2001     return setContainerData(State, Cont, CData);
2002   }
2003   const auto CData = ContainerData::fromBegin(Sym);
2004   return setContainerData(State, Cont, CData);
2005 }
2006
2007 ProgramStateRef createContainerEnd(ProgramStateRef State, const MemRegion *Cont,
2008                                    const SymbolRef Sym) {
2009   // Only create if it does not exist
2010   const auto *CDataPtr = getContainerData(State, Cont);
2011   if (CDataPtr) {
2012     if (CDataPtr->getEnd()) {
2013       return State;
2014     }
2015     const auto CData = CDataPtr->newEnd(Sym);
2016     return setContainerData(State, Cont, CData);
2017   }
2018   const auto CData = ContainerData::fromEnd(Sym);
2019   return setContainerData(State, Cont, CData);
2020 }
2021
2022 const ContainerData *getContainerData(ProgramStateRef State,
2023                                       const MemRegion *Cont) {
2024   return State->get<ContainerMap>(Cont);
2025 }
2026
2027 ProgramStateRef setContainerData(ProgramStateRef State, const MemRegion *Cont,
2028                                  const ContainerData &CData) {
2029   return State->set<ContainerMap>(Cont, CData);
2030 }
2031
2032 const IteratorPosition *getIteratorPosition(ProgramStateRef State,
2033                                             const SVal &Val) {
2034   if (auto Reg = Val.getAsRegion()) {
2035     Reg = Reg->getMostDerivedObjectRegion();
2036     return State->get<IteratorRegionMap>(Reg);
2037   } else if (const auto Sym = Val.getAsSymbol()) {
2038     return State->get<IteratorSymbolMap>(Sym);
2039   } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
2040     return State->get<IteratorRegionMap>(LCVal->getRegion());
2041   }
2042   return nullptr;
2043 }
2044
2045 const IteratorPosition *getIteratorPosition(ProgramStateRef State,
2046                                             RegionOrSymbol RegOrSym) {
2047   if (RegOrSym.is<const MemRegion *>()) {
2048     auto Reg = RegOrSym.get<const MemRegion *>()->getMostDerivedObjectRegion();
2049     return State->get<IteratorRegionMap>(Reg);
2050   } else if (RegOrSym.is<SymbolRef>()) {
2051     return State->get<IteratorSymbolMap>(RegOrSym.get<SymbolRef>());
2052   }
2053   return nullptr;
2054 }
2055
2056 ProgramStateRef setIteratorPosition(ProgramStateRef State, const SVal &Val,
2057                                     const IteratorPosition &Pos) {
2058   if (auto Reg = Val.getAsRegion()) {
2059     Reg = Reg->getMostDerivedObjectRegion();
2060     return State->set<IteratorRegionMap>(Reg, Pos);
2061   } else if (const auto Sym = Val.getAsSymbol()) {
2062     return State->set<IteratorSymbolMap>(Sym, Pos);
2063   } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
2064     return State->set<IteratorRegionMap>(LCVal->getRegion(), Pos);
2065   }
2066   return nullptr;
2067 }
2068
2069 ProgramStateRef setIteratorPosition(ProgramStateRef State,
2070                                     RegionOrSymbol RegOrSym,
2071                                     const IteratorPosition &Pos) {
2072   if (RegOrSym.is<const MemRegion *>()) {
2073     auto Reg = RegOrSym.get<const MemRegion *>()->getMostDerivedObjectRegion();
2074     return State->set<IteratorRegionMap>(Reg, Pos);
2075   } else if (RegOrSym.is<SymbolRef>()) {
2076     return State->set<IteratorSymbolMap>(RegOrSym.get<SymbolRef>(), Pos);
2077   }
2078   return nullptr;
2079 }
2080
2081 ProgramStateRef removeIteratorPosition(ProgramStateRef State, const SVal &Val) {
2082   if (auto Reg = Val.getAsRegion()) {
2083     Reg = Reg->getMostDerivedObjectRegion();
2084     return State->remove<IteratorRegionMap>(Reg);
2085   } else if (const auto Sym = Val.getAsSymbol()) {
2086     return State->remove<IteratorSymbolMap>(Sym);
2087   } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
2088     return State->remove<IteratorRegionMap>(LCVal->getRegion());
2089   }
2090   return nullptr;
2091 }
2092
2093 ProgramStateRef adjustIteratorPosition(ProgramStateRef State,
2094                                        RegionOrSymbol RegOrSym,
2095                                        const IteratorPosition &Pos,
2096                                        bool Equal) {
2097   if (Equal) {
2098     return setIteratorPosition(State, RegOrSym, Pos);
2099   } else {
2100     return State;
2101   }
2102 }
2103
2104 ProgramStateRef relateIteratorPositions(ProgramStateRef State,
2105                                         const IteratorPosition &Pos1,
2106                                         const IteratorPosition &Pos2,
2107                                         bool Equal) {
2108   auto &SVB = State->getStateManager().getSValBuilder();
2109
2110   // FIXME: This code should be reworked as follows:
2111   // 1. Subtract the operands using evalBinOp().
2112   // 2. Assume that the result doesn't overflow.
2113   // 3. Compare the result to 0.
2114   // 4. Assume the result of the comparison.
2115   const auto comparison =
2116       SVB.evalBinOp(State, BO_EQ, nonloc::SymbolVal(Pos1.getOffset()),
2117                     nonloc::SymbolVal(Pos2.getOffset()),
2118                     SVB.getConditionType());
2119
2120   assert(comparison.getAs<DefinedSVal>() &&
2121     "Symbol comparison must be a `DefinedSVal`");
2122
2123   auto NewState = State->assume(comparison.castAs<DefinedSVal>(), Equal);
2124   if (const auto CompSym = comparison.getAsSymbol()) {
2125     assert(isa<SymIntExpr>(CompSym) &&
2126            "Symbol comparison must be a `SymIntExpr`");
2127     assert(BinaryOperator::isComparisonOp(
2128                cast<SymIntExpr>(CompSym)->getOpcode()) &&
2129            "Symbol comparison must be a comparison");
2130     return assumeNoOverflow(NewState, cast<SymIntExpr>(CompSym)->getLHS(), 2);
2131   }
2132
2133   return NewState;
2134 }
2135
2136 bool hasLiveIterators(ProgramStateRef State, const MemRegion *Cont) {
2137   auto RegionMap = State->get<IteratorRegionMap>();
2138   for (const auto Reg : RegionMap) {
2139     if (Reg.second.getContainer() == Cont)
2140       return true;
2141   }
2142
2143   auto SymbolMap = State->get<IteratorSymbolMap>();
2144   for (const auto Sym : SymbolMap) {
2145     if (Sym.second.getContainer() == Cont)
2146       return true;
2147   }
2148
2149   return false;
2150 }
2151
2152 bool isBoundThroughLazyCompoundVal(const Environment &Env,
2153                                    const MemRegion *Reg) {
2154   for (const auto Binding: Env) {
2155     if (const auto LCVal = Binding.second.getAs<nonloc::LazyCompoundVal>()) {
2156       if (LCVal->getRegion() == Reg)
2157         return true;
2158     }
2159   }
2160
2161   return false;
2162 }
2163
2164 template <typename Condition, typename Process>
2165 ProgramStateRef processIteratorPositions(ProgramStateRef State, Condition Cond,
2166                                          Process Proc) {
2167   auto &RegionMapFactory = State->get_context<IteratorRegionMap>();
2168   auto RegionMap = State->get<IteratorRegionMap>();
2169   bool Changed = false;
2170   for (const auto Reg : RegionMap) {
2171     if (Cond(Reg.second)) {
2172       RegionMap = RegionMapFactory.add(RegionMap, Reg.first, Proc(Reg.second));
2173       Changed = true;
2174     }
2175   }
2176
2177   if (Changed)
2178     State = State->set<IteratorRegionMap>(RegionMap);
2179
2180   auto &SymbolMapFactory = State->get_context<IteratorSymbolMap>();
2181   auto SymbolMap = State->get<IteratorSymbolMap>();
2182   Changed = false;
2183   for (const auto Sym : SymbolMap) {
2184     if (Cond(Sym.second)) {
2185       SymbolMap = SymbolMapFactory.add(SymbolMap, Sym.first, Proc(Sym.second));
2186       Changed = true;
2187     }
2188   }
2189
2190   if (Changed)
2191     State = State->set<IteratorSymbolMap>(SymbolMap);
2192
2193   return State;
2194 }
2195
2196 ProgramStateRef invalidateAllIteratorPositions(ProgramStateRef State,
2197                                                const MemRegion *Cont) {
2198   auto MatchCont = [&](const IteratorPosition &Pos) {
2199     return Pos.getContainer() == Cont;
2200   };
2201   auto Invalidate = [&](const IteratorPosition &Pos) {
2202     return Pos.invalidate();
2203   };
2204   return processIteratorPositions(State, MatchCont, Invalidate);
2205 }
2206
2207 ProgramStateRef
2208 invalidateAllIteratorPositionsExcept(ProgramStateRef State,
2209                                      const MemRegion *Cont, SymbolRef Offset,
2210                                      BinaryOperator::Opcode Opc) {
2211   auto MatchContAndCompare = [&](const IteratorPosition &Pos) {
2212     return Pos.getContainer() == Cont &&
2213            !compare(State, Pos.getOffset(), Offset, Opc);
2214   };
2215   auto Invalidate = [&](const IteratorPosition &Pos) {
2216     return Pos.invalidate();
2217   };
2218   return processIteratorPositions(State, MatchContAndCompare, Invalidate);
2219 }
2220
2221 ProgramStateRef invalidateIteratorPositions(ProgramStateRef State,
2222                                             SymbolRef Offset,
2223                                             BinaryOperator::Opcode Opc) {
2224   auto Compare = [&](const IteratorPosition &Pos) {
2225     return compare(State, Pos.getOffset(), Offset, Opc);
2226   };
2227   auto Invalidate = [&](const IteratorPosition &Pos) {
2228     return Pos.invalidate();
2229   };
2230   return processIteratorPositions(State, Compare, Invalidate);
2231 }
2232
2233 ProgramStateRef invalidateIteratorPositions(ProgramStateRef State,
2234                                             SymbolRef Offset1,
2235                                             BinaryOperator::Opcode Opc1,
2236                                             SymbolRef Offset2,
2237                                             BinaryOperator::Opcode Opc2) {
2238   auto Compare = [&](const IteratorPosition &Pos) {
2239     return compare(State, Pos.getOffset(), Offset1, Opc1) &&
2240            compare(State, Pos.getOffset(), Offset2, Opc2);
2241   };
2242   auto Invalidate = [&](const IteratorPosition &Pos) {
2243     return Pos.invalidate();
2244   };
2245   return processIteratorPositions(State, Compare, Invalidate);
2246 }
2247
2248 ProgramStateRef reassignAllIteratorPositions(ProgramStateRef State,
2249                                              const MemRegion *Cont,
2250                                              const MemRegion *NewCont) {
2251   auto MatchCont = [&](const IteratorPosition &Pos) {
2252     return Pos.getContainer() == Cont;
2253   };
2254   auto ReAssign = [&](const IteratorPosition &Pos) {
2255     return Pos.reAssign(NewCont);
2256   };
2257   return processIteratorPositions(State, MatchCont, ReAssign);
2258 }
2259
2260 ProgramStateRef reassignAllIteratorPositionsUnless(ProgramStateRef State,
2261                                                    const MemRegion *Cont,
2262                                                    const MemRegion *NewCont,
2263                                                    SymbolRef Offset,
2264                                                    BinaryOperator::Opcode Opc) {
2265   auto MatchContAndCompare = [&](const IteratorPosition &Pos) {
2266     return Pos.getContainer() == Cont &&
2267     !compare(State, Pos.getOffset(), Offset, Opc);
2268   };
2269   auto ReAssign = [&](const IteratorPosition &Pos) {
2270     return Pos.reAssign(NewCont);
2271   };
2272   return processIteratorPositions(State, MatchContAndCompare, ReAssign);
2273 }
2274
2275 // This function rebases symbolic expression `OldSym + Int` to `NewSym + Int`,
2276 // `OldSym - Int` to `NewSym - Int` and  `OldSym` to `NewSym` in any iterator
2277 // position offsets where `CondSym` is true.
2278 ProgramStateRef rebaseSymbolInIteratorPositionsIf(
2279     ProgramStateRef State, SValBuilder &SVB, SymbolRef OldSym,
2280     SymbolRef NewSym, SymbolRef CondSym, BinaryOperator::Opcode Opc) {
2281   auto LessThanEnd = [&](const IteratorPosition &Pos) {
2282     return compare(State, Pos.getOffset(), CondSym, Opc);
2283   };
2284   auto RebaseSymbol = [&](const IteratorPosition &Pos) {
2285     return Pos.setTo(rebaseSymbol(State, SVB, Pos.getOffset(), OldSym,
2286                                    NewSym));
2287   };
2288   return processIteratorPositions(State, LessThanEnd, RebaseSymbol);
2289 }
2290
2291 // This function rebases symbolic expression `OldExpr + Int` to `NewExpr + Int`,
2292 // `OldExpr - Int` to `NewExpr - Int` and  `OldExpr` to `NewExpr` in expression
2293 // `OrigExpr`.
2294 SymbolRef rebaseSymbol(ProgramStateRef State, SValBuilder &SVB,
2295                        SymbolRef OrigExpr, SymbolRef OldExpr,
2296                        SymbolRef NewSym) {
2297   auto &SymMgr = SVB.getSymbolManager();
2298   auto Diff = SVB.evalBinOpNN(State, BO_Sub, nonloc::SymbolVal(OrigExpr),
2299                               nonloc::SymbolVal(OldExpr), 
2300                               SymMgr.getType(OrigExpr));
2301
2302   const auto DiffInt = Diff.getAs<nonloc::ConcreteInt>();
2303   if (!DiffInt)
2304     return OrigExpr;
2305
2306   return SVB.evalBinOpNN(State, BO_Add, *DiffInt, nonloc::SymbolVal(NewSym),
2307                          SymMgr.getType(OrigExpr)).getAsSymbol();
2308 }
2309
2310 bool isZero(ProgramStateRef State, const NonLoc &Val) {
2311   auto &BVF = State->getBasicVals();
2312   return compare(State, Val,
2313                  nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))),
2314                  BO_EQ);
2315 }
2316
2317 bool isPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos) {
2318   const auto *Cont = Pos.getContainer();
2319   const auto *CData = getContainerData(State, Cont);
2320   if (!CData)
2321     return false;
2322
2323   const auto End = CData->getEnd();
2324   if (End) {
2325     if (isEqual(State, Pos.getOffset(), End)) {
2326       return true;
2327     }
2328   }
2329
2330   return false;
2331 }
2332
2333 bool isAheadOfRange(ProgramStateRef State, const IteratorPosition &Pos) {
2334   const auto *Cont = Pos.getContainer();
2335   const auto *CData = getContainerData(State, Cont);
2336   if (!CData)
2337     return false;
2338
2339   const auto Beg = CData->getBegin();
2340   if (Beg) {
2341     if (isLess(State, Pos.getOffset(), Beg)) {
2342       return true;
2343     }
2344   }
2345
2346   return false;
2347 }
2348
2349 bool isBehindPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos) {
2350   const auto *Cont = Pos.getContainer();
2351   const auto *CData = getContainerData(State, Cont);
2352   if (!CData)
2353     return false;
2354
2355   const auto End = CData->getEnd();
2356   if (End) {
2357     if (isGreater(State, Pos.getOffset(), End)) {
2358       return true;
2359     }
2360   }
2361
2362   return false;
2363 }
2364
2365 bool isLess(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) {
2366   return compare(State, Sym1, Sym2, BO_LT);
2367 }
2368
2369 bool isGreater(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) {
2370   return compare(State, Sym1, Sym2, BO_GT);
2371 }
2372
2373 bool isEqual(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) {
2374   return compare(State, Sym1, Sym2, BO_EQ);
2375 }
2376
2377 bool compare(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2,
2378              BinaryOperator::Opcode Opc) {
2379   return compare(State, nonloc::SymbolVal(Sym1), nonloc::SymbolVal(Sym2), Opc);
2380 }
2381
2382
2383 bool compare(ProgramStateRef State, NonLoc NL1, NonLoc NL2,
2384              BinaryOperator::Opcode Opc) {
2385   auto &SVB = State->getStateManager().getSValBuilder();
2386
2387   const auto comparison =
2388     SVB.evalBinOp(State, Opc, NL1, NL2, SVB.getConditionType());
2389
2390   assert(comparison.getAs<DefinedSVal>() &&
2391     "Symbol comparison must be a `DefinedSVal`");
2392
2393   return !State->assume(comparison.castAs<DefinedSVal>(), false);
2394 }
2395
2396 } // namespace
2397
2398 #define REGISTER_CHECKER(name)                                                 \
2399   void ento::register##name(CheckerManager &Mgr) {                             \
2400     auto *checker = Mgr.registerChecker<IteratorChecker>();                    \
2401     checker->ChecksEnabled[IteratorChecker::CK_##name] = true;                 \
2402     checker->CheckNames[IteratorChecker::CK_##name] =                          \
2403         Mgr.getCurrentCheckName();                                             \
2404   }
2405
2406 REGISTER_CHECKER(IteratorRangeChecker)
2407 REGISTER_CHECKER(MismatchedIteratorChecker)
2408 REGISTER_CHECKER(InvalidatedIteratorChecker)