clang  7.0.0
IteratorChecker.cpp
Go to the documentation of this file.
1 //===-- IteratorChecker.cpp ---------------------------------------*- C++ -*--//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // Defines a checker for using iterators outside their range (past end). Usage
11 // means here dereferencing, incrementing etc.
12 //
13 //===----------------------------------------------------------------------===//
14 //
15 // In the code, iterator can be represented as a:
16 // * type-I: typedef-ed pointer. Operations over such iterator, such as
17 // comparisons or increments, are modeled straightforwardly by the
18 // analyzer.
19 // * type-II: structure with its method bodies available. Operations over such
20 // iterator are inlined by the analyzer, and results of modeling
21 // these operations are exposing implementation details of the
22 // iterators, which is not necessarily helping.
23 // * type-III: completely opaque structure. Operations over such iterator are
24 // modeled conservatively, producing conjured symbols everywhere.
25 //
26 // To handle all these types in a common way we introduce a structure called
27 // IteratorPosition which is an abstraction of the position the iterator
28 // represents using symbolic expressions. The checker handles all the
29 // operations on this structure.
30 //
31 // Additionally, depending on the circumstances, operators of types II and III
32 // can be represented as:
33 // * type-IIa, type-IIIa: conjured structure symbols - when returned by value
34 // from conservatively evaluated methods such as
35 // `.begin()`.
36 // * type-IIb, type-IIIb: memory regions of iterator-typed objects, such as
37 // variables or temporaries, when the iterator object is
38 // currently treated as an lvalue.
39 // * type-IIc, type-IIIc: compound values of iterator-typed objects, when the
40 // iterator object is treated as an rvalue taken of a
41 // particular lvalue, eg. a copy of "type-a" iterator
42 // object, or an iterator that existed before the
43 // analysis has started.
44 //
45 // To handle any of these three different representations stored in an SVal we
46 // use setter and getters functions which separate the three cases. To store
47 // them we use a pointer union of symbol and memory region.
48 //
49 // The checker works the following way: We record the begin and the
50 // past-end iterator for all containers whenever their `.begin()` and `.end()`
51 // are called. Since the Constraint Manager cannot handle such SVals we need
52 // to take over its role. We post-check equality and non-equality comparisons
53 // and record that the two sides are equal if we are in the 'equal' branch
54 // (true-branch for `==` and false-branch for `!=`).
55 //
56 // In case of type-I or type-II iterators we get a concrete integer as a result
57 // of the comparison (1 or 0) but in case of type-III we only get a Symbol. In
58 // this latter case we record the symbol and reload it in evalAssume() and do
59 // the propagation there. We also handle (maybe double) negated comparisons
60 // which are represented in the form of (x == 0 or x != 0) where x is the
61 // comparison itself.
62 //
63 // Since `SimpleConstraintManager` cannot handle complex symbolic expressions
64 // we only use expressions of the format S, S+n or S-n for iterator positions
65 // where S is a conjured symbol and n is an unsigned concrete integer. When
66 // making an assumption e.g. `S1 + n == S2 + m` we store `S1 - S2 == m - n` as
67 // a constraint which we later retrieve when doing an actual comparison.
68 
69 #include "ClangSACheckers.h"
74 
75 using namespace clang;
76 using namespace ento;
77 
78 namespace {
79 
80 // Abstract position of an iterator. This helps to handle all three kinds
81 // of operators in a common way by using a symbolic position.
82 struct IteratorPosition {
83 private:
84 
85  // Container the iterator belongs to
86  const MemRegion *Cont;
87 
88  // Abstract offset
89  const SymbolRef Offset;
90 
91  IteratorPosition(const MemRegion *C, SymbolRef Of)
92  : Cont(C), Offset(Of) {}
93 
94 public:
95  const MemRegion *getContainer() const { return Cont; }
96  SymbolRef getOffset() const { return Offset; }
97 
98  static IteratorPosition getPosition(const MemRegion *C, SymbolRef Of) {
99  return IteratorPosition(C, Of);
100  }
101 
102  IteratorPosition setTo(SymbolRef NewOf) const {
103  return IteratorPosition(Cont, NewOf);
104  }
105 
106  bool operator==(const IteratorPosition &X) const {
107  return Cont == X.Cont && Offset == X.Offset;
108  }
109 
110  bool operator!=(const IteratorPosition &X) const {
111  return Cont != X.Cont || Offset != X.Offset;
112  }
113 
114  void Profile(llvm::FoldingSetNodeID &ID) const {
115  ID.AddPointer(Cont);
116  ID.Add(Offset);
117  }
118 };
119 
120 typedef llvm::PointerUnion<const MemRegion *, SymbolRef> RegionOrSymbol;
121 
122 // Structure to record the symbolic begin and end position of a container
123 struct ContainerData {
124 private:
125  const SymbolRef Begin, End;
126 
127  ContainerData(SymbolRef B, SymbolRef E) : Begin(B), End(E) {}
128 
129 public:
130  static ContainerData fromBegin(SymbolRef B) {
131  return ContainerData(B, nullptr);
132  }
133 
134  static ContainerData fromEnd(SymbolRef E) {
135  return ContainerData(nullptr, E);
136  }
137 
138  SymbolRef getBegin() const { return Begin; }
139  SymbolRef getEnd() const { return End; }
140 
141  ContainerData newBegin(SymbolRef B) const { return ContainerData(B, End); }
142 
143  ContainerData newEnd(SymbolRef E) const { return ContainerData(Begin, E); }
144 
145  bool operator==(const ContainerData &X) const {
146  return Begin == X.Begin && End == X.End;
147  }
148 
149  bool operator!=(const ContainerData &X) const {
150  return Begin != X.Begin || End != X.End;
151  }
152 
153  void Profile(llvm::FoldingSetNodeID &ID) const {
154  ID.Add(Begin);
155  ID.Add(End);
156  }
157 };
158 
159 // Structure fo recording iterator comparisons. We needed to retrieve the
160 // original comparison expression in assumptions.
161 struct IteratorComparison {
162 private:
163  RegionOrSymbol Left, Right;
164  bool Equality;
165 
166 public:
167  IteratorComparison(RegionOrSymbol L, RegionOrSymbol R, bool Eq)
168  : Left(L), Right(R), Equality(Eq) {}
169 
170  RegionOrSymbol getLeft() const { return Left; }
171  RegionOrSymbol getRight() const { return Right; }
172  bool isEquality() const { return Equality; }
173  bool operator==(const IteratorComparison &X) const {
174  return Left == X.Left && Right == X.Right && Equality == X.Equality;
175  }
176  bool operator!=(const IteratorComparison &X) const {
177  return Left != X.Left || Right != X.Right || Equality != X.Equality;
178  }
179  void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(Equality); }
180 };
181 
182 class IteratorChecker
183  : public Checker<check::PreCall, check::PostCall,
184  check::PreStmt<CXXOperatorCallExpr>,
185  check::PostStmt<MaterializeTemporaryExpr>,
186  check::LiveSymbols, check::DeadSymbols,
187  eval::Assume> {
188 
189  std::unique_ptr<BugType> OutOfRangeBugType;
190 
191  void handleComparison(CheckerContext &C, const SVal &RetVal, const SVal &LVal,
192  const SVal &RVal, OverloadedOperatorKind Op) const;
193  void verifyDereference(CheckerContext &C, const SVal &Val) const;
194  void handleIncrement(CheckerContext &C, const SVal &RetVal, const SVal &Iter,
195  bool Postfix) const;
196  void handleDecrement(CheckerContext &C, const SVal &RetVal, const SVal &Iter,
197  bool Postfix) const;
198  void handleRandomIncrOrDecr(CheckerContext &C, OverloadedOperatorKind Op,
199  const SVal &RetVal, const SVal &LHS,
200  const SVal &RHS) const;
201  void handleBegin(CheckerContext &C, const Expr *CE, const SVal &RetVal,
202  const SVal &Cont) const;
203  void handleEnd(CheckerContext &C, const Expr *CE, const SVal &RetVal,
204  const SVal &Cont) const;
205  void assignToContainer(CheckerContext &C, const Expr *CE, const SVal &RetVal,
206  const MemRegion *Cont) const;
207  void verifyRandomIncrOrDecr(CheckerContext &C, OverloadedOperatorKind Op,
208  const SVal &RetVal, const SVal &LHS,
209  const SVal &RHS) const;
210  void reportOutOfRangeBug(const StringRef &Message, const SVal &Val,
211  CheckerContext &C, ExplodedNode *ErrNode) const;
212 
213 public:
214  IteratorChecker();
215 
216  enum CheckKind {
217  CK_IteratorRangeChecker,
218  CK_NumCheckKinds
219  };
220 
221  DefaultBool ChecksEnabled[CK_NumCheckKinds];
222  CheckName CheckNames[CK_NumCheckKinds];
223 
224  void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
225  void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
226  void checkPreStmt(const CXXOperatorCallExpr *COCE, CheckerContext &C) const;
227  void checkPostStmt(const MaterializeTemporaryExpr *MTE,
228  CheckerContext &C) const;
229  void checkLiveSymbols(ProgramStateRef State, SymbolReaper &SR) const;
230  void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
231  ProgramStateRef evalAssume(ProgramStateRef State, SVal Cond,
232  bool Assumption) const;
233 };
234 } // namespace
235 
236 REGISTER_MAP_WITH_PROGRAMSTATE(IteratorSymbolMap, SymbolRef, IteratorPosition)
237 REGISTER_MAP_WITH_PROGRAMSTATE(IteratorRegionMap, const MemRegion *,
238  IteratorPosition)
239 
240 REGISTER_MAP_WITH_PROGRAMSTATE(ContainerMap, const MemRegion *, ContainerData)
241 
242 REGISTER_MAP_WITH_PROGRAMSTATE(IteratorComparisonMap, const SymExpr *,
244 
245 namespace {
246 
247 bool isIteratorType(const QualType &Type);
248 bool isIterator(const CXXRecordDecl *CRD);
249 bool isBeginCall(const FunctionDecl *Func);
250 bool isEndCall(const FunctionDecl *Func);
257 const RegionOrSymbol getRegionOrSymbol(const SVal &Val);
259  RegionOrSymbol LVal,
260  RegionOrSymbol RVal, bool Equal);
262  const SymExpr *Condition, const SVal &LVal,
263  const SVal &RVal, bool Eq);
265  const SymExpr *Condition);
269  const MemRegion *Cont,
270  const SymbolRef Sym);
272  const SymbolRef Sym);
273 const IteratorPosition *getIteratorPosition(ProgramStateRef State,
274  const SVal &Val);
275 const IteratorPosition *getIteratorPosition(ProgramStateRef State,
276  RegionOrSymbol RegOrSym);
278  const IteratorPosition &Pos);
280  RegionOrSymbol RegOrSym,
281  const IteratorPosition &Pos);
284  RegionOrSymbol RegOrSym,
285  const IteratorPosition &Pos, bool Equal);
287  const IteratorPosition &Pos1,
288  const IteratorPosition &Pos2,
289  bool Equal);
290 const ContainerData *getContainerData(ProgramStateRef State,
291  const MemRegion *Cont);
293  const ContainerData &CData);
294 bool hasLiveIterators(ProgramStateRef State, const MemRegion *Cont);
295 bool isOutOfRange(ProgramStateRef State, const IteratorPosition &Pos);
296 bool isZero(ProgramStateRef State, const NonLoc &Val);
297 } // namespace
298 
299 IteratorChecker::IteratorChecker() {
300  OutOfRangeBugType.reset(
301  new BugType(this, "Iterator out of range", "Misuse of STL APIs"));
302  OutOfRangeBugType->setSuppressOnSink(true);
303 }
304 
305 void IteratorChecker::checkPreCall(const CallEvent &Call,
306  CheckerContext &C) const {
307  // Check for out of range access
308  const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
309  if (!Func)
310  return;
311 
312  if (Func->isOverloadedOperator()) {
313  if (ChecksEnabled[CK_IteratorRangeChecker] &&
314  isRandomIncrOrDecrOperator(Func->getOverloadedOperator())) {
315  if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
316  // Check for out-of-range incrementions and decrementions
317  if (Call.getNumArgs() >= 1) {
318  verifyRandomIncrOrDecr(C, Func->getOverloadedOperator(),
319  Call.getReturnValue(),
320  InstCall->getCXXThisVal(), Call.getArgSVal(0));
321  }
322  } else {
323  if (Call.getNumArgs() >= 2) {
324  verifyRandomIncrOrDecr(C, Func->getOverloadedOperator(),
325  Call.getReturnValue(), Call.getArgSVal(0),
326  Call.getArgSVal(1));
327  }
328  }
329  } else if (ChecksEnabled[CK_IteratorRangeChecker] &&
330  isDereferenceOperator(Func->getOverloadedOperator())) {
331  // Check for dereference of out-of-range iterators
332  if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
333  verifyDereference(C, InstCall->getCXXThisVal());
334  } else {
335  verifyDereference(C, Call.getArgSVal(0));
336  }
337  }
338  }
339 }
340 
341 void IteratorChecker::checkPostCall(const CallEvent &Call,
342  CheckerContext &C) const {
343  // Record new iterator positions and iterator position changes
344  const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
345  if (!Func)
346  return;
347 
348  if (Func->isOverloadedOperator()) {
349  const auto Op = Func->getOverloadedOperator();
350  if (isSimpleComparisonOperator(Op)) {
351  if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
352  handleComparison(C, Call.getReturnValue(), InstCall->getCXXThisVal(),
353  Call.getArgSVal(0), Op);
354  } else {
355  handleComparison(C, Call.getReturnValue(), Call.getArgSVal(0),
356  Call.getArgSVal(1), Op);
357  }
358  } else if (isRandomIncrOrDecrOperator(Func->getOverloadedOperator())) {
359  if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
360  if (Call.getNumArgs() >= 1) {
361  handleRandomIncrOrDecr(C, Func->getOverloadedOperator(),
362  Call.getReturnValue(),
363  InstCall->getCXXThisVal(), Call.getArgSVal(0));
364  }
365  } else {
366  if (Call.getNumArgs() >= 2) {
367  handleRandomIncrOrDecr(C, Func->getOverloadedOperator(),
368  Call.getReturnValue(), Call.getArgSVal(0),
369  Call.getArgSVal(1));
370  }
371  }
372  } else if (isIncrementOperator(Func->getOverloadedOperator())) {
373  if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
374  handleIncrement(C, Call.getReturnValue(), InstCall->getCXXThisVal(),
375  Call.getNumArgs());
376  } else {
377  handleIncrement(C, Call.getReturnValue(), Call.getArgSVal(0),
378  Call.getNumArgs());
379  }
380  } else if (isDecrementOperator(Func->getOverloadedOperator())) {
381  if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
382  handleDecrement(C, Call.getReturnValue(), InstCall->getCXXThisVal(),
383  Call.getNumArgs());
384  } else {
385  handleDecrement(C, Call.getReturnValue(), Call.getArgSVal(0),
386  Call.getNumArgs());
387  }
388  }
389  } else {
390  const auto *OrigExpr = Call.getOriginExpr();
391  if (!OrigExpr)
392  return;
393 
394  if (!isIteratorType(Call.getResultType()))
395  return;
396 
397  auto State = C.getState();
398  // Already bound to container?
400  return;
401 
402  if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
403  if (isBeginCall(Func)) {
404  handleBegin(C, OrigExpr, Call.getReturnValue(),
405  InstCall->getCXXThisVal());
406  return;
407  }
408  if (isEndCall(Func)) {
409  handleEnd(C, OrigExpr, Call.getReturnValue(),
410  InstCall->getCXXThisVal());
411  return;
412  }
413  }
414 
415  // Copy-like and move constructors
416  if (isa<CXXConstructorCall>(&Call) && Call.getNumArgs() == 1) {
417  if (const auto *Pos = getIteratorPosition(State, Call.getArgSVal(0))) {
419  if (cast<CXXConstructorDecl>(Func)->isMoveConstructor()) {
421  }
422  C.addTransition(State);
423  return;
424  }
425  }
426 
427  // Assumption: if return value is an iterator which is not yet bound to a
428  // container, then look for the first iterator argument, and
429  // bind the return value to the same container. This approach
430  // works for STL algorithms.
431  // FIXME: Add a more conservative mode
432  for (unsigned i = 0; i < Call.getNumArgs(); ++i) {
433  if (isIteratorType(Call.getArgExpr(i)->getType())) {
434  if (const auto *Pos = getIteratorPosition(State, Call.getArgSVal(i))) {
435  assignToContainer(C, OrigExpr, Call.getReturnValue(),
436  Pos->getContainer());
437  return;
438  }
439  }
440  }
441  }
442 }
443 
444 void IteratorChecker::checkPreStmt(const CXXOperatorCallExpr *COCE,
445  CheckerContext &C) const {
446  const auto *ThisExpr = COCE->getArg(0);
447 
448  auto State = C.getState();
449  const auto *LCtx = C.getLocationContext();
450 
451  const auto CurrentThis = State->getSVal(ThisExpr, LCtx);
452  if (const auto *Reg = CurrentThis.getAsRegion()) {
453  if (!Reg->getAs<CXXTempObjectRegion>())
454  return;
455  const auto OldState = C.getPredecessor()->getFirstPred()->getState();
456  const auto OldThis = OldState->getSVal(ThisExpr, LCtx);
457  // FIXME: This solution is unreliable. It may happen that another checker
458  // subscribes to the pre-statement check of `CXXOperatorCallExpr`
459  // and adds a transition before us. The proper fix is to make the
460  // CFG provide a `ConstructionContext` for the `CXXOperatorCallExpr`,
461  // which would turn the corresponding `CFGStmt` element into a
462  // `CFGCXXRecordTypedCall` element, which will allow `ExprEngine` to
463  // foresee that the `begin()`/`end()` call constructs the object
464  // directly in the temporary region that `CXXOperatorCallExpr` takes
465  // as its implicit object argument.
466  const auto *Pos = getIteratorPosition(OldState, OldThis);
467  if (!Pos)
468  return;
469  State = setIteratorPosition(State, CurrentThis, *Pos);
470  C.addTransition(State);
471  }
472 }
473 
474 void IteratorChecker::checkPostStmt(const MaterializeTemporaryExpr *MTE,
475  CheckerContext &C) const {
476  /* Transfer iterator state to temporary objects */
477  auto State = C.getState();
478  const auto *Pos =
480  if (!Pos)
481  return;
482  State = setIteratorPosition(State, C.getSVal(MTE), *Pos);
483  C.addTransition(State);
484 }
485 
486 void IteratorChecker::checkLiveSymbols(ProgramStateRef State,
487  SymbolReaper &SR) const {
488  // Keep symbolic expressions of iterator positions, container begins and ends
489  // alive
490  auto RegionMap = State->get<IteratorRegionMap>();
491  for (const auto Reg : RegionMap) {
492  const auto Offset = Reg.second.getOffset();
493  for (auto i = Offset->symbol_begin(); i != Offset->symbol_end(); ++i)
494  if (isa<SymbolData>(*i))
495  SR.markLive(*i);
496  }
497 
498  auto SymbolMap = State->get<IteratorSymbolMap>();
499  for (const auto Sym : SymbolMap) {
500  const auto Offset = Sym.second.getOffset();
501  for (auto i = Offset->symbol_begin(); i != Offset->symbol_end(); ++i)
502  if (isa<SymbolData>(*i))
503  SR.markLive(*i);
504  }
505 
506  auto ContMap = State->get<ContainerMap>();
507  for (const auto Cont : ContMap) {
508  const auto CData = Cont.second;
509  if (CData.getBegin()) {
510  SR.markLive(CData.getBegin());
511  }
512  if (CData.getEnd()) {
513  SR.markLive(CData.getEnd());
514  }
515  }
516 }
517 
518 void IteratorChecker::checkDeadSymbols(SymbolReaper &SR,
519  CheckerContext &C) const {
520  // Cleanup
521  auto State = C.getState();
522 
523  auto RegionMap = State->get<IteratorRegionMap>();
524  for (const auto Reg : RegionMap) {
525  if (!SR.isLiveRegion(Reg.first)) {
526  State = State->remove<IteratorRegionMap>(Reg.first);
527  }
528  }
529 
530  auto SymbolMap = State->get<IteratorSymbolMap>();
531  for (const auto Sym : SymbolMap) {
532  if (!SR.isLive(Sym.first)) {
533  State = State->remove<IteratorSymbolMap>(Sym.first);
534  }
535  }
536 
537  auto ContMap = State->get<ContainerMap>();
538  for (const auto Cont : ContMap) {
539  if (!SR.isLiveRegion(Cont.first)) {
540  // We must keep the container data while it has live iterators to be able
541  // to compare them to the begin and the end of the container.
542  if (!hasLiveIterators(State, Cont.first)) {
543  State = State->remove<ContainerMap>(Cont.first);
544  }
545  }
546  }
547 
548  auto ComparisonMap = State->get<IteratorComparisonMap>();
549  for (const auto Comp : ComparisonMap) {
550  if (!SR.isLive(Comp.first)) {
551  State = State->remove<IteratorComparisonMap>(Comp.first);
552  }
553  }
554 
555  C.addTransition(State);
556 }
557 
558 ProgramStateRef IteratorChecker::evalAssume(ProgramStateRef State, SVal Cond,
559  bool Assumption) const {
560  // Load recorded comparison and transfer iterator state between sides
561  // according to comparison operator and assumption
562  const auto *SE = Cond.getAsSymExpr();
563  if (!SE)
564  return State;
565 
566  auto Opc = getOpcode(SE);
567  if (Opc != BO_EQ && Opc != BO_NE)
568  return State;
569 
570  bool Negated = false;
571  const auto *Comp = loadComparison(State, SE);
572  if (!Comp) {
573  // Try negated comparison, which is a SymExpr to 0 integer comparison
574  const auto *SIE = dyn_cast<SymIntExpr>(SE);
575  if (!SIE)
576  return State;
577 
578  if (SIE->getRHS() != 0)
579  return State;
580 
581  SE = SIE->getLHS();
582  Negated = SIE->getOpcode() == BO_EQ; // Equal to zero means negation
583  Opc = getOpcode(SE);
584  if (Opc != BO_EQ && Opc != BO_NE)
585  return State;
586 
587  Comp = loadComparison(State, SE);
588  if (!Comp)
589  return State;
590  }
591 
592  return processComparison(State, Comp->getLeft(), Comp->getRight(),
593  (Comp->isEquality() == Assumption) != Negated);
594 }
595 
596 void IteratorChecker::handleComparison(CheckerContext &C, const SVal &RetVal,
597  const SVal &LVal, const SVal &RVal,
598  OverloadedOperatorKind Op) const {
599  // Record the operands and the operator of the comparison for the next
600  // evalAssume, if the result is a symbolic expression. If it is a concrete
601  // value (only one branch is possible), then transfer the state between
602  // the operands according to the operator and the result
603  auto State = C.getState();
604  if (const auto *Condition = RetVal.getAsSymbolicExpression()) {
605  const auto *LPos = getIteratorPosition(State, LVal);
606  const auto *RPos = getIteratorPosition(State, RVal);
607  if (!LPos && !RPos)
608  return;
609  State = saveComparison(State, Condition, LVal, RVal, Op == OO_EqualEqual);
610  C.addTransition(State);
611  } else if (const auto TruthVal = RetVal.getAs<nonloc::ConcreteInt>()) {
612  if ((State = processComparison(
613  State, getRegionOrSymbol(LVal), getRegionOrSymbol(RVal),
614  (Op == OO_EqualEqual) == (TruthVal->getValue() != 0)))) {
615  C.addTransition(State);
616  } else {
617  C.generateSink(State, C.getPredecessor());
618  }
619  }
620 }
621 
622 void IteratorChecker::verifyDereference(CheckerContext &C,
623  const SVal &Val) const {
624  auto State = C.getState();
625  const auto *Pos = getIteratorPosition(State, Val);
626  if (Pos && isOutOfRange(State, *Pos)) {
627  // If I do not put a tag here, some range tests will fail
628  static CheckerProgramPointTag Tag("IteratorRangeChecker",
629  "IteratorOutOfRange");
630  auto *N = C.generateNonFatalErrorNode(State, &Tag);
631  if (!N)
632  return;
633  reportOutOfRangeBug("Iterator accessed outside of its range.", Val, C, N);
634  }
635 }
636 
637 void IteratorChecker::handleIncrement(CheckerContext &C, const SVal &RetVal,
638  const SVal &Iter, bool Postfix) const {
639  // Increment the symbolic expressions which represents the position of the
640  // iterator
641  auto State = C.getState();
642  const auto *Pos = getIteratorPosition(State, Iter);
643  if (Pos) {
644  auto &SymMgr = C.getSymbolManager();
645  auto &BVF = SymMgr.getBasicVals();
646  auto &SVB = C.getSValBuilder();
647  const auto OldOffset = Pos->getOffset();
648  auto NewOffset =
649  SVB.evalBinOp(State, BO_Add,
650  nonloc::SymbolVal(OldOffset),
651  nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
652  SymMgr.getType(OldOffset)).getAsSymbol();
653  auto NewPos = Pos->setTo(NewOffset);
654  State = setIteratorPosition(State, Iter, NewPos);
655  State = setIteratorPosition(State, RetVal, Postfix ? *Pos : NewPos);
656  C.addTransition(State);
657  }
658 }
659 
660 void IteratorChecker::handleDecrement(CheckerContext &C, const SVal &RetVal,
661  const SVal &Iter, bool Postfix) const {
662  // Decrement the symbolic expressions which represents the position of the
663  // iterator
664  auto State = C.getState();
665  const auto *Pos = getIteratorPosition(State, Iter);
666  if (Pos) {
667  auto &SymMgr = C.getSymbolManager();
668  auto &BVF = SymMgr.getBasicVals();
669  auto &SVB = C.getSValBuilder();
670  const auto OldOffset = Pos->getOffset();
671  auto NewOffset =
672  SVB.evalBinOp(State, BO_Sub,
673  nonloc::SymbolVal(OldOffset),
674  nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
675  SymMgr.getType(OldOffset)).getAsSymbol();
676  auto NewPos = Pos->setTo(NewOffset);
677  State = setIteratorPosition(State, Iter, NewPos);
678  State = setIteratorPosition(State, RetVal, Postfix ? *Pos : NewPos);
679  C.addTransition(State);
680  }
681 }
682 
683 // This function tells the analyzer's engine that symbols produced by our
684 // checker, most notably iterator positions, are relatively small.
685 // A distance between items in the container should not be very large.
686 // By assuming that it is within around 1/8 of the address space,
687 // we can help the analyzer perform operations on these symbols
688 // without being afraid of integer overflows.
689 // FIXME: Should we provide it as an API, so that all checkers could use it?
691  long Scale) {
692  SValBuilder &SVB = State->getStateManager().getSValBuilder();
694 
695  QualType T = Sym->getType();
697  APSIntType AT = BV.getAPSIntType(T);
698 
699  ProgramStateRef NewState = State;
700 
701  llvm::APSInt Max = AT.getMaxValue() / AT.getValue(Scale);
702  SVal IsCappedFromAbove =
703  SVB.evalBinOpNN(State, BO_LE, nonloc::SymbolVal(Sym),
705  if (auto DV = IsCappedFromAbove.getAs<DefinedSVal>()) {
706  NewState = NewState->assume(*DV, true);
707  if (!NewState)
708  return State;
709  }
710 
711  llvm::APSInt Min = -Max;
712  SVal IsCappedFromBelow =
713  SVB.evalBinOpNN(State, BO_GE, nonloc::SymbolVal(Sym),
715  if (auto DV = IsCappedFromBelow.getAs<DefinedSVal>()) {
716  NewState = NewState->assume(*DV, true);
717  if (!NewState)
718  return State;
719  }
720 
721  return NewState;
722 }
723 
724 void IteratorChecker::handleRandomIncrOrDecr(CheckerContext &C,
726  const SVal &RetVal,
727  const SVal &LHS,
728  const SVal &RHS) const {
729  // Increment or decrement the symbolic expressions which represents the
730  // position of the iterator
731  auto State = C.getState();
732  const auto *Pos = getIteratorPosition(State, LHS);
733  if (!Pos)
734  return;
735 
736  const auto *value = &RHS;
737  if (auto loc = RHS.getAs<Loc>()) {
738  const auto val = State->getRawSVal(*loc);
739  value = &val;
740  }
741 
742  auto &SymMgr = C.getSymbolManager();
743  auto &SVB = C.getSValBuilder();
744  auto BinOp = (Op == OO_Plus || Op == OO_PlusEqual) ? BO_Add : BO_Sub;
745  const auto OldOffset = Pos->getOffset();
746  SymbolRef NewOffset;
747  if (const auto intValue = value->getAs<nonloc::ConcreteInt>()) {
748  // For concrete integers we can calculate the new position
749  NewOffset = SVB.evalBinOp(State, BinOp, nonloc::SymbolVal(OldOffset),
750  *intValue,
751  SymMgr.getType(OldOffset)).getAsSymbol();
752  } else {
753  // For other symbols create a new symbol to keep expressions simple
754  const auto &LCtx = C.getLocationContext();
755  NewOffset = SymMgr.conjureSymbol(nullptr, LCtx, SymMgr.getType(OldOffset),
756  C.blockCount());
757  State = assumeNoOverflow(State, NewOffset, 4);
758  }
759  auto NewPos = Pos->setTo(NewOffset);
760  auto &TgtVal = (Op == OO_PlusEqual || Op == OO_MinusEqual) ? LHS : RetVal;
761  State = setIteratorPosition(State, TgtVal, NewPos);
762  C.addTransition(State);
763 }
764 
765 void IteratorChecker::verifyRandomIncrOrDecr(CheckerContext &C,
767  const SVal &RetVal,
768  const SVal &LHS,
769  const SVal &RHS) const {
770  auto State = C.getState();
771 
772  // If the iterator is initially inside its range, then the operation is valid
773  const auto *Pos = getIteratorPosition(State, LHS);
774  if (!Pos || !isOutOfRange(State, *Pos))
775  return;
776 
777  auto value = RHS;
778  if (auto loc = RHS.getAs<Loc>()) {
779  value = State->getRawSVal(*loc);
780  }
781 
782  // Incremention or decremention by 0 is never bug
783  if (isZero(State, value.castAs<NonLoc>()))
784  return;
785 
786  auto &SymMgr = C.getSymbolManager();
787  auto &SVB = C.getSValBuilder();
788  auto BinOp = (Op == OO_Plus || Op == OO_PlusEqual) ? BO_Add : BO_Sub;
789  const auto OldOffset = Pos->getOffset();
790  const auto intValue = value.getAs<nonloc::ConcreteInt>();
791  if (!intValue)
792  return;
793 
794  auto NewOffset = SVB.evalBinOp(State, BinOp, nonloc::SymbolVal(OldOffset),
795  *intValue,
796  SymMgr.getType(OldOffset)).getAsSymbol();
797  auto NewPos = Pos->setTo(NewOffset);
798 
799  // If out of range, the only valid operation is to step into the range
800  if (isOutOfRange(State, NewPos)) {
801  auto *N = C.generateNonFatalErrorNode(State);
802  if (!N)
803  return;
804  reportOutOfRangeBug("Iterator accessed past its end.", LHS, C, N);
805  }
806 }
807 
808 void IteratorChecker::handleBegin(CheckerContext &C, const Expr *CE,
809  const SVal &RetVal, const SVal &Cont) const {
810  const auto *ContReg = Cont.getAsRegion();
811  if (!ContReg)
812  return;
813 
814  while (const auto *CBOR = ContReg->getAs<CXXBaseObjectRegion>()) {
815  ContReg = CBOR->getSuperRegion();
816  }
817 
818  // If the container already has a begin symbol then use it. Otherwise first
819  // create a new one.
820  auto State = C.getState();
821  auto BeginSym = getContainerBegin(State, ContReg);
822  if (!BeginSym) {
823  auto &SymMgr = C.getSymbolManager();
824  BeginSym = SymMgr.conjureSymbol(CE, C.getLocationContext(),
825  C.getASTContext().LongTy, C.blockCount());
826  State = assumeNoOverflow(State, BeginSym, 4);
827  State = createContainerBegin(State, ContReg, BeginSym);
828  }
829  State = setIteratorPosition(State, RetVal,
830  IteratorPosition::getPosition(ContReg, BeginSym));
831  C.addTransition(State);
832 }
833 
834 void IteratorChecker::handleEnd(CheckerContext &C, const Expr *CE,
835  const SVal &RetVal, const SVal &Cont) const {
836  const auto *ContReg = Cont.getAsRegion();
837  if (!ContReg)
838  return;
839 
840  while (const auto *CBOR = ContReg->getAs<CXXBaseObjectRegion>()) {
841  ContReg = CBOR->getSuperRegion();
842  }
843 
844  // If the container already has an end symbol then use it. Otherwise first
845  // create a new one.
846  auto State = C.getState();
847  auto EndSym = getContainerEnd(State, ContReg);
848  if (!EndSym) {
849  auto &SymMgr = C.getSymbolManager();
850  EndSym = SymMgr.conjureSymbol(CE, C.getLocationContext(),
851  C.getASTContext().LongTy, C.blockCount());
852  State = assumeNoOverflow(State, EndSym, 4);
853  State = createContainerEnd(State, ContReg, EndSym);
854  }
855  State = setIteratorPosition(State, RetVal,
856  IteratorPosition::getPosition(ContReg, EndSym));
857  C.addTransition(State);
858 }
859 
860 void IteratorChecker::assignToContainer(CheckerContext &C, const Expr *CE,
861  const SVal &RetVal,
862  const MemRegion *Cont) const {
863  while (const auto *CBOR = Cont->getAs<CXXBaseObjectRegion>()) {
864  Cont = CBOR->getSuperRegion();
865  }
866 
867  auto State = C.getState();
868  auto &SymMgr = C.getSymbolManager();
869  auto Sym = SymMgr.conjureSymbol(CE, C.getLocationContext(),
870  C.getASTContext().LongTy, C.blockCount());
871  State = assumeNoOverflow(State, Sym, 4);
872  State = setIteratorPosition(State, RetVal,
873  IteratorPosition::getPosition(Cont, Sym));
874  C.addTransition(State);
875 }
876 
877 void IteratorChecker::reportOutOfRangeBug(const StringRef &Message,
878  const SVal &Val, CheckerContext &C,
879  ExplodedNode *ErrNode) const {
880  auto R = llvm::make_unique<BugReport>(*OutOfRangeBugType, Message, ErrNode);
881  R->markInteresting(Val);
882  C.emitReport(std::move(R));
883 }
884 
885 namespace {
886 
887 bool isLess(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2);
888 bool isGreaterOrEqual(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2);
889 bool compare(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2,
891 bool compare(ProgramStateRef State, NonLoc NL1, NonLoc NL2,
893 
894 bool isIteratorType(const QualType &Type) {
895  if (Type->isPointerType())
896  return true;
897 
898  const auto *CRD = Type->getUnqualifiedDesugaredType()->getAsCXXRecordDecl();
899  return isIterator(CRD);
900 }
901 
902 bool isIterator(const CXXRecordDecl *CRD) {
903  if (!CRD)
904  return false;
905 
906  const auto Name = CRD->getName();
907  if (!(Name.endswith_lower("iterator") || Name.endswith_lower("iter") ||
908  Name.endswith_lower("it")))
909  return false;
910 
911  bool HasCopyCtor = false, HasCopyAssign = true, HasDtor = false,
912  HasPreIncrOp = false, HasPostIncrOp = false, HasDerefOp = false;
913  for (const auto *Method : CRD->methods()) {
914  if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(Method)) {
915  if (Ctor->isCopyConstructor()) {
916  HasCopyCtor = !Ctor->isDeleted() && Ctor->getAccess() == AS_public;
917  }
918  continue;
919  }
920  if (const auto *Dtor = dyn_cast<CXXDestructorDecl>(Method)) {
921  HasDtor = !Dtor->isDeleted() && Dtor->getAccess() == AS_public;
922  continue;
923  }
924  if (Method->isCopyAssignmentOperator()) {
925  HasCopyAssign = !Method->isDeleted() && Method->getAccess() == AS_public;
926  continue;
927  }
928  if (!Method->isOverloadedOperator())
929  continue;
930  const auto OPK = Method->getOverloadedOperator();
931  if (OPK == OO_PlusPlus) {
932  HasPreIncrOp = HasPreIncrOp || (Method->getNumParams() == 0);
933  HasPostIncrOp = HasPostIncrOp || (Method->getNumParams() == 1);
934  continue;
935  }
936  if (OPK == OO_Star) {
937  HasDerefOp = (Method->getNumParams() == 0);
938  continue;
939  }
940  }
941 
942  return HasCopyCtor && HasCopyAssign && HasDtor && HasPreIncrOp &&
943  HasPostIncrOp && HasDerefOp;
944 }
945 
946 bool isBeginCall(const FunctionDecl *Func) {
947  const auto *IdInfo = Func->getIdentifier();
948  if (!IdInfo)
949  return false;
950  return IdInfo->getName().endswith_lower("begin");
951 }
952 
953 bool isEndCall(const FunctionDecl *Func) {
954  const auto *IdInfo = Func->getIdentifier();
955  if (!IdInfo)
956  return false;
957  return IdInfo->getName().endswith_lower("end");
958 }
959 
961  return OK == OO_EqualEqual || OK == OO_ExclaimEqual;
962 }
963 
965  return OK == OO_Star || OK == OO_Arrow || OK == OO_ArrowStar ||
966  OK == OO_Subscript;
967 }
968 
970  return OK == OO_PlusPlus;
971 }
972 
974  return OK == OO_MinusMinus;
975 }
976 
978  return OK == OO_Plus || OK == OO_PlusEqual || OK == OO_Minus ||
979  OK == OO_MinusEqual;
980 }
981 
983  if (const auto *BSE = dyn_cast<BinarySymExpr>(SE)) {
984  return BSE->getOpcode();
985  } else if (const auto *SC = dyn_cast<SymbolConjured>(SE)) {
986  const auto *COE = dyn_cast_or_null<CXXOperatorCallExpr>(SC->getStmt());
987  if (!COE)
988  return BO_Comma; // Extremal value, neither EQ nor NE
989  if (COE->getOperator() == OO_EqualEqual) {
990  return BO_EQ;
991  } else if (COE->getOperator() == OO_ExclaimEqual) {
992  return BO_NE;
993  }
994  return BO_Comma; // Extremal value, neither EQ nor NE
995  }
996  return BO_Comma; // Extremal value, neither EQ nor NE
997 }
998 
999 const RegionOrSymbol getRegionOrSymbol(const SVal &Val) {
1000  if (const auto Reg = Val.getAsRegion()) {
1001  return Reg;
1002  } else if (const auto Sym = Val.getAsSymbol()) {
1003  return Sym;
1004  } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
1005  return LCVal->getRegion();
1006  }
1007  return RegionOrSymbol();
1008 }
1009 
1011  RegionOrSymbol LVal,
1012  RegionOrSymbol RVal, bool Equal) {
1013  const auto *LPos = getIteratorPosition(State, LVal);
1014  const auto *RPos = getIteratorPosition(State, RVal);
1015  if (LPos && !RPos) {
1016  State = adjustIteratorPosition(State, RVal, *LPos, Equal);
1017  } else if (!LPos && RPos) {
1018  State = adjustIteratorPosition(State, LVal, *RPos, Equal);
1019  } else if (LPos && RPos) {
1020  State = relateIteratorPositions(State, *LPos, *RPos, Equal);
1021  }
1022  return State;
1023 }
1024 
1026  const SymExpr *Condition, const SVal &LVal,
1027  const SVal &RVal, bool Eq) {
1028  const auto Left = getRegionOrSymbol(LVal);
1029  const auto Right = getRegionOrSymbol(RVal);
1030  if (!Left || !Right)
1031  return State;
1032  return State->set<IteratorComparisonMap>(Condition,
1033  IteratorComparison(Left, Right, Eq));
1034 }
1035 
1037  const SymExpr *Condition) {
1038  return State->get<IteratorComparisonMap>(Condition);
1039 }
1040 
1042  const auto *CDataPtr = getContainerData(State, Cont);
1043  if (!CDataPtr)
1044  return nullptr;
1045 
1046  return CDataPtr->getBegin();
1047 }
1048 
1049 SymbolRef getContainerEnd(ProgramStateRef State, const MemRegion *Cont) {
1050  const auto *CDataPtr = getContainerData(State, Cont);
1051  if (!CDataPtr)
1052  return nullptr;
1053 
1054  return CDataPtr->getEnd();
1055 }
1056 
1058  const MemRegion *Cont,
1059  const SymbolRef Sym) {
1060  // Only create if it does not exist
1061  const auto *CDataPtr = getContainerData(State, Cont);
1062  if (CDataPtr) {
1063  if (CDataPtr->getBegin()) {
1064  return State;
1065  }
1066  const auto CData = CDataPtr->newBegin(Sym);
1067  return setContainerData(State, Cont, CData);
1068  }
1069  const auto CData = ContainerData::fromBegin(Sym);
1070  return setContainerData(State, Cont, CData);
1071 }
1072 
1074  const SymbolRef Sym) {
1075  // Only create if it does not exist
1076  const auto *CDataPtr = getContainerData(State, Cont);
1077  if (CDataPtr) {
1078  if (CDataPtr->getEnd()) {
1079  return State;
1080  }
1081  const auto CData = CDataPtr->newEnd(Sym);
1082  return setContainerData(State, Cont, CData);
1083  }
1084  const auto CData = ContainerData::fromEnd(Sym);
1085  return setContainerData(State, Cont, CData);
1086 }
1087 
1088 const ContainerData *getContainerData(ProgramStateRef State,
1089  const MemRegion *Cont) {
1090  return State->get<ContainerMap>(Cont);
1091 }
1092 
1094  const ContainerData &CData) {
1095  return State->set<ContainerMap>(Cont, CData);
1096 }
1097 
1098 const IteratorPosition *getIteratorPosition(ProgramStateRef State,
1099  const SVal &Val) {
1100  if (const auto Reg = Val.getAsRegion()) {
1101  return State->get<IteratorRegionMap>(Reg);
1102  } else if (const auto Sym = Val.getAsSymbol()) {
1103  return State->get<IteratorSymbolMap>(Sym);
1104  } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
1105  return State->get<IteratorRegionMap>(LCVal->getRegion());
1106  }
1107  return nullptr;
1108 }
1109 
1110 const IteratorPosition *getIteratorPosition(ProgramStateRef State,
1111  RegionOrSymbol RegOrSym) {
1112  if (RegOrSym.is<const MemRegion *>()) {
1113  return State->get<IteratorRegionMap>(RegOrSym.get<const MemRegion *>());
1114  } else if (RegOrSym.is<SymbolRef>()) {
1115  return State->get<IteratorSymbolMap>(RegOrSym.get<SymbolRef>());
1116  }
1117  return nullptr;
1118 }
1119 
1121  const IteratorPosition &Pos) {
1122  if (const auto Reg = Val.getAsRegion()) {
1123  return State->set<IteratorRegionMap>(Reg, Pos);
1124  } else if (const auto Sym = Val.getAsSymbol()) {
1125  return State->set<IteratorSymbolMap>(Sym, Pos);
1126  } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
1127  return State->set<IteratorRegionMap>(LCVal->getRegion(), Pos);
1128  }
1129  return nullptr;
1130 }
1131 
1133  RegionOrSymbol RegOrSym,
1134  const IteratorPosition &Pos) {
1135  if (RegOrSym.is<const MemRegion *>()) {
1136  return State->set<IteratorRegionMap>(RegOrSym.get<const MemRegion *>(),
1137  Pos);
1138  } else if (RegOrSym.is<SymbolRef>()) {
1139  return State->set<IteratorSymbolMap>(RegOrSym.get<SymbolRef>(), Pos);
1140  }
1141  return nullptr;
1142 }
1143 
1145  if (const auto Reg = Val.getAsRegion()) {
1146  return State->remove<IteratorRegionMap>(Reg);
1147  } else if (const auto Sym = Val.getAsSymbol()) {
1148  return State->remove<IteratorSymbolMap>(Sym);
1149  } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
1150  return State->remove<IteratorRegionMap>(LCVal->getRegion());
1151  }
1152  return nullptr;
1153 }
1154 
1156  RegionOrSymbol RegOrSym,
1157  const IteratorPosition &Pos,
1158  bool Equal) {
1159  if (Equal) {
1160  return setIteratorPosition(State, RegOrSym, Pos);
1161  } else {
1162  return State;
1163  }
1164 }
1165 
1167  const IteratorPosition &Pos1,
1168  const IteratorPosition &Pos2,
1169  bool Equal) {
1170  auto &SVB = State->getStateManager().getSValBuilder();
1171 
1172  // FIXME: This code should be reworked as follows:
1173  // 1. Subtract the operands using evalBinOp().
1174  // 2. Assume that the result doesn't overflow.
1175  // 3. Compare the result to 0.
1176  // 4. Assume the result of the comparison.
1177  const auto comparison =
1178  SVB.evalBinOp(State, BO_EQ, nonloc::SymbolVal(Pos1.getOffset()),
1179  nonloc::SymbolVal(Pos2.getOffset()),
1180  SVB.getConditionType());
1181 
1182  assert(comparison.getAs<DefinedSVal>() &&
1183  "Symbol comparison must be a `DefinedSVal`");
1184 
1185  auto NewState = State->assume(comparison.castAs<DefinedSVal>(), Equal);
1186  if (const auto CompSym = comparison.getAsSymbol()) {
1187  assert(isa<SymIntExpr>(CompSym) &&
1188  "Symbol comparison must be a `SymIntExpr`");
1190  cast<SymIntExpr>(CompSym)->getOpcode()) &&
1191  "Symbol comparison must be a comparison");
1192  return assumeNoOverflow(NewState, cast<SymIntExpr>(CompSym)->getLHS(), 2);
1193  }
1194 
1195  return NewState;
1196 }
1197 
1198 bool hasLiveIterators(ProgramStateRef State, const MemRegion *Cont) {
1199  auto RegionMap = State->get<IteratorRegionMap>();
1200  for (const auto Reg : RegionMap) {
1201  if (Reg.second.getContainer() == Cont)
1202  return true;
1203  }
1204 
1205  auto SymbolMap = State->get<IteratorSymbolMap>();
1206  for (const auto Sym : SymbolMap) {
1207  if (Sym.second.getContainer() == Cont)
1208  return true;
1209  }
1210 
1211  return false;
1212 }
1213 
1214 bool isZero(ProgramStateRef State, const NonLoc &Val) {
1215  auto &BVF = State->getBasicVals();
1216  return compare(State, Val,
1217  nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))),
1218  BO_EQ);
1219 }
1220 
1221 bool isOutOfRange(ProgramStateRef State, const IteratorPosition &Pos) {
1222  const auto *Cont = Pos.getContainer();
1223  const auto *CData = getContainerData(State, Cont);
1224  if (!CData)
1225  return false;
1226 
1227  // Out of range means less than the begin symbol or greater or equal to the
1228  // end symbol.
1229 
1230  const auto Beg = CData->getBegin();
1231  if (Beg) {
1232  if (isLess(State, Pos.getOffset(), Beg)) {
1233  return true;
1234  }
1235  }
1236 
1237  const auto End = CData->getEnd();
1238  if (End) {
1239  if (isGreaterOrEqual(State, Pos.getOffset(), End)) {
1240  return true;
1241  }
1242  }
1243 
1244  return false;
1245 }
1246 
1247 bool isLess(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) {
1248  return compare(State, Sym1, Sym2, BO_LT);
1249 }
1250 
1251 bool isGreaterOrEqual(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) {
1252  return compare(State, Sym1, Sym2, BO_GE);
1253 }
1254 
1255 bool compare(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2,
1256  BinaryOperator::Opcode Opc) {
1257  return compare(State, nonloc::SymbolVal(Sym1), nonloc::SymbolVal(Sym2), Opc);
1258 }
1259 
1260 bool compare(ProgramStateRef State, NonLoc NL1, NonLoc NL2,
1261  BinaryOperator::Opcode Opc) {
1262  auto &SVB = State->getStateManager().getSValBuilder();
1263 
1264  const auto comparison =
1265  SVB.evalBinOp(State, Opc, NL1, NL2, SVB.getConditionType());
1266 
1267  assert(comparison.getAs<DefinedSVal>() &&
1268  "Symbol comparison must be a `DefinedSVal`");
1269 
1270  return !State->assume(comparison.castAs<DefinedSVal>(), false);
1271 }
1272 
1273 } // namespace
1274 
1275 #define REGISTER_CHECKER(name) \
1276  void ento::register##name(CheckerManager &Mgr) { \
1277  auto *checker = Mgr.registerChecker<IteratorChecker>(); \
1278  checker->ChecksEnabled[IteratorChecker::CK_##name] = true; \
1279  checker->CheckNames[IteratorChecker::CK_##name] = \
1280  Mgr.getCurrentCheckName(); \
1281  }
1282 
1283 REGISTER_CHECKER(IteratorRangeChecker)
1284 
A call to an overloaded operator written using operator syntax.
Definition: ExprCXX.h:78
const ProgramStateRef processComparison(ProgramStateRef State, RegionOrSymbol LVal, RegionOrSymbol RVal, bool Equal)
Represents a function declaration or definition.
Definition: Decl.h:1716
A (possibly-)qualified type.
Definition: Type.h:655
MemRegion - The root abstract class for all memory regions.
Definition: MemRegion.h:94
void markLive(SymbolRef sym)
Unconditionally marks a symbol as live.
SymbolRef getContainerEnd(ProgramStateRef State, const MemRegion *Cont)
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition: Expr.h:2385
bool isSimpleComparisonOperator(OverloadedOperatorKind OK)
bool operator==(CanQual< T > x, CanQual< U > y)
REGISTER_MAP_WITH_PROGRAMSTATE(IteratorRegionMap, const MemRegion *, IteratorPosition) REGISTER_MAP_WITH_PROGRAMSTATE(IteratorComparisonMap
A helper class which wraps a boolean value set to false by default.
Definition: Checker.h:567
ExplodedNode * addTransition(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generates a new transition in the program state graph (ExplodedGraph).
The base class of the type hierarchy.
Definition: Type.h:1428
CanQualType LongTy
Definition: ASTContext.h:1013
bool isOutOfRange(ProgramStateRef State, const IteratorPosition &Pos)
const ProgramStateRef & getState() const
bool isZero(ProgramStateRef State, const NonLoc &Val)
Represents a prvalue temporary that is written into memory so that a reference can bind to it...
Definition: ExprCXX.h:4150
Value representing integer constant.
Definition: SVals.h:377
const Expr * getOriginExpr() const
Returns the expression whose value will be the result of this call.
Definition: CallEvent.h:249
BasicValueFactory & getBasicVals()
ExplodedNode * getPredecessor()
Returns the previous node in the exploded graph, which includes the state of the program before the c...
SVal getSVal(const Stmt *S) const
Get the value of arbitrary expressions at this point in the path.
Symbolic value.
Definition: SymExpr.h:30
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
Definition: Decl.h:269
Expr * GetTemporaryExpr() const
Retrieve the temporary-generating subexpression whose value will be materialized into a glvalue...
Definition: ExprCXX.h:4191
LineState State
symbol_iterator symbol_begin() const
Definition: SymExpr.h:87
ProgramStateRef adjustIteratorPosition(ProgramStateRef State, RegionOrSymbol RegOrSym, const IteratorPosition &Pos, bool Equal)
virtual const Expr * getArgExpr(unsigned Index) const
Returns the expression associated with a given argument.
Definition: CallEvent.h:299
const SymExpr * getAsSymbolicExpression() const
getAsSymbolicExpression - If this Sval wraps a symbolic expression then return that expression...
Definition: SVals.cpp:137
BinaryOperatorKind
uint32_t Offset
Definition: CacheTokens.cpp:43
bool isLiveRegion(const MemRegion *region)
SVal getReturnValue() const
Returns the return value of the call.
Definition: CallEvent.cpp:345
A record of the "type" of an APSInt, used for conversions.
Definition: APSIntType.h:20
Represents a symbolic expression like &#39;x&#39; + 3.
bool isEndCall(const FunctionDecl *Func)
ExplodedNode * getFirstPred()
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:411
virtual QualType getType() const =0
SymbolRef getAsSymbol(bool IncludeBaseRegions=false) const
If this SVal wraps a symbol return that SymbolRef.
Definition: SVals.cpp:127
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
Definition: Type.cpp:1627
const IteratorPosition * getIteratorPosition(ProgramStateRef State, RegionOrSymbol RegOrSym)
const RegionTy * getAs() const
Definition: MemRegion.h:1180
Expr - This represents one expression.
Definition: Expr.h:106
SourceLocation End
static bool compare(const PathDiagnostic &X, const PathDiagnostic &Y)
bool isDereferenceOperator(OverloadedOperatorKind OK)
QualType getConditionType() const
Definition: SValBuilder.h:161
SourceLocation Begin
SymbolManager & getSymbolManager()
ProgramStateRef createContainerEnd(ProgramStateRef State, const MemRegion *Cont, const SymbolRef Sym)
QualType getType() const
Definition: Expr.h:128
virtual const Decl * getDecl() const
Returns the declaration of the function or method that will be called.
Definition: CallEvent.h:229
SVal evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op, SVal lhs, SVal rhs, QualType type)
ExplodedNode * generateNonFatalErrorNode(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generate a transition to a node that will be used to report an error.
Optional< T > getAs() const
Convert to the specified SVal type, returning None if this SVal is not of the desired type...
Definition: SVals.h:112
const ContainerData * getContainerData(ProgramStateRef State, const MemRegion *Cont)
bool isComparisonOp() const
Definition: Expr.h:3236
void emitReport(std::unique_ptr< BugReport > R)
Emit the diagnostics report.
ExplodedNode * generateSink(ProgramStateRef State, ExplodedNode *Pred, const ProgramPointTag *Tag=nullptr)
Generate a sink node.
ProgramStateRef setIteratorPosition(ProgramStateRef State, RegionOrSymbol RegOrSym, const IteratorPosition &Pos)
const MemRegion * getAsRegion() const
Definition: SVals.cpp:151
SVal - This represents a symbolic expression, which can be either an L-value or an R-value...
Definition: SVals.h:76
bool isSignedIntegerOrEnumerationType() const
Determines whether this is an integer type that is signed or an enumeration types whose underlying ty...
Definition: Type.cpp:1864
SymbolRef getContainerBegin(ProgramStateRef State, const MemRegion *Cont)
A class responsible for cleaning up unused symbols.
bool isDecrementOperator(OverloadedOperatorKind OK)
ProgramStateRef relateIteratorPositions(ProgramStateRef State, const IteratorPosition &Pos1, const IteratorPosition &Pos2, bool Equal)
const IteratorComparison * loadComparison(ProgramStateRef State, const SymExpr *Condition)
virtual SVal evalBinOpNN(ProgramStateRef state, BinaryOperator::Opcode op, NonLoc lhs, NonLoc rhs, QualType resultTy)=0
Create a new value which represents a binary expression with two non- location operands.
unsigned blockCount() const
Returns the number of times the current block has been visited along the analyzed path...
StringRef getName() const
Return the actual identifier string.
Dataflow Directional Tag Classes.
OverloadedOperatorKind
Enumeration specifying the different kinds of C++ overloaded operators.
Definition: OperatorKinds.h:22
#define REGISTER_CHECKER(name)
static symbol_iterator symbol_end()
Definition: SymExpr.h:88
BinaryOperator::Opcode getOpcode(const SymExpr *SE)
Represents symbolic expression that isn&#39;t a location.
Definition: SVals.h:347
Represents an abstract call to a function or method along a particular path.
Definition: CallEvent.h:165
const SymbolConjured * conjureSymbol(const Stmt *E, const LocationContext *LCtx, QualType T, unsigned VisitCount, const void *SymbolTag=nullptr)
bool isIteratorType(const QualType &Type)
ProgramStateRef removeIteratorPosition(ProgramStateRef State, const SVal &Val)
APSIntType getAPSIntType(QualType T) const
Returns the type of the APSInt used to store values of the given QualType.
ProgramStateRef setContainerData(ProgramStateRef State, const MemRegion *Cont, const ContainerData &CData)
BasicValueFactory & getBasicValueFactory()
Definition: SValBuilder.h:169
const ProgramStateRef & getState() const
SVal evalBinOp(SValBuilder &svalBuilder, BinaryOperator::Opcode Op, const ConcreteInt &R) const
Definition: SVals.cpp:238
const ProgramStateRef saveComparison(ProgramStateRef State, const SymExpr *Condition, const SVal &LVal, const SVal &RVal, bool Eq)
const SymExpr * getAsSymExpr() const
Definition: SVals.cpp:144
QualType getResultType() const
Returns the result type, adjusted for references.
Definition: CallEvent.cpp:70
X
Add a minimal nested name specifier fixit hint to allow lookup of a tag name from an outer enclosing ...
Definition: SemaDecl.cpp:13820
bool hasLiveIterators(ProgramStateRef State, const MemRegion *Cont)
Represents a C++ struct/union/class.
Definition: DeclCXX.h:302
bool isBeginCall(const FunctionDecl *Func)
const RegionOrSymbol getRegionOrSymbol(const SVal &Val)
bool operator!=(CanQual< T > x, CanQual< U > y)
virtual unsigned getNumArgs() const =0
Returns the number of arguments (explicit and implicit).
SValBuilder & getSValBuilder()
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
Definition: Decl.h:275
ProgramStateRef createContainerBegin(ProgramStateRef State, const MemRegion *Cont, const SymbolRef Sym)
bool isPointerType() const
Definition: Type.h:6113
bool isIncrementOperator(OverloadedOperatorKind OK)
virtual SVal getArgSVal(unsigned Index) const
Returns the value of a given argument at the time of the call.
Definition: CallEvent.cpp:331
Tag that can use a checker name as a message provider (see SimpleProgramPointTag).
Definition: Checker.h:509
const LocationContext * getLocationContext() const
bool isIterator(const CXXRecordDecl *CRD)
static ProgramStateRef assumeNoOverflow(ProgramStateRef State, SymbolRef Sym, long Scale)
bool isLive(SymbolRef sym)
bool isRandomIncrOrDecrOperator(OverloadedOperatorKind OK)
method_range methods() const
Definition: DeclCXX.h:867