xref: /freebsd-src/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp (revision e8d8bef961a50d4dc22501cde4fb9fb0be1b2532)
1480093f4SDimitry Andric //===-- IteratorModeling.cpp --------------------------------------*- C++ -*--//
2480093f4SDimitry Andric //
3480093f4SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4480093f4SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5480093f4SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6480093f4SDimitry Andric //
7480093f4SDimitry Andric //===----------------------------------------------------------------------===//
8480093f4SDimitry Andric //
95ffd83dbSDimitry Andric // Defines a modeling-checker for modeling STL iterator-like iterators.
10480093f4SDimitry Andric //
11480093f4SDimitry Andric //===----------------------------------------------------------------------===//
12480093f4SDimitry Andric //
13480093f4SDimitry Andric // In the code, iterator can be represented as a:
14480093f4SDimitry Andric // * type-I: typedef-ed pointer. Operations over such iterator, such as
15480093f4SDimitry Andric //           comparisons or increments, are modeled straightforwardly by the
16480093f4SDimitry Andric //           analyzer.
17480093f4SDimitry Andric // * type-II: structure with its method bodies available.  Operations over such
18480093f4SDimitry Andric //            iterator are inlined by the analyzer, and results of modeling
19480093f4SDimitry Andric //            these operations are exposing implementation details of the
20480093f4SDimitry Andric //            iterators, which is not necessarily helping.
21480093f4SDimitry Andric // * type-III: completely opaque structure. Operations over such iterator are
22480093f4SDimitry Andric //             modeled conservatively, producing conjured symbols everywhere.
23480093f4SDimitry Andric //
24480093f4SDimitry Andric // To handle all these types in a common way we introduce a structure called
25480093f4SDimitry Andric // IteratorPosition which is an abstraction of the position the iterator
26480093f4SDimitry Andric // represents using symbolic expressions. The checker handles all the
27480093f4SDimitry Andric // operations on this structure.
28480093f4SDimitry Andric //
29480093f4SDimitry Andric // Additionally, depending on the circumstances, operators of types II and III
30480093f4SDimitry Andric // can be represented as:
31480093f4SDimitry Andric // * type-IIa, type-IIIa: conjured structure symbols - when returned by value
32480093f4SDimitry Andric //                        from conservatively evaluated methods such as
33480093f4SDimitry Andric //                        `.begin()`.
34480093f4SDimitry Andric // * type-IIb, type-IIIb: memory regions of iterator-typed objects, such as
35480093f4SDimitry Andric //                        variables or temporaries, when the iterator object is
36480093f4SDimitry Andric //                        currently treated as an lvalue.
37480093f4SDimitry Andric // * type-IIc, type-IIIc: compound values of iterator-typed objects, when the
38480093f4SDimitry Andric //                        iterator object is treated as an rvalue taken of a
39480093f4SDimitry Andric //                        particular lvalue, eg. a copy of "type-a" iterator
40480093f4SDimitry Andric //                        object, or an iterator that existed before the
41480093f4SDimitry Andric //                        analysis has started.
42480093f4SDimitry Andric //
43480093f4SDimitry Andric // To handle any of these three different representations stored in an SVal we
44480093f4SDimitry Andric // use setter and getters functions which separate the three cases. To store
45480093f4SDimitry Andric // them we use a pointer union of symbol and memory region.
46480093f4SDimitry Andric //
47480093f4SDimitry Andric // The checker works the following way: We record the begin and the
48480093f4SDimitry Andric // past-end iterator for all containers whenever their `.begin()` and `.end()`
49480093f4SDimitry Andric // are called. Since the Constraint Manager cannot handle such SVals we need
50480093f4SDimitry Andric // to take over its role. We post-check equality and non-equality comparisons
51480093f4SDimitry Andric // and record that the two sides are equal if we are in the 'equal' branch
52480093f4SDimitry Andric // (true-branch for `==` and false-branch for `!=`).
53480093f4SDimitry Andric //
54480093f4SDimitry Andric // In case of type-I or type-II iterators we get a concrete integer as a result
55480093f4SDimitry Andric // of the comparison (1 or 0) but in case of type-III we only get a Symbol. In
56480093f4SDimitry Andric // this latter case we record the symbol and reload it in evalAssume() and do
57480093f4SDimitry Andric // the propagation there. We also handle (maybe double) negated comparisons
58480093f4SDimitry Andric // which are represented in the form of (x == 0 or x != 0) where x is the
59480093f4SDimitry Andric // comparison itself.
60480093f4SDimitry Andric //
61480093f4SDimitry Andric // Since `SimpleConstraintManager` cannot handle complex symbolic expressions
62480093f4SDimitry Andric // we only use expressions of the format S, S+n or S-n for iterator positions
63480093f4SDimitry Andric // where S is a conjured symbol and n is an unsigned concrete integer. When
64480093f4SDimitry Andric // making an assumption e.g. `S1 + n == S2 + m` we store `S1 - S2 == m - n` as
65480093f4SDimitry Andric // a constraint which we later retrieve when doing an actual comparison.
66480093f4SDimitry Andric 
67480093f4SDimitry Andric #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
68480093f4SDimitry Andric #include "clang/AST/DeclTemplate.h"
69480093f4SDimitry Andric #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
70480093f4SDimitry Andric #include "clang/StaticAnalyzer/Core/Checker.h"
71480093f4SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
72480093f4SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
73480093f4SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h"
74480093f4SDimitry Andric 
75480093f4SDimitry Andric #include "Iterator.h"
76480093f4SDimitry Andric 
77480093f4SDimitry Andric #include <utility>
78480093f4SDimitry Andric 
79480093f4SDimitry Andric using namespace clang;
80480093f4SDimitry Andric using namespace ento;
81480093f4SDimitry Andric using namespace iterator;
82480093f4SDimitry Andric 
83480093f4SDimitry Andric namespace {
84480093f4SDimitry Andric 
85480093f4SDimitry Andric class IteratorModeling
865ffd83dbSDimitry Andric     : public Checker<check::PostCall, check::PostStmt<UnaryOperator>,
875ffd83dbSDimitry Andric                      check::PostStmt<BinaryOperator>,
885ffd83dbSDimitry Andric                      check::PostStmt<MaterializeTemporaryExpr>,
89480093f4SDimitry Andric                      check::Bind, check::LiveSymbols, check::DeadSymbols> {
90480093f4SDimitry Andric 
915ffd83dbSDimitry Andric   using AdvanceFn = void (IteratorModeling::*)(CheckerContext &, const Expr *,
925ffd83dbSDimitry Andric                                                SVal, SVal, SVal) const;
935ffd83dbSDimitry Andric 
945ffd83dbSDimitry Andric   void handleOverloadedOperator(CheckerContext &C, const CallEvent &Call,
955ffd83dbSDimitry Andric                                 OverloadedOperatorKind Op) const;
965ffd83dbSDimitry Andric   void handleAdvanceLikeFunction(CheckerContext &C, const CallEvent &Call,
975ffd83dbSDimitry Andric                                  const Expr *OrigExpr,
985ffd83dbSDimitry Andric                                  const AdvanceFn *Handler) const;
995ffd83dbSDimitry Andric 
100480093f4SDimitry Andric   void handleComparison(CheckerContext &C, const Expr *CE, SVal RetVal,
101480093f4SDimitry Andric                         const SVal &LVal, const SVal &RVal,
102480093f4SDimitry Andric                         OverloadedOperatorKind Op) const;
103480093f4SDimitry Andric   void processComparison(CheckerContext &C, ProgramStateRef State,
104480093f4SDimitry Andric                          SymbolRef Sym1, SymbolRef Sym2, const SVal &RetVal,
105480093f4SDimitry Andric                          OverloadedOperatorKind Op) const;
106480093f4SDimitry Andric   void handleIncrement(CheckerContext &C, const SVal &RetVal, const SVal &Iter,
107480093f4SDimitry Andric                        bool Postfix) const;
108480093f4SDimitry Andric   void handleDecrement(CheckerContext &C, const SVal &RetVal, const SVal &Iter,
109480093f4SDimitry Andric                        bool Postfix) const;
110480093f4SDimitry Andric   void handleRandomIncrOrDecr(CheckerContext &C, const Expr *CE,
111480093f4SDimitry Andric                               OverloadedOperatorKind Op, const SVal &RetVal,
112*e8d8bef9SDimitry Andric                               const SVal &Iterator, const SVal &Amount) const;
1135ffd83dbSDimitry Andric   void handlePtrIncrOrDecr(CheckerContext &C, const Expr *Iterator,
1145ffd83dbSDimitry Andric                            OverloadedOperatorKind OK, SVal Offset) const;
1155ffd83dbSDimitry Andric   void handleAdvance(CheckerContext &C, const Expr *CE, SVal RetVal, SVal Iter,
1165ffd83dbSDimitry Andric                      SVal Amount) const;
1175ffd83dbSDimitry Andric   void handlePrev(CheckerContext &C, const Expr *CE, SVal RetVal, SVal Iter,
1185ffd83dbSDimitry Andric                   SVal Amount) const;
1195ffd83dbSDimitry Andric   void handleNext(CheckerContext &C, const Expr *CE, SVal RetVal, SVal Iter,
1205ffd83dbSDimitry Andric                   SVal Amount) const;
121480093f4SDimitry Andric   void assignToContainer(CheckerContext &C, const Expr *CE, const SVal &RetVal,
122480093f4SDimitry Andric                          const MemRegion *Cont) const;
1235ffd83dbSDimitry Andric   bool noChangeInAdvance(CheckerContext &C, SVal Iter, const Expr *CE) const;
124480093f4SDimitry Andric   void printState(raw_ostream &Out, ProgramStateRef State, const char *NL,
125480093f4SDimitry Andric                   const char *Sep) const override;
126480093f4SDimitry Andric 
1275ffd83dbSDimitry Andric   // std::advance, std::prev & std::next
1285ffd83dbSDimitry Andric   CallDescriptionMap<AdvanceFn> AdvanceLikeFunctions = {
1295ffd83dbSDimitry Andric       // template<class InputIt, class Distance>
1305ffd83dbSDimitry Andric       // void advance(InputIt& it, Distance n);
1315ffd83dbSDimitry Andric       {{{"std", "advance"}, 2}, &IteratorModeling::handleAdvance},
1325ffd83dbSDimitry Andric 
1335ffd83dbSDimitry Andric       // template<class BidirIt>
1345ffd83dbSDimitry Andric       // BidirIt prev(
1355ffd83dbSDimitry Andric       //   BidirIt it,
1365ffd83dbSDimitry Andric       //   typename std::iterator_traits<BidirIt>::difference_type n = 1);
1375ffd83dbSDimitry Andric       {{{"std", "prev"}, 2}, &IteratorModeling::handlePrev},
1385ffd83dbSDimitry Andric 
1395ffd83dbSDimitry Andric       // template<class ForwardIt>
1405ffd83dbSDimitry Andric       // ForwardIt next(
1415ffd83dbSDimitry Andric       //   ForwardIt it,
1425ffd83dbSDimitry Andric       //   typename std::iterator_traits<ForwardIt>::difference_type n = 1);
1435ffd83dbSDimitry Andric       {{{"std", "next"}, 2}, &IteratorModeling::handleNext},
1445ffd83dbSDimitry Andric   };
1455ffd83dbSDimitry Andric 
146480093f4SDimitry Andric public:
1475ffd83dbSDimitry Andric   IteratorModeling() = default;
148480093f4SDimitry Andric 
149480093f4SDimitry Andric   void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
150480093f4SDimitry Andric   void checkBind(SVal Loc, SVal Val, const Stmt *S, CheckerContext &C) const;
1515ffd83dbSDimitry Andric   void checkPostStmt(const UnaryOperator *UO, CheckerContext &C) const;
1525ffd83dbSDimitry Andric   void checkPostStmt(const BinaryOperator *BO, CheckerContext &C) const;
153480093f4SDimitry Andric   void checkPostStmt(const CXXConstructExpr *CCE, CheckerContext &C) const;
154480093f4SDimitry Andric   void checkPostStmt(const DeclStmt *DS, CheckerContext &C) const;
155480093f4SDimitry Andric   void checkPostStmt(const MaterializeTemporaryExpr *MTE,
156480093f4SDimitry Andric                      CheckerContext &C) const;
157480093f4SDimitry Andric   void checkLiveSymbols(ProgramStateRef State, SymbolReaper &SR) const;
158480093f4SDimitry Andric   void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
159480093f4SDimitry Andric };
160480093f4SDimitry Andric 
161480093f4SDimitry Andric bool isSimpleComparisonOperator(OverloadedOperatorKind OK);
1625ffd83dbSDimitry Andric bool isSimpleComparisonOperator(BinaryOperatorKind OK);
163480093f4SDimitry Andric ProgramStateRef removeIteratorPosition(ProgramStateRef State, const SVal &Val);
164480093f4SDimitry Andric ProgramStateRef relateSymbols(ProgramStateRef State, SymbolRef Sym1,
165480093f4SDimitry Andric                               SymbolRef Sym2, bool Equal);
166480093f4SDimitry Andric bool isBoundThroughLazyCompoundVal(const Environment &Env,
167480093f4SDimitry Andric                                    const MemRegion *Reg);
1685ffd83dbSDimitry Andric const ExplodedNode *findCallEnter(const ExplodedNode *Node, const Expr *Call);
169480093f4SDimitry Andric 
170480093f4SDimitry Andric } // namespace
171480093f4SDimitry Andric 
172480093f4SDimitry Andric void IteratorModeling::checkPostCall(const CallEvent &Call,
173480093f4SDimitry Andric                                      CheckerContext &C) const {
174480093f4SDimitry Andric   // Record new iterator positions and iterator position changes
175480093f4SDimitry Andric   const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
176480093f4SDimitry Andric   if (!Func)
177480093f4SDimitry Andric     return;
178480093f4SDimitry Andric 
179480093f4SDimitry Andric   if (Func->isOverloadedOperator()) {
180480093f4SDimitry Andric     const auto Op = Func->getOverloadedOperator();
1815ffd83dbSDimitry Andric     handleOverloadedOperator(C, Call, Op);
182480093f4SDimitry Andric     return;
183480093f4SDimitry Andric   }
184480093f4SDimitry Andric 
185480093f4SDimitry Andric   const auto *OrigExpr = Call.getOriginExpr();
186480093f4SDimitry Andric   if (!OrigExpr)
187480093f4SDimitry Andric     return;
188480093f4SDimitry Andric 
1895ffd83dbSDimitry Andric   const AdvanceFn *Handler = AdvanceLikeFunctions.lookup(Call);
1905ffd83dbSDimitry Andric   if (Handler) {
1915ffd83dbSDimitry Andric     handleAdvanceLikeFunction(C, Call, OrigExpr, Handler);
1925ffd83dbSDimitry Andric     return;
1935ffd83dbSDimitry Andric   }
1945ffd83dbSDimitry Andric 
195480093f4SDimitry Andric   if (!isIteratorType(Call.getResultType()))
196480093f4SDimitry Andric     return;
197480093f4SDimitry Andric 
198480093f4SDimitry Andric   auto State = C.getState();
199480093f4SDimitry Andric 
200480093f4SDimitry Andric   // Already bound to container?
201480093f4SDimitry Andric   if (getIteratorPosition(State, Call.getReturnValue()))
202480093f4SDimitry Andric     return;
203480093f4SDimitry Andric 
204480093f4SDimitry Andric   // Copy-like and move constructors
205480093f4SDimitry Andric   if (isa<CXXConstructorCall>(&Call) && Call.getNumArgs() == 1) {
206480093f4SDimitry Andric     if (const auto *Pos = getIteratorPosition(State, Call.getArgSVal(0))) {
207480093f4SDimitry Andric       State = setIteratorPosition(State, Call.getReturnValue(), *Pos);
208480093f4SDimitry Andric       if (cast<CXXConstructorDecl>(Func)->isMoveConstructor()) {
209480093f4SDimitry Andric         State = removeIteratorPosition(State, Call.getArgSVal(0));
210480093f4SDimitry Andric       }
211480093f4SDimitry Andric       C.addTransition(State);
212480093f4SDimitry Andric       return;
213480093f4SDimitry Andric     }
214480093f4SDimitry Andric   }
215480093f4SDimitry Andric 
216480093f4SDimitry Andric   // Assumption: if return value is an iterator which is not yet bound to a
2175ffd83dbSDimitry Andric   //             container, then look for the first iterator argument of the
2185ffd83dbSDimitry Andric   //             same type as the return value and bind the return value to
2195ffd83dbSDimitry Andric   //             the same container. This approach works for STL algorithms.
220480093f4SDimitry Andric   // FIXME: Add a more conservative mode
221480093f4SDimitry Andric   for (unsigned i = 0; i < Call.getNumArgs(); ++i) {
2225ffd83dbSDimitry Andric     if (isIteratorType(Call.getArgExpr(i)->getType()) &&
2235ffd83dbSDimitry Andric         Call.getArgExpr(i)->getType().getNonReferenceType().getDesugaredType(
2245ffd83dbSDimitry Andric             C.getASTContext()).getTypePtr() ==
2255ffd83dbSDimitry Andric         Call.getResultType().getDesugaredType(C.getASTContext()).getTypePtr()) {
226480093f4SDimitry Andric       if (const auto *Pos = getIteratorPosition(State, Call.getArgSVal(i))) {
227480093f4SDimitry Andric         assignToContainer(C, OrigExpr, Call.getReturnValue(),
228480093f4SDimitry Andric                           Pos->getContainer());
229480093f4SDimitry Andric         return;
230480093f4SDimitry Andric       }
231480093f4SDimitry Andric     }
232480093f4SDimitry Andric   }
233480093f4SDimitry Andric }
234480093f4SDimitry Andric 
235480093f4SDimitry Andric void IteratorModeling::checkBind(SVal Loc, SVal Val, const Stmt *S,
236480093f4SDimitry Andric                                  CheckerContext &C) const {
237480093f4SDimitry Andric   auto State = C.getState();
238480093f4SDimitry Andric   const auto *Pos = getIteratorPosition(State, Val);
239480093f4SDimitry Andric   if (Pos) {
240480093f4SDimitry Andric     State = setIteratorPosition(State, Loc, *Pos);
241480093f4SDimitry Andric     C.addTransition(State);
242480093f4SDimitry Andric   } else {
243480093f4SDimitry Andric     const auto *OldPos = getIteratorPosition(State, Loc);
244480093f4SDimitry Andric     if (OldPos) {
245480093f4SDimitry Andric       State = removeIteratorPosition(State, Loc);
246480093f4SDimitry Andric       C.addTransition(State);
247480093f4SDimitry Andric     }
248480093f4SDimitry Andric   }
249480093f4SDimitry Andric }
250480093f4SDimitry Andric 
2515ffd83dbSDimitry Andric void IteratorModeling::checkPostStmt(const UnaryOperator *UO,
2525ffd83dbSDimitry Andric                                      CheckerContext &C) const {
2535ffd83dbSDimitry Andric   UnaryOperatorKind OK = UO->getOpcode();
2545ffd83dbSDimitry Andric   if (!isIncrementOperator(OK) && !isDecrementOperator(OK))
2555ffd83dbSDimitry Andric     return;
2565ffd83dbSDimitry Andric 
2575ffd83dbSDimitry Andric   auto &SVB = C.getSValBuilder();
2585ffd83dbSDimitry Andric   handlePtrIncrOrDecr(C, UO->getSubExpr(),
2595ffd83dbSDimitry Andric                       isIncrementOperator(OK) ? OO_Plus : OO_Minus,
2605ffd83dbSDimitry Andric                       SVB.makeArrayIndex(1));
2615ffd83dbSDimitry Andric }
2625ffd83dbSDimitry Andric 
2635ffd83dbSDimitry Andric void IteratorModeling::checkPostStmt(const BinaryOperator *BO,
2645ffd83dbSDimitry Andric                                      CheckerContext &C) const {
265*e8d8bef9SDimitry Andric   const ProgramStateRef State = C.getState();
266*e8d8bef9SDimitry Andric   const BinaryOperatorKind OK = BO->getOpcode();
267*e8d8bef9SDimitry Andric   const Expr *const LHS = BO->getLHS();
268*e8d8bef9SDimitry Andric   const Expr *const RHS = BO->getRHS();
269*e8d8bef9SDimitry Andric   const SVal LVal = State->getSVal(LHS, C.getLocationContext());
270*e8d8bef9SDimitry Andric   const SVal RVal = State->getSVal(RHS, C.getLocationContext());
2715ffd83dbSDimitry Andric 
2725ffd83dbSDimitry Andric   if (isSimpleComparisonOperator(BO->getOpcode())) {
2735ffd83dbSDimitry Andric     SVal Result = State->getSVal(BO, C.getLocationContext());
2745ffd83dbSDimitry Andric     handleComparison(C, BO, Result, LVal, RVal,
2755ffd83dbSDimitry Andric                      BinaryOperator::getOverloadedOperator(OK));
2765ffd83dbSDimitry Andric   } else if (isRandomIncrOrDecrOperator(OK)) {
277*e8d8bef9SDimitry Andric     // In case of operator+ the iterator can be either on the LHS (eg.: it + 1),
278*e8d8bef9SDimitry Andric     // or on the RHS (eg.: 1 + it). Both cases are modeled.
279*e8d8bef9SDimitry Andric     const bool IsIterOnLHS = BO->getLHS()->getType()->isPointerType();
280*e8d8bef9SDimitry Andric     const Expr *const &IterExpr = IsIterOnLHS ? LHS : RHS;
281*e8d8bef9SDimitry Andric     const Expr *const &AmountExpr = IsIterOnLHS ? RHS : LHS;
282*e8d8bef9SDimitry Andric 
283*e8d8bef9SDimitry Andric     // The non-iterator side must have an integral or enumeration type.
284*e8d8bef9SDimitry Andric     if (!AmountExpr->getType()->isIntegralOrEnumerationType())
285*e8d8bef9SDimitry Andric       return;
286*e8d8bef9SDimitry Andric     const SVal &AmountVal = IsIterOnLHS ? RVal : LVal;
287*e8d8bef9SDimitry Andric     handlePtrIncrOrDecr(C, IterExpr, BinaryOperator::getOverloadedOperator(OK),
288*e8d8bef9SDimitry Andric                         AmountVal);
2895ffd83dbSDimitry Andric   }
2905ffd83dbSDimitry Andric }
2915ffd83dbSDimitry Andric 
292480093f4SDimitry Andric void IteratorModeling::checkPostStmt(const MaterializeTemporaryExpr *MTE,
293480093f4SDimitry Andric                                      CheckerContext &C) const {
294480093f4SDimitry Andric   /* Transfer iterator state to temporary objects */
295480093f4SDimitry Andric   auto State = C.getState();
296480093f4SDimitry Andric   const auto *Pos = getIteratorPosition(State, C.getSVal(MTE->getSubExpr()));
297480093f4SDimitry Andric   if (!Pos)
298480093f4SDimitry Andric     return;
299480093f4SDimitry Andric   State = setIteratorPosition(State, C.getSVal(MTE), *Pos);
300480093f4SDimitry Andric   C.addTransition(State);
301480093f4SDimitry Andric }
302480093f4SDimitry Andric 
303480093f4SDimitry Andric void IteratorModeling::checkLiveSymbols(ProgramStateRef State,
304480093f4SDimitry Andric                                         SymbolReaper &SR) const {
3055ffd83dbSDimitry Andric   // Keep symbolic expressions of iterator positions alive
306480093f4SDimitry Andric   auto RegionMap = State->get<IteratorRegionMap>();
307480093f4SDimitry Andric   for (const auto &Reg : RegionMap) {
308480093f4SDimitry Andric     const auto Offset = Reg.second.getOffset();
309480093f4SDimitry Andric     for (auto i = Offset->symbol_begin(); i != Offset->symbol_end(); ++i)
310480093f4SDimitry Andric       if (isa<SymbolData>(*i))
311480093f4SDimitry Andric         SR.markLive(*i);
312480093f4SDimitry Andric   }
313480093f4SDimitry Andric 
314480093f4SDimitry Andric   auto SymbolMap = State->get<IteratorSymbolMap>();
315480093f4SDimitry Andric   for (const auto &Sym : SymbolMap) {
316480093f4SDimitry Andric     const auto Offset = Sym.second.getOffset();
317480093f4SDimitry Andric     for (auto i = Offset->symbol_begin(); i != Offset->symbol_end(); ++i)
318480093f4SDimitry Andric       if (isa<SymbolData>(*i))
319480093f4SDimitry Andric         SR.markLive(*i);
320480093f4SDimitry Andric   }
321480093f4SDimitry Andric 
322480093f4SDimitry Andric }
323480093f4SDimitry Andric 
324480093f4SDimitry Andric void IteratorModeling::checkDeadSymbols(SymbolReaper &SR,
325480093f4SDimitry Andric                                         CheckerContext &C) const {
326480093f4SDimitry Andric   // Cleanup
327480093f4SDimitry Andric   auto State = C.getState();
328480093f4SDimitry Andric 
329480093f4SDimitry Andric   auto RegionMap = State->get<IteratorRegionMap>();
330480093f4SDimitry Andric   for (const auto &Reg : RegionMap) {
331480093f4SDimitry Andric     if (!SR.isLiveRegion(Reg.first)) {
332480093f4SDimitry Andric       // The region behind the `LazyCompoundVal` is often cleaned up before
333480093f4SDimitry Andric       // the `LazyCompoundVal` itself. If there are iterator positions keyed
334480093f4SDimitry Andric       // by these regions their cleanup must be deferred.
335480093f4SDimitry Andric       if (!isBoundThroughLazyCompoundVal(State->getEnvironment(), Reg.first)) {
336480093f4SDimitry Andric         State = State->remove<IteratorRegionMap>(Reg.first);
337480093f4SDimitry Andric       }
338480093f4SDimitry Andric     }
339480093f4SDimitry Andric   }
340480093f4SDimitry Andric 
341480093f4SDimitry Andric   auto SymbolMap = State->get<IteratorSymbolMap>();
342480093f4SDimitry Andric   for (const auto &Sym : SymbolMap) {
343480093f4SDimitry Andric     if (!SR.isLive(Sym.first)) {
344480093f4SDimitry Andric       State = State->remove<IteratorSymbolMap>(Sym.first);
345480093f4SDimitry Andric     }
346480093f4SDimitry Andric   }
347480093f4SDimitry Andric 
3485ffd83dbSDimitry Andric   C.addTransition(State);
349480093f4SDimitry Andric }
3505ffd83dbSDimitry Andric 
3515ffd83dbSDimitry Andric void
3525ffd83dbSDimitry Andric IteratorModeling::handleOverloadedOperator(CheckerContext &C,
3535ffd83dbSDimitry Andric                                            const CallEvent &Call,
3545ffd83dbSDimitry Andric                                            OverloadedOperatorKind Op) const {
3555ffd83dbSDimitry Andric     if (isSimpleComparisonOperator(Op)) {
3565ffd83dbSDimitry Andric       const auto *OrigExpr = Call.getOriginExpr();
3575ffd83dbSDimitry Andric       if (!OrigExpr)
3585ffd83dbSDimitry Andric         return;
3595ffd83dbSDimitry Andric 
3605ffd83dbSDimitry Andric       if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
3615ffd83dbSDimitry Andric         handleComparison(C, OrigExpr, Call.getReturnValue(),
3625ffd83dbSDimitry Andric                          InstCall->getCXXThisVal(), Call.getArgSVal(0), Op);
3635ffd83dbSDimitry Andric         return;
3645ffd83dbSDimitry Andric       }
3655ffd83dbSDimitry Andric 
3665ffd83dbSDimitry Andric       handleComparison(C, OrigExpr, Call.getReturnValue(), Call.getArgSVal(0),
3675ffd83dbSDimitry Andric                          Call.getArgSVal(1), Op);
3685ffd83dbSDimitry Andric       return;
3695ffd83dbSDimitry Andric     } else if (isRandomIncrOrDecrOperator(Op)) {
3705ffd83dbSDimitry Andric       const auto *OrigExpr = Call.getOriginExpr();
3715ffd83dbSDimitry Andric       if (!OrigExpr)
3725ffd83dbSDimitry Andric         return;
3735ffd83dbSDimitry Andric 
3745ffd83dbSDimitry Andric       if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
3755ffd83dbSDimitry Andric         if (Call.getNumArgs() >= 1 &&
3765ffd83dbSDimitry Andric               Call.getArgExpr(0)->getType()->isIntegralOrEnumerationType()) {
3775ffd83dbSDimitry Andric           handleRandomIncrOrDecr(C, OrigExpr, Op, Call.getReturnValue(),
3785ffd83dbSDimitry Andric                                  InstCall->getCXXThisVal(), Call.getArgSVal(0));
3795ffd83dbSDimitry Andric           return;
3805ffd83dbSDimitry Andric         }
381*e8d8bef9SDimitry Andric       } else if (Call.getNumArgs() >= 2) {
382*e8d8bef9SDimitry Andric         const Expr *FirstArg = Call.getArgExpr(0);
383*e8d8bef9SDimitry Andric         const Expr *SecondArg = Call.getArgExpr(1);
384*e8d8bef9SDimitry Andric         const QualType FirstType = FirstArg->getType();
385*e8d8bef9SDimitry Andric         const QualType SecondType = SecondArg->getType();
386*e8d8bef9SDimitry Andric 
387*e8d8bef9SDimitry Andric         if (FirstType->isIntegralOrEnumerationType() ||
388*e8d8bef9SDimitry Andric             SecondType->isIntegralOrEnumerationType()) {
389*e8d8bef9SDimitry Andric           // In case of operator+ the iterator can be either on the LHS (eg.:
390*e8d8bef9SDimitry Andric           // it + 1), or on the RHS (eg.: 1 + it). Both cases are modeled.
391*e8d8bef9SDimitry Andric           const bool IsIterFirst = FirstType->isStructureOrClassType();
392*e8d8bef9SDimitry Andric           const SVal FirstArg = Call.getArgSVal(0);
393*e8d8bef9SDimitry Andric           const SVal SecondArg = Call.getArgSVal(1);
394*e8d8bef9SDimitry Andric           const SVal &Iterator = IsIterFirst ? FirstArg : SecondArg;
395*e8d8bef9SDimitry Andric           const SVal &Amount = IsIterFirst ? SecondArg : FirstArg;
396*e8d8bef9SDimitry Andric 
3975ffd83dbSDimitry Andric           handleRandomIncrOrDecr(C, OrigExpr, Op, Call.getReturnValue(),
398*e8d8bef9SDimitry Andric                                  Iterator, Amount);
3995ffd83dbSDimitry Andric           return;
4005ffd83dbSDimitry Andric         }
4015ffd83dbSDimitry Andric       }
4025ffd83dbSDimitry Andric     } else if (isIncrementOperator(Op)) {
4035ffd83dbSDimitry Andric       if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
4045ffd83dbSDimitry Andric         handleIncrement(C, Call.getReturnValue(), InstCall->getCXXThisVal(),
4055ffd83dbSDimitry Andric                         Call.getNumArgs());
4065ffd83dbSDimitry Andric         return;
4075ffd83dbSDimitry Andric       }
4085ffd83dbSDimitry Andric 
4095ffd83dbSDimitry Andric       handleIncrement(C, Call.getReturnValue(), Call.getArgSVal(0),
4105ffd83dbSDimitry Andric                       Call.getNumArgs());
4115ffd83dbSDimitry Andric       return;
4125ffd83dbSDimitry Andric     } else if (isDecrementOperator(Op)) {
4135ffd83dbSDimitry Andric       if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
4145ffd83dbSDimitry Andric         handleDecrement(C, Call.getReturnValue(), InstCall->getCXXThisVal(),
4155ffd83dbSDimitry Andric                         Call.getNumArgs());
4165ffd83dbSDimitry Andric         return;
4175ffd83dbSDimitry Andric       }
4185ffd83dbSDimitry Andric 
4195ffd83dbSDimitry Andric       handleDecrement(C, Call.getReturnValue(), Call.getArgSVal(0),
4205ffd83dbSDimitry Andric                         Call.getNumArgs());
4215ffd83dbSDimitry Andric       return;
422480093f4SDimitry Andric     }
423480093f4SDimitry Andric }
424480093f4SDimitry Andric 
4255ffd83dbSDimitry Andric void
4265ffd83dbSDimitry Andric IteratorModeling::handleAdvanceLikeFunction(CheckerContext &C,
4275ffd83dbSDimitry Andric                                             const CallEvent &Call,
4285ffd83dbSDimitry Andric                                             const Expr *OrigExpr,
4295ffd83dbSDimitry Andric                                             const AdvanceFn *Handler) const {
4305ffd83dbSDimitry Andric   if (!C.wasInlined) {
4315ffd83dbSDimitry Andric     (this->**Handler)(C, OrigExpr, Call.getReturnValue(),
4325ffd83dbSDimitry Andric                       Call.getArgSVal(0), Call.getArgSVal(1));
4335ffd83dbSDimitry Andric     return;
4345ffd83dbSDimitry Andric   }
4355ffd83dbSDimitry Andric 
4365ffd83dbSDimitry Andric   // If std::advance() was inlined, but a non-standard function it calls inside
4375ffd83dbSDimitry Andric   // was not, then we have to model it explicitly
4385ffd83dbSDimitry Andric   const auto *IdInfo = cast<FunctionDecl>(Call.getDecl())->getIdentifier();
4395ffd83dbSDimitry Andric   if (IdInfo) {
4405ffd83dbSDimitry Andric     if (IdInfo->getName() == "advance") {
4415ffd83dbSDimitry Andric       if (noChangeInAdvance(C, Call.getArgSVal(0), OrigExpr)) {
4425ffd83dbSDimitry Andric         (this->**Handler)(C, OrigExpr, Call.getReturnValue(),
4435ffd83dbSDimitry Andric                           Call.getArgSVal(0), Call.getArgSVal(1));
4445ffd83dbSDimitry Andric       }
4455ffd83dbSDimitry Andric     }
4465ffd83dbSDimitry Andric   }
447480093f4SDimitry Andric }
448480093f4SDimitry Andric 
449480093f4SDimitry Andric void IteratorModeling::handleComparison(CheckerContext &C, const Expr *CE,
450480093f4SDimitry Andric                                        SVal RetVal, const SVal &LVal,
451480093f4SDimitry Andric                                        const SVal &RVal,
452480093f4SDimitry Andric                                        OverloadedOperatorKind Op) const {
453480093f4SDimitry Andric   // Record the operands and the operator of the comparison for the next
454480093f4SDimitry Andric   // evalAssume, if the result is a symbolic expression. If it is a concrete
455480093f4SDimitry Andric   // value (only one branch is possible), then transfer the state between
456480093f4SDimitry Andric   // the operands according to the operator and the result
457480093f4SDimitry Andric    auto State = C.getState();
458480093f4SDimitry Andric   const auto *LPos = getIteratorPosition(State, LVal);
459480093f4SDimitry Andric   const auto *RPos = getIteratorPosition(State, RVal);
460480093f4SDimitry Andric   const MemRegion *Cont = nullptr;
461480093f4SDimitry Andric   if (LPos) {
462480093f4SDimitry Andric     Cont = LPos->getContainer();
463480093f4SDimitry Andric   } else if (RPos) {
464480093f4SDimitry Andric     Cont = RPos->getContainer();
465480093f4SDimitry Andric   }
466480093f4SDimitry Andric   if (!Cont)
467480093f4SDimitry Andric     return;
468480093f4SDimitry Andric 
4695ffd83dbSDimitry Andric   // At least one of the iterators has recorded positions. If one of them does
470480093f4SDimitry Andric   // not then create a new symbol for the offset.
471480093f4SDimitry Andric   SymbolRef Sym;
472480093f4SDimitry Andric   if (!LPos || !RPos) {
473480093f4SDimitry Andric     auto &SymMgr = C.getSymbolManager();
474480093f4SDimitry Andric     Sym = SymMgr.conjureSymbol(CE, C.getLocationContext(),
475480093f4SDimitry Andric                                C.getASTContext().LongTy, C.blockCount());
476480093f4SDimitry Andric     State = assumeNoOverflow(State, Sym, 4);
477480093f4SDimitry Andric   }
478480093f4SDimitry Andric 
479480093f4SDimitry Andric   if (!LPos) {
480480093f4SDimitry Andric     State = setIteratorPosition(State, LVal,
481480093f4SDimitry Andric                                 IteratorPosition::getPosition(Cont, Sym));
482480093f4SDimitry Andric     LPos = getIteratorPosition(State, LVal);
483480093f4SDimitry Andric   } else if (!RPos) {
484480093f4SDimitry Andric     State = setIteratorPosition(State, RVal,
485480093f4SDimitry Andric                                 IteratorPosition::getPosition(Cont, Sym));
486480093f4SDimitry Andric     RPos = getIteratorPosition(State, RVal);
487480093f4SDimitry Andric   }
488480093f4SDimitry Andric 
489*e8d8bef9SDimitry Andric   // If the value for which we just tried to set a new iterator position is
490*e8d8bef9SDimitry Andric   // an `SVal`for which no iterator position can be set then the setting was
491*e8d8bef9SDimitry Andric   // unsuccessful. We cannot handle the comparison in this case.
492*e8d8bef9SDimitry Andric   if (!LPos || !RPos)
493*e8d8bef9SDimitry Andric     return;
494*e8d8bef9SDimitry Andric 
4955ffd83dbSDimitry Andric   // We cannot make assumptions on `UnknownVal`. Let us conjure a symbol
496480093f4SDimitry Andric   // instead.
497480093f4SDimitry Andric   if (RetVal.isUnknown()) {
498480093f4SDimitry Andric     auto &SymMgr = C.getSymbolManager();
499480093f4SDimitry Andric     auto *LCtx = C.getLocationContext();
500480093f4SDimitry Andric     RetVal = nonloc::SymbolVal(SymMgr.conjureSymbol(
501480093f4SDimitry Andric         CE, LCtx, C.getASTContext().BoolTy, C.blockCount()));
502480093f4SDimitry Andric     State = State->BindExpr(CE, LCtx, RetVal);
503480093f4SDimitry Andric   }
504480093f4SDimitry Andric 
505480093f4SDimitry Andric   processComparison(C, State, LPos->getOffset(), RPos->getOffset(), RetVal, Op);
506480093f4SDimitry Andric }
507480093f4SDimitry Andric 
508480093f4SDimitry Andric void IteratorModeling::processComparison(CheckerContext &C,
509480093f4SDimitry Andric                                          ProgramStateRef State, SymbolRef Sym1,
510480093f4SDimitry Andric                                          SymbolRef Sym2, const SVal &RetVal,
511480093f4SDimitry Andric                                          OverloadedOperatorKind Op) const {
512480093f4SDimitry Andric   if (const auto TruthVal = RetVal.getAs<nonloc::ConcreteInt>()) {
513480093f4SDimitry Andric     if ((State = relateSymbols(State, Sym1, Sym2,
514480093f4SDimitry Andric                               (Op == OO_EqualEqual) ==
515480093f4SDimitry Andric                                (TruthVal->getValue() != 0)))) {
516480093f4SDimitry Andric       C.addTransition(State);
517480093f4SDimitry Andric     } else {
518480093f4SDimitry Andric       C.generateSink(State, C.getPredecessor());
519480093f4SDimitry Andric     }
520480093f4SDimitry Andric     return;
521480093f4SDimitry Andric   }
522480093f4SDimitry Andric 
523480093f4SDimitry Andric   const auto ConditionVal = RetVal.getAs<DefinedSVal>();
524480093f4SDimitry Andric   if (!ConditionVal)
525480093f4SDimitry Andric     return;
526480093f4SDimitry Andric 
527480093f4SDimitry Andric   if (auto StateTrue = relateSymbols(State, Sym1, Sym2, Op == OO_EqualEqual)) {
528480093f4SDimitry Andric     StateTrue = StateTrue->assume(*ConditionVal, true);
529480093f4SDimitry Andric     C.addTransition(StateTrue);
530480093f4SDimitry Andric   }
531480093f4SDimitry Andric 
532480093f4SDimitry Andric   if (auto StateFalse = relateSymbols(State, Sym1, Sym2, Op != OO_EqualEqual)) {
533480093f4SDimitry Andric     StateFalse = StateFalse->assume(*ConditionVal, false);
534480093f4SDimitry Andric     C.addTransition(StateFalse);
535480093f4SDimitry Andric   }
536480093f4SDimitry Andric }
537480093f4SDimitry Andric 
538480093f4SDimitry Andric void IteratorModeling::handleIncrement(CheckerContext &C, const SVal &RetVal,
539480093f4SDimitry Andric                                        const SVal &Iter, bool Postfix) const {
540480093f4SDimitry Andric   // Increment the symbolic expressions which represents the position of the
541480093f4SDimitry Andric   // iterator
542480093f4SDimitry Andric   auto State = C.getState();
543480093f4SDimitry Andric   auto &BVF = C.getSymbolManager().getBasicVals();
544480093f4SDimitry Andric 
545480093f4SDimitry Andric   const auto *Pos = getIteratorPosition(State, Iter);
546480093f4SDimitry Andric   if (!Pos)
547480093f4SDimitry Andric     return;
548480093f4SDimitry Andric 
549480093f4SDimitry Andric   auto NewState =
550480093f4SDimitry Andric     advancePosition(State, Iter, OO_Plus,
551480093f4SDimitry Andric                     nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
552480093f4SDimitry Andric   assert(NewState &&
553480093f4SDimitry Andric          "Advancing position by concrete int should always be successful");
554480093f4SDimitry Andric 
555480093f4SDimitry Andric   const auto *NewPos = getIteratorPosition(NewState, Iter);
556480093f4SDimitry Andric   assert(NewPos &&
557480093f4SDimitry Andric          "Iterator should have position after successful advancement");
558480093f4SDimitry Andric 
559480093f4SDimitry Andric   State = setIteratorPosition(State, Iter, *NewPos);
560480093f4SDimitry Andric   State = setIteratorPosition(State, RetVal, Postfix ? *Pos : *NewPos);
561480093f4SDimitry Andric   C.addTransition(State);
562480093f4SDimitry Andric }
563480093f4SDimitry Andric 
564480093f4SDimitry Andric void IteratorModeling::handleDecrement(CheckerContext &C, const SVal &RetVal,
565480093f4SDimitry Andric                                        const SVal &Iter, bool Postfix) const {
566480093f4SDimitry Andric   // Decrement the symbolic expressions which represents the position of the
567480093f4SDimitry Andric   // iterator
568480093f4SDimitry Andric   auto State = C.getState();
569480093f4SDimitry Andric   auto &BVF = C.getSymbolManager().getBasicVals();
570480093f4SDimitry Andric 
571480093f4SDimitry Andric   const auto *Pos = getIteratorPosition(State, Iter);
572480093f4SDimitry Andric   if (!Pos)
573480093f4SDimitry Andric     return;
574480093f4SDimitry Andric 
575480093f4SDimitry Andric   auto NewState =
576480093f4SDimitry Andric     advancePosition(State, Iter, OO_Minus,
577480093f4SDimitry Andric                     nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
578480093f4SDimitry Andric   assert(NewState &&
579480093f4SDimitry Andric          "Advancing position by concrete int should always be successful");
580480093f4SDimitry Andric 
581480093f4SDimitry Andric   const auto *NewPos = getIteratorPosition(NewState, Iter);
582480093f4SDimitry Andric   assert(NewPos &&
583480093f4SDimitry Andric          "Iterator should have position after successful advancement");
584480093f4SDimitry Andric 
585480093f4SDimitry Andric   State = setIteratorPosition(State, Iter, *NewPos);
586480093f4SDimitry Andric   State = setIteratorPosition(State, RetVal, Postfix ? *Pos : *NewPos);
587480093f4SDimitry Andric   C.addTransition(State);
588480093f4SDimitry Andric }
589480093f4SDimitry Andric 
590*e8d8bef9SDimitry Andric void IteratorModeling::handleRandomIncrOrDecr(CheckerContext &C, const Expr *CE,
591480093f4SDimitry Andric                                               OverloadedOperatorKind Op,
592480093f4SDimitry Andric                                               const SVal &RetVal,
593*e8d8bef9SDimitry Andric                                               const SVal &Iterator,
594*e8d8bef9SDimitry Andric                                               const SVal &Amount) const {
595480093f4SDimitry Andric   // Increment or decrement the symbolic expressions which represents the
596480093f4SDimitry Andric   // position of the iterator
597480093f4SDimitry Andric   auto State = C.getState();
598480093f4SDimitry Andric 
599*e8d8bef9SDimitry Andric   const auto *Pos = getIteratorPosition(State, Iterator);
600480093f4SDimitry Andric   if (!Pos)
601480093f4SDimitry Andric     return;
602480093f4SDimitry Andric 
603*e8d8bef9SDimitry Andric   const auto *Value = &Amount;
604*e8d8bef9SDimitry Andric   SVal Val;
605*e8d8bef9SDimitry Andric   if (auto LocAmount = Amount.getAs<Loc>()) {
606*e8d8bef9SDimitry Andric     Val = State->getRawSVal(*LocAmount);
607*e8d8bef9SDimitry Andric     Value = &Val;
608480093f4SDimitry Andric   }
609480093f4SDimitry Andric 
610*e8d8bef9SDimitry Andric   const auto &TgtVal =
611*e8d8bef9SDimitry Andric       (Op == OO_PlusEqual || Op == OO_MinusEqual) ? Iterator : RetVal;
612480093f4SDimitry Andric 
6135ffd83dbSDimitry Andric   // `AdvancedState` is a state where the position of `LHS` is advanced. We
6145ffd83dbSDimitry Andric   // only need this state to retrieve the new position, but we do not want
6155ffd83dbSDimitry Andric   // to change the position of `LHS` (in every case).
616*e8d8bef9SDimitry Andric   auto AdvancedState = advancePosition(State, Iterator, Op, *Value);
6175ffd83dbSDimitry Andric   if (AdvancedState) {
618*e8d8bef9SDimitry Andric     const auto *NewPos = getIteratorPosition(AdvancedState, Iterator);
619480093f4SDimitry Andric     assert(NewPos &&
620480093f4SDimitry Andric            "Iterator should have position after successful advancement");
621480093f4SDimitry Andric 
6225ffd83dbSDimitry Andric     State = setIteratorPosition(State, TgtVal, *NewPos);
623480093f4SDimitry Andric     C.addTransition(State);
624480093f4SDimitry Andric   } else {
625480093f4SDimitry Andric     assignToContainer(C, CE, TgtVal, Pos->getContainer());
626480093f4SDimitry Andric   }
627480093f4SDimitry Andric }
628480093f4SDimitry Andric 
6295ffd83dbSDimitry Andric void IteratorModeling::handlePtrIncrOrDecr(CheckerContext &C,
6305ffd83dbSDimitry Andric                                            const Expr *Iterator,
6315ffd83dbSDimitry Andric                                            OverloadedOperatorKind OK,
6325ffd83dbSDimitry Andric                                            SVal Offset) const {
633*e8d8bef9SDimitry Andric   if (!Offset.getAs<DefinedSVal>())
634*e8d8bef9SDimitry Andric     return;
635*e8d8bef9SDimitry Andric 
6365ffd83dbSDimitry Andric   QualType PtrType = Iterator->getType();
6375ffd83dbSDimitry Andric   if (!PtrType->isPointerType())
6385ffd83dbSDimitry Andric     return;
6395ffd83dbSDimitry Andric   QualType ElementType = PtrType->getPointeeType();
6405ffd83dbSDimitry Andric 
6415ffd83dbSDimitry Andric   ProgramStateRef State = C.getState();
6425ffd83dbSDimitry Andric   SVal OldVal = State->getSVal(Iterator, C.getLocationContext());
6435ffd83dbSDimitry Andric 
6445ffd83dbSDimitry Andric   const IteratorPosition *OldPos = getIteratorPosition(State, OldVal);
6455ffd83dbSDimitry Andric   if (!OldPos)
646480093f4SDimitry Andric     return;
647480093f4SDimitry Andric 
6485ffd83dbSDimitry Andric   SVal NewVal;
649*e8d8bef9SDimitry Andric   if (OK == OO_Plus || OK == OO_PlusEqual) {
6505ffd83dbSDimitry Andric     NewVal = State->getLValue(ElementType, Offset, OldVal);
651*e8d8bef9SDimitry Andric   } else {
652*e8d8bef9SDimitry Andric     auto &SVB = C.getSValBuilder();
653*e8d8bef9SDimitry Andric     SVal NegatedOffset = SVB.evalMinus(Offset.castAs<NonLoc>());
6545ffd83dbSDimitry Andric     NewVal = State->getLValue(ElementType, NegatedOffset, OldVal);
655480093f4SDimitry Andric   }
656480093f4SDimitry Andric 
6575ffd83dbSDimitry Andric   // `AdvancedState` is a state where the position of `Old` is advanced. We
6585ffd83dbSDimitry Andric   // only need this state to retrieve the new position, but we do not want
6595ffd83dbSDimitry Andric   // ever to change the position of `OldVal`.
6605ffd83dbSDimitry Andric   auto AdvancedState = advancePosition(State, OldVal, OK, Offset);
6615ffd83dbSDimitry Andric   if (AdvancedState) {
6625ffd83dbSDimitry Andric     const IteratorPosition *NewPos = getIteratorPosition(AdvancedState, OldVal);
6635ffd83dbSDimitry Andric     assert(NewPos &&
6645ffd83dbSDimitry Andric            "Iterator should have position after successful advancement");
665480093f4SDimitry Andric 
6665ffd83dbSDimitry Andric     ProgramStateRef NewState = setIteratorPosition(State, NewVal, *NewPos);
6675ffd83dbSDimitry Andric     C.addTransition(NewState);
6685ffd83dbSDimitry Andric   } else {
6695ffd83dbSDimitry Andric     assignToContainer(C, Iterator, NewVal, OldPos->getContainer());
670480093f4SDimitry Andric   }
6715ffd83dbSDimitry Andric }
6725ffd83dbSDimitry Andric 
6735ffd83dbSDimitry Andric void IteratorModeling::handleAdvance(CheckerContext &C, const Expr *CE,
6745ffd83dbSDimitry Andric                                      SVal RetVal, SVal Iter,
6755ffd83dbSDimitry Andric                                      SVal Amount) const {
6765ffd83dbSDimitry Andric   handleRandomIncrOrDecr(C, CE, OO_PlusEqual, RetVal, Iter, Amount);
6775ffd83dbSDimitry Andric }
6785ffd83dbSDimitry Andric 
6795ffd83dbSDimitry Andric void IteratorModeling::handlePrev(CheckerContext &C, const Expr *CE,
6805ffd83dbSDimitry Andric                                   SVal RetVal, SVal Iter, SVal Amount) const {
6815ffd83dbSDimitry Andric   handleRandomIncrOrDecr(C, CE, OO_Minus, RetVal, Iter, Amount);
6825ffd83dbSDimitry Andric }
6835ffd83dbSDimitry Andric 
6845ffd83dbSDimitry Andric void IteratorModeling::handleNext(CheckerContext &C, const Expr *CE,
6855ffd83dbSDimitry Andric                                   SVal RetVal, SVal Iter, SVal Amount) const {
6865ffd83dbSDimitry Andric   handleRandomIncrOrDecr(C, CE, OO_Plus, RetVal, Iter, Amount);
687480093f4SDimitry Andric }
688480093f4SDimitry Andric 
689480093f4SDimitry Andric void IteratorModeling::assignToContainer(CheckerContext &C, const Expr *CE,
690480093f4SDimitry Andric                                          const SVal &RetVal,
691480093f4SDimitry Andric                                          const MemRegion *Cont) const {
692480093f4SDimitry Andric   Cont = Cont->getMostDerivedObjectRegion();
693480093f4SDimitry Andric 
694480093f4SDimitry Andric   auto State = C.getState();
6955ffd83dbSDimitry Andric   const auto *LCtx = C.getLocationContext();
6965ffd83dbSDimitry Andric   State = createIteratorPosition(State, RetVal, Cont, CE, LCtx, C.blockCount());
6975ffd83dbSDimitry Andric 
698480093f4SDimitry Andric   C.addTransition(State);
699480093f4SDimitry Andric }
700480093f4SDimitry Andric 
7015ffd83dbSDimitry Andric bool IteratorModeling::noChangeInAdvance(CheckerContext &C, SVal Iter,
7025ffd83dbSDimitry Andric                                          const Expr *CE) const {
7035ffd83dbSDimitry Andric   // Compare the iterator position before and after the call. (To be called
7045ffd83dbSDimitry Andric   // from `checkPostCall()`.)
7055ffd83dbSDimitry Andric   const auto StateAfter = C.getState();
706480093f4SDimitry Andric 
7075ffd83dbSDimitry Andric   const auto *PosAfter = getIteratorPosition(StateAfter, Iter);
7085ffd83dbSDimitry Andric   // If we have no position after the call of `std::advance`, then we are not
7095ffd83dbSDimitry Andric   // interested. (Modeling of an inlined `std::advance()` should not remove the
7105ffd83dbSDimitry Andric   // position in any case.)
7115ffd83dbSDimitry Andric   if (!PosAfter)
7125ffd83dbSDimitry Andric     return false;
713480093f4SDimitry Andric 
7145ffd83dbSDimitry Andric   const ExplodedNode *N = findCallEnter(C.getPredecessor(), CE);
7155ffd83dbSDimitry Andric   assert(N && "Any call should have a `CallEnter` node.");
716480093f4SDimitry Andric 
7175ffd83dbSDimitry Andric   const auto StateBefore = N->getState();
7185ffd83dbSDimitry Andric   const auto *PosBefore = getIteratorPosition(StateBefore, Iter);
719*e8d8bef9SDimitry Andric   // FIXME: `std::advance()` should not create a new iterator position but
720*e8d8bef9SDimitry Andric   //        change existing ones. However, in case of iterators implemented as
721*e8d8bef9SDimitry Andric   //        pointers the handling of parameters in `std::advance()`-like
722*e8d8bef9SDimitry Andric   //        functions is still incomplete which may result in cases where
723*e8d8bef9SDimitry Andric   //        the new position is assigned to the wrong pointer. This causes
724*e8d8bef9SDimitry Andric   //        crash if we use an assertion here.
725*e8d8bef9SDimitry Andric   if (!PosBefore)
726*e8d8bef9SDimitry Andric     return false;
727480093f4SDimitry Andric 
7285ffd83dbSDimitry Andric   return PosBefore->getOffset() == PosAfter->getOffset();
729480093f4SDimitry Andric }
730480093f4SDimitry Andric 
731480093f4SDimitry Andric void IteratorModeling::printState(raw_ostream &Out, ProgramStateRef State,
732480093f4SDimitry Andric                                   const char *NL, const char *Sep) const {
733480093f4SDimitry Andric   auto SymbolMap = State->get<IteratorSymbolMap>();
734480093f4SDimitry Andric   auto RegionMap = State->get<IteratorRegionMap>();
7355ffd83dbSDimitry Andric   // Use a counter to add newlines before every line except the first one.
7365ffd83dbSDimitry Andric   unsigned Count = 0;
737480093f4SDimitry Andric 
738480093f4SDimitry Andric   if (!SymbolMap.isEmpty() || !RegionMap.isEmpty()) {
739480093f4SDimitry Andric     Out << Sep << "Iterator Positions :" << NL;
740480093f4SDimitry Andric     for (const auto &Sym : SymbolMap) {
7415ffd83dbSDimitry Andric       if (Count++)
7425ffd83dbSDimitry Andric         Out << NL;
7435ffd83dbSDimitry Andric 
744480093f4SDimitry Andric       Sym.first->dumpToStream(Out);
745480093f4SDimitry Andric       Out << " : ";
746480093f4SDimitry Andric       const auto Pos = Sym.second;
747480093f4SDimitry Andric       Out << (Pos.isValid() ? "Valid" : "Invalid") << " ; Container == ";
748480093f4SDimitry Andric       Pos.getContainer()->dumpToStream(Out);
749480093f4SDimitry Andric       Out<<" ; Offset == ";
750480093f4SDimitry Andric       Pos.getOffset()->dumpToStream(Out);
751480093f4SDimitry Andric     }
752480093f4SDimitry Andric 
753480093f4SDimitry Andric     for (const auto &Reg : RegionMap) {
7545ffd83dbSDimitry Andric       if (Count++)
7555ffd83dbSDimitry Andric         Out << NL;
7565ffd83dbSDimitry Andric 
757480093f4SDimitry Andric       Reg.first->dumpToStream(Out);
758480093f4SDimitry Andric       Out << " : ";
759480093f4SDimitry Andric       const auto Pos = Reg.second;
760480093f4SDimitry Andric       Out << (Pos.isValid() ? "Valid" : "Invalid") << " ; Container == ";
761480093f4SDimitry Andric       Pos.getContainer()->dumpToStream(Out);
762480093f4SDimitry Andric       Out<<" ; Offset == ";
763480093f4SDimitry Andric       Pos.getOffset()->dumpToStream(Out);
764480093f4SDimitry Andric     }
765480093f4SDimitry Andric   }
766480093f4SDimitry Andric }
767480093f4SDimitry Andric 
768480093f4SDimitry Andric namespace {
769480093f4SDimitry Andric 
770480093f4SDimitry Andric bool isSimpleComparisonOperator(OverloadedOperatorKind OK) {
771480093f4SDimitry Andric   return OK == OO_EqualEqual || OK == OO_ExclaimEqual;
772480093f4SDimitry Andric }
773480093f4SDimitry Andric 
7745ffd83dbSDimitry Andric bool isSimpleComparisonOperator(BinaryOperatorKind OK) {
7755ffd83dbSDimitry Andric   return OK == BO_EQ || OK == BO_NE;
776480093f4SDimitry Andric }
777480093f4SDimitry Andric 
778480093f4SDimitry Andric ProgramStateRef removeIteratorPosition(ProgramStateRef State, const SVal &Val) {
779480093f4SDimitry Andric   if (auto Reg = Val.getAsRegion()) {
780480093f4SDimitry Andric     Reg = Reg->getMostDerivedObjectRegion();
781480093f4SDimitry Andric     return State->remove<IteratorRegionMap>(Reg);
782480093f4SDimitry Andric   } else if (const auto Sym = Val.getAsSymbol()) {
783480093f4SDimitry Andric     return State->remove<IteratorSymbolMap>(Sym);
784480093f4SDimitry Andric   } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
785480093f4SDimitry Andric     return State->remove<IteratorRegionMap>(LCVal->getRegion());
786480093f4SDimitry Andric   }
787480093f4SDimitry Andric   return nullptr;
788480093f4SDimitry Andric }
789480093f4SDimitry Andric 
790480093f4SDimitry Andric ProgramStateRef relateSymbols(ProgramStateRef State, SymbolRef Sym1,
791480093f4SDimitry Andric                               SymbolRef Sym2, bool Equal) {
792480093f4SDimitry Andric   auto &SVB = State->getStateManager().getSValBuilder();
793480093f4SDimitry Andric 
794480093f4SDimitry Andric   // FIXME: This code should be reworked as follows:
795480093f4SDimitry Andric   // 1. Subtract the operands using evalBinOp().
796480093f4SDimitry Andric   // 2. Assume that the result doesn't overflow.
797480093f4SDimitry Andric   // 3. Compare the result to 0.
798480093f4SDimitry Andric   // 4. Assume the result of the comparison.
799480093f4SDimitry Andric   const auto comparison =
800480093f4SDimitry Andric     SVB.evalBinOp(State, BO_EQ, nonloc::SymbolVal(Sym1),
801480093f4SDimitry Andric                   nonloc::SymbolVal(Sym2), SVB.getConditionType());
802480093f4SDimitry Andric 
803480093f4SDimitry Andric   assert(comparison.getAs<DefinedSVal>() &&
804480093f4SDimitry Andric     "Symbol comparison must be a `DefinedSVal`");
805480093f4SDimitry Andric 
806480093f4SDimitry Andric   auto NewState = State->assume(comparison.castAs<DefinedSVal>(), Equal);
807480093f4SDimitry Andric   if (!NewState)
808480093f4SDimitry Andric     return nullptr;
809480093f4SDimitry Andric 
810480093f4SDimitry Andric   if (const auto CompSym = comparison.getAsSymbol()) {
811480093f4SDimitry Andric     assert(isa<SymIntExpr>(CompSym) &&
812480093f4SDimitry Andric            "Symbol comparison must be a `SymIntExpr`");
813480093f4SDimitry Andric     assert(BinaryOperator::isComparisonOp(
814480093f4SDimitry Andric                cast<SymIntExpr>(CompSym)->getOpcode()) &&
815480093f4SDimitry Andric            "Symbol comparison must be a comparison");
816480093f4SDimitry Andric     return assumeNoOverflow(NewState, cast<SymIntExpr>(CompSym)->getLHS(), 2);
817480093f4SDimitry Andric   }
818480093f4SDimitry Andric 
819480093f4SDimitry Andric   return NewState;
820480093f4SDimitry Andric }
821480093f4SDimitry Andric 
822480093f4SDimitry Andric bool isBoundThroughLazyCompoundVal(const Environment &Env,
823480093f4SDimitry Andric                                    const MemRegion *Reg) {
824480093f4SDimitry Andric   for (const auto &Binding : Env) {
825480093f4SDimitry Andric     if (const auto LCVal = Binding.second.getAs<nonloc::LazyCompoundVal>()) {
826480093f4SDimitry Andric       if (LCVal->getRegion() == Reg)
827480093f4SDimitry Andric         return true;
828480093f4SDimitry Andric     }
829480093f4SDimitry Andric   }
830480093f4SDimitry Andric 
831480093f4SDimitry Andric   return false;
832480093f4SDimitry Andric }
833480093f4SDimitry Andric 
8345ffd83dbSDimitry Andric const ExplodedNode *findCallEnter(const ExplodedNode *Node, const Expr *Call) {
8355ffd83dbSDimitry Andric   while (Node) {
8365ffd83dbSDimitry Andric     ProgramPoint PP = Node->getLocation();
8375ffd83dbSDimitry Andric     if (auto Enter = PP.getAs<CallEnter>()) {
8385ffd83dbSDimitry Andric       if (Enter->getCallExpr() == Call)
8395ffd83dbSDimitry Andric         break;
840480093f4SDimitry Andric     }
841480093f4SDimitry Andric 
8425ffd83dbSDimitry Andric     Node = Node->getFirstPred();
843480093f4SDimitry Andric   }
844480093f4SDimitry Andric 
8455ffd83dbSDimitry Andric   return Node;
846480093f4SDimitry Andric }
847480093f4SDimitry Andric 
848480093f4SDimitry Andric } // namespace
849480093f4SDimitry Andric 
850480093f4SDimitry Andric void ento::registerIteratorModeling(CheckerManager &mgr) {
851480093f4SDimitry Andric   mgr.registerChecker<IteratorModeling>();
852480093f4SDimitry Andric }
853480093f4SDimitry Andric 
8545ffd83dbSDimitry Andric bool ento::shouldRegisterIteratorModeling(const CheckerManager &mgr) {
855480093f4SDimitry Andric   return true;
856480093f4SDimitry Andric }
857