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