blob: e46325543e949d5c2dd27897ca51672aa0992669 [file] [log] [blame]
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001//===-- 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//
Adam Baloghb03ed5e2018-06-28 10:58:53 +000049// 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 `!=`).
Artem Dergachev8fa639e2017-05-29 15:03:20 +000055//
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
Adam Baloghb03ed5e2018-06-28 10:58:53 +000060// which are represented in the form of (x == 0 or x != 0) where x is the
Artem Dergachev8fa639e2017-05-29 15:03:20 +000061// comparison itself.
Adam Baloghb03ed5e2018-06-28 10:58:53 +000062//
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.
Artem Dergachev8fa639e2017-05-29 15:03:20 +000068
69#include "ClangSACheckers.h"
Adam Balogh2cfbe932018-08-28 08:41:15 +000070#include "clang/AST/DeclTemplate.h"
Artem Dergachev8fa639e2017-05-29 15:03:20 +000071#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
72#include "clang/StaticAnalyzer/Core/Checker.h"
73#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
74#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
Adam Balogh9a48ba62018-09-10 09:06:31 +000075#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h"
Artem Dergachev8fa639e2017-05-29 15:03:20 +000076
Adam Balogh2cfbe932018-08-28 08:41:15 +000077#include <utility>
78
Artem Dergachev8fa639e2017-05-29 15:03:20 +000079using namespace clang;
80using namespace ento;
81
82namespace {
83
84// Abstract position of an iterator. This helps to handle all three kinds
85// of operators in a common way by using a symbolic position.
86struct IteratorPosition {
87private:
88
89 // Container the iterator belongs to
90 const MemRegion *Cont;
91
Adam Balogh2cfbe932018-08-28 08:41:15 +000092 // Whether iterator is valid
93 const bool Valid;
94
Artem Dergachev8fa639e2017-05-29 15:03:20 +000095 // Abstract offset
Adam Baloghb03ed5e2018-06-28 10:58:53 +000096 const SymbolRef Offset;
Artem Dergachev8fa639e2017-05-29 15:03:20 +000097
Adam Balogh2cfbe932018-08-28 08:41:15 +000098 IteratorPosition(const MemRegion *C, bool V, SymbolRef Of)
99 : Cont(C), Valid(V), Offset(Of) {}
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000100
101public:
102 const MemRegion *getContainer() const { return Cont; }
Adam Balogh2cfbe932018-08-28 08:41:15 +0000103 bool isValid() const { return Valid; }
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000104 SymbolRef getOffset() const { return Offset; }
105
Adam Balogh2cfbe932018-08-28 08:41:15 +0000106 IteratorPosition invalidate() const {
107 return IteratorPosition(Cont, false, Offset);
108 }
109
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000110 static IteratorPosition getPosition(const MemRegion *C, SymbolRef Of) {
Adam Balogh2cfbe932018-08-28 08:41:15 +0000111 return IteratorPosition(C, true, Of);
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000112 }
113
114 IteratorPosition setTo(SymbolRef NewOf) const {
Adam Balogh2cfbe932018-08-28 08:41:15 +0000115 return IteratorPosition(Cont, Valid, NewOf);
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000116 }
117
Adam Balogh6b23b1a2018-09-10 09:04:27 +0000118 IteratorPosition reAssign(const MemRegion *NewCont) const {
119 return IteratorPosition(NewCont, Valid, Offset);
120 }
121
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000122 bool operator==(const IteratorPosition &X) const {
Adam Balogh2cfbe932018-08-28 08:41:15 +0000123 return Cont == X.Cont && Valid == X.Valid && Offset == X.Offset;
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000124 }
125
126 bool operator!=(const IteratorPosition &X) const {
Adam Balogh2cfbe932018-08-28 08:41:15 +0000127 return Cont != X.Cont || Valid != X.Valid || Offset != X.Offset;
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000128 }
129
130 void Profile(llvm::FoldingSetNodeID &ID) const {
131 ID.AddPointer(Cont);
Adam Balogh2cfbe932018-08-28 08:41:15 +0000132 ID.AddInteger(Valid);
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000133 ID.Add(Offset);
134 }
135};
136
137typedef llvm::PointerUnion<const MemRegion *, SymbolRef> RegionOrSymbol;
138
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000139// Structure to record the symbolic begin and end position of a container
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000140struct ContainerData {
141private:
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000142 const SymbolRef Begin, End;
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000143
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000144 ContainerData(SymbolRef B, SymbolRef E) : Begin(B), End(E) {}
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000145
146public:
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000147 static ContainerData fromBegin(SymbolRef B) {
148 return ContainerData(B, nullptr);
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000149 }
150
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000151 static ContainerData fromEnd(SymbolRef E) {
152 return ContainerData(nullptr, E);
153 }
154
155 SymbolRef getBegin() const { return Begin; }
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000156 SymbolRef getEnd() const { return End; }
157
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000158 ContainerData newBegin(SymbolRef B) const { return ContainerData(B, End); }
159
160 ContainerData newEnd(SymbolRef E) const { return ContainerData(Begin, E); }
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000161
162 bool operator==(const ContainerData &X) const {
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000163 return Begin == X.Begin && End == X.End;
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000164 }
165
166 bool operator!=(const ContainerData &X) const {
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000167 return Begin != X.Begin || End != X.End;
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000168 }
169
170 void Profile(llvm::FoldingSetNodeID &ID) const {
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000171 ID.Add(Begin);
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000172 ID.Add(End);
173 }
174};
175
176// Structure fo recording iterator comparisons. We needed to retrieve the
177// original comparison expression in assumptions.
178struct IteratorComparison {
179private:
180 RegionOrSymbol Left, Right;
181 bool Equality;
182
183public:
184 IteratorComparison(RegionOrSymbol L, RegionOrSymbol R, bool Eq)
185 : Left(L), Right(R), Equality(Eq) {}
186
187 RegionOrSymbol getLeft() const { return Left; }
188 RegionOrSymbol getRight() const { return Right; }
189 bool isEquality() const { return Equality; }
190 bool operator==(const IteratorComparison &X) const {
191 return Left == X.Left && Right == X.Right && Equality == X.Equality;
192 }
193 bool operator!=(const IteratorComparison &X) const {
194 return Left != X.Left || Right != X.Right || Equality != X.Equality;
195 }
196 void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(Equality); }
197};
198
199class IteratorChecker
200 : public Checker<check::PreCall, check::PostCall,
201 check::PostStmt<MaterializeTemporaryExpr>,
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000202 check::LiveSymbols, check::DeadSymbols,
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000203 eval::Assume> {
204
205 std::unique_ptr<BugType> OutOfRangeBugType;
Adam Balogh21583b72018-09-10 09:03:22 +0000206 std::unique_ptr<BugType> MismatchedBugType;
Adam Balogh2cfbe932018-08-28 08:41:15 +0000207 std::unique_ptr<BugType> InvalidatedBugType;
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000208
209 void handleComparison(CheckerContext &C, const SVal &RetVal, const SVal &LVal,
210 const SVal &RVal, OverloadedOperatorKind Op) const;
Adam Balogh2cfbe932018-08-28 08:41:15 +0000211 void verifyAccess(CheckerContext &C, const SVal &Val) const;
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000212 void verifyDereference(CheckerContext &C, const SVal &Val) const;
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000213 void handleIncrement(CheckerContext &C, const SVal &RetVal, const SVal &Iter,
214 bool Postfix) const;
215 void handleDecrement(CheckerContext &C, const SVal &RetVal, const SVal &Iter,
216 bool Postfix) const;
217 void handleRandomIncrOrDecr(CheckerContext &C, OverloadedOperatorKind Op,
218 const SVal &RetVal, const SVal &LHS,
219 const SVal &RHS) const;
220 void handleBegin(CheckerContext &C, const Expr *CE, const SVal &RetVal,
221 const SVal &Cont) const;
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000222 void handleEnd(CheckerContext &C, const Expr *CE, const SVal &RetVal,
223 const SVal &Cont) const;
224 void assignToContainer(CheckerContext &C, const Expr *CE, const SVal &RetVal,
225 const MemRegion *Cont) const;
Adam Balogh6b23b1a2018-09-10 09:04:27 +0000226 void handleAssign(CheckerContext &C, const SVal &Cont,
227 const Expr *CE = nullptr,
228 const SVal &OldCont = UndefinedVal()) const;
Adam Balogh9a48ba62018-09-10 09:06:31 +0000229 void handlePushBack(CheckerContext &C, const SVal &Cont) const;
230 void handlePopBack(CheckerContext &C, const SVal &Cont) const;
231 void handlePushFront(CheckerContext &C, const SVal &Cont) const;
232 void handlePopFront(CheckerContext &C, const SVal &Cont) const;
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000233 void verifyRandomIncrOrDecr(CheckerContext &C, OverloadedOperatorKind Op,
234 const SVal &RetVal, const SVal &LHS,
235 const SVal &RHS) const;
Adam Balogh21583b72018-09-10 09:03:22 +0000236 void verifyMatch(CheckerContext &C, const SVal &Iter1,
237 const SVal &Iter2) const;
238
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000239 void reportOutOfRangeBug(const StringRef &Message, const SVal &Val,
240 CheckerContext &C, ExplodedNode *ErrNode) const;
Adam Balogh21583b72018-09-10 09:03:22 +0000241 void reportMismatchedBug(const StringRef &Message, const SVal &Val1,
242 const SVal &Val2, CheckerContext &C,
243 ExplodedNode *ErrNode) const;
Adam Balogh3659f7a2018-09-10 09:05:31 +0000244 void reportMismatchedBug(const StringRef &Message, const SVal &Val,
245 const MemRegion *Reg, CheckerContext &C,
246 ExplodedNode *ErrNode) const;
Adam Balogh2cfbe932018-08-28 08:41:15 +0000247 void reportInvalidatedBug(const StringRef &Message, const SVal &Val,
248 CheckerContext &C, ExplodedNode *ErrNode) const;
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000249
250public:
251 IteratorChecker();
252
253 enum CheckKind {
254 CK_IteratorRangeChecker,
Adam Balogh21583b72018-09-10 09:03:22 +0000255 CK_MismatchedIteratorChecker,
Adam Balogh2cfbe932018-08-28 08:41:15 +0000256 CK_InvalidatedIteratorChecker,
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000257 CK_NumCheckKinds
258 };
259
260 DefaultBool ChecksEnabled[CK_NumCheckKinds];
261 CheckName CheckNames[CK_NumCheckKinds];
262
263 void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
264 void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
265 void checkPostStmt(const MaterializeTemporaryExpr *MTE,
266 CheckerContext &C) const;
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000267 void checkLiveSymbols(ProgramStateRef State, SymbolReaper &SR) const;
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000268 void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
269 ProgramStateRef evalAssume(ProgramStateRef State, SVal Cond,
270 bool Assumption) const;
271};
272} // namespace
273
274REGISTER_MAP_WITH_PROGRAMSTATE(IteratorSymbolMap, SymbolRef, IteratorPosition)
275REGISTER_MAP_WITH_PROGRAMSTATE(IteratorRegionMap, const MemRegion *,
276 IteratorPosition)
277
278REGISTER_MAP_WITH_PROGRAMSTATE(ContainerMap, const MemRegion *, ContainerData)
279
280REGISTER_MAP_WITH_PROGRAMSTATE(IteratorComparisonMap, const SymExpr *,
281 IteratorComparison)
282
283namespace {
284
285bool isIteratorType(const QualType &Type);
286bool isIterator(const CXXRecordDecl *CRD);
Adam Balogh3659f7a2018-09-10 09:05:31 +0000287bool isComparisonOperator(OverloadedOperatorKind OK);
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000288bool isBeginCall(const FunctionDecl *Func);
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000289bool isEndCall(const FunctionDecl *Func);
Adam Balogh9a48ba62018-09-10 09:06:31 +0000290bool isPushBackCall(const FunctionDecl *Func);
291bool isEmplaceBackCall(const FunctionDecl *Func);
292bool isPopBackCall(const FunctionDecl *Func);
293bool isPushFrontCall(const FunctionDecl *Func);
294bool isEmplaceFrontCall(const FunctionDecl *Func);
295bool isPopFrontCall(const FunctionDecl *Func);
Adam Balogh2cfbe932018-08-28 08:41:15 +0000296bool isAssignmentOperator(OverloadedOperatorKind OK);
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000297bool isSimpleComparisonOperator(OverloadedOperatorKind OK);
Adam Balogh2cfbe932018-08-28 08:41:15 +0000298bool isAccessOperator(OverloadedOperatorKind OK);
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000299bool isDereferenceOperator(OverloadedOperatorKind OK);
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000300bool isIncrementOperator(OverloadedOperatorKind OK);
301bool isDecrementOperator(OverloadedOperatorKind OK);
302bool isRandomIncrOrDecrOperator(OverloadedOperatorKind OK);
Adam Balogh9a48ba62018-09-10 09:06:31 +0000303bool hasSubscriptOperator(ProgramStateRef State, const MemRegion *Reg);
304bool frontModifiable(ProgramStateRef State, const MemRegion *Reg);
305bool backModifiable(ProgramStateRef State, const MemRegion *Reg);
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000306BinaryOperator::Opcode getOpcode(const SymExpr *SE);
307const RegionOrSymbol getRegionOrSymbol(const SVal &Val);
308const ProgramStateRef processComparison(ProgramStateRef State,
309 RegionOrSymbol LVal,
310 RegionOrSymbol RVal, bool Equal);
311const ProgramStateRef saveComparison(ProgramStateRef State,
312 const SymExpr *Condition, const SVal &LVal,
313 const SVal &RVal, bool Eq);
314const IteratorComparison *loadComparison(ProgramStateRef State,
315 const SymExpr *Condition);
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000316SymbolRef getContainerBegin(ProgramStateRef State, const MemRegion *Cont);
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000317SymbolRef getContainerEnd(ProgramStateRef State, const MemRegion *Cont);
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000318ProgramStateRef createContainerBegin(ProgramStateRef State,
319 const MemRegion *Cont,
320 const SymbolRef Sym);
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000321ProgramStateRef createContainerEnd(ProgramStateRef State, const MemRegion *Cont,
322 const SymbolRef Sym);
323const IteratorPosition *getIteratorPosition(ProgramStateRef State,
324 const SVal &Val);
325const IteratorPosition *getIteratorPosition(ProgramStateRef State,
326 RegionOrSymbol RegOrSym);
327ProgramStateRef setIteratorPosition(ProgramStateRef State, const SVal &Val,
328 const IteratorPosition &Pos);
329ProgramStateRef setIteratorPosition(ProgramStateRef State,
330 RegionOrSymbol RegOrSym,
331 const IteratorPosition &Pos);
332ProgramStateRef removeIteratorPosition(ProgramStateRef State, const SVal &Val);
333ProgramStateRef adjustIteratorPosition(ProgramStateRef State,
334 RegionOrSymbol RegOrSym,
335 const IteratorPosition &Pos, bool Equal);
336ProgramStateRef relateIteratorPositions(ProgramStateRef State,
337 const IteratorPosition &Pos1,
338 const IteratorPosition &Pos2,
339 bool Equal);
Adam Balogh2cfbe932018-08-28 08:41:15 +0000340ProgramStateRef invalidateAllIteratorPositions(ProgramStateRef State,
341 const MemRegion *Cont);
Adam Balogh9a48ba62018-09-10 09:06:31 +0000342ProgramStateRef invalidateIteratorPositions(ProgramStateRef State,
343 SymbolRef Offset,
344 BinaryOperator::Opcode Opc);
Adam Balogh6b23b1a2018-09-10 09:04:27 +0000345ProgramStateRef reassignAllIteratorPositions(ProgramStateRef State,
346 const MemRegion *Cont,
347 const MemRegion *NewCont);
348ProgramStateRef reassignAllIteratorPositionsUnless(ProgramStateRef State,
349 const MemRegion *Cont,
350 const MemRegion *NewCont,
351 SymbolRef Offset,
352 BinaryOperator::Opcode Opc);
353ProgramStateRef rebaseSymbolInIteratorPositionsIf(
354 ProgramStateRef State, SValBuilder &SVB, SymbolRef OldSym,
355 SymbolRef NewSym, SymbolRef CondSym, BinaryOperator::Opcode Opc);
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000356const ContainerData *getContainerData(ProgramStateRef State,
357 const MemRegion *Cont);
358ProgramStateRef setContainerData(ProgramStateRef State, const MemRegion *Cont,
359 const ContainerData &CData);
Adam Balogha6921202018-07-30 08:52:21 +0000360bool hasLiveIterators(ProgramStateRef State, const MemRegion *Cont);
Adam Balogh21583b72018-09-10 09:03:22 +0000361bool isBoundThroughLazyCompoundVal(const Environment &Env,
362 const MemRegion *Reg);
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000363bool isOutOfRange(ProgramStateRef State, const IteratorPosition &Pos);
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000364bool isZero(ProgramStateRef State, const NonLoc &Val);
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000365} // namespace
366
367IteratorChecker::IteratorChecker() {
368 OutOfRangeBugType.reset(
369 new BugType(this, "Iterator out of range", "Misuse of STL APIs"));
370 OutOfRangeBugType->setSuppressOnSink(true);
Adam Balogh21583b72018-09-10 09:03:22 +0000371 MismatchedBugType.reset(
372 new BugType(this, "Iterator(s) mismatched", "Misuse of STL APIs"));
373 MismatchedBugType->setSuppressOnSink(true);
Adam Balogh2cfbe932018-08-28 08:41:15 +0000374 InvalidatedBugType.reset(
375 new BugType(this, "Iterator invalidated", "Misuse of STL APIs"));
376 InvalidatedBugType->setSuppressOnSink(true);
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000377}
378
379void IteratorChecker::checkPreCall(const CallEvent &Call,
380 CheckerContext &C) const {
Adam Balogh2cfbe932018-08-28 08:41:15 +0000381 // Check for out of range access or access of invalidated position and
382 // iterator mismatches
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000383 const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
384 if (!Func)
385 return;
386
387 if (Func->isOverloadedOperator()) {
Adam Balogh2cfbe932018-08-28 08:41:15 +0000388 if (ChecksEnabled[CK_InvalidatedIteratorChecker] &&
389 isAccessOperator(Func->getOverloadedOperator())) {
390 // Check for any kind of access of invalidated iterator positions
391 if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
392 verifyAccess(C, InstCall->getCXXThisVal());
393 } else {
394 verifyAccess(C, Call.getArgSVal(0));
395 }
396 }
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000397 if (ChecksEnabled[CK_IteratorRangeChecker] &&
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000398 isRandomIncrOrDecrOperator(Func->getOverloadedOperator())) {
399 if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
400 // Check for out-of-range incrementions and decrementions
401 if (Call.getNumArgs() >= 1) {
402 verifyRandomIncrOrDecr(C, Func->getOverloadedOperator(),
403 Call.getReturnValue(),
404 InstCall->getCXXThisVal(), Call.getArgSVal(0));
405 }
406 } else {
407 if (Call.getNumArgs() >= 2) {
408 verifyRandomIncrOrDecr(C, Func->getOverloadedOperator(),
409 Call.getReturnValue(), Call.getArgSVal(0),
410 Call.getArgSVal(1));
411 }
412 }
413 } else if (ChecksEnabled[CK_IteratorRangeChecker] &&
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000414 isDereferenceOperator(Func->getOverloadedOperator())) {
415 // Check for dereference of out-of-range iterators
416 if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
417 verifyDereference(C, InstCall->getCXXThisVal());
418 } else {
419 verifyDereference(C, Call.getArgSVal(0));
420 }
Adam Balogh3659f7a2018-09-10 09:05:31 +0000421 } else if (ChecksEnabled[CK_MismatchedIteratorChecker] &&
422 isComparisonOperator(Func->getOverloadedOperator())) {
423 // Check for comparisons of iterators of different containers
424 if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
425 if (Call.getNumArgs() < 1)
426 return;
427
428 if (!isIteratorType(InstCall->getCXXThisExpr()->getType()) ||
429 !isIteratorType(Call.getArgExpr(0)->getType()))
430 return;
431
432 verifyMatch(C, InstCall->getCXXThisVal(), Call.getArgSVal(0));
433 } else {
434 if (Call.getNumArgs() < 2)
435 return;
436
437 if (!isIteratorType(Call.getArgExpr(0)->getType()) ||
438 !isIteratorType(Call.getArgExpr(1)->getType()))
439 return;
440
441 verifyMatch(C, Call.getArgSVal(0), Call.getArgSVal(1));
442 }
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000443 }
Adam Balogh3659f7a2018-09-10 09:05:31 +0000444 } else if (isa<CXXConstructorCall>(&Call)) {
445 // Check match of first-last iterator pair in a constructor of a container
446 if (Call.getNumArgs() < 2)
447 return;
448
449 const auto *Ctr = cast<CXXConstructorDecl>(Call.getDecl());
450 if (Ctr->getNumParams() < 2)
451 return;
452
453 if (Ctr->getParamDecl(0)->getName() != "first" ||
454 Ctr->getParamDecl(1)->getName() != "last")
455 return;
456
457 if (!isIteratorType(Call.getArgExpr(0)->getType()) ||
458 !isIteratorType(Call.getArgExpr(1)->getType()))
459 return;
460
461 verifyMatch(C, Call.getArgSVal(0), Call.getArgSVal(1));
462 } else {
Adam Balogh21583b72018-09-10 09:03:22 +0000463 // The main purpose of iterators is to abstract away from different
464 // containers and provide a (maybe limited) uniform access to them.
465 // This implies that any correctly written template function that
466 // works on multiple containers using iterators takes different
467 // template parameters for different containers. So we can safely
468 // assume that passing iterators of different containers as arguments
469 // whose type replaces the same template parameter is a bug.
470 //
471 // Example:
472 // template<typename I1, typename I2>
473 // void f(I1 first1, I1 last1, I2 first2, I2 last2);
474 //
475 // In this case the first two arguments to f() must be iterators must belong
476 // to the same container and the last to also to the same container but
477 // not neccessarily to the same as the first two.
478
479 if (!ChecksEnabled[CK_MismatchedIteratorChecker])
480 return;
481
482 const auto *Templ = Func->getPrimaryTemplate();
483 if (!Templ)
484 return;
485
486 const auto *TParams = Templ->getTemplateParameters();
487 const auto *TArgs = Func->getTemplateSpecializationArgs();
488
489 // Iterate over all the template parameters
490 for (size_t I = 0; I < TParams->size(); ++I) {
491 const auto *TPDecl = dyn_cast<TemplateTypeParmDecl>(TParams->getParam(I));
492 if (!TPDecl)
493 continue;
494
495 if (TPDecl->isParameterPack())
496 continue;
497
498 const auto TAType = TArgs->get(I).getAsType();
499 if (!isIteratorType(TAType))
500 continue;
501
502 SVal LHS = UndefinedVal();
503
504 // For every template parameter which is an iterator type in the
505 // instantiation look for all functions' parameters' type by it and
506 // check whether they belong to the same container
507 for (auto J = 0U; J < Func->getNumParams(); ++J) {
508 const auto *Param = Func->getParamDecl(J);
509 const auto *ParamType =
510 Param->getType()->getAs<SubstTemplateTypeParmType>();
511 if (!ParamType ||
512 ParamType->getReplacedParameter()->getDecl() != TPDecl)
513 continue;
514 if (LHS.isUndef()) {
515 LHS = Call.getArgSVal(J);
516 } else {
517 verifyMatch(C, LHS, Call.getArgSVal(J));
518 }
519 }
520 }
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000521 }
522}
523
524void IteratorChecker::checkPostCall(const CallEvent &Call,
525 CheckerContext &C) const {
526 // Record new iterator positions and iterator position changes
527 const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
528 if (!Func)
529 return;
530
531 if (Func->isOverloadedOperator()) {
532 const auto Op = Func->getOverloadedOperator();
Adam Balogh2cfbe932018-08-28 08:41:15 +0000533 if (isAssignmentOperator(Op)) {
534 const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call);
Adam Balogh6b23b1a2018-09-10 09:04:27 +0000535 if (Func->getParamDecl(0)->getType()->isRValueReferenceType()) {
536 handleAssign(C, InstCall->getCXXThisVal(), Call.getOriginExpr(),
537 Call.getArgSVal(0));
538 } else {
539 handleAssign(C, InstCall->getCXXThisVal());
540 }
Adam Balogh2cfbe932018-08-28 08:41:15 +0000541 } else if (isSimpleComparisonOperator(Op)) {
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000542 if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
543 handleComparison(C, Call.getReturnValue(), InstCall->getCXXThisVal(),
544 Call.getArgSVal(0), Op);
545 } else {
546 handleComparison(C, Call.getReturnValue(), Call.getArgSVal(0),
547 Call.getArgSVal(1), Op);
548 }
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000549 } else if (isRandomIncrOrDecrOperator(Func->getOverloadedOperator())) {
550 if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
551 if (Call.getNumArgs() >= 1) {
552 handleRandomIncrOrDecr(C, Func->getOverloadedOperator(),
553 Call.getReturnValue(),
554 InstCall->getCXXThisVal(), Call.getArgSVal(0));
555 }
556 } else {
557 if (Call.getNumArgs() >= 2) {
558 handleRandomIncrOrDecr(C, Func->getOverloadedOperator(),
559 Call.getReturnValue(), Call.getArgSVal(0),
560 Call.getArgSVal(1));
561 }
562 }
563 } else if (isIncrementOperator(Func->getOverloadedOperator())) {
564 if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
565 handleIncrement(C, Call.getReturnValue(), InstCall->getCXXThisVal(),
566 Call.getNumArgs());
567 } else {
568 handleIncrement(C, Call.getReturnValue(), Call.getArgSVal(0),
569 Call.getNumArgs());
570 }
571 } else if (isDecrementOperator(Func->getOverloadedOperator())) {
572 if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
573 handleDecrement(C, Call.getReturnValue(), InstCall->getCXXThisVal(),
574 Call.getNumArgs());
575 } else {
576 handleDecrement(C, Call.getReturnValue(), Call.getArgSVal(0),
577 Call.getNumArgs());
578 }
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000579 }
580 } else {
Adam Balogh9a48ba62018-09-10 09:06:31 +0000581 if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
582 if (isPushBackCall(Func) || isEmplaceBackCall(Func)) {
583 handlePushBack(C, InstCall->getCXXThisVal());
584 } else if (isPopBackCall(Func)) {
585 handlePopBack(C, InstCall->getCXXThisVal());
586 } else if (isPushFrontCall(Func) || isEmplaceFrontCall(Func)) {
587 handlePushFront(C, InstCall->getCXXThisVal());
588 } else if (isPopFrontCall(Func)) {
589 handlePopFront(C, InstCall->getCXXThisVal());
590 }
591 }
592
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000593 const auto *OrigExpr = Call.getOriginExpr();
594 if (!OrigExpr)
595 return;
596
597 if (!isIteratorType(Call.getResultType()))
598 return;
599
600 auto State = C.getState();
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000601
602 if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000603 if (isBeginCall(Func)) {
604 handleBegin(C, OrigExpr, Call.getReturnValue(),
605 InstCall->getCXXThisVal());
606 return;
607 }
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000608 if (isEndCall(Func)) {
609 handleEnd(C, OrigExpr, Call.getReturnValue(),
610 InstCall->getCXXThisVal());
611 return;
612 }
613 }
614
Adam Balogh6b23b1a2018-09-10 09:04:27 +0000615 // Already bound to container?
616 if (getIteratorPosition(State, Call.getReturnValue()))
617 return;
618
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000619 // Copy-like and move constructors
620 if (isa<CXXConstructorCall>(&Call) && Call.getNumArgs() == 1) {
621 if (const auto *Pos = getIteratorPosition(State, Call.getArgSVal(0))) {
622 State = setIteratorPosition(State, Call.getReturnValue(), *Pos);
623 if (cast<CXXConstructorDecl>(Func)->isMoveConstructor()) {
624 State = removeIteratorPosition(State, Call.getArgSVal(0));
625 }
626 C.addTransition(State);
627 return;
628 }
629 }
630
631 // Assumption: if return value is an iterator which is not yet bound to a
632 // container, then look for the first iterator argument, and
633 // bind the return value to the same container. This approach
634 // works for STL algorithms.
635 // FIXME: Add a more conservative mode
636 for (unsigned i = 0; i < Call.getNumArgs(); ++i) {
637 if (isIteratorType(Call.getArgExpr(i)->getType())) {
638 if (const auto *Pos = getIteratorPosition(State, Call.getArgSVal(i))) {
639 assignToContainer(C, OrigExpr, Call.getReturnValue(),
640 Pos->getContainer());
641 return;
642 }
643 }
644 }
645 }
646}
647
648void IteratorChecker::checkPostStmt(const MaterializeTemporaryExpr *MTE,
649 CheckerContext &C) const {
650 /* Transfer iterator state to temporary objects */
651 auto State = C.getState();
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000652 const auto *Pos =
George Karpenkovd703ec92018-01-17 20:27:29 +0000653 getIteratorPosition(State, C.getSVal(MTE->GetTemporaryExpr()));
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000654 if (!Pos)
655 return;
George Karpenkovd703ec92018-01-17 20:27:29 +0000656 State = setIteratorPosition(State, C.getSVal(MTE), *Pos);
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000657 C.addTransition(State);
658}
659
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000660void IteratorChecker::checkLiveSymbols(ProgramStateRef State,
661 SymbolReaper &SR) const {
662 // Keep symbolic expressions of iterator positions, container begins and ends
663 // alive
664 auto RegionMap = State->get<IteratorRegionMap>();
665 for (const auto Reg : RegionMap) {
Adam Balogh0a7592b2018-07-16 09:27:27 +0000666 const auto Offset = Reg.second.getOffset();
667 for (auto i = Offset->symbol_begin(); i != Offset->symbol_end(); ++i)
668 if (isa<SymbolData>(*i))
669 SR.markLive(*i);
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000670 }
671
672 auto SymbolMap = State->get<IteratorSymbolMap>();
673 for (const auto Sym : SymbolMap) {
Adam Balogh0a7592b2018-07-16 09:27:27 +0000674 const auto Offset = Sym.second.getOffset();
675 for (auto i = Offset->symbol_begin(); i != Offset->symbol_end(); ++i)
676 if (isa<SymbolData>(*i))
677 SR.markLive(*i);
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000678 }
679
680 auto ContMap = State->get<ContainerMap>();
681 for (const auto Cont : ContMap) {
682 const auto CData = Cont.second;
683 if (CData.getBegin()) {
684 SR.markLive(CData.getBegin());
Adam Balogh9a48ba62018-09-10 09:06:31 +0000685 if(const auto *SIE = dyn_cast<SymIntExpr>(CData.getBegin()))
686 SR.markLive(SIE->getLHS());
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000687 }
688 if (CData.getEnd()) {
689 SR.markLive(CData.getEnd());
Adam Balogh9a48ba62018-09-10 09:06:31 +0000690 if(const auto *SIE = dyn_cast<SymIntExpr>(CData.getEnd()))
691 SR.markLive(SIE->getLHS());
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000692 }
693 }
694}
695
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000696void IteratorChecker::checkDeadSymbols(SymbolReaper &SR,
697 CheckerContext &C) const {
698 // Cleanup
699 auto State = C.getState();
700
701 auto RegionMap = State->get<IteratorRegionMap>();
702 for (const auto Reg : RegionMap) {
703 if (!SR.isLiveRegion(Reg.first)) {
Adam Balogh21583b72018-09-10 09:03:22 +0000704 // The region behind the `LazyCompoundVal` is often cleaned up before
705 // the `LazyCompoundVal` itself. If there are iterator positions keyed
706 // by these regions their cleanup must be deferred.
707 if (!isBoundThroughLazyCompoundVal(State->getEnvironment(), Reg.first)) {
708 State = State->remove<IteratorRegionMap>(Reg.first);
709 }
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000710 }
711 }
712
713 auto SymbolMap = State->get<IteratorSymbolMap>();
714 for (const auto Sym : SymbolMap) {
715 if (!SR.isLive(Sym.first)) {
716 State = State->remove<IteratorSymbolMap>(Sym.first);
717 }
718 }
719
720 auto ContMap = State->get<ContainerMap>();
721 for (const auto Cont : ContMap) {
722 if (!SR.isLiveRegion(Cont.first)) {
Adam Balogha6921202018-07-30 08:52:21 +0000723 // We must keep the container data while it has live iterators to be able
724 // to compare them to the begin and the end of the container.
725 if (!hasLiveIterators(State, Cont.first)) {
726 State = State->remove<ContainerMap>(Cont.first);
727 }
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000728 }
729 }
730
731 auto ComparisonMap = State->get<IteratorComparisonMap>();
732 for (const auto Comp : ComparisonMap) {
733 if (!SR.isLive(Comp.first)) {
734 State = State->remove<IteratorComparisonMap>(Comp.first);
735 }
736 }
Reka Kovacse48ea892018-07-30 16:14:59 +0000737
738 C.addTransition(State);
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000739}
740
741ProgramStateRef IteratorChecker::evalAssume(ProgramStateRef State, SVal Cond,
742 bool Assumption) const {
743 // Load recorded comparison and transfer iterator state between sides
744 // according to comparison operator and assumption
745 const auto *SE = Cond.getAsSymExpr();
746 if (!SE)
747 return State;
748
749 auto Opc = getOpcode(SE);
750 if (Opc != BO_EQ && Opc != BO_NE)
751 return State;
752
753 bool Negated = false;
754 const auto *Comp = loadComparison(State, SE);
755 if (!Comp) {
756 // Try negated comparison, which is a SymExpr to 0 integer comparison
757 const auto *SIE = dyn_cast<SymIntExpr>(SE);
758 if (!SIE)
759 return State;
760
761 if (SIE->getRHS() != 0)
762 return State;
763
764 SE = SIE->getLHS();
765 Negated = SIE->getOpcode() == BO_EQ; // Equal to zero means negation
766 Opc = getOpcode(SE);
767 if (Opc != BO_EQ && Opc != BO_NE)
768 return State;
769
770 Comp = loadComparison(State, SE);
771 if (!Comp)
772 return State;
773 }
774
775 return processComparison(State, Comp->getLeft(), Comp->getRight(),
776 (Comp->isEquality() == Assumption) != Negated);
777}
778
779void IteratorChecker::handleComparison(CheckerContext &C, const SVal &RetVal,
780 const SVal &LVal, const SVal &RVal,
781 OverloadedOperatorKind Op) const {
782 // Record the operands and the operator of the comparison for the next
783 // evalAssume, if the result is a symbolic expression. If it is a concrete
784 // value (only one branch is possible), then transfer the state between
785 // the operands according to the operator and the result
786 auto State = C.getState();
787 if (const auto *Condition = RetVal.getAsSymbolicExpression()) {
788 const auto *LPos = getIteratorPosition(State, LVal);
789 const auto *RPos = getIteratorPosition(State, RVal);
790 if (!LPos && !RPos)
791 return;
792 State = saveComparison(State, Condition, LVal, RVal, Op == OO_EqualEqual);
793 C.addTransition(State);
794 } else if (const auto TruthVal = RetVal.getAs<nonloc::ConcreteInt>()) {
795 if ((State = processComparison(
796 State, getRegionOrSymbol(LVal), getRegionOrSymbol(RVal),
797 (Op == OO_EqualEqual) == (TruthVal->getValue() != 0)))) {
798 C.addTransition(State);
799 } else {
800 C.generateSink(State, C.getPredecessor());
801 }
802 }
803}
804
805void IteratorChecker::verifyDereference(CheckerContext &C,
806 const SVal &Val) const {
807 auto State = C.getState();
808 const auto *Pos = getIteratorPosition(State, Val);
809 if (Pos && isOutOfRange(State, *Pos)) {
Adam Balogh2cfbe932018-08-28 08:41:15 +0000810 auto *N = C.generateNonFatalErrorNode(State);
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000811 if (!N)
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000812 return;
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000813 reportOutOfRangeBug("Iterator accessed outside of its range.", Val, C, N);
814 }
815}
816
Adam Balogh2cfbe932018-08-28 08:41:15 +0000817void IteratorChecker::verifyAccess(CheckerContext &C, const SVal &Val) const {
818 auto State = C.getState();
819 const auto *Pos = getIteratorPosition(State, Val);
820 if (Pos && !Pos->isValid()) {
821 auto *N = C.generateNonFatalErrorNode(State);
822 if (!N) {
823 return;
824 }
825 reportInvalidatedBug("Invalidated iterator accessed.", Val, C, N);
826 }
827}
828
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000829void IteratorChecker::handleIncrement(CheckerContext &C, const SVal &RetVal,
830 const SVal &Iter, bool Postfix) const {
831 // Increment the symbolic expressions which represents the position of the
832 // iterator
833 auto State = C.getState();
834 const auto *Pos = getIteratorPosition(State, Iter);
835 if (Pos) {
836 auto &SymMgr = C.getSymbolManager();
837 auto &BVF = SymMgr.getBasicVals();
838 auto &SVB = C.getSValBuilder();
839 const auto OldOffset = Pos->getOffset();
840 auto NewOffset =
841 SVB.evalBinOp(State, BO_Add,
842 nonloc::SymbolVal(OldOffset),
843 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
844 SymMgr.getType(OldOffset)).getAsSymbol();
845 auto NewPos = Pos->setTo(NewOffset);
846 State = setIteratorPosition(State, Iter, NewPos);
847 State = setIteratorPosition(State, RetVal, Postfix ? *Pos : NewPos);
848 C.addTransition(State);
849 }
850}
851
852void IteratorChecker::handleDecrement(CheckerContext &C, const SVal &RetVal,
853 const SVal &Iter, bool Postfix) const {
854 // Decrement the symbolic expressions which represents the position of the
855 // iterator
856 auto State = C.getState();
857 const auto *Pos = getIteratorPosition(State, Iter);
858 if (Pos) {
859 auto &SymMgr = C.getSymbolManager();
860 auto &BVF = SymMgr.getBasicVals();
861 auto &SVB = C.getSValBuilder();
862 const auto OldOffset = Pos->getOffset();
863 auto NewOffset =
864 SVB.evalBinOp(State, BO_Sub,
865 nonloc::SymbolVal(OldOffset),
866 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
867 SymMgr.getType(OldOffset)).getAsSymbol();
868 auto NewPos = Pos->setTo(NewOffset);
869 State = setIteratorPosition(State, Iter, NewPos);
870 State = setIteratorPosition(State, RetVal, Postfix ? *Pos : NewPos);
871 C.addTransition(State);
872 }
873}
874
875// This function tells the analyzer's engine that symbols produced by our
876// checker, most notably iterator positions, are relatively small.
877// A distance between items in the container should not be very large.
878// By assuming that it is within around 1/8 of the address space,
879// we can help the analyzer perform operations on these symbols
880// without being afraid of integer overflows.
881// FIXME: Should we provide it as an API, so that all checkers could use it?
882static ProgramStateRef assumeNoOverflow(ProgramStateRef State, SymbolRef Sym,
883 long Scale) {
884 SValBuilder &SVB = State->getStateManager().getSValBuilder();
885 BasicValueFactory &BV = SVB.getBasicValueFactory();
886
887 QualType T = Sym->getType();
888 assert(T->isSignedIntegerOrEnumerationType());
889 APSIntType AT = BV.getAPSIntType(T);
890
891 ProgramStateRef NewState = State;
892
893 llvm::APSInt Max = AT.getMaxValue() / AT.getValue(Scale);
894 SVal IsCappedFromAbove =
895 SVB.evalBinOpNN(State, BO_LE, nonloc::SymbolVal(Sym),
896 nonloc::ConcreteInt(Max), SVB.getConditionType());
897 if (auto DV = IsCappedFromAbove.getAs<DefinedSVal>()) {
898 NewState = NewState->assume(*DV, true);
899 if (!NewState)
900 return State;
901 }
902
903 llvm::APSInt Min = -Max;
904 SVal IsCappedFromBelow =
905 SVB.evalBinOpNN(State, BO_GE, nonloc::SymbolVal(Sym),
906 nonloc::ConcreteInt(Min), SVB.getConditionType());
907 if (auto DV = IsCappedFromBelow.getAs<DefinedSVal>()) {
908 NewState = NewState->assume(*DV, true);
909 if (!NewState)
910 return State;
911 }
912
913 return NewState;
914}
915
916void IteratorChecker::handleRandomIncrOrDecr(CheckerContext &C,
917 OverloadedOperatorKind Op,
918 const SVal &RetVal,
919 const SVal &LHS,
920 const SVal &RHS) const {
921 // Increment or decrement the symbolic expressions which represents the
922 // position of the iterator
923 auto State = C.getState();
924 const auto *Pos = getIteratorPosition(State, LHS);
925 if (!Pos)
926 return;
927
928 const auto *value = &RHS;
929 if (auto loc = RHS.getAs<Loc>()) {
930 const auto val = State->getRawSVal(*loc);
931 value = &val;
932 }
933
934 auto &SymMgr = C.getSymbolManager();
935 auto &SVB = C.getSValBuilder();
936 auto BinOp = (Op == OO_Plus || Op == OO_PlusEqual) ? BO_Add : BO_Sub;
937 const auto OldOffset = Pos->getOffset();
938 SymbolRef NewOffset;
939 if (const auto intValue = value->getAs<nonloc::ConcreteInt>()) {
940 // For concrete integers we can calculate the new position
941 NewOffset = SVB.evalBinOp(State, BinOp, nonloc::SymbolVal(OldOffset),
942 *intValue,
943 SymMgr.getType(OldOffset)).getAsSymbol();
944 } else {
945 // For other symbols create a new symbol to keep expressions simple
946 const auto &LCtx = C.getLocationContext();
947 NewOffset = SymMgr.conjureSymbol(nullptr, LCtx, SymMgr.getType(OldOffset),
948 C.blockCount());
949 State = assumeNoOverflow(State, NewOffset, 4);
950 }
951 auto NewPos = Pos->setTo(NewOffset);
952 auto &TgtVal = (Op == OO_PlusEqual || Op == OO_MinusEqual) ? LHS : RetVal;
953 State = setIteratorPosition(State, TgtVal, NewPos);
954 C.addTransition(State);
955}
956
957void IteratorChecker::verifyRandomIncrOrDecr(CheckerContext &C,
958 OverloadedOperatorKind Op,
959 const SVal &RetVal,
960 const SVal &LHS,
961 const SVal &RHS) const {
962 auto State = C.getState();
963
964 // If the iterator is initially inside its range, then the operation is valid
965 const auto *Pos = getIteratorPosition(State, LHS);
966 if (!Pos || !isOutOfRange(State, *Pos))
967 return;
968
969 auto value = RHS;
970 if (auto loc = RHS.getAs<Loc>()) {
971 value = State->getRawSVal(*loc);
972 }
973
974 // Incremention or decremention by 0 is never bug
975 if (isZero(State, value.castAs<NonLoc>()))
976 return;
977
978 auto &SymMgr = C.getSymbolManager();
979 auto &SVB = C.getSValBuilder();
980 auto BinOp = (Op == OO_Plus || Op == OO_PlusEqual) ? BO_Add : BO_Sub;
981 const auto OldOffset = Pos->getOffset();
982 const auto intValue = value.getAs<nonloc::ConcreteInt>();
983 if (!intValue)
984 return;
985
986 auto NewOffset = SVB.evalBinOp(State, BinOp, nonloc::SymbolVal(OldOffset),
987 *intValue,
988 SymMgr.getType(OldOffset)).getAsSymbol();
989 auto NewPos = Pos->setTo(NewOffset);
990
991 // If out of range, the only valid operation is to step into the range
992 if (isOutOfRange(State, NewPos)) {
993 auto *N = C.generateNonFatalErrorNode(State);
994 if (!N)
995 return;
996 reportOutOfRangeBug("Iterator accessed past its end.", LHS, C, N);
997 }
998}
999
Adam Balogh21583b72018-09-10 09:03:22 +00001000void IteratorChecker::verifyMatch(CheckerContext &C, const SVal &Iter1,
1001 const SVal &Iter2) const {
1002 // Verify match between the containers of two iterators
1003 auto State = C.getState();
1004 const auto *Pos1 = getIteratorPosition(State, Iter1);
1005 const auto *Pos2 = getIteratorPosition(State, Iter2);
1006 if (Pos1 && Pos2 && Pos1->getContainer() != Pos2->getContainer()) {
1007 auto *N = C.generateNonFatalErrorNode(State);
1008 if (!N)
1009 return;
1010 reportMismatchedBug("Iterators of different containers used where the "
1011 "same container is expected.", Iter1, Iter2, C, N);
1012 }
1013}
1014
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001015void IteratorChecker::handleBegin(CheckerContext &C, const Expr *CE,
1016 const SVal &RetVal, const SVal &Cont) const {
1017 const auto *ContReg = Cont.getAsRegion();
1018 if (!ContReg)
1019 return;
1020
1021 while (const auto *CBOR = ContReg->getAs<CXXBaseObjectRegion>()) {
1022 ContReg = CBOR->getSuperRegion();
1023 }
1024
1025 // If the container already has a begin symbol then use it. Otherwise first
1026 // create a new one.
1027 auto State = C.getState();
1028 auto BeginSym = getContainerBegin(State, ContReg);
1029 if (!BeginSym) {
1030 auto &SymMgr = C.getSymbolManager();
1031 BeginSym = SymMgr.conjureSymbol(CE, C.getLocationContext(),
1032 C.getASTContext().LongTy, C.blockCount());
1033 State = assumeNoOverflow(State, BeginSym, 4);
1034 State = createContainerBegin(State, ContReg, BeginSym);
1035 }
1036 State = setIteratorPosition(State, RetVal,
1037 IteratorPosition::getPosition(ContReg, BeginSym));
1038 C.addTransition(State);
1039}
1040
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001041void IteratorChecker::handleEnd(CheckerContext &C, const Expr *CE,
1042 const SVal &RetVal, const SVal &Cont) const {
1043 const auto *ContReg = Cont.getAsRegion();
1044 if (!ContReg)
1045 return;
1046
1047 while (const auto *CBOR = ContReg->getAs<CXXBaseObjectRegion>()) {
1048 ContReg = CBOR->getSuperRegion();
1049 }
1050
1051 // If the container already has an end symbol then use it. Otherwise first
1052 // create a new one.
1053 auto State = C.getState();
1054 auto EndSym = getContainerEnd(State, ContReg);
1055 if (!EndSym) {
1056 auto &SymMgr = C.getSymbolManager();
1057 EndSym = SymMgr.conjureSymbol(CE, C.getLocationContext(),
1058 C.getASTContext().LongTy, C.blockCount());
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001059 State = assumeNoOverflow(State, EndSym, 4);
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001060 State = createContainerEnd(State, ContReg, EndSym);
1061 }
1062 State = setIteratorPosition(State, RetVal,
1063 IteratorPosition::getPosition(ContReg, EndSym));
1064 C.addTransition(State);
1065}
1066
1067void IteratorChecker::assignToContainer(CheckerContext &C, const Expr *CE,
1068 const SVal &RetVal,
1069 const MemRegion *Cont) const {
1070 while (const auto *CBOR = Cont->getAs<CXXBaseObjectRegion>()) {
1071 Cont = CBOR->getSuperRegion();
1072 }
1073
1074 auto State = C.getState();
1075 auto &SymMgr = C.getSymbolManager();
1076 auto Sym = SymMgr.conjureSymbol(CE, C.getLocationContext(),
1077 C.getASTContext().LongTy, C.blockCount());
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001078 State = assumeNoOverflow(State, Sym, 4);
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001079 State = setIteratorPosition(State, RetVal,
1080 IteratorPosition::getPosition(Cont, Sym));
1081 C.addTransition(State);
1082}
1083
Adam Balogh6b23b1a2018-09-10 09:04:27 +00001084void IteratorChecker::handleAssign(CheckerContext &C, const SVal &Cont,
1085 const Expr *CE, const SVal &OldCont) const {
Adam Balogh2cfbe932018-08-28 08:41:15 +00001086 const auto *ContReg = Cont.getAsRegion();
1087 if (!ContReg)
1088 return;
1089
1090 while (const auto *CBOR = ContReg->getAs<CXXBaseObjectRegion>()) {
1091 ContReg = CBOR->getSuperRegion();
1092 }
1093
1094 // Assignment of a new value to a container always invalidates all its
1095 // iterators
1096 auto State = C.getState();
1097 const auto CData = getContainerData(State, ContReg);
1098 if (CData) {
1099 State = invalidateAllIteratorPositions(State, ContReg);
1100 }
1101
Adam Balogh6b23b1a2018-09-10 09:04:27 +00001102 // In case of move, iterators of the old container (except the past-end
1103 // iterators) remain valid but refer to the new container
1104 if (!OldCont.isUndef()) {
1105 const auto *OldContReg = OldCont.getAsRegion();
1106 if (OldContReg) {
1107 while (const auto *CBOR = OldContReg->getAs<CXXBaseObjectRegion>()) {
1108 OldContReg = CBOR->getSuperRegion();
1109 }
1110 const auto OldCData = getContainerData(State, OldContReg);
1111 if (OldCData) {
1112 if (const auto OldEndSym = OldCData->getEnd()) {
1113 // If we already assigned an "end" symbol to the old conainer, then
1114 // first reassign all iterator positions to the new container which
1115 // are not past the container (thus not greater or equal to the
1116 // current "end" symbol).
1117 State = reassignAllIteratorPositionsUnless(State, OldContReg, ContReg,
1118 OldEndSym, BO_GE);
1119 auto &SymMgr = C.getSymbolManager();
1120 auto &SVB = C.getSValBuilder();
1121 // Then generate and assign a new "end" symbol for the new container.
1122 auto NewEndSym =
1123 SymMgr.conjureSymbol(CE, C.getLocationContext(),
1124 C.getASTContext().LongTy, C.blockCount());
1125 State = assumeNoOverflow(State, NewEndSym, 4);
1126 if (CData) {
1127 State = setContainerData(State, ContReg, CData->newEnd(NewEndSym));
1128 } else {
1129 State = setContainerData(State, ContReg,
1130 ContainerData::fromEnd(NewEndSym));
1131 }
1132 // Finally, replace the old "end" symbol in the already reassigned
1133 // iterator positions with the new "end" symbol.
1134 State = rebaseSymbolInIteratorPositionsIf(
1135 State, SVB, OldEndSym, NewEndSym, OldEndSym, BO_LT);
1136 } else {
1137 // There was no "end" symbol assigned yet to the old container,
1138 // so reassign all iterator positions to the new container.
1139 State = reassignAllIteratorPositions(State, OldContReg, ContReg);
1140 }
1141 if (const auto OldBeginSym = OldCData->getBegin()) {
1142 // If we already assigned a "begin" symbol to the old container, then
1143 // assign it to the new container and remove it from the old one.
1144 if (CData) {
1145 State =
1146 setContainerData(State, ContReg, CData->newBegin(OldBeginSym));
1147 } else {
1148 State = setContainerData(State, ContReg,
1149 ContainerData::fromBegin(OldBeginSym));
1150 }
1151 State =
1152 setContainerData(State, OldContReg, OldCData->newEnd(nullptr));
1153 }
1154 } else {
1155 // There was neither "begin" nor "end" symbol assigned yet to the old
1156 // container, so reassign all iterator positions to the new container.
1157 State = reassignAllIteratorPositions(State, OldContReg, ContReg);
1158 }
1159 }
1160 }
Adam Balogh2cfbe932018-08-28 08:41:15 +00001161 C.addTransition(State);
1162}
1163
Adam Balogh9a48ba62018-09-10 09:06:31 +00001164void IteratorChecker::handlePushBack(CheckerContext &C,
1165 const SVal &Cont) const {
1166 const auto *ContReg = Cont.getAsRegion();
1167 if (!ContReg)
1168 return;
1169
1170 while (const auto *CBOR = ContReg->getAs<CXXBaseObjectRegion>()) {
1171 ContReg = CBOR->getSuperRegion();
1172 }
1173
1174 // For deque-like containers invalidate all iterator positions
1175 auto State = C.getState();
1176 if (hasSubscriptOperator(State, ContReg) && frontModifiable(State, ContReg)) {
1177 State = invalidateAllIteratorPositions(State, ContReg);
1178 C.addTransition(State);
1179 return;
1180 }
1181
1182 const auto CData = getContainerData(State, ContReg);
1183 if (!CData)
1184 return;
1185
1186 // For vector-like containers invalidate the past-end iterator positions
1187 if (const auto EndSym = CData->getEnd()) {
1188 if (hasSubscriptOperator(State, ContReg)) {
1189 State = invalidateIteratorPositions(State, EndSym, BO_GE);
1190 }
1191 auto &SymMgr = C.getSymbolManager();
1192 auto &BVF = SymMgr.getBasicVals();
1193 auto &SVB = C.getSValBuilder();
1194 const auto newEndSym =
1195 SVB.evalBinOp(State, BO_Add,
1196 nonloc::SymbolVal(EndSym),
1197 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
1198 SymMgr.getType(EndSym)).getAsSymbol();
1199 State = setContainerData(State, ContReg, CData->newEnd(newEndSym));
1200 }
1201 C.addTransition(State);
1202}
1203
1204void IteratorChecker::handlePopBack(CheckerContext &C, const SVal &Cont) const {
1205 const auto *ContReg = Cont.getAsRegion();
1206 if (!ContReg)
1207 return;
1208
1209 while (const auto *CBOR = ContReg->getAs<CXXBaseObjectRegion>()) {
1210 ContReg = CBOR->getSuperRegion();
1211 }
1212
1213 auto State = C.getState();
1214 const auto CData = getContainerData(State, ContReg);
1215 if (!CData)
1216 return;
1217
1218 if (const auto EndSym = CData->getEnd()) {
1219 auto &SymMgr = C.getSymbolManager();
1220 auto &BVF = SymMgr.getBasicVals();
1221 auto &SVB = C.getSValBuilder();
1222 const auto BackSym =
1223 SVB.evalBinOp(State, BO_Sub,
1224 nonloc::SymbolVal(EndSym),
1225 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
1226 SymMgr.getType(EndSym)).getAsSymbol();
1227 // For vector-like and deque-like containers invalidate the last and the
1228 // past-end iterator positions. For list-like containers only invalidate
1229 // the last position
1230 if (hasSubscriptOperator(State, ContReg) &&
1231 backModifiable(State, ContReg)) {
1232 State = invalidateIteratorPositions(State, BackSym, BO_GE);
1233 State = setContainerData(State, ContReg, CData->newEnd(nullptr));
1234 } else {
1235 State = invalidateIteratorPositions(State, BackSym, BO_EQ);
1236 }
1237 auto newEndSym = BackSym;
1238 State = setContainerData(State, ContReg, CData->newEnd(newEndSym));
1239 C.addTransition(State);
1240 }
1241}
1242
1243void IteratorChecker::handlePushFront(CheckerContext &C,
1244 const SVal &Cont) const {
1245 const auto *ContReg = Cont.getAsRegion();
1246 if (!ContReg)
1247 return;
1248
1249 while (const auto *CBOR = ContReg->getAs<CXXBaseObjectRegion>()) {
1250 ContReg = CBOR->getSuperRegion();
1251 }
1252
1253 // For deque-like containers invalidate all iterator positions
1254 auto State = C.getState();
1255 if (hasSubscriptOperator(State, ContReg)) {
1256 State = invalidateAllIteratorPositions(State, ContReg);
1257 C.addTransition(State);
1258 } else {
1259 const auto CData = getContainerData(State, ContReg);
1260 if (!CData)
1261 return;
1262
1263 if (const auto BeginSym = CData->getBegin()) {
1264 auto &SymMgr = C.getSymbolManager();
1265 auto &BVF = SymMgr.getBasicVals();
1266 auto &SVB = C.getSValBuilder();
1267 const auto newBeginSym =
1268 SVB.evalBinOp(State, BO_Sub,
1269 nonloc::SymbolVal(BeginSym),
1270 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
1271 SymMgr.getType(BeginSym)).getAsSymbol();
1272 State = setContainerData(State, ContReg, CData->newBegin(newBeginSym));
1273 C.addTransition(State);
1274 }
1275 }
1276}
1277
1278void IteratorChecker::handlePopFront(CheckerContext &C,
1279 const SVal &Cont) const {
1280 const auto *ContReg = Cont.getAsRegion();
1281 if (!ContReg)
1282 return;
1283
1284 while (const auto *CBOR = ContReg->getAs<CXXBaseObjectRegion>()) {
1285 ContReg = CBOR->getSuperRegion();
1286 }
1287
1288 auto State = C.getState();
1289 const auto CData = getContainerData(State, ContReg);
1290 if (!CData)
1291 return;
1292
1293 // For deque-like containers invalidate all iterator positions. For list-like
1294 // iterators only invalidate the first position
1295 if (const auto BeginSym = CData->getBegin()) {
1296 if (hasSubscriptOperator(State, ContReg)) {
1297 State = invalidateIteratorPositions(State, BeginSym, BO_LE);
1298 } else {
1299 State = invalidateIteratorPositions(State, BeginSym, BO_EQ);
1300 }
1301 auto &SymMgr = C.getSymbolManager();
1302 auto &BVF = SymMgr.getBasicVals();
1303 auto &SVB = C.getSValBuilder();
1304 const auto newBeginSym =
1305 SVB.evalBinOp(State, BO_Add,
1306 nonloc::SymbolVal(BeginSym),
1307 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
1308 SymMgr.getType(BeginSym)).getAsSymbol();
1309 State = setContainerData(State, ContReg, CData->newBegin(newBeginSym));
1310 C.addTransition(State);
1311 }
1312}
1313
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001314void IteratorChecker::reportOutOfRangeBug(const StringRef &Message,
1315 const SVal &Val, CheckerContext &C,
1316 ExplodedNode *ErrNode) const {
1317 auto R = llvm::make_unique<BugReport>(*OutOfRangeBugType, Message, ErrNode);
1318 R->markInteresting(Val);
1319 C.emitReport(std::move(R));
1320}
1321
Adam Balogh21583b72018-09-10 09:03:22 +00001322void IteratorChecker::reportMismatchedBug(const StringRef &Message,
1323 const SVal &Val1, const SVal &Val2,
1324 CheckerContext &C,
1325 ExplodedNode *ErrNode) const {
1326 auto R = llvm::make_unique<BugReport>(*MismatchedBugType, Message, ErrNode);
1327 R->markInteresting(Val1);
1328 R->markInteresting(Val2);
1329 C.emitReport(std::move(R));
1330}
1331
Adam Balogh3659f7a2018-09-10 09:05:31 +00001332void IteratorChecker::reportMismatchedBug(const StringRef &Message,
1333 const SVal &Val, const MemRegion *Reg,
1334 CheckerContext &C,
1335 ExplodedNode *ErrNode) const {
1336 auto R = llvm::make_unique<BugReport>(*MismatchedBugType, Message, ErrNode);
1337 R->markInteresting(Val);
1338 R->markInteresting(Reg);
1339 C.emitReport(std::move(R));
1340}
1341
Adam Balogh2cfbe932018-08-28 08:41:15 +00001342void IteratorChecker::reportInvalidatedBug(const StringRef &Message,
1343 const SVal &Val, CheckerContext &C,
1344 ExplodedNode *ErrNode) const {
1345 auto R = llvm::make_unique<BugReport>(*InvalidatedBugType, Message, ErrNode);
1346 R->markInteresting(Val);
1347 C.emitReport(std::move(R));
1348}
1349
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001350namespace {
1351
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001352bool isLess(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2);
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001353bool isGreaterOrEqual(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2);
1354bool compare(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2,
1355 BinaryOperator::Opcode Opc);
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001356bool compare(ProgramStateRef State, NonLoc NL1, NonLoc NL2,
1357 BinaryOperator::Opcode Opc);
Adam Balogh9a48ba62018-09-10 09:06:31 +00001358const CXXRecordDecl *getCXXRecordDecl(ProgramStateRef State,
1359 const MemRegion *Reg);
Adam Balogh6b23b1a2018-09-10 09:04:27 +00001360SymbolRef rebaseSymbol(ProgramStateRef State, SValBuilder &SVB, SymbolRef Expr,
1361 SymbolRef OldSym, SymbolRef NewSym);
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001362
1363bool isIteratorType(const QualType &Type) {
1364 if (Type->isPointerType())
1365 return true;
1366
1367 const auto *CRD = Type->getUnqualifiedDesugaredType()->getAsCXXRecordDecl();
1368 return isIterator(CRD);
1369}
1370
1371bool isIterator(const CXXRecordDecl *CRD) {
1372 if (!CRD)
1373 return false;
1374
1375 const auto Name = CRD->getName();
1376 if (!(Name.endswith_lower("iterator") || Name.endswith_lower("iter") ||
1377 Name.endswith_lower("it")))
1378 return false;
1379
1380 bool HasCopyCtor = false, HasCopyAssign = true, HasDtor = false,
1381 HasPreIncrOp = false, HasPostIncrOp = false, HasDerefOp = false;
1382 for (const auto *Method : CRD->methods()) {
1383 if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(Method)) {
1384 if (Ctor->isCopyConstructor()) {
1385 HasCopyCtor = !Ctor->isDeleted() && Ctor->getAccess() == AS_public;
1386 }
1387 continue;
1388 }
1389 if (const auto *Dtor = dyn_cast<CXXDestructorDecl>(Method)) {
1390 HasDtor = !Dtor->isDeleted() && Dtor->getAccess() == AS_public;
1391 continue;
1392 }
1393 if (Method->isCopyAssignmentOperator()) {
1394 HasCopyAssign = !Method->isDeleted() && Method->getAccess() == AS_public;
1395 continue;
1396 }
1397 if (!Method->isOverloadedOperator())
1398 continue;
1399 const auto OPK = Method->getOverloadedOperator();
1400 if (OPK == OO_PlusPlus) {
1401 HasPreIncrOp = HasPreIncrOp || (Method->getNumParams() == 0);
1402 HasPostIncrOp = HasPostIncrOp || (Method->getNumParams() == 1);
1403 continue;
1404 }
1405 if (OPK == OO_Star) {
1406 HasDerefOp = (Method->getNumParams() == 0);
1407 continue;
1408 }
1409 }
1410
1411 return HasCopyCtor && HasCopyAssign && HasDtor && HasPreIncrOp &&
1412 HasPostIncrOp && HasDerefOp;
1413}
1414
Adam Balogh3659f7a2018-09-10 09:05:31 +00001415bool isComparisonOperator(OverloadedOperatorKind OK) {
1416 return OK == OO_EqualEqual || OK == OO_ExclaimEqual || OK == OO_Less ||
1417 OK == OO_LessEqual || OK == OO_Greater || OK == OO_GreaterEqual;
1418}
1419
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001420bool isBeginCall(const FunctionDecl *Func) {
1421 const auto *IdInfo = Func->getIdentifier();
1422 if (!IdInfo)
1423 return false;
1424 return IdInfo->getName().endswith_lower("begin");
1425}
1426
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001427bool isEndCall(const FunctionDecl *Func) {
1428 const auto *IdInfo = Func->getIdentifier();
1429 if (!IdInfo)
1430 return false;
1431 return IdInfo->getName().endswith_lower("end");
1432}
1433
Adam Balogh9a48ba62018-09-10 09:06:31 +00001434bool isPushBackCall(const FunctionDecl *Func) {
1435 const auto *IdInfo = Func->getIdentifier();
1436 if (!IdInfo)
1437 return false;
1438 if (Func->getNumParams() != 1)
1439 return false;
1440 return IdInfo->getName() == "push_back";
1441}
1442
1443bool isEmplaceBackCall(const FunctionDecl *Func) {
1444 const auto *IdInfo = Func->getIdentifier();
1445 if (!IdInfo)
1446 return false;
1447 if (Func->getNumParams() < 1)
1448 return false;
1449 return IdInfo->getName() == "emplace_back";
1450}
1451
1452bool isPopBackCall(const FunctionDecl *Func) {
1453 const auto *IdInfo = Func->getIdentifier();
1454 if (!IdInfo)
1455 return false;
1456 if (Func->getNumParams() > 0)
1457 return false;
1458 return IdInfo->getName() == "pop_back";
1459}
1460
1461bool isPushFrontCall(const FunctionDecl *Func) {
1462 const auto *IdInfo = Func->getIdentifier();
1463 if (!IdInfo)
1464 return false;
1465 if (Func->getNumParams() != 1)
1466 return false;
1467 return IdInfo->getName() == "push_front";
1468}
1469
1470bool isEmplaceFrontCall(const FunctionDecl *Func) {
1471 const auto *IdInfo = Func->getIdentifier();
1472 if (!IdInfo)
1473 return false;
1474 if (Func->getNumParams() < 1)
1475 return false;
1476 return IdInfo->getName() == "emplace_front";
1477}
1478
1479bool isPopFrontCall(const FunctionDecl *Func) {
1480 const auto *IdInfo = Func->getIdentifier();
1481 if (!IdInfo)
1482 return false;
1483 if (Func->getNumParams() > 0)
1484 return false;
1485 return IdInfo->getName() == "pop_front";
1486}
1487
Adam Balogh2cfbe932018-08-28 08:41:15 +00001488bool isAssignmentOperator(OverloadedOperatorKind OK) { return OK == OO_Equal; }
1489
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001490bool isSimpleComparisonOperator(OverloadedOperatorKind OK) {
1491 return OK == OO_EqualEqual || OK == OO_ExclaimEqual;
1492}
1493
Adam Balogh2cfbe932018-08-28 08:41:15 +00001494bool isAccessOperator(OverloadedOperatorKind OK) {
1495 return isDereferenceOperator(OK) || isIncrementOperator(OK) ||
1496 isDecrementOperator(OK) || isRandomIncrOrDecrOperator(OK);
1497}
1498
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001499bool isDereferenceOperator(OverloadedOperatorKind OK) {
1500 return OK == OO_Star || OK == OO_Arrow || OK == OO_ArrowStar ||
1501 OK == OO_Subscript;
1502}
1503
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001504bool isIncrementOperator(OverloadedOperatorKind OK) {
1505 return OK == OO_PlusPlus;
1506}
1507
1508bool isDecrementOperator(OverloadedOperatorKind OK) {
1509 return OK == OO_MinusMinus;
1510}
1511
1512bool isRandomIncrOrDecrOperator(OverloadedOperatorKind OK) {
1513 return OK == OO_Plus || OK == OO_PlusEqual || OK == OO_Minus ||
1514 OK == OO_MinusEqual;
1515}
1516
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001517BinaryOperator::Opcode getOpcode(const SymExpr *SE) {
1518 if (const auto *BSE = dyn_cast<BinarySymExpr>(SE)) {
1519 return BSE->getOpcode();
1520 } else if (const auto *SC = dyn_cast<SymbolConjured>(SE)) {
Henry Wong073d5f02018-03-20 09:27:02 +00001521 const auto *COE = dyn_cast_or_null<CXXOperatorCallExpr>(SC->getStmt());
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001522 if (!COE)
1523 return BO_Comma; // Extremal value, neither EQ nor NE
1524 if (COE->getOperator() == OO_EqualEqual) {
1525 return BO_EQ;
1526 } else if (COE->getOperator() == OO_ExclaimEqual) {
1527 return BO_NE;
1528 }
1529 return BO_Comma; // Extremal value, neither EQ nor NE
1530 }
1531 return BO_Comma; // Extremal value, neither EQ nor NE
1532}
1533
Adam Balogh9a48ba62018-09-10 09:06:31 +00001534bool hasSubscriptOperator(ProgramStateRef State, const MemRegion *Reg) {
1535 const auto *CRD = getCXXRecordDecl(State, Reg);
1536 if (!CRD)
1537 return false;
1538
1539 for (const auto *Method : CRD->methods()) {
1540 if (!Method->isOverloadedOperator())
1541 continue;
1542 const auto OPK = Method->getOverloadedOperator();
1543 if (OPK == OO_Subscript) {
1544 return true;
1545 }
1546 }
1547 return false;
1548}
1549
1550bool frontModifiable(ProgramStateRef State, const MemRegion *Reg) {
1551 const auto *CRD = getCXXRecordDecl(State, Reg);
1552 if (!CRD)
1553 return false;
1554
1555 for (const auto *Method : CRD->methods()) {
1556 if (!Method->getDeclName().isIdentifier())
1557 continue;
1558 if (Method->getName() == "push_front" || Method->getName() == "pop_front") {
1559 return true;
1560 }
1561 }
1562 return false;
1563}
1564
1565bool backModifiable(ProgramStateRef State, const MemRegion *Reg) {
1566 const auto *CRD = getCXXRecordDecl(State, Reg);
1567 if (!CRD)
1568 return false;
1569
1570 for (const auto *Method : CRD->methods()) {
1571 if (!Method->getDeclName().isIdentifier())
1572 continue;
1573 if (Method->getName() == "push_back" || Method->getName() == "pop_back") {
1574 return true;
1575 }
1576 }
1577 return false;
1578}
1579
1580const CXXRecordDecl *getCXXRecordDecl(ProgramStateRef State,
1581 const MemRegion *Reg) {
1582 auto TI = getDynamicTypeInfo(State, Reg);
1583 if (!TI.isValid())
1584 return nullptr;
1585
1586 auto Type = TI.getType();
1587 if (const auto *RefT = Type->getAs<ReferenceType>()) {
1588 Type = RefT->getPointeeType();
1589 }
1590
1591 return Type->getUnqualifiedDesugaredType()->getAsCXXRecordDecl();
1592}
1593
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001594const RegionOrSymbol getRegionOrSymbol(const SVal &Val) {
1595 if (const auto Reg = Val.getAsRegion()) {
1596 return Reg;
1597 } else if (const auto Sym = Val.getAsSymbol()) {
1598 return Sym;
1599 } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
1600 return LCVal->getRegion();
1601 }
1602 return RegionOrSymbol();
1603}
1604
1605const ProgramStateRef processComparison(ProgramStateRef State,
1606 RegionOrSymbol LVal,
1607 RegionOrSymbol RVal, bool Equal) {
1608 const auto *LPos = getIteratorPosition(State, LVal);
1609 const auto *RPos = getIteratorPosition(State, RVal);
1610 if (LPos && !RPos) {
1611 State = adjustIteratorPosition(State, RVal, *LPos, Equal);
1612 } else if (!LPos && RPos) {
1613 State = adjustIteratorPosition(State, LVal, *RPos, Equal);
1614 } else if (LPos && RPos) {
1615 State = relateIteratorPositions(State, *LPos, *RPos, Equal);
1616 }
1617 return State;
1618}
1619
1620const ProgramStateRef saveComparison(ProgramStateRef State,
1621 const SymExpr *Condition, const SVal &LVal,
1622 const SVal &RVal, bool Eq) {
1623 const auto Left = getRegionOrSymbol(LVal);
1624 const auto Right = getRegionOrSymbol(RVal);
1625 if (!Left || !Right)
1626 return State;
1627 return State->set<IteratorComparisonMap>(Condition,
1628 IteratorComparison(Left, Right, Eq));
1629}
1630
1631const IteratorComparison *loadComparison(ProgramStateRef State,
1632 const SymExpr *Condition) {
1633 return State->get<IteratorComparisonMap>(Condition);
1634}
1635
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001636SymbolRef getContainerBegin(ProgramStateRef State, const MemRegion *Cont) {
1637 const auto *CDataPtr = getContainerData(State, Cont);
1638 if (!CDataPtr)
1639 return nullptr;
1640
1641 return CDataPtr->getBegin();
1642}
1643
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001644SymbolRef getContainerEnd(ProgramStateRef State, const MemRegion *Cont) {
1645 const auto *CDataPtr = getContainerData(State, Cont);
1646 if (!CDataPtr)
1647 return nullptr;
1648
1649 return CDataPtr->getEnd();
1650}
1651
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001652ProgramStateRef createContainerBegin(ProgramStateRef State,
1653 const MemRegion *Cont,
1654 const SymbolRef Sym) {
1655 // Only create if it does not exist
1656 const auto *CDataPtr = getContainerData(State, Cont);
1657 if (CDataPtr) {
1658 if (CDataPtr->getBegin()) {
1659 return State;
1660 }
1661 const auto CData = CDataPtr->newBegin(Sym);
1662 return setContainerData(State, Cont, CData);
1663 }
1664 const auto CData = ContainerData::fromBegin(Sym);
1665 return setContainerData(State, Cont, CData);
1666}
1667
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001668ProgramStateRef createContainerEnd(ProgramStateRef State, const MemRegion *Cont,
1669 const SymbolRef Sym) {
1670 // Only create if it does not exist
1671 const auto *CDataPtr = getContainerData(State, Cont);
1672 if (CDataPtr) {
1673 if (CDataPtr->getEnd()) {
1674 return State;
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001675 }
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001676 const auto CData = CDataPtr->newEnd(Sym);
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001677 return setContainerData(State, Cont, CData);
1678 }
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001679 const auto CData = ContainerData::fromEnd(Sym);
1680 return setContainerData(State, Cont, CData);
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001681}
1682
1683const ContainerData *getContainerData(ProgramStateRef State,
1684 const MemRegion *Cont) {
1685 return State->get<ContainerMap>(Cont);
1686}
1687
1688ProgramStateRef setContainerData(ProgramStateRef State, const MemRegion *Cont,
1689 const ContainerData &CData) {
1690 return State->set<ContainerMap>(Cont, CData);
1691}
1692
1693const IteratorPosition *getIteratorPosition(ProgramStateRef State,
1694 const SVal &Val) {
1695 if (const auto Reg = Val.getAsRegion()) {
1696 return State->get<IteratorRegionMap>(Reg);
1697 } else if (const auto Sym = Val.getAsSymbol()) {
1698 return State->get<IteratorSymbolMap>(Sym);
1699 } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
1700 return State->get<IteratorRegionMap>(LCVal->getRegion());
1701 }
1702 return nullptr;
1703}
1704
1705const IteratorPosition *getIteratorPosition(ProgramStateRef State,
1706 RegionOrSymbol RegOrSym) {
1707 if (RegOrSym.is<const MemRegion *>()) {
1708 return State->get<IteratorRegionMap>(RegOrSym.get<const MemRegion *>());
1709 } else if (RegOrSym.is<SymbolRef>()) {
1710 return State->get<IteratorSymbolMap>(RegOrSym.get<SymbolRef>());
1711 }
1712 return nullptr;
1713}
1714
1715ProgramStateRef setIteratorPosition(ProgramStateRef State, const SVal &Val,
1716 const IteratorPosition &Pos) {
1717 if (const auto Reg = Val.getAsRegion()) {
1718 return State->set<IteratorRegionMap>(Reg, Pos);
1719 } else if (const auto Sym = Val.getAsSymbol()) {
1720 return State->set<IteratorSymbolMap>(Sym, Pos);
1721 } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
1722 return State->set<IteratorRegionMap>(LCVal->getRegion(), Pos);
1723 }
1724 return nullptr;
1725}
1726
1727ProgramStateRef setIteratorPosition(ProgramStateRef State,
1728 RegionOrSymbol RegOrSym,
1729 const IteratorPosition &Pos) {
1730 if (RegOrSym.is<const MemRegion *>()) {
1731 return State->set<IteratorRegionMap>(RegOrSym.get<const MemRegion *>(),
1732 Pos);
1733 } else if (RegOrSym.is<SymbolRef>()) {
1734 return State->set<IteratorSymbolMap>(RegOrSym.get<SymbolRef>(), Pos);
1735 }
1736 return nullptr;
1737}
1738
1739ProgramStateRef removeIteratorPosition(ProgramStateRef State, const SVal &Val) {
1740 if (const auto Reg = Val.getAsRegion()) {
1741 return State->remove<IteratorRegionMap>(Reg);
1742 } else if (const auto Sym = Val.getAsSymbol()) {
1743 return State->remove<IteratorSymbolMap>(Sym);
1744 } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
1745 return State->remove<IteratorRegionMap>(LCVal->getRegion());
1746 }
1747 return nullptr;
1748}
1749
1750ProgramStateRef adjustIteratorPosition(ProgramStateRef State,
1751 RegionOrSymbol RegOrSym,
1752 const IteratorPosition &Pos,
1753 bool Equal) {
1754 if (Equal) {
1755 return setIteratorPosition(State, RegOrSym, Pos);
1756 } else {
1757 return State;
1758 }
1759}
1760
1761ProgramStateRef relateIteratorPositions(ProgramStateRef State,
1762 const IteratorPosition &Pos1,
1763 const IteratorPosition &Pos2,
1764 bool Equal) {
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001765 auto &SVB = State->getStateManager().getSValBuilder();
Adam Balogh0a7592b2018-07-16 09:27:27 +00001766
1767 // FIXME: This code should be reworked as follows:
1768 // 1. Subtract the operands using evalBinOp().
1769 // 2. Assume that the result doesn't overflow.
1770 // 3. Compare the result to 0.
1771 // 4. Assume the result of the comparison.
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001772 const auto comparison =
1773 SVB.evalBinOp(State, BO_EQ, nonloc::SymbolVal(Pos1.getOffset()),
Adam Balogh0a7592b2018-07-16 09:27:27 +00001774 nonloc::SymbolVal(Pos2.getOffset()),
1775 SVB.getConditionType());
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001776
Adam Balogh0a7592b2018-07-16 09:27:27 +00001777 assert(comparison.getAs<DefinedSVal>() &&
1778 "Symbol comparison must be a `DefinedSVal`");
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001779
Adam Balogh0a7592b2018-07-16 09:27:27 +00001780 auto NewState = State->assume(comparison.castAs<DefinedSVal>(), Equal);
1781 if (const auto CompSym = comparison.getAsSymbol()) {
1782 assert(isa<SymIntExpr>(CompSym) &&
1783 "Symbol comparison must be a `SymIntExpr`");
1784 assert(BinaryOperator::isComparisonOp(
1785 cast<SymIntExpr>(CompSym)->getOpcode()) &&
1786 "Symbol comparison must be a comparison");
1787 return assumeNoOverflow(NewState, cast<SymIntExpr>(CompSym)->getLHS(), 2);
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001788 }
1789
Adam Balogh0a7592b2018-07-16 09:27:27 +00001790 return NewState;
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001791}
1792
Adam Balogha6921202018-07-30 08:52:21 +00001793bool hasLiveIterators(ProgramStateRef State, const MemRegion *Cont) {
1794 auto RegionMap = State->get<IteratorRegionMap>();
1795 for (const auto Reg : RegionMap) {
1796 if (Reg.second.getContainer() == Cont)
1797 return true;
1798 }
1799
1800 auto SymbolMap = State->get<IteratorSymbolMap>();
1801 for (const auto Sym : SymbolMap) {
1802 if (Sym.second.getContainer() == Cont)
1803 return true;
1804 }
1805
1806 return false;
1807}
1808
Adam Balogh21583b72018-09-10 09:03:22 +00001809bool isBoundThroughLazyCompoundVal(const Environment &Env,
1810 const MemRegion *Reg) {
1811 for (const auto Binding: Env) {
1812 if (const auto LCVal = Binding.second.getAs<nonloc::LazyCompoundVal>()) {
1813 if (LCVal->getRegion() == Reg)
1814 return true;
1815 }
1816 }
1817
1818 return false;
1819}
1820
Adam Balogh2cfbe932018-08-28 08:41:15 +00001821template <typename Condition, typename Process>
1822ProgramStateRef processIteratorPositions(ProgramStateRef State, Condition Cond,
1823 Process Proc) {
1824 auto &RegionMapFactory = State->get_context<IteratorRegionMap>();
1825 auto RegionMap = State->get<IteratorRegionMap>();
1826 bool Changed = false;
1827 for (const auto Reg : RegionMap) {
1828 if (Cond(Reg.second)) {
1829 RegionMap = RegionMapFactory.add(RegionMap, Reg.first, Proc(Reg.second));
1830 Changed = true;
1831 }
1832 }
1833
1834 if (Changed)
1835 State = State->set<IteratorRegionMap>(RegionMap);
1836
1837 auto &SymbolMapFactory = State->get_context<IteratorSymbolMap>();
1838 auto SymbolMap = State->get<IteratorSymbolMap>();
1839 Changed = false;
1840 for (const auto Sym : SymbolMap) {
1841 if (Cond(Sym.second)) {
1842 SymbolMap = SymbolMapFactory.add(SymbolMap, Sym.first, Proc(Sym.second));
1843 Changed = true;
1844 }
1845 }
1846
1847 if (Changed)
1848 State = State->set<IteratorSymbolMap>(SymbolMap);
1849
1850 return State;
1851}
1852
1853ProgramStateRef invalidateAllIteratorPositions(ProgramStateRef State,
1854 const MemRegion *Cont) {
1855 auto MatchCont = [&](const IteratorPosition &Pos) {
1856 return Pos.getContainer() == Cont;
1857 };
1858 auto Invalidate = [&](const IteratorPosition &Pos) {
1859 return Pos.invalidate();
1860 };
1861 return processIteratorPositions(State, MatchCont, Invalidate);
1862}
1863
Adam Balogh9a48ba62018-09-10 09:06:31 +00001864ProgramStateRef invalidateIteratorPositions(ProgramStateRef State,
1865 SymbolRef Offset,
1866 BinaryOperator::Opcode Opc) {
1867 auto Compare = [&](const IteratorPosition &Pos) {
1868 return compare(State, Pos.getOffset(), Offset, Opc);
1869 };
1870 auto Invalidate = [&](const IteratorPosition &Pos) {
1871 return Pos.invalidate();
1872 };
1873 return processIteratorPositions(State, Compare, Invalidate);
1874}
1875
Adam Balogh6b23b1a2018-09-10 09:04:27 +00001876ProgramStateRef reassignAllIteratorPositions(ProgramStateRef State,
1877 const MemRegion *Cont,
1878 const MemRegion *NewCont) {
1879 auto MatchCont = [&](const IteratorPosition &Pos) {
1880 return Pos.getContainer() == Cont;
1881 };
1882 auto ReAssign = [&](const IteratorPosition &Pos) {
1883 return Pos.reAssign(NewCont);
1884 };
1885 return processIteratorPositions(State, MatchCont, ReAssign);
1886}
1887
1888ProgramStateRef reassignAllIteratorPositionsUnless(ProgramStateRef State,
1889 const MemRegion *Cont,
1890 const MemRegion *NewCont,
1891 SymbolRef Offset,
1892 BinaryOperator::Opcode Opc) {
1893 auto MatchContAndCompare = [&](const IteratorPosition &Pos) {
1894 return Pos.getContainer() == Cont &&
1895 !compare(State, Pos.getOffset(), Offset, Opc);
1896 };
1897 auto ReAssign = [&](const IteratorPosition &Pos) {
1898 return Pos.reAssign(NewCont);
1899 };
1900 return processIteratorPositions(State, MatchContAndCompare, ReAssign);
1901}
1902
1903// This function rebases symbolic expression `OldSym + Int` to `NewSym + Int`,
1904// `OldSym - Int` to `NewSym - Int` and `OldSym` to `NewSym` in any iterator
1905// position offsets where `CondSym` is true.
1906ProgramStateRef rebaseSymbolInIteratorPositionsIf(
1907 ProgramStateRef State, SValBuilder &SVB, SymbolRef OldSym,
1908 SymbolRef NewSym, SymbolRef CondSym, BinaryOperator::Opcode Opc) {
1909 auto LessThanEnd = [&](const IteratorPosition &Pos) {
1910 return compare(State, Pos.getOffset(), CondSym, Opc);
1911 };
1912 auto RebaseSymbol = [&](const IteratorPosition &Pos) {
1913 return Pos.setTo(rebaseSymbol(State, SVB, Pos.getOffset(), OldSym,
1914 NewSym));
1915 };
1916 return processIteratorPositions(State, LessThanEnd, RebaseSymbol);
1917}
1918
1919// This function rebases symbolic expression `OldExpr + Int` to `NewExpr + Int`,
1920// `OldExpr - Int` to `NewExpr - Int` and `OldExpr` to `NewExpr` in expression
1921// `OrigExpr`.
1922SymbolRef rebaseSymbol(ProgramStateRef State, SValBuilder &SVB,
1923 SymbolRef OrigExpr, SymbolRef OldExpr,
1924 SymbolRef NewSym) {
1925 auto &SymMgr = SVB.getSymbolManager();
1926 auto Diff = SVB.evalBinOpNN(State, BO_Sub, nonloc::SymbolVal(OrigExpr),
1927 nonloc::SymbolVal(OldExpr),
1928 SymMgr.getType(OrigExpr));
1929
1930 const auto DiffInt = Diff.getAs<nonloc::ConcreteInt>();
1931 if (!DiffInt)
1932 return OrigExpr;
1933
1934 return SVB.evalBinOpNN(State, BO_Add, *DiffInt, nonloc::SymbolVal(NewSym),
1935 SymMgr.getType(OrigExpr)).getAsSymbol();
1936}
1937
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001938bool isZero(ProgramStateRef State, const NonLoc &Val) {
1939 auto &BVF = State->getBasicVals();
1940 return compare(State, Val,
1941 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))),
1942 BO_EQ);
1943}
1944
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001945bool isOutOfRange(ProgramStateRef State, const IteratorPosition &Pos) {
1946 const auto *Cont = Pos.getContainer();
1947 const auto *CData = getContainerData(State, Cont);
1948 if (!CData)
1949 return false;
1950
1951 // Out of range means less than the begin symbol or greater or equal to the
1952 // end symbol.
1953
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001954 const auto Beg = CData->getBegin();
1955 if (Beg) {
1956 if (isLess(State, Pos.getOffset(), Beg)) {
1957 return true;
1958 }
1959 }
1960
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001961 const auto End = CData->getEnd();
1962 if (End) {
1963 if (isGreaterOrEqual(State, Pos.getOffset(), End)) {
1964 return true;
1965 }
1966 }
1967
1968 return false;
1969}
1970
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001971bool isLess(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) {
1972 return compare(State, Sym1, Sym2, BO_LT);
1973}
1974
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001975bool isGreaterOrEqual(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) {
1976 return compare(State, Sym1, Sym2, BO_GE);
1977}
1978
1979bool compare(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2,
1980 BinaryOperator::Opcode Opc) {
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001981 return compare(State, nonloc::SymbolVal(Sym1), nonloc::SymbolVal(Sym2), Opc);
1982}
1983
Adam Balogh9a48ba62018-09-10 09:06:31 +00001984
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001985bool compare(ProgramStateRef State, NonLoc NL1, NonLoc NL2,
1986 BinaryOperator::Opcode Opc) {
1987 auto &SVB = State->getStateManager().getSValBuilder();
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001988
1989 const auto comparison =
Adam Balogh0a7592b2018-07-16 09:27:27 +00001990 SVB.evalBinOp(State, Opc, NL1, NL2, SVB.getConditionType());
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001991
Adam Balogh0a7592b2018-07-16 09:27:27 +00001992 assert(comparison.getAs<DefinedSVal>() &&
1993 "Symbol comparison must be a `DefinedSVal`");
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001994
Adam Balogh0a7592b2018-07-16 09:27:27 +00001995 return !State->assume(comparison.castAs<DefinedSVal>(), false);
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001996}
1997
1998} // namespace
1999
2000#define REGISTER_CHECKER(name) \
2001 void ento::register##name(CheckerManager &Mgr) { \
2002 auto *checker = Mgr.registerChecker<IteratorChecker>(); \
2003 checker->ChecksEnabled[IteratorChecker::CK_##name] = true; \
2004 checker->CheckNames[IteratorChecker::CK_##name] = \
2005 Mgr.getCurrentCheckName(); \
2006 }
2007
2008REGISTER_CHECKER(IteratorRangeChecker)
Adam Balogh21583b72018-09-10 09:03:22 +00002009REGISTER_CHECKER(MismatchedIteratorChecker)
Adam Balogh2cfbe932018-08-28 08:41:15 +00002010REGISTER_CHECKER(InvalidatedIteratorChecker)