blob: ee2ed43ec579612b95ea1c75e85544969a8d6b3b [file] [log] [blame]
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001//===-- IteratorChecker.cpp ---------------------------------------*- C++ -*--//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Artem Dergachev8fa639e2017-05-29 15:03:20 +00006//
7//===----------------------------------------------------------------------===//
8//
9// Defines a checker for using iterators outside their range (past end). Usage
10// means here dereferencing, incrementing etc.
11//
12//===----------------------------------------------------------------------===//
13//
14// In the code, iterator can be represented as a:
15// * type-I: typedef-ed pointer. Operations over such iterator, such as
16// comparisons or increments, are modeled straightforwardly by the
17// analyzer.
18// * type-II: structure with its method bodies available. Operations over such
19// iterator are inlined by the analyzer, and results of modeling
20// these operations are exposing implementation details of the
21// iterators, which is not necessarily helping.
22// * type-III: completely opaque structure. Operations over such iterator are
23// modeled conservatively, producing conjured symbols everywhere.
24//
25// To handle all these types in a common way we introduce a structure called
26// IteratorPosition which is an abstraction of the position the iterator
27// represents using symbolic expressions. The checker handles all the
28// operations on this structure.
29//
30// Additionally, depending on the circumstances, operators of types II and III
31// can be represented as:
32// * type-IIa, type-IIIa: conjured structure symbols - when returned by value
33// from conservatively evaluated methods such as
34// `.begin()`.
35// * type-IIb, type-IIIb: memory regions of iterator-typed objects, such as
36// variables or temporaries, when the iterator object is
37// currently treated as an lvalue.
38// * type-IIc, type-IIIc: compound values of iterator-typed objects, when the
39// iterator object is treated as an rvalue taken of a
40// particular lvalue, eg. a copy of "type-a" iterator
41// object, or an iterator that existed before the
42// analysis has started.
43//
44// To handle any of these three different representations stored in an SVal we
45// use setter and getters functions which separate the three cases. To store
46// them we use a pointer union of symbol and memory region.
47//
Adam Baloghb03ed5e2018-06-28 10:58:53 +000048// The checker works the following way: We record the begin and the
49// past-end iterator for all containers whenever their `.begin()` and `.end()`
50// are called. Since the Constraint Manager cannot handle such SVals we need
51// to take over its role. We post-check equality and non-equality comparisons
52// and record that the two sides are equal if we are in the 'equal' branch
53// (true-branch for `==` and false-branch for `!=`).
Artem Dergachev8fa639e2017-05-29 15:03:20 +000054//
55// In case of type-I or type-II iterators we get a concrete integer as a result
56// of the comparison (1 or 0) but in case of type-III we only get a Symbol. In
57// this latter case we record the symbol and reload it in evalAssume() and do
58// the propagation there. We also handle (maybe double) negated comparisons
Adam Baloghb03ed5e2018-06-28 10:58:53 +000059// which are represented in the form of (x == 0 or x != 0) where x is the
Artem Dergachev8fa639e2017-05-29 15:03:20 +000060// comparison itself.
Adam Baloghb03ed5e2018-06-28 10:58:53 +000061//
62// Since `SimpleConstraintManager` cannot handle complex symbolic expressions
63// we only use expressions of the format S, S+n or S-n for iterator positions
64// where S is a conjured symbol and n is an unsigned concrete integer. When
65// making an assumption e.g. `S1 + n == S2 + m` we store `S1 - S2 == m - n` as
66// a constraint which we later retrieve when doing an actual comparison.
Artem Dergachev8fa639e2017-05-29 15:03:20 +000067
Kristof Umann76a21502018-12-15 16:23:51 +000068#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
Adam Balogh2cfbe932018-08-28 08:41:15 +000069#include "clang/AST/DeclTemplate.h"
Artem Dergachev8fa639e2017-05-29 15:03:20 +000070#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
71#include "clang/StaticAnalyzer/Core/Checker.h"
72#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
73#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
Csaba Dabise4bf4562019-08-22 00:36:42 +000074#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h"
Artem Dergachev8fa639e2017-05-29 15:03:20 +000075
Adam Balogh2cfbe932018-08-28 08:41:15 +000076#include <utility>
77
Artem Dergachev8fa639e2017-05-29 15:03:20 +000078using namespace clang;
79using namespace ento;
80
81namespace {
82
83// Abstract position of an iterator. This helps to handle all three kinds
84// of operators in a common way by using a symbolic position.
85struct IteratorPosition {
86private:
87
88 // Container the iterator belongs to
89 const MemRegion *Cont;
90
Adam Balogh2cfbe932018-08-28 08:41:15 +000091 // Whether iterator is valid
92 const bool Valid;
93
Artem Dergachev8fa639e2017-05-29 15:03:20 +000094 // Abstract offset
Adam Baloghb03ed5e2018-06-28 10:58:53 +000095 const SymbolRef Offset;
Artem Dergachev8fa639e2017-05-29 15:03:20 +000096
Adam Balogh2cfbe932018-08-28 08:41:15 +000097 IteratorPosition(const MemRegion *C, bool V, SymbolRef Of)
98 : Cont(C), Valid(V), Offset(Of) {}
Artem Dergachev8fa639e2017-05-29 15:03:20 +000099
100public:
101 const MemRegion *getContainer() const { return Cont; }
Adam Balogh2cfbe932018-08-28 08:41:15 +0000102 bool isValid() const { return Valid; }
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000103 SymbolRef getOffset() const { return Offset; }
104
Adam Balogh2cfbe932018-08-28 08:41:15 +0000105 IteratorPosition invalidate() const {
106 return IteratorPosition(Cont, false, Offset);
107 }
108
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000109 static IteratorPosition getPosition(const MemRegion *C, SymbolRef Of) {
Adam Balogh2cfbe932018-08-28 08:41:15 +0000110 return IteratorPosition(C, true, Of);
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000111 }
112
113 IteratorPosition setTo(SymbolRef NewOf) const {
Adam Balogh2cfbe932018-08-28 08:41:15 +0000114 return IteratorPosition(Cont, Valid, NewOf);
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000115 }
116
Adam Balogh6b23b1a2018-09-10 09:04:27 +0000117 IteratorPosition reAssign(const MemRegion *NewCont) const {
118 return IteratorPosition(NewCont, Valid, Offset);
119 }
120
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000121 bool operator==(const IteratorPosition &X) const {
Adam Balogh2cfbe932018-08-28 08:41:15 +0000122 return Cont == X.Cont && Valid == X.Valid && Offset == X.Offset;
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000123 }
124
125 bool operator!=(const IteratorPosition &X) const {
Adam Balogh2cfbe932018-08-28 08:41:15 +0000126 return Cont != X.Cont || Valid != X.Valid || Offset != X.Offset;
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000127 }
128
129 void Profile(llvm::FoldingSetNodeID &ID) const {
130 ID.AddPointer(Cont);
Adam Balogh2cfbe932018-08-28 08:41:15 +0000131 ID.AddInteger(Valid);
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000132 ID.Add(Offset);
133 }
134};
135
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000136// Structure to record the symbolic begin and end position of a container
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000137struct ContainerData {
138private:
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000139 const SymbolRef Begin, End;
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000140
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000141 ContainerData(SymbolRef B, SymbolRef E) : Begin(B), End(E) {}
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000142
143public:
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000144 static ContainerData fromBegin(SymbolRef B) {
145 return ContainerData(B, nullptr);
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000146 }
147
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000148 static ContainerData fromEnd(SymbolRef E) {
149 return ContainerData(nullptr, E);
150 }
151
152 SymbolRef getBegin() const { return Begin; }
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000153 SymbolRef getEnd() const { return End; }
154
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000155 ContainerData newBegin(SymbolRef B) const { return ContainerData(B, End); }
156
157 ContainerData newEnd(SymbolRef E) const { return ContainerData(Begin, E); }
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000158
159 bool operator==(const ContainerData &X) const {
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000160 return Begin == X.Begin && End == X.End;
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000161 }
162
163 bool operator!=(const ContainerData &X) const {
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000164 return Begin != X.Begin || End != X.End;
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000165 }
166
167 void Profile(llvm::FoldingSetNodeID &ID) const {
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000168 ID.Add(Begin);
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000169 ID.Add(End);
170 }
171};
172
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000173class IteratorChecker
174 : public Checker<check::PreCall, check::PostCall,
Adam Balogh2e7cb342018-09-10 09:07:47 +0000175 check::PostStmt<MaterializeTemporaryExpr>, check::Bind,
Adam Balogh54976e72019-04-23 07:15:55 +0000176 check::LiveSymbols, check::DeadSymbols> {
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000177
178 std::unique_ptr<BugType> OutOfRangeBugType;
Adam Balogh21583b72018-09-10 09:03:22 +0000179 std::unique_ptr<BugType> MismatchedBugType;
Adam Balogh2cfbe932018-08-28 08:41:15 +0000180 std::unique_ptr<BugType> InvalidatedBugType;
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000181
Adam Balogh54976e72019-04-23 07:15:55 +0000182 void handleComparison(CheckerContext &C, const Expr *CE, const SVal &RetVal,
183 const SVal &LVal, const SVal &RVal,
184 OverloadedOperatorKind Op) const;
185 void processComparison(CheckerContext &C, ProgramStateRef State,
186 SymbolRef Sym1, SymbolRef Sym2, const SVal &RetVal,
187 OverloadedOperatorKind Op) const;
Adam Balogh2cfbe932018-08-28 08:41:15 +0000188 void verifyAccess(CheckerContext &C, const SVal &Val) const;
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000189 void verifyDereference(CheckerContext &C, const SVal &Val) const;
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000190 void handleIncrement(CheckerContext &C, const SVal &RetVal, const SVal &Iter,
191 bool Postfix) const;
192 void handleDecrement(CheckerContext &C, const SVal &RetVal, const SVal &Iter,
193 bool Postfix) const;
194 void handleRandomIncrOrDecr(CheckerContext &C, OverloadedOperatorKind Op,
195 const SVal &RetVal, const SVal &LHS,
196 const SVal &RHS) const;
197 void handleBegin(CheckerContext &C, const Expr *CE, const SVal &RetVal,
198 const SVal &Cont) const;
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000199 void handleEnd(CheckerContext &C, const Expr *CE, const SVal &RetVal,
200 const SVal &Cont) const;
201 void assignToContainer(CheckerContext &C, const Expr *CE, const SVal &RetVal,
202 const MemRegion *Cont) const;
Adam Balogh6b23b1a2018-09-10 09:04:27 +0000203 void handleAssign(CheckerContext &C, const SVal &Cont,
204 const Expr *CE = nullptr,
205 const SVal &OldCont = UndefinedVal()) const;
Adam Balogh2e7cb342018-09-10 09:07:47 +0000206 void handleClear(CheckerContext &C, const SVal &Cont) const;
Adam Balogh9a48ba62018-09-10 09:06:31 +0000207 void handlePushBack(CheckerContext &C, const SVal &Cont) const;
208 void handlePopBack(CheckerContext &C, const SVal &Cont) const;
209 void handlePushFront(CheckerContext &C, const SVal &Cont) const;
210 void handlePopFront(CheckerContext &C, const SVal &Cont) const;
Adam Balogh2e7cb342018-09-10 09:07:47 +0000211 void handleInsert(CheckerContext &C, const SVal &Iter) const;
212 void handleErase(CheckerContext &C, const SVal &Iter) const;
213 void handleErase(CheckerContext &C, const SVal &Iter1,
214 const SVal &Iter2) const;
215 void handleEraseAfter(CheckerContext &C, const SVal &Iter) const;
216 void handleEraseAfter(CheckerContext &C, const SVal &Iter1,
217 const SVal &Iter2) const;
Adam Baloghd5bd3f62018-12-04 10:27:27 +0000218 void verifyIncrement(CheckerContext &C, const SVal &Iter) const;
219 void verifyDecrement(CheckerContext &C, const SVal &Iter) const;
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000220 void verifyRandomIncrOrDecr(CheckerContext &C, OverloadedOperatorKind Op,
Adam Baloghd5bd3f62018-12-04 10:27:27 +0000221 const SVal &LHS, const SVal &RHS) const;
Adam Balogh2e7cb342018-09-10 09:07:47 +0000222 void verifyMatch(CheckerContext &C, const SVal &Iter,
223 const MemRegion *Cont) const;
Adam Balogh21583b72018-09-10 09:03:22 +0000224 void verifyMatch(CheckerContext &C, const SVal &Iter1,
225 const SVal &Iter2) const;
Adam Baloghd5bd3f62018-12-04 10:27:27 +0000226 IteratorPosition advancePosition(CheckerContext &C, OverloadedOperatorKind Op,
227 const IteratorPosition &Pos,
228 const SVal &Distance) const;
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000229 void reportOutOfRangeBug(const StringRef &Message, const SVal &Val,
230 CheckerContext &C, ExplodedNode *ErrNode) const;
Adam Balogh21583b72018-09-10 09:03:22 +0000231 void reportMismatchedBug(const StringRef &Message, const SVal &Val1,
232 const SVal &Val2, CheckerContext &C,
233 ExplodedNode *ErrNode) const;
Adam Balogh3659f7a2018-09-10 09:05:31 +0000234 void reportMismatchedBug(const StringRef &Message, const SVal &Val,
235 const MemRegion *Reg, CheckerContext &C,
236 ExplodedNode *ErrNode) const;
Adam Balogh2cfbe932018-08-28 08:41:15 +0000237 void reportInvalidatedBug(const StringRef &Message, const SVal &Val,
238 CheckerContext &C, ExplodedNode *ErrNode) const;
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000239
240public:
241 IteratorChecker();
242
243 enum CheckKind {
244 CK_IteratorRangeChecker,
Adam Balogh21583b72018-09-10 09:03:22 +0000245 CK_MismatchedIteratorChecker,
Adam Balogh2cfbe932018-08-28 08:41:15 +0000246 CK_InvalidatedIteratorChecker,
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000247 CK_NumCheckKinds
248 };
249
250 DefaultBool ChecksEnabled[CK_NumCheckKinds];
251 CheckName CheckNames[CK_NumCheckKinds];
252
253 void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
254 void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
Adam Balogh2e7cb342018-09-10 09:07:47 +0000255 void checkBind(SVal Loc, SVal Val, const Stmt *S, CheckerContext &C) const;
256 void checkPostStmt(const CXXConstructExpr *CCE, CheckerContext &C) const;
257 void checkPostStmt(const DeclStmt *DS, CheckerContext &C) const;
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000258 void checkPostStmt(const MaterializeTemporaryExpr *MTE,
259 CheckerContext &C) const;
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000260 void checkLiveSymbols(ProgramStateRef State, SymbolReaper &SR) const;
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000261 void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000262};
263} // namespace
264
265REGISTER_MAP_WITH_PROGRAMSTATE(IteratorSymbolMap, SymbolRef, IteratorPosition)
266REGISTER_MAP_WITH_PROGRAMSTATE(IteratorRegionMap, const MemRegion *,
267 IteratorPosition)
268
269REGISTER_MAP_WITH_PROGRAMSTATE(ContainerMap, const MemRegion *, ContainerData)
270
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000271namespace {
272
273bool isIteratorType(const QualType &Type);
274bool isIterator(const CXXRecordDecl *CRD);
Adam Balogh3659f7a2018-09-10 09:05:31 +0000275bool isComparisonOperator(OverloadedOperatorKind OK);
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000276bool isBeginCall(const FunctionDecl *Func);
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000277bool isEndCall(const FunctionDecl *Func);
Adam Balogh2e7cb342018-09-10 09:07:47 +0000278bool isAssignCall(const FunctionDecl *Func);
279bool isClearCall(const FunctionDecl *Func);
Adam Balogh9a48ba62018-09-10 09:06:31 +0000280bool isPushBackCall(const FunctionDecl *Func);
281bool isEmplaceBackCall(const FunctionDecl *Func);
282bool isPopBackCall(const FunctionDecl *Func);
283bool isPushFrontCall(const FunctionDecl *Func);
284bool isEmplaceFrontCall(const FunctionDecl *Func);
285bool isPopFrontCall(const FunctionDecl *Func);
Adam Balogh2e7cb342018-09-10 09:07:47 +0000286bool isInsertCall(const FunctionDecl *Func);
287bool isEraseCall(const FunctionDecl *Func);
288bool isEraseAfterCall(const FunctionDecl *Func);
289bool isEmplaceCall(const FunctionDecl *Func);
Adam Balogh2cfbe932018-08-28 08:41:15 +0000290bool isAssignmentOperator(OverloadedOperatorKind OK);
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000291bool isSimpleComparisonOperator(OverloadedOperatorKind OK);
Adam Balogh2cfbe932018-08-28 08:41:15 +0000292bool isAccessOperator(OverloadedOperatorKind OK);
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000293bool isDereferenceOperator(OverloadedOperatorKind OK);
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000294bool isIncrementOperator(OverloadedOperatorKind OK);
295bool isDecrementOperator(OverloadedOperatorKind OK);
296bool isRandomIncrOrDecrOperator(OverloadedOperatorKind OK);
Adam Balogh9a48ba62018-09-10 09:06:31 +0000297bool hasSubscriptOperator(ProgramStateRef State, const MemRegion *Reg);
298bool frontModifiable(ProgramStateRef State, const MemRegion *Reg);
299bool backModifiable(ProgramStateRef State, const MemRegion *Reg);
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000300SymbolRef getContainerBegin(ProgramStateRef State, const MemRegion *Cont);
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000301SymbolRef getContainerEnd(ProgramStateRef State, const MemRegion *Cont);
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000302ProgramStateRef createContainerBegin(ProgramStateRef State,
Adam Balogh33160c42019-05-20 11:04:27 +0000303 const MemRegion *Cont, const Expr *E,
304 QualType T, const LocationContext *LCtx,
305 unsigned BlockCount);
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000306ProgramStateRef createContainerEnd(ProgramStateRef State, const MemRegion *Cont,
Adam Balogh33160c42019-05-20 11:04:27 +0000307 const Expr *E, QualType T,
308 const LocationContext *LCtx,
309 unsigned BlockCount);
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000310const IteratorPosition *getIteratorPosition(ProgramStateRef State,
311 const SVal &Val);
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000312ProgramStateRef setIteratorPosition(ProgramStateRef State, const SVal &Val,
313 const IteratorPosition &Pos);
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000314ProgramStateRef removeIteratorPosition(ProgramStateRef State, const SVal &Val);
Adam Balogh54976e72019-04-23 07:15:55 +0000315ProgramStateRef assumeNoOverflow(ProgramStateRef State, SymbolRef Sym,
316 long Scale);
Adam Balogh2cfbe932018-08-28 08:41:15 +0000317ProgramStateRef invalidateAllIteratorPositions(ProgramStateRef State,
318 const MemRegion *Cont);
Adam Balogh2e7cb342018-09-10 09:07:47 +0000319ProgramStateRef
320invalidateAllIteratorPositionsExcept(ProgramStateRef State,
321 const MemRegion *Cont, SymbolRef Offset,
322 BinaryOperator::Opcode Opc);
Adam Balogh9a48ba62018-09-10 09:06:31 +0000323ProgramStateRef invalidateIteratorPositions(ProgramStateRef State,
324 SymbolRef Offset,
325 BinaryOperator::Opcode Opc);
Adam Balogh2e7cb342018-09-10 09:07:47 +0000326ProgramStateRef invalidateIteratorPositions(ProgramStateRef State,
327 SymbolRef Offset1,
328 BinaryOperator::Opcode Opc1,
329 SymbolRef Offset2,
330 BinaryOperator::Opcode Opc2);
Adam Balogh6b23b1a2018-09-10 09:04:27 +0000331ProgramStateRef reassignAllIteratorPositions(ProgramStateRef State,
332 const MemRegion *Cont,
333 const MemRegion *NewCont);
334ProgramStateRef reassignAllIteratorPositionsUnless(ProgramStateRef State,
335 const MemRegion *Cont,
336 const MemRegion *NewCont,
337 SymbolRef Offset,
338 BinaryOperator::Opcode Opc);
339ProgramStateRef rebaseSymbolInIteratorPositionsIf(
340 ProgramStateRef State, SValBuilder &SVB, SymbolRef OldSym,
341 SymbolRef NewSym, SymbolRef CondSym, BinaryOperator::Opcode Opc);
Adam Balogh54976e72019-04-23 07:15:55 +0000342ProgramStateRef relateSymbols(ProgramStateRef State, SymbolRef Sym1,
343 SymbolRef Sym2, bool Equal);
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000344const ContainerData *getContainerData(ProgramStateRef State,
345 const MemRegion *Cont);
346ProgramStateRef setContainerData(ProgramStateRef State, const MemRegion *Cont,
347 const ContainerData &CData);
Adam Balogha6921202018-07-30 08:52:21 +0000348bool hasLiveIterators(ProgramStateRef State, const MemRegion *Cont);
Adam Balogh21583b72018-09-10 09:03:22 +0000349bool isBoundThroughLazyCompoundVal(const Environment &Env,
350 const MemRegion *Reg);
Adam Baloghd5bd3f62018-12-04 10:27:27 +0000351bool isPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos);
352bool isAheadOfRange(ProgramStateRef State, const IteratorPosition &Pos);
353bool isBehindPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos);
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000354bool isZero(ProgramStateRef State, const NonLoc &Val);
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000355} // namespace
356
357IteratorChecker::IteratorChecker() {
358 OutOfRangeBugType.reset(
Adam Balogh12f5c7f2019-08-29 09:35:47 +0000359 new BugType(this, "Iterator out of range", "Misuse of STL APIs"));
Adam Balogh21583b72018-09-10 09:03:22 +0000360 MismatchedBugType.reset(
George Karpenkov2c2d0b62019-01-18 19:24:55 +0000361 new BugType(this, "Iterator(s) mismatched", "Misuse of STL APIs",
362 /*SuppressOnSink=*/true));
Adam Balogh2cfbe932018-08-28 08:41:15 +0000363 InvalidatedBugType.reset(
Adam Balogh12f5c7f2019-08-29 09:35:47 +0000364 new BugType(this, "Iterator invalidated", "Misuse of STL APIs"));
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000365}
366
367void IteratorChecker::checkPreCall(const CallEvent &Call,
368 CheckerContext &C) const {
Adam Balogh2cfbe932018-08-28 08:41:15 +0000369 // Check for out of range access or access of invalidated position and
370 // iterator mismatches
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000371 const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
372 if (!Func)
373 return;
374
375 if (Func->isOverloadedOperator()) {
Adam Balogh2cfbe932018-08-28 08:41:15 +0000376 if (ChecksEnabled[CK_InvalidatedIteratorChecker] &&
377 isAccessOperator(Func->getOverloadedOperator())) {
378 // Check for any kind of access of invalidated iterator positions
379 if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
380 verifyAccess(C, InstCall->getCXXThisVal());
381 } else {
382 verifyAccess(C, Call.getArgSVal(0));
383 }
384 }
Adam Baloghd5bd3f62018-12-04 10:27:27 +0000385 if (ChecksEnabled[CK_IteratorRangeChecker]) {
386 if (isIncrementOperator(Func->getOverloadedOperator())) {
387 // Check for out-of-range incrementions
388 if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
389 verifyIncrement(C, InstCall->getCXXThisVal());
390 } else {
391 if (Call.getNumArgs() >= 1) {
392 verifyIncrement(C, Call.getArgSVal(0));
393 }
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000394 }
Adam Baloghd5bd3f62018-12-04 10:27:27 +0000395 } else if (isDecrementOperator(Func->getOverloadedOperator())) {
396 // Check for out-of-range decrementions
397 if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
398 verifyDecrement(C, InstCall->getCXXThisVal());
399 } else {
400 if (Call.getNumArgs() >= 1) {
401 verifyDecrement(C, Call.getArgSVal(0));
402 }
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000403 }
Adam Baloghd5bd3f62018-12-04 10:27:27 +0000404 } else if (isRandomIncrOrDecrOperator(Func->getOverloadedOperator())) {
405 if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
406 // Check for out-of-range incrementions and decrementions
Adam Balogh8557f172019-08-05 06:45:41 +0000407 if (Call.getNumArgs() >= 1 &&
408 Call.getArgExpr(0)->getType()->isIntegralOrEnumerationType()) {
Adam Baloghd5bd3f62018-12-04 10:27:27 +0000409 verifyRandomIncrOrDecr(C, Func->getOverloadedOperator(),
410 InstCall->getCXXThisVal(),
411 Call.getArgSVal(0));
412 }
413 } else {
Adam Balogh8557f172019-08-05 06:45:41 +0000414 if (Call.getNumArgs() >= 2 &&
415 Call.getArgExpr(1)->getType()->isIntegralOrEnumerationType()) {
Adam Baloghd5bd3f62018-12-04 10:27:27 +0000416 verifyRandomIncrOrDecr(C, Func->getOverloadedOperator(),
417 Call.getArgSVal(0), Call.getArgSVal(1));
418 }
419 }
420 } else if (isDereferenceOperator(Func->getOverloadedOperator())) {
421 // Check for dereference of out-of-range iterators
422 if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
423 verifyDereference(C, InstCall->getCXXThisVal());
424 } else {
425 verifyDereference(C, Call.getArgSVal(0));
426 }
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000427 }
Adam Balogh3659f7a2018-09-10 09:05:31 +0000428 } else if (ChecksEnabled[CK_MismatchedIteratorChecker] &&
429 isComparisonOperator(Func->getOverloadedOperator())) {
430 // Check for comparisons of iterators of different containers
431 if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
432 if (Call.getNumArgs() < 1)
433 return;
434
435 if (!isIteratorType(InstCall->getCXXThisExpr()->getType()) ||
436 !isIteratorType(Call.getArgExpr(0)->getType()))
437 return;
438
439 verifyMatch(C, InstCall->getCXXThisVal(), Call.getArgSVal(0));
440 } else {
441 if (Call.getNumArgs() < 2)
442 return;
443
444 if (!isIteratorType(Call.getArgExpr(0)->getType()) ||
445 !isIteratorType(Call.getArgExpr(1)->getType()))
446 return;
447
448 verifyMatch(C, Call.getArgSVal(0), Call.getArgSVal(1));
449 }
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000450 }
Adam Balogh2e7cb342018-09-10 09:07:47 +0000451 } else if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
452 if (!ChecksEnabled[CK_MismatchedIteratorChecker])
453 return;
454
455 const auto *ContReg = InstCall->getCXXThisVal().getAsRegion();
456 if (!ContReg)
457 return;
458 // Check for erase, insert and emplace using iterator of another container
459 if (isEraseCall(Func) || isEraseAfterCall(Func)) {
460 verifyMatch(C, Call.getArgSVal(0),
461 InstCall->getCXXThisVal().getAsRegion());
462 if (Call.getNumArgs() == 2) {
463 verifyMatch(C, Call.getArgSVal(1),
464 InstCall->getCXXThisVal().getAsRegion());
465 }
466 } else if (isInsertCall(Func)) {
467 verifyMatch(C, Call.getArgSVal(0),
468 InstCall->getCXXThisVal().getAsRegion());
469 if (Call.getNumArgs() == 3 &&
470 isIteratorType(Call.getArgExpr(1)->getType()) &&
471 isIteratorType(Call.getArgExpr(2)->getType())) {
472 verifyMatch(C, Call.getArgSVal(1), Call.getArgSVal(2));
473 }
474 } else if (isEmplaceCall(Func)) {
475 verifyMatch(C, Call.getArgSVal(0),
476 InstCall->getCXXThisVal().getAsRegion());
477 }
Adam Balogh3659f7a2018-09-10 09:05:31 +0000478 } else if (isa<CXXConstructorCall>(&Call)) {
479 // Check match of first-last iterator pair in a constructor of a container
480 if (Call.getNumArgs() < 2)
481 return;
482
483 const auto *Ctr = cast<CXXConstructorDecl>(Call.getDecl());
484 if (Ctr->getNumParams() < 2)
485 return;
486
487 if (Ctr->getParamDecl(0)->getName() != "first" ||
488 Ctr->getParamDecl(1)->getName() != "last")
489 return;
490
491 if (!isIteratorType(Call.getArgExpr(0)->getType()) ||
492 !isIteratorType(Call.getArgExpr(1)->getType()))
493 return;
494
495 verifyMatch(C, Call.getArgSVal(0), Call.getArgSVal(1));
496 } else {
Adam Balogh21583b72018-09-10 09:03:22 +0000497 // The main purpose of iterators is to abstract away from different
498 // containers and provide a (maybe limited) uniform access to them.
499 // This implies that any correctly written template function that
500 // works on multiple containers using iterators takes different
501 // template parameters for different containers. So we can safely
502 // assume that passing iterators of different containers as arguments
503 // whose type replaces the same template parameter is a bug.
504 //
505 // Example:
506 // template<typename I1, typename I2>
507 // void f(I1 first1, I1 last1, I2 first2, I2 last2);
508 //
509 // In this case the first two arguments to f() must be iterators must belong
510 // to the same container and the last to also to the same container but
Raphael Isemannb23ccec2018-12-10 12:37:46 +0000511 // not necessarily to the same as the first two.
Adam Balogh21583b72018-09-10 09:03:22 +0000512
513 if (!ChecksEnabled[CK_MismatchedIteratorChecker])
514 return;
515
516 const auto *Templ = Func->getPrimaryTemplate();
517 if (!Templ)
518 return;
519
520 const auto *TParams = Templ->getTemplateParameters();
521 const auto *TArgs = Func->getTemplateSpecializationArgs();
522
523 // Iterate over all the template parameters
524 for (size_t I = 0; I < TParams->size(); ++I) {
525 const auto *TPDecl = dyn_cast<TemplateTypeParmDecl>(TParams->getParam(I));
526 if (!TPDecl)
527 continue;
528
529 if (TPDecl->isParameterPack())
530 continue;
531
532 const auto TAType = TArgs->get(I).getAsType();
533 if (!isIteratorType(TAType))
534 continue;
535
536 SVal LHS = UndefinedVal();
537
538 // For every template parameter which is an iterator type in the
539 // instantiation look for all functions' parameters' type by it and
540 // check whether they belong to the same container
541 for (auto J = 0U; J < Func->getNumParams(); ++J) {
542 const auto *Param = Func->getParamDecl(J);
543 const auto *ParamType =
544 Param->getType()->getAs<SubstTemplateTypeParmType>();
545 if (!ParamType ||
546 ParamType->getReplacedParameter()->getDecl() != TPDecl)
547 continue;
548 if (LHS.isUndef()) {
549 LHS = Call.getArgSVal(J);
550 } else {
551 verifyMatch(C, LHS, Call.getArgSVal(J));
552 }
553 }
554 }
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000555 }
556}
557
558void IteratorChecker::checkPostCall(const CallEvent &Call,
559 CheckerContext &C) const {
560 // Record new iterator positions and iterator position changes
561 const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
562 if (!Func)
563 return;
564
565 if (Func->isOverloadedOperator()) {
566 const auto Op = Func->getOverloadedOperator();
Adam Balogh2cfbe932018-08-28 08:41:15 +0000567 if (isAssignmentOperator(Op)) {
Artem Dergachev630f7da2019-08-28 18:44:38 +0000568 // Overloaded 'operator=' must be a non-static member function.
569 const auto *InstCall = cast<CXXInstanceCall>(&Call);
Adam Baloghd538b702019-04-26 07:30:07 +0000570 if (cast<CXXMethodDecl>(Func)->isMoveAssignmentOperator()) {
Adam Balogh6b23b1a2018-09-10 09:04:27 +0000571 handleAssign(C, InstCall->getCXXThisVal(), Call.getOriginExpr(),
572 Call.getArgSVal(0));
Adam Baloghd538b702019-04-26 07:30:07 +0000573 return;
Adam Balogh6b23b1a2018-09-10 09:04:27 +0000574 }
Adam Baloghd538b702019-04-26 07:30:07 +0000575
576 handleAssign(C, InstCall->getCXXThisVal());
577 return;
Adam Balogh2cfbe932018-08-28 08:41:15 +0000578 } else if (isSimpleComparisonOperator(Op)) {
Adam Balogh54976e72019-04-23 07:15:55 +0000579 const auto *OrigExpr = Call.getOriginExpr();
580 if (!OrigExpr)
581 return;
582
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000583 if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
Adam Balogh54976e72019-04-23 07:15:55 +0000584 handleComparison(C, OrigExpr, Call.getReturnValue(),
585 InstCall->getCXXThisVal(), Call.getArgSVal(0), Op);
Adam Baloghd538b702019-04-26 07:30:07 +0000586 return;
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000587 }
Adam Baloghd538b702019-04-26 07:30:07 +0000588
589 handleComparison(C, OrigExpr, Call.getReturnValue(), Call.getArgSVal(0),
590 Call.getArgSVal(1), Op);
591 return;
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000592 } else if (isRandomIncrOrDecrOperator(Func->getOverloadedOperator())) {
593 if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
Adam Balogh8557f172019-08-05 06:45:41 +0000594 if (Call.getNumArgs() >= 1 &&
595 Call.getArgExpr(0)->getType()->isIntegralOrEnumerationType()) {
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000596 handleRandomIncrOrDecr(C, Func->getOverloadedOperator(),
597 Call.getReturnValue(),
598 InstCall->getCXXThisVal(), Call.getArgSVal(0));
Adam Baloghd538b702019-04-26 07:30:07 +0000599 return;
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000600 }
601 } else {
Adam Balogh8557f172019-08-05 06:45:41 +0000602 if (Call.getNumArgs() >= 2 &&
603 Call.getArgExpr(1)->getType()->isIntegralOrEnumerationType()) {
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000604 handleRandomIncrOrDecr(C, Func->getOverloadedOperator(),
605 Call.getReturnValue(), Call.getArgSVal(0),
606 Call.getArgSVal(1));
Adam Baloghd538b702019-04-26 07:30:07 +0000607 return;
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000608 }
609 }
610 } else if (isIncrementOperator(Func->getOverloadedOperator())) {
611 if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
612 handleIncrement(C, Call.getReturnValue(), InstCall->getCXXThisVal(),
613 Call.getNumArgs());
Adam Baloghd538b702019-04-26 07:30:07 +0000614 return;
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000615 }
Adam Baloghd538b702019-04-26 07:30:07 +0000616
617 handleIncrement(C, Call.getReturnValue(), Call.getArgSVal(0),
618 Call.getNumArgs());
619 return;
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000620 } else if (isDecrementOperator(Func->getOverloadedOperator())) {
621 if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
622 handleDecrement(C, Call.getReturnValue(), InstCall->getCXXThisVal(),
623 Call.getNumArgs());
Adam Baloghd538b702019-04-26 07:30:07 +0000624 return;
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000625 }
Adam Baloghd538b702019-04-26 07:30:07 +0000626
627 handleDecrement(C, Call.getReturnValue(), Call.getArgSVal(0),
628 Call.getNumArgs());
629 return;
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000630 }
631 } else {
Adam Balogh9a48ba62018-09-10 09:06:31 +0000632 if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
Adam Balogh2e7cb342018-09-10 09:07:47 +0000633 if (isAssignCall(Func)) {
634 handleAssign(C, InstCall->getCXXThisVal());
Adam Baloghd538b702019-04-26 07:30:07 +0000635 return;
636 }
637
638 if (isClearCall(Func)) {
Adam Balogh2e7cb342018-09-10 09:07:47 +0000639 handleClear(C, InstCall->getCXXThisVal());
Adam Baloghd538b702019-04-26 07:30:07 +0000640 return;
641 }
642
643 if (isPushBackCall(Func) || isEmplaceBackCall(Func)) {
Adam Balogh9a48ba62018-09-10 09:06:31 +0000644 handlePushBack(C, InstCall->getCXXThisVal());
Adam Baloghd538b702019-04-26 07:30:07 +0000645 return;
646 }
647
648 if (isPopBackCall(Func)) {
Adam Balogh9a48ba62018-09-10 09:06:31 +0000649 handlePopBack(C, InstCall->getCXXThisVal());
Adam Baloghd538b702019-04-26 07:30:07 +0000650 return;
651 }
652
653 if (isPushFrontCall(Func) || isEmplaceFrontCall(Func)) {
Adam Balogh9a48ba62018-09-10 09:06:31 +0000654 handlePushFront(C, InstCall->getCXXThisVal());
Adam Baloghd538b702019-04-26 07:30:07 +0000655 return;
656 }
657
658 if (isPopFrontCall(Func)) {
Adam Balogh9a48ba62018-09-10 09:06:31 +0000659 handlePopFront(C, InstCall->getCXXThisVal());
Adam Baloghd538b702019-04-26 07:30:07 +0000660 return;
661 }
662
663 if (isInsertCall(Func) || isEmplaceCall(Func)) {
Adam Balogh2e7cb342018-09-10 09:07:47 +0000664 handleInsert(C, Call.getArgSVal(0));
Adam Baloghd538b702019-04-26 07:30:07 +0000665 return;
666 }
667
668 if (isEraseCall(Func)) {
Adam Balogh2e7cb342018-09-10 09:07:47 +0000669 if (Call.getNumArgs() == 1) {
670 handleErase(C, Call.getArgSVal(0));
Adam Baloghd538b702019-04-26 07:30:07 +0000671 return;
Adam Balogh2e7cb342018-09-10 09:07:47 +0000672 }
Adam Baloghd538b702019-04-26 07:30:07 +0000673
674 if (Call.getNumArgs() == 2) {
675 handleErase(C, Call.getArgSVal(0), Call.getArgSVal(1));
676 return;
677 }
678 }
679
680 if (isEraseAfterCall(Func)) {
Adam Balogh2e7cb342018-09-10 09:07:47 +0000681 if (Call.getNumArgs() == 1) {
682 handleEraseAfter(C, Call.getArgSVal(0));
Adam Baloghd538b702019-04-26 07:30:07 +0000683 return;
684 }
685
686 if (Call.getNumArgs() == 2) {
Adam Balogh2e7cb342018-09-10 09:07:47 +0000687 handleEraseAfter(C, Call.getArgSVal(0), Call.getArgSVal(1));
Adam Baloghd538b702019-04-26 07:30:07 +0000688 return;
Adam Balogh2e7cb342018-09-10 09:07:47 +0000689 }
Adam Balogh9a48ba62018-09-10 09:06:31 +0000690 }
691 }
692
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000693 const auto *OrigExpr = Call.getOriginExpr();
694 if (!OrigExpr)
695 return;
696
697 if (!isIteratorType(Call.getResultType()))
698 return;
699
700 auto State = C.getState();
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000701
702 if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000703 if (isBeginCall(Func)) {
704 handleBegin(C, OrigExpr, Call.getReturnValue(),
705 InstCall->getCXXThisVal());
706 return;
707 }
Adam Baloghd538b702019-04-26 07:30:07 +0000708
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000709 if (isEndCall(Func)) {
710 handleEnd(C, OrigExpr, Call.getReturnValue(),
711 InstCall->getCXXThisVal());
712 return;
713 }
714 }
715
Adam Balogh6b23b1a2018-09-10 09:04:27 +0000716 // Already bound to container?
717 if (getIteratorPosition(State, Call.getReturnValue()))
718 return;
719
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000720 // Copy-like and move constructors
721 if (isa<CXXConstructorCall>(&Call) && Call.getNumArgs() == 1) {
722 if (const auto *Pos = getIteratorPosition(State, Call.getArgSVal(0))) {
723 State = setIteratorPosition(State, Call.getReturnValue(), *Pos);
724 if (cast<CXXConstructorDecl>(Func)->isMoveConstructor()) {
725 State = removeIteratorPosition(State, Call.getArgSVal(0));
726 }
727 C.addTransition(State);
728 return;
729 }
730 }
731
732 // Assumption: if return value is an iterator which is not yet bound to a
733 // container, then look for the first iterator argument, and
734 // bind the return value to the same container. This approach
735 // works for STL algorithms.
736 // FIXME: Add a more conservative mode
737 for (unsigned i = 0; i < Call.getNumArgs(); ++i) {
738 if (isIteratorType(Call.getArgExpr(i)->getType())) {
739 if (const auto *Pos = getIteratorPosition(State, Call.getArgSVal(i))) {
740 assignToContainer(C, OrigExpr, Call.getReturnValue(),
741 Pos->getContainer());
742 return;
743 }
744 }
745 }
746 }
747}
748
Adam Balogh2e7cb342018-09-10 09:07:47 +0000749void IteratorChecker::checkBind(SVal Loc, SVal Val, const Stmt *S,
750 CheckerContext &C) const {
751 auto State = C.getState();
752 const auto *Pos = getIteratorPosition(State, Val);
753 if (Pos) {
754 State = setIteratorPosition(State, Loc, *Pos);
755 C.addTransition(State);
756 } else {
757 const auto *OldPos = getIteratorPosition(State, Loc);
758 if (OldPos) {
759 State = removeIteratorPosition(State, Loc);
760 C.addTransition(State);
761 }
762 }
763}
764
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000765void IteratorChecker::checkPostStmt(const MaterializeTemporaryExpr *MTE,
766 CheckerContext &C) const {
767 /* Transfer iterator state to temporary objects */
768 auto State = C.getState();
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000769 const auto *Pos =
George Karpenkovd703ec92018-01-17 20:27:29 +0000770 getIteratorPosition(State, C.getSVal(MTE->GetTemporaryExpr()));
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000771 if (!Pos)
772 return;
George Karpenkovd703ec92018-01-17 20:27:29 +0000773 State = setIteratorPosition(State, C.getSVal(MTE), *Pos);
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000774 C.addTransition(State);
775}
776
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000777void IteratorChecker::checkLiveSymbols(ProgramStateRef State,
778 SymbolReaper &SR) const {
779 // Keep symbolic expressions of iterator positions, container begins and ends
780 // alive
781 auto RegionMap = State->get<IteratorRegionMap>();
782 for (const auto Reg : RegionMap) {
Adam Balogh0a7592b2018-07-16 09:27:27 +0000783 const auto Offset = Reg.second.getOffset();
784 for (auto i = Offset->symbol_begin(); i != Offset->symbol_end(); ++i)
785 if (isa<SymbolData>(*i))
786 SR.markLive(*i);
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000787 }
788
789 auto SymbolMap = State->get<IteratorSymbolMap>();
790 for (const auto Sym : SymbolMap) {
Adam Balogh0a7592b2018-07-16 09:27:27 +0000791 const auto Offset = Sym.second.getOffset();
792 for (auto i = Offset->symbol_begin(); i != Offset->symbol_end(); ++i)
793 if (isa<SymbolData>(*i))
794 SR.markLive(*i);
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000795 }
796
797 auto ContMap = State->get<ContainerMap>();
798 for (const auto Cont : ContMap) {
799 const auto CData = Cont.second;
800 if (CData.getBegin()) {
801 SR.markLive(CData.getBegin());
Adam Balogh9a48ba62018-09-10 09:06:31 +0000802 if(const auto *SIE = dyn_cast<SymIntExpr>(CData.getBegin()))
803 SR.markLive(SIE->getLHS());
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000804 }
805 if (CData.getEnd()) {
806 SR.markLive(CData.getEnd());
Adam Balogh9a48ba62018-09-10 09:06:31 +0000807 if(const auto *SIE = dyn_cast<SymIntExpr>(CData.getEnd()))
808 SR.markLive(SIE->getLHS());
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000809 }
810 }
811}
812
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000813void IteratorChecker::checkDeadSymbols(SymbolReaper &SR,
814 CheckerContext &C) const {
815 // Cleanup
816 auto State = C.getState();
817
818 auto RegionMap = State->get<IteratorRegionMap>();
819 for (const auto Reg : RegionMap) {
820 if (!SR.isLiveRegion(Reg.first)) {
Adam Balogh21583b72018-09-10 09:03:22 +0000821 // The region behind the `LazyCompoundVal` is often cleaned up before
822 // the `LazyCompoundVal` itself. If there are iterator positions keyed
823 // by these regions their cleanup must be deferred.
824 if (!isBoundThroughLazyCompoundVal(State->getEnvironment(), Reg.first)) {
825 State = State->remove<IteratorRegionMap>(Reg.first);
826 }
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000827 }
828 }
829
830 auto SymbolMap = State->get<IteratorSymbolMap>();
831 for (const auto Sym : SymbolMap) {
832 if (!SR.isLive(Sym.first)) {
833 State = State->remove<IteratorSymbolMap>(Sym.first);
834 }
835 }
836
837 auto ContMap = State->get<ContainerMap>();
838 for (const auto Cont : ContMap) {
839 if (!SR.isLiveRegion(Cont.first)) {
Adam Balogha6921202018-07-30 08:52:21 +0000840 // We must keep the container data while it has live iterators to be able
841 // to compare them to the begin and the end of the container.
842 if (!hasLiveIterators(State, Cont.first)) {
843 State = State->remove<ContainerMap>(Cont.first);
844 }
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000845 }
846 }
847
Reka Kovacse48ea892018-07-30 16:14:59 +0000848 C.addTransition(State);
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000849}
850
Adam Balogh54976e72019-04-23 07:15:55 +0000851void IteratorChecker::handleComparison(CheckerContext &C, const Expr *CE,
852 const SVal &RetVal, const SVal &LVal,
853 const SVal &RVal,
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000854 OverloadedOperatorKind Op) const {
855 // Record the operands and the operator of the comparison for the next
856 // evalAssume, if the result is a symbolic expression. If it is a concrete
857 // value (only one branch is possible), then transfer the state between
858 // the operands according to the operator and the result
Adam Balogh54976e72019-04-23 07:15:55 +0000859 auto State = C.getState();
860 const auto *LPos = getIteratorPosition(State, LVal);
861 const auto *RPos = getIteratorPosition(State, RVal);
862 const MemRegion *Cont = nullptr;
863 if (LPos) {
864 Cont = LPos->getContainer();
865 } else if (RPos) {
866 Cont = RPos->getContainer();
867 }
868 if (!Cont)
869 return;
870
871 // At least one of the iterators have recorded positions. If one of them has
872 // not then create a new symbol for the offset.
873 SymbolRef Sym;
874 if (!LPos || !RPos) {
875 auto &SymMgr = C.getSymbolManager();
Adam Baloghd2e2e202019-04-23 11:18:50 +0000876 Sym = SymMgr.conjureSymbol(CE, C.getLocationContext(),
Adam Balogh54976e72019-04-23 07:15:55 +0000877 C.getASTContext().LongTy, C.blockCount());
878 State = assumeNoOverflow(State, Sym, 4);
879 }
880
881 if (!LPos) {
882 State = setIteratorPosition(State, LVal,
883 IteratorPosition::getPosition(Cont, Sym));
884 LPos = getIteratorPosition(State, LVal);
885 } else if (!RPos) {
886 State = setIteratorPosition(State, RVal,
887 IteratorPosition::getPosition(Cont, Sym));
888 RPos = getIteratorPosition(State, RVal);
889 }
890
891 processComparison(C, State, LPos->getOffset(), RPos->getOffset(), RetVal, Op);
892}
893
894void IteratorChecker::processComparison(CheckerContext &C,
895 ProgramStateRef State, SymbolRef Sym1,
896 SymbolRef Sym2, const SVal &RetVal,
897 OverloadedOperatorKind Op) const {
898 if (const auto TruthVal = RetVal.getAs<nonloc::ConcreteInt>()) {
Adam Balogh8f882702019-04-23 07:45:10 +0000899 if ((State = relateSymbols(State, Sym1, Sym2,
Adam Balogh54976e72019-04-23 07:15:55 +0000900 (Op == OO_EqualEqual) ==
Adam Balogh8f882702019-04-23 07:45:10 +0000901 (TruthVal->getValue() != 0)))) {
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000902 C.addTransition(State);
903 } else {
904 C.generateSink(State, C.getPredecessor());
905 }
Adam Balogh54976e72019-04-23 07:15:55 +0000906 return;
907 }
908
909 const auto ConditionVal = RetVal.getAs<DefinedSVal>();
910 if (!ConditionVal)
911 return;
912
913 if (auto StateTrue = relateSymbols(State, Sym1, Sym2, Op == OO_EqualEqual)) {
914 StateTrue = StateTrue->assume(*ConditionVal, true);
915 C.addTransition(StateTrue);
916 }
917
918 if (auto StateFalse = relateSymbols(State, Sym1, Sym2, Op != OO_EqualEqual)) {
919 StateFalse = StateFalse->assume(*ConditionVal, false);
920 C.addTransition(StateFalse);
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000921 }
922}
923
924void IteratorChecker::verifyDereference(CheckerContext &C,
925 const SVal &Val) const {
926 auto State = C.getState();
927 const auto *Pos = getIteratorPosition(State, Val);
Adam Baloghd5bd3f62018-12-04 10:27:27 +0000928 if (Pos && isPastTheEnd(State, *Pos)) {
Adam Balogh12f5c7f2019-08-29 09:35:47 +0000929 auto *N = C.generateErrorNode(State);
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000930 if (!N)
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000931 return;
Adam Baloghd5bd3f62018-12-04 10:27:27 +0000932 reportOutOfRangeBug("Past-the-end iterator dereferenced.", Val, C, N);
933 return;
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000934 }
935}
936
Adam Balogh2cfbe932018-08-28 08:41:15 +0000937void IteratorChecker::verifyAccess(CheckerContext &C, const SVal &Val) const {
938 auto State = C.getState();
939 const auto *Pos = getIteratorPosition(State, Val);
940 if (Pos && !Pos->isValid()) {
Adam Balogh12f5c7f2019-08-29 09:35:47 +0000941 auto *N = C.generateErrorNode(State);
Adam Balogh2cfbe932018-08-28 08:41:15 +0000942 if (!N) {
943 return;
944 }
945 reportInvalidatedBug("Invalidated iterator accessed.", Val, C, N);
946 }
947}
948
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000949void IteratorChecker::handleIncrement(CheckerContext &C, const SVal &RetVal,
950 const SVal &Iter, bool Postfix) const {
951 // Increment the symbolic expressions which represents the position of the
952 // iterator
953 auto State = C.getState();
954 const auto *Pos = getIteratorPosition(State, Iter);
955 if (Pos) {
956 auto &SymMgr = C.getSymbolManager();
957 auto &BVF = SymMgr.getBasicVals();
Adam Baloghd5bd3f62018-12-04 10:27:27 +0000958 const auto NewPos =
959 advancePosition(C, OO_Plus, *Pos,
960 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000961 State = setIteratorPosition(State, Iter, NewPos);
962 State = setIteratorPosition(State, RetVal, Postfix ? *Pos : NewPos);
963 C.addTransition(State);
964 }
965}
966
967void IteratorChecker::handleDecrement(CheckerContext &C, const SVal &RetVal,
968 const SVal &Iter, bool Postfix) const {
969 // Decrement the symbolic expressions which represents the position of the
970 // iterator
971 auto State = C.getState();
972 const auto *Pos = getIteratorPosition(State, Iter);
973 if (Pos) {
974 auto &SymMgr = C.getSymbolManager();
975 auto &BVF = SymMgr.getBasicVals();
Adam Baloghd5bd3f62018-12-04 10:27:27 +0000976 const auto NewPos =
977 advancePosition(C, OO_Minus, *Pos,
978 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000979 State = setIteratorPosition(State, Iter, NewPos);
980 State = setIteratorPosition(State, RetVal, Postfix ? *Pos : NewPos);
981 C.addTransition(State);
982 }
983}
984
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000985void IteratorChecker::handleRandomIncrOrDecr(CheckerContext &C,
986 OverloadedOperatorKind Op,
987 const SVal &RetVal,
988 const SVal &LHS,
989 const SVal &RHS) const {
990 // Increment or decrement the symbolic expressions which represents the
991 // position of the iterator
992 auto State = C.getState();
993 const auto *Pos = getIteratorPosition(State, LHS);
994 if (!Pos)
995 return;
996
997 const auto *value = &RHS;
998 if (auto loc = RHS.getAs<Loc>()) {
999 const auto val = State->getRawSVal(*loc);
1000 value = &val;
1001 }
1002
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001003 auto &TgtVal = (Op == OO_PlusEqual || Op == OO_MinusEqual) ? LHS : RetVal;
Adam Baloghd5bd3f62018-12-04 10:27:27 +00001004 State =
1005 setIteratorPosition(State, TgtVal, advancePosition(C, Op, *Pos, *value));
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001006 C.addTransition(State);
1007}
1008
Adam Baloghd5bd3f62018-12-04 10:27:27 +00001009void IteratorChecker::verifyIncrement(CheckerContext &C,
1010 const SVal &Iter) const {
1011 auto &BVF = C.getSValBuilder().getBasicValueFactory();
1012 verifyRandomIncrOrDecr(C, OO_Plus, Iter,
1013 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
1014}
1015
1016void IteratorChecker::verifyDecrement(CheckerContext &C,
1017 const SVal &Iter) const {
1018 auto &BVF = C.getSValBuilder().getBasicValueFactory();
1019 verifyRandomIncrOrDecr(C, OO_Minus, Iter,
1020 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
1021}
1022
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001023void IteratorChecker::verifyRandomIncrOrDecr(CheckerContext &C,
1024 OverloadedOperatorKind Op,
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001025 const SVal &LHS,
1026 const SVal &RHS) const {
1027 auto State = C.getState();
1028
1029 // If the iterator is initially inside its range, then the operation is valid
1030 const auto *Pos = getIteratorPosition(State, LHS);
Adam Baloghd5bd3f62018-12-04 10:27:27 +00001031 if (!Pos)
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001032 return;
1033
Adam Baloghd5bd3f62018-12-04 10:27:27 +00001034 auto Value = RHS;
1035 if (auto ValAsLoc = RHS.getAs<Loc>()) {
1036 Value = State->getRawSVal(*ValAsLoc);
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001037 }
1038
Adam Baloghd5bd3f62018-12-04 10:27:27 +00001039 if (Value.isUnknown())
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001040 return;
1041
Adam Baloghd5bd3f62018-12-04 10:27:27 +00001042 // Incremention or decremention by 0 is never a bug.
1043 if (isZero(State, Value.castAs<NonLoc>()))
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001044 return;
1045
Adam Baloghd5bd3f62018-12-04 10:27:27 +00001046 // The result may be the past-end iterator of the container, but any other
1047 // out of range position is undefined behaviour
1048 if (isAheadOfRange(State, advancePosition(C, Op, *Pos, Value))) {
Adam Balogh12f5c7f2019-08-29 09:35:47 +00001049 auto *N = C.generateErrorNode(State);
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001050 if (!N)
1051 return;
Adam Baloghd5bd3f62018-12-04 10:27:27 +00001052 reportOutOfRangeBug("Iterator decremented ahead of its valid range.", LHS,
1053 C, N);
1054 }
1055 if (isBehindPastTheEnd(State, advancePosition(C, Op, *Pos, Value))) {
Adam Balogh12f5c7f2019-08-29 09:35:47 +00001056 auto *N = C.generateErrorNode(State);
Adam Baloghd5bd3f62018-12-04 10:27:27 +00001057 if (!N)
1058 return;
1059 reportOutOfRangeBug("Iterator incremented behind the past-the-end "
1060 "iterator.", LHS, C, N);
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001061 }
1062}
1063
Adam Balogh2e7cb342018-09-10 09:07:47 +00001064void IteratorChecker::verifyMatch(CheckerContext &C, const SVal &Iter,
1065 const MemRegion *Cont) const {
1066 // Verify match between a container and the container of an iterator
Adam Balogh42d241f2018-12-04 10:22:28 +00001067 Cont = Cont->getMostDerivedObjectRegion();
Adam Balogh2e7cb342018-09-10 09:07:47 +00001068
Adam Baloghd7033052019-03-13 13:55:11 +00001069 if (const auto *ContSym = Cont->getSymbolicBase()) {
1070 if (isa<SymbolConjured>(ContSym->getSymbol()))
1071 return;
1072 }
1073
Adam Balogh2e7cb342018-09-10 09:07:47 +00001074 auto State = C.getState();
1075 const auto *Pos = getIteratorPosition(State, Iter);
Adam Baloghd7033052019-03-13 13:55:11 +00001076 if (!Pos)
1077 return;
1078
1079 const auto *IterCont = Pos->getContainer();
1080
1081 // Skip symbolic regions based on conjured symbols. Two conjured symbols
1082 // may or may not be the same. For example, the same function can return
1083 // the same or a different container but we get different conjured symbols
1084 // for each call. This may cause false positives so omit them from the check.
1085 if (const auto *ContSym = IterCont->getSymbolicBase()) {
1086 if (isa<SymbolConjured>(ContSym->getSymbol()))
1087 return;
1088 }
1089
1090 if (IterCont != Cont) {
Adam Balogh2e7cb342018-09-10 09:07:47 +00001091 auto *N = C.generateNonFatalErrorNode(State);
1092 if (!N) {
1093 return;
1094 }
Adam Baloghd7033052019-03-13 13:55:11 +00001095 reportMismatchedBug("Container accessed using foreign iterator argument.",
1096 Iter, Cont, C, N);
Adam Balogh2e7cb342018-09-10 09:07:47 +00001097 }
1098}
1099
Adam Balogh21583b72018-09-10 09:03:22 +00001100void IteratorChecker::verifyMatch(CheckerContext &C, const SVal &Iter1,
1101 const SVal &Iter2) const {
1102 // Verify match between the containers of two iterators
1103 auto State = C.getState();
1104 const auto *Pos1 = getIteratorPosition(State, Iter1);
Adam Baloghd7033052019-03-13 13:55:11 +00001105 if (!Pos1)
1106 return;
1107
1108 const auto *IterCont1 = Pos1->getContainer();
1109
1110 // Skip symbolic regions based on conjured symbols. Two conjured symbols
1111 // may or may not be the same. For example, the same function can return
1112 // the same or a different container but we get different conjured symbols
1113 // for each call. This may cause false positives so omit them from the check.
1114 if (const auto *ContSym = IterCont1->getSymbolicBase()) {
1115 if (isa<SymbolConjured>(ContSym->getSymbol()))
1116 return;
1117 }
1118
Adam Balogh21583b72018-09-10 09:03:22 +00001119 const auto *Pos2 = getIteratorPosition(State, Iter2);
Adam Baloghd7033052019-03-13 13:55:11 +00001120 if (!Pos2)
1121 return;
1122
1123 const auto *IterCont2 = Pos2->getContainer();
1124 if (const auto *ContSym = IterCont2->getSymbolicBase()) {
1125 if (isa<SymbolConjured>(ContSym->getSymbol()))
1126 return;
1127 }
1128
1129 if (IterCont1 != IterCont2) {
Adam Balogh21583b72018-09-10 09:03:22 +00001130 auto *N = C.generateNonFatalErrorNode(State);
1131 if (!N)
1132 return;
1133 reportMismatchedBug("Iterators of different containers used where the "
1134 "same container is expected.", Iter1, Iter2, C, N);
1135 }
1136}
1137
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001138void IteratorChecker::handleBegin(CheckerContext &C, const Expr *CE,
1139 const SVal &RetVal, const SVal &Cont) const {
1140 const auto *ContReg = Cont.getAsRegion();
1141 if (!ContReg)
1142 return;
1143
Adam Balogh42d241f2018-12-04 10:22:28 +00001144 ContReg = ContReg->getMostDerivedObjectRegion();
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001145
1146 // If the container already has a begin symbol then use it. Otherwise first
1147 // create a new one.
1148 auto State = C.getState();
1149 auto BeginSym = getContainerBegin(State, ContReg);
1150 if (!BeginSym) {
Adam Balogh33160c42019-05-20 11:04:27 +00001151 State = createContainerBegin(State, ContReg, CE, C.getASTContext().LongTy,
1152 C.getLocationContext(), C.blockCount());
1153 BeginSym = getContainerBegin(State, ContReg);
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001154 }
1155 State = setIteratorPosition(State, RetVal,
1156 IteratorPosition::getPosition(ContReg, BeginSym));
1157 C.addTransition(State);
1158}
1159
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001160void IteratorChecker::handleEnd(CheckerContext &C, const Expr *CE,
1161 const SVal &RetVal, const SVal &Cont) const {
1162 const auto *ContReg = Cont.getAsRegion();
1163 if (!ContReg)
1164 return;
1165
Adam Balogh42d241f2018-12-04 10:22:28 +00001166 ContReg = ContReg->getMostDerivedObjectRegion();
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001167
1168 // If the container already has an end symbol then use it. Otherwise first
1169 // create a new one.
1170 auto State = C.getState();
1171 auto EndSym = getContainerEnd(State, ContReg);
1172 if (!EndSym) {
Adam Balogh33160c42019-05-20 11:04:27 +00001173 State = createContainerEnd(State, ContReg, CE, C.getASTContext().LongTy,
1174 C.getLocationContext(), C.blockCount());
1175 EndSym = getContainerEnd(State, ContReg);
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001176 }
1177 State = setIteratorPosition(State, RetVal,
1178 IteratorPosition::getPosition(ContReg, EndSym));
1179 C.addTransition(State);
1180}
1181
1182void IteratorChecker::assignToContainer(CheckerContext &C, const Expr *CE,
1183 const SVal &RetVal,
1184 const MemRegion *Cont) const {
Adam Balogh42d241f2018-12-04 10:22:28 +00001185 Cont = Cont->getMostDerivedObjectRegion();
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001186
1187 auto State = C.getState();
1188 auto &SymMgr = C.getSymbolManager();
1189 auto Sym = SymMgr.conjureSymbol(CE, C.getLocationContext(),
1190 C.getASTContext().LongTy, C.blockCount());
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001191 State = assumeNoOverflow(State, Sym, 4);
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001192 State = setIteratorPosition(State, RetVal,
1193 IteratorPosition::getPosition(Cont, Sym));
1194 C.addTransition(State);
1195}
1196
Adam Balogh6b23b1a2018-09-10 09:04:27 +00001197void IteratorChecker::handleAssign(CheckerContext &C, const SVal &Cont,
1198 const Expr *CE, const SVal &OldCont) const {
Adam Balogh2cfbe932018-08-28 08:41:15 +00001199 const auto *ContReg = Cont.getAsRegion();
1200 if (!ContReg)
1201 return;
1202
Adam Balogh42d241f2018-12-04 10:22:28 +00001203 ContReg = ContReg->getMostDerivedObjectRegion();
Adam Balogh2cfbe932018-08-28 08:41:15 +00001204
1205 // Assignment of a new value to a container always invalidates all its
1206 // iterators
1207 auto State = C.getState();
1208 const auto CData = getContainerData(State, ContReg);
1209 if (CData) {
1210 State = invalidateAllIteratorPositions(State, ContReg);
1211 }
1212
Adam Balogh6b23b1a2018-09-10 09:04:27 +00001213 // In case of move, iterators of the old container (except the past-end
1214 // iterators) remain valid but refer to the new container
1215 if (!OldCont.isUndef()) {
1216 const auto *OldContReg = OldCont.getAsRegion();
1217 if (OldContReg) {
Adam Balogh42d241f2018-12-04 10:22:28 +00001218 OldContReg = OldContReg->getMostDerivedObjectRegion();
Adam Balogh6b23b1a2018-09-10 09:04:27 +00001219 const auto OldCData = getContainerData(State, OldContReg);
1220 if (OldCData) {
1221 if (const auto OldEndSym = OldCData->getEnd()) {
Raphael Isemannb23ccec2018-12-10 12:37:46 +00001222 // If we already assigned an "end" symbol to the old container, then
Adam Balogh6b23b1a2018-09-10 09:04:27 +00001223 // first reassign all iterator positions to the new container which
1224 // are not past the container (thus not greater or equal to the
1225 // current "end" symbol).
1226 State = reassignAllIteratorPositionsUnless(State, OldContReg, ContReg,
1227 OldEndSym, BO_GE);
1228 auto &SymMgr = C.getSymbolManager();
1229 auto &SVB = C.getSValBuilder();
1230 // Then generate and assign a new "end" symbol for the new container.
1231 auto NewEndSym =
1232 SymMgr.conjureSymbol(CE, C.getLocationContext(),
1233 C.getASTContext().LongTy, C.blockCount());
1234 State = assumeNoOverflow(State, NewEndSym, 4);
1235 if (CData) {
1236 State = setContainerData(State, ContReg, CData->newEnd(NewEndSym));
1237 } else {
1238 State = setContainerData(State, ContReg,
1239 ContainerData::fromEnd(NewEndSym));
1240 }
1241 // Finally, replace the old "end" symbol in the already reassigned
1242 // iterator positions with the new "end" symbol.
1243 State = rebaseSymbolInIteratorPositionsIf(
1244 State, SVB, OldEndSym, NewEndSym, OldEndSym, BO_LT);
1245 } else {
1246 // There was no "end" symbol assigned yet to the old container,
1247 // so reassign all iterator positions to the new container.
1248 State = reassignAllIteratorPositions(State, OldContReg, ContReg);
1249 }
1250 if (const auto OldBeginSym = OldCData->getBegin()) {
1251 // If we already assigned a "begin" symbol to the old container, then
1252 // assign it to the new container and remove it from the old one.
1253 if (CData) {
1254 State =
1255 setContainerData(State, ContReg, CData->newBegin(OldBeginSym));
1256 } else {
1257 State = setContainerData(State, ContReg,
1258 ContainerData::fromBegin(OldBeginSym));
1259 }
1260 State =
1261 setContainerData(State, OldContReg, OldCData->newEnd(nullptr));
1262 }
1263 } else {
1264 // There was neither "begin" nor "end" symbol assigned yet to the old
1265 // container, so reassign all iterator positions to the new container.
1266 State = reassignAllIteratorPositions(State, OldContReg, ContReg);
1267 }
1268 }
1269 }
Adam Balogh2cfbe932018-08-28 08:41:15 +00001270 C.addTransition(State);
1271}
1272
Adam Balogh2e7cb342018-09-10 09:07:47 +00001273void IteratorChecker::handleClear(CheckerContext &C, const SVal &Cont) const {
1274 const auto *ContReg = Cont.getAsRegion();
1275 if (!ContReg)
1276 return;
1277
Adam Balogh42d241f2018-12-04 10:22:28 +00001278 ContReg = ContReg->getMostDerivedObjectRegion();
Adam Balogh2e7cb342018-09-10 09:07:47 +00001279
1280 // The clear() operation invalidates all the iterators, except the past-end
1281 // iterators of list-like containers
1282 auto State = C.getState();
1283 if (!hasSubscriptOperator(State, ContReg) ||
1284 !backModifiable(State, ContReg)) {
1285 const auto CData = getContainerData(State, ContReg);
1286 if (CData) {
1287 if (const auto EndSym = CData->getEnd()) {
1288 State =
1289 invalidateAllIteratorPositionsExcept(State, ContReg, EndSym, BO_GE);
1290 C.addTransition(State);
1291 return;
1292 }
1293 }
1294 }
1295 State = invalidateAllIteratorPositions(State, ContReg);
1296 C.addTransition(State);
1297}
1298
Adam Balogh9a48ba62018-09-10 09:06:31 +00001299void IteratorChecker::handlePushBack(CheckerContext &C,
1300 const SVal &Cont) const {
1301 const auto *ContReg = Cont.getAsRegion();
1302 if (!ContReg)
1303 return;
1304
Adam Balogh42d241f2018-12-04 10:22:28 +00001305 ContReg = ContReg->getMostDerivedObjectRegion();
Adam Balogh9a48ba62018-09-10 09:06:31 +00001306
1307 // For deque-like containers invalidate all iterator positions
1308 auto State = C.getState();
1309 if (hasSubscriptOperator(State, ContReg) && frontModifiable(State, ContReg)) {
1310 State = invalidateAllIteratorPositions(State, ContReg);
1311 C.addTransition(State);
1312 return;
1313 }
1314
1315 const auto CData = getContainerData(State, ContReg);
1316 if (!CData)
1317 return;
1318
1319 // For vector-like containers invalidate the past-end iterator positions
1320 if (const auto EndSym = CData->getEnd()) {
1321 if (hasSubscriptOperator(State, ContReg)) {
1322 State = invalidateIteratorPositions(State, EndSym, BO_GE);
1323 }
1324 auto &SymMgr = C.getSymbolManager();
1325 auto &BVF = SymMgr.getBasicVals();
1326 auto &SVB = C.getSValBuilder();
1327 const auto newEndSym =
1328 SVB.evalBinOp(State, BO_Add,
1329 nonloc::SymbolVal(EndSym),
1330 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
1331 SymMgr.getType(EndSym)).getAsSymbol();
1332 State = setContainerData(State, ContReg, CData->newEnd(newEndSym));
1333 }
1334 C.addTransition(State);
1335}
1336
1337void IteratorChecker::handlePopBack(CheckerContext &C, const SVal &Cont) const {
1338 const auto *ContReg = Cont.getAsRegion();
1339 if (!ContReg)
1340 return;
1341
Adam Balogh42d241f2018-12-04 10:22:28 +00001342 ContReg = ContReg->getMostDerivedObjectRegion();
Adam Balogh9a48ba62018-09-10 09:06:31 +00001343
1344 auto State = C.getState();
1345 const auto CData = getContainerData(State, ContReg);
1346 if (!CData)
1347 return;
1348
1349 if (const auto EndSym = CData->getEnd()) {
1350 auto &SymMgr = C.getSymbolManager();
1351 auto &BVF = SymMgr.getBasicVals();
1352 auto &SVB = C.getSValBuilder();
1353 const auto BackSym =
1354 SVB.evalBinOp(State, BO_Sub,
1355 nonloc::SymbolVal(EndSym),
1356 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
1357 SymMgr.getType(EndSym)).getAsSymbol();
1358 // For vector-like and deque-like containers invalidate the last and the
1359 // past-end iterator positions. For list-like containers only invalidate
1360 // the last position
1361 if (hasSubscriptOperator(State, ContReg) &&
1362 backModifiable(State, ContReg)) {
1363 State = invalidateIteratorPositions(State, BackSym, BO_GE);
1364 State = setContainerData(State, ContReg, CData->newEnd(nullptr));
1365 } else {
1366 State = invalidateIteratorPositions(State, BackSym, BO_EQ);
1367 }
1368 auto newEndSym = BackSym;
1369 State = setContainerData(State, ContReg, CData->newEnd(newEndSym));
1370 C.addTransition(State);
1371 }
1372}
1373
1374void IteratorChecker::handlePushFront(CheckerContext &C,
1375 const SVal &Cont) const {
1376 const auto *ContReg = Cont.getAsRegion();
1377 if (!ContReg)
1378 return;
1379
Adam Balogh42d241f2018-12-04 10:22:28 +00001380 ContReg = ContReg->getMostDerivedObjectRegion();
Adam Balogh9a48ba62018-09-10 09:06:31 +00001381
1382 // For deque-like containers invalidate all iterator positions
1383 auto State = C.getState();
1384 if (hasSubscriptOperator(State, ContReg)) {
1385 State = invalidateAllIteratorPositions(State, ContReg);
1386 C.addTransition(State);
1387 } else {
1388 const auto CData = getContainerData(State, ContReg);
1389 if (!CData)
1390 return;
1391
1392 if (const auto BeginSym = CData->getBegin()) {
1393 auto &SymMgr = C.getSymbolManager();
1394 auto &BVF = SymMgr.getBasicVals();
1395 auto &SVB = C.getSValBuilder();
1396 const auto newBeginSym =
1397 SVB.evalBinOp(State, BO_Sub,
1398 nonloc::SymbolVal(BeginSym),
1399 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
1400 SymMgr.getType(BeginSym)).getAsSymbol();
1401 State = setContainerData(State, ContReg, CData->newBegin(newBeginSym));
1402 C.addTransition(State);
1403 }
1404 }
1405}
1406
1407void IteratorChecker::handlePopFront(CheckerContext &C,
1408 const SVal &Cont) const {
1409 const auto *ContReg = Cont.getAsRegion();
1410 if (!ContReg)
1411 return;
1412
Adam Balogh42d241f2018-12-04 10:22:28 +00001413 ContReg = ContReg->getMostDerivedObjectRegion();
Adam Balogh9a48ba62018-09-10 09:06:31 +00001414
1415 auto State = C.getState();
1416 const auto CData = getContainerData(State, ContReg);
1417 if (!CData)
1418 return;
1419
1420 // For deque-like containers invalidate all iterator positions. For list-like
1421 // iterators only invalidate the first position
1422 if (const auto BeginSym = CData->getBegin()) {
1423 if (hasSubscriptOperator(State, ContReg)) {
1424 State = invalidateIteratorPositions(State, BeginSym, BO_LE);
1425 } else {
1426 State = invalidateIteratorPositions(State, BeginSym, BO_EQ);
1427 }
1428 auto &SymMgr = C.getSymbolManager();
1429 auto &BVF = SymMgr.getBasicVals();
1430 auto &SVB = C.getSValBuilder();
1431 const auto newBeginSym =
1432 SVB.evalBinOp(State, BO_Add,
1433 nonloc::SymbolVal(BeginSym),
1434 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
1435 SymMgr.getType(BeginSym)).getAsSymbol();
1436 State = setContainerData(State, ContReg, CData->newBegin(newBeginSym));
1437 C.addTransition(State);
1438 }
1439}
1440
Adam Balogh2e7cb342018-09-10 09:07:47 +00001441void IteratorChecker::handleInsert(CheckerContext &C, const SVal &Iter) const {
1442 auto State = C.getState();
1443 const auto *Pos = getIteratorPosition(State, Iter);
1444 if (!Pos)
1445 return;
1446
1447 // For deque-like containers invalidate all iterator positions. For
1448 // vector-like containers invalidate iterator positions after the insertion.
1449 const auto *Cont = Pos->getContainer();
1450 if (hasSubscriptOperator(State, Cont) && backModifiable(State, Cont)) {
1451 if (frontModifiable(State, Cont)) {
1452 State = invalidateAllIteratorPositions(State, Cont);
1453 } else {
1454 State = invalidateIteratorPositions(State, Pos->getOffset(), BO_GE);
1455 }
1456 if (const auto *CData = getContainerData(State, Cont)) {
1457 if (const auto EndSym = CData->getEnd()) {
1458 State = invalidateIteratorPositions(State, EndSym, BO_GE);
1459 State = setContainerData(State, Cont, CData->newEnd(nullptr));
1460 }
1461 }
1462 C.addTransition(State);
1463 }
1464}
1465
1466void IteratorChecker::handleErase(CheckerContext &C, const SVal &Iter) const {
1467 auto State = C.getState();
1468 const auto *Pos = getIteratorPosition(State, Iter);
1469 if (!Pos)
1470 return;
1471
1472 // For deque-like containers invalidate all iterator positions. For
1473 // vector-like containers invalidate iterator positions at and after the
1474 // deletion. For list-like containers only invalidate the deleted position.
1475 const auto *Cont = Pos->getContainer();
1476 if (hasSubscriptOperator(State, Cont) && backModifiable(State, Cont)) {
1477 if (frontModifiable(State, Cont)) {
1478 State = invalidateAllIteratorPositions(State, Cont);
1479 } else {
1480 State = invalidateIteratorPositions(State, Pos->getOffset(), BO_GE);
1481 }
1482 if (const auto *CData = getContainerData(State, Cont)) {
1483 if (const auto EndSym = CData->getEnd()) {
1484 State = invalidateIteratorPositions(State, EndSym, BO_GE);
1485 State = setContainerData(State, Cont, CData->newEnd(nullptr));
1486 }
1487 }
1488 } else {
1489 State = invalidateIteratorPositions(State, Pos->getOffset(), BO_EQ);
1490 }
1491 C.addTransition(State);
1492}
1493
1494void IteratorChecker::handleErase(CheckerContext &C, const SVal &Iter1,
1495 const SVal &Iter2) const {
1496 auto State = C.getState();
1497 const auto *Pos1 = getIteratorPosition(State, Iter1);
1498 const auto *Pos2 = getIteratorPosition(State, Iter2);
1499 if (!Pos1 || !Pos2)
1500 return;
1501
1502 // For deque-like containers invalidate all iterator positions. For
1503 // vector-like containers invalidate iterator positions at and after the
1504 // deletion range. For list-like containers only invalidate the deleted
1505 // position range [first..last].
1506 const auto *Cont = Pos1->getContainer();
1507 if (hasSubscriptOperator(State, Cont) && backModifiable(State, Cont)) {
1508 if (frontModifiable(State, Cont)) {
1509 State = invalidateAllIteratorPositions(State, Cont);
1510 } else {
1511 State = invalidateIteratorPositions(State, Pos1->getOffset(), BO_GE);
1512 }
1513 if (const auto *CData = getContainerData(State, Cont)) {
1514 if (const auto EndSym = CData->getEnd()) {
1515 State = invalidateIteratorPositions(State, EndSym, BO_GE);
1516 State = setContainerData(State, Cont, CData->newEnd(nullptr));
1517 }
1518 }
1519 } else {
1520 State = invalidateIteratorPositions(State, Pos1->getOffset(), BO_GE,
1521 Pos2->getOffset(), BO_LT);
1522 }
1523 C.addTransition(State);
1524}
1525
1526void IteratorChecker::handleEraseAfter(CheckerContext &C,
1527 const SVal &Iter) const {
1528 auto State = C.getState();
1529 const auto *Pos = getIteratorPosition(State, Iter);
1530 if (!Pos)
1531 return;
1532
1533 // Invalidate the deleted iterator position, which is the position of the
1534 // parameter plus one.
1535 auto &SymMgr = C.getSymbolManager();
1536 auto &BVF = SymMgr.getBasicVals();
1537 auto &SVB = C.getSValBuilder();
1538 const auto NextSym =
1539 SVB.evalBinOp(State, BO_Add,
1540 nonloc::SymbolVal(Pos->getOffset()),
1541 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
1542 SymMgr.getType(Pos->getOffset())).getAsSymbol();
1543 State = invalidateIteratorPositions(State, NextSym, BO_EQ);
1544 C.addTransition(State);
1545}
1546
1547void IteratorChecker::handleEraseAfter(CheckerContext &C, const SVal &Iter1,
1548 const SVal &Iter2) const {
1549 auto State = C.getState();
1550 const auto *Pos1 = getIteratorPosition(State, Iter1);
1551 const auto *Pos2 = getIteratorPosition(State, Iter2);
1552 if (!Pos1 || !Pos2)
1553 return;
1554
1555 // Invalidate the deleted iterator position range (first..last)
1556 State = invalidateIteratorPositions(State, Pos1->getOffset(), BO_GT,
1557 Pos2->getOffset(), BO_LT);
1558 C.addTransition(State);
1559}
1560
Adam Baloghd5bd3f62018-12-04 10:27:27 +00001561IteratorPosition IteratorChecker::advancePosition(CheckerContext &C,
1562 OverloadedOperatorKind Op,
1563 const IteratorPosition &Pos,
1564 const SVal &Distance) const {
1565 auto State = C.getState();
1566 auto &SymMgr = C.getSymbolManager();
1567 auto &SVB = C.getSValBuilder();
1568
1569 assert ((Op == OO_Plus || Op == OO_PlusEqual ||
1570 Op == OO_Minus || Op == OO_MinusEqual) &&
1571 "Advance operator must be one of +, -, += and -=.");
1572 auto BinOp = (Op == OO_Plus || Op == OO_PlusEqual) ? BO_Add : BO_Sub;
1573 if (const auto IntDist = Distance.getAs<nonloc::ConcreteInt>()) {
1574 // For concrete integers we can calculate the new position
1575 return Pos.setTo(SVB.evalBinOp(State, BinOp,
1576 nonloc::SymbolVal(Pos.getOffset()), *IntDist,
1577 SymMgr.getType(Pos.getOffset()))
1578 .getAsSymbol());
1579 } else {
1580 // For other symbols create a new symbol to keep expressions simple
1581 const auto &LCtx = C.getLocationContext();
1582 const auto NewPosSym = SymMgr.conjureSymbol(nullptr, LCtx,
1583 SymMgr.getType(Pos.getOffset()),
1584 C.blockCount());
1585 State = assumeNoOverflow(State, NewPosSym, 4);
1586 return Pos.setTo(NewPosSym);
1587 }
1588}
1589
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001590void IteratorChecker::reportOutOfRangeBug(const StringRef &Message,
1591 const SVal &Val, CheckerContext &C,
1592 ExplodedNode *ErrNode) const {
Jonas Devlieghere2b3d49b2019-08-14 23:04:18 +00001593 auto R = std::make_unique<BugReport>(*OutOfRangeBugType, Message, ErrNode);
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001594 R->markInteresting(Val);
1595 C.emitReport(std::move(R));
1596}
1597
Adam Balogh21583b72018-09-10 09:03:22 +00001598void IteratorChecker::reportMismatchedBug(const StringRef &Message,
1599 const SVal &Val1, const SVal &Val2,
1600 CheckerContext &C,
1601 ExplodedNode *ErrNode) const {
Jonas Devlieghere2b3d49b2019-08-14 23:04:18 +00001602 auto R = std::make_unique<BugReport>(*MismatchedBugType, Message, ErrNode);
Adam Balogh21583b72018-09-10 09:03:22 +00001603 R->markInteresting(Val1);
1604 R->markInteresting(Val2);
1605 C.emitReport(std::move(R));
1606}
1607
Adam Balogh3659f7a2018-09-10 09:05:31 +00001608void IteratorChecker::reportMismatchedBug(const StringRef &Message,
1609 const SVal &Val, const MemRegion *Reg,
1610 CheckerContext &C,
1611 ExplodedNode *ErrNode) const {
Jonas Devlieghere2b3d49b2019-08-14 23:04:18 +00001612 auto R = std::make_unique<BugReport>(*MismatchedBugType, Message, ErrNode);
Adam Balogh3659f7a2018-09-10 09:05:31 +00001613 R->markInteresting(Val);
1614 R->markInteresting(Reg);
1615 C.emitReport(std::move(R));
1616}
1617
Adam Balogh2cfbe932018-08-28 08:41:15 +00001618void IteratorChecker::reportInvalidatedBug(const StringRef &Message,
1619 const SVal &Val, CheckerContext &C,
1620 ExplodedNode *ErrNode) const {
Jonas Devlieghere2b3d49b2019-08-14 23:04:18 +00001621 auto R = std::make_unique<BugReport>(*InvalidatedBugType, Message, ErrNode);
Adam Balogh2cfbe932018-08-28 08:41:15 +00001622 R->markInteresting(Val);
1623 C.emitReport(std::move(R));
1624}
1625
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001626namespace {
1627
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001628bool isLess(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2);
Adam Baloghd5bd3f62018-12-04 10:27:27 +00001629bool isGreater(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2);
1630bool isEqual(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2);
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001631bool compare(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2,
1632 BinaryOperator::Opcode Opc);
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001633bool compare(ProgramStateRef State, NonLoc NL1, NonLoc NL2,
1634 BinaryOperator::Opcode Opc);
Adam Balogh9a48ba62018-09-10 09:06:31 +00001635const CXXRecordDecl *getCXXRecordDecl(ProgramStateRef State,
1636 const MemRegion *Reg);
Adam Balogh6b23b1a2018-09-10 09:04:27 +00001637SymbolRef rebaseSymbol(ProgramStateRef State, SValBuilder &SVB, SymbolRef Expr,
1638 SymbolRef OldSym, SymbolRef NewSym);
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001639
1640bool isIteratorType(const QualType &Type) {
1641 if (Type->isPointerType())
1642 return true;
1643
1644 const auto *CRD = Type->getUnqualifiedDesugaredType()->getAsCXXRecordDecl();
1645 return isIterator(CRD);
1646}
1647
1648bool isIterator(const CXXRecordDecl *CRD) {
1649 if (!CRD)
1650 return false;
1651
1652 const auto Name = CRD->getName();
1653 if (!(Name.endswith_lower("iterator") || Name.endswith_lower("iter") ||
1654 Name.endswith_lower("it")))
1655 return false;
1656
1657 bool HasCopyCtor = false, HasCopyAssign = true, HasDtor = false,
1658 HasPreIncrOp = false, HasPostIncrOp = false, HasDerefOp = false;
1659 for (const auto *Method : CRD->methods()) {
1660 if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(Method)) {
1661 if (Ctor->isCopyConstructor()) {
1662 HasCopyCtor = !Ctor->isDeleted() && Ctor->getAccess() == AS_public;
1663 }
1664 continue;
1665 }
1666 if (const auto *Dtor = dyn_cast<CXXDestructorDecl>(Method)) {
1667 HasDtor = !Dtor->isDeleted() && Dtor->getAccess() == AS_public;
1668 continue;
1669 }
1670 if (Method->isCopyAssignmentOperator()) {
1671 HasCopyAssign = !Method->isDeleted() && Method->getAccess() == AS_public;
1672 continue;
1673 }
1674 if (!Method->isOverloadedOperator())
1675 continue;
1676 const auto OPK = Method->getOverloadedOperator();
1677 if (OPK == OO_PlusPlus) {
1678 HasPreIncrOp = HasPreIncrOp || (Method->getNumParams() == 0);
1679 HasPostIncrOp = HasPostIncrOp || (Method->getNumParams() == 1);
1680 continue;
1681 }
1682 if (OPK == OO_Star) {
1683 HasDerefOp = (Method->getNumParams() == 0);
1684 continue;
1685 }
1686 }
1687
1688 return HasCopyCtor && HasCopyAssign && HasDtor && HasPreIncrOp &&
1689 HasPostIncrOp && HasDerefOp;
1690}
1691
Adam Balogh3659f7a2018-09-10 09:05:31 +00001692bool isComparisonOperator(OverloadedOperatorKind OK) {
1693 return OK == OO_EqualEqual || OK == OO_ExclaimEqual || OK == OO_Less ||
1694 OK == OO_LessEqual || OK == OO_Greater || OK == OO_GreaterEqual;
1695}
1696
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001697bool isBeginCall(const FunctionDecl *Func) {
1698 const auto *IdInfo = Func->getIdentifier();
1699 if (!IdInfo)
1700 return false;
1701 return IdInfo->getName().endswith_lower("begin");
1702}
1703
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001704bool isEndCall(const FunctionDecl *Func) {
1705 const auto *IdInfo = Func->getIdentifier();
1706 if (!IdInfo)
1707 return false;
1708 return IdInfo->getName().endswith_lower("end");
1709}
1710
Adam Balogh2e7cb342018-09-10 09:07:47 +00001711bool isAssignCall(const FunctionDecl *Func) {
1712 const auto *IdInfo = Func->getIdentifier();
1713 if (!IdInfo)
1714 return false;
1715 if (Func->getNumParams() > 2)
1716 return false;
1717 return IdInfo->getName() == "assign";
1718}
1719
1720bool isClearCall(const FunctionDecl *Func) {
1721 const auto *IdInfo = Func->getIdentifier();
1722 if (!IdInfo)
1723 return false;
1724 if (Func->getNumParams() > 0)
1725 return false;
1726 return IdInfo->getName() == "clear";
1727}
1728
Adam Balogh9a48ba62018-09-10 09:06:31 +00001729bool isPushBackCall(const FunctionDecl *Func) {
1730 const auto *IdInfo = Func->getIdentifier();
1731 if (!IdInfo)
1732 return false;
1733 if (Func->getNumParams() != 1)
1734 return false;
1735 return IdInfo->getName() == "push_back";
1736}
1737
1738bool isEmplaceBackCall(const FunctionDecl *Func) {
1739 const auto *IdInfo = Func->getIdentifier();
1740 if (!IdInfo)
1741 return false;
1742 if (Func->getNumParams() < 1)
1743 return false;
1744 return IdInfo->getName() == "emplace_back";
1745}
1746
1747bool isPopBackCall(const FunctionDecl *Func) {
1748 const auto *IdInfo = Func->getIdentifier();
1749 if (!IdInfo)
1750 return false;
1751 if (Func->getNumParams() > 0)
1752 return false;
1753 return IdInfo->getName() == "pop_back";
1754}
1755
1756bool isPushFrontCall(const FunctionDecl *Func) {
1757 const auto *IdInfo = Func->getIdentifier();
1758 if (!IdInfo)
1759 return false;
1760 if (Func->getNumParams() != 1)
1761 return false;
1762 return IdInfo->getName() == "push_front";
1763}
1764
1765bool isEmplaceFrontCall(const FunctionDecl *Func) {
1766 const auto *IdInfo = Func->getIdentifier();
1767 if (!IdInfo)
1768 return false;
1769 if (Func->getNumParams() < 1)
1770 return false;
1771 return IdInfo->getName() == "emplace_front";
1772}
1773
1774bool isPopFrontCall(const FunctionDecl *Func) {
1775 const auto *IdInfo = Func->getIdentifier();
1776 if (!IdInfo)
1777 return false;
1778 if (Func->getNumParams() > 0)
1779 return false;
1780 return IdInfo->getName() == "pop_front";
1781}
1782
Adam Balogh2e7cb342018-09-10 09:07:47 +00001783bool isInsertCall(const FunctionDecl *Func) {
1784 const auto *IdInfo = Func->getIdentifier();
1785 if (!IdInfo)
1786 return false;
1787 if (Func->getNumParams() < 2 || Func->getNumParams() > 3)
1788 return false;
1789 if (!isIteratorType(Func->getParamDecl(0)->getType()))
1790 return false;
1791 return IdInfo->getName() == "insert";
1792}
1793
1794bool isEmplaceCall(const FunctionDecl *Func) {
1795 const auto *IdInfo = Func->getIdentifier();
1796 if (!IdInfo)
1797 return false;
1798 if (Func->getNumParams() < 2)
1799 return false;
1800 if (!isIteratorType(Func->getParamDecl(0)->getType()))
1801 return false;
1802 return IdInfo->getName() == "emplace";
1803}
1804
1805bool isEraseCall(const FunctionDecl *Func) {
1806 const auto *IdInfo = Func->getIdentifier();
1807 if (!IdInfo)
1808 return false;
1809 if (Func->getNumParams() < 1 || Func->getNumParams() > 2)
1810 return false;
1811 if (!isIteratorType(Func->getParamDecl(0)->getType()))
1812 return false;
1813 if (Func->getNumParams() == 2 &&
1814 !isIteratorType(Func->getParamDecl(1)->getType()))
1815 return false;
1816 return IdInfo->getName() == "erase";
1817}
1818
1819bool isEraseAfterCall(const FunctionDecl *Func) {
1820 const auto *IdInfo = Func->getIdentifier();
1821 if (!IdInfo)
1822 return false;
1823 if (Func->getNumParams() < 1 || Func->getNumParams() > 2)
1824 return false;
1825 if (!isIteratorType(Func->getParamDecl(0)->getType()))
1826 return false;
1827 if (Func->getNumParams() == 2 &&
1828 !isIteratorType(Func->getParamDecl(1)->getType()))
1829 return false;
1830 return IdInfo->getName() == "erase_after";
1831}
1832
Adam Balogh2cfbe932018-08-28 08:41:15 +00001833bool isAssignmentOperator(OverloadedOperatorKind OK) { return OK == OO_Equal; }
1834
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001835bool isSimpleComparisonOperator(OverloadedOperatorKind OK) {
1836 return OK == OO_EqualEqual || OK == OO_ExclaimEqual;
1837}
1838
Adam Balogh2cfbe932018-08-28 08:41:15 +00001839bool isAccessOperator(OverloadedOperatorKind OK) {
1840 return isDereferenceOperator(OK) || isIncrementOperator(OK) ||
1841 isDecrementOperator(OK) || isRandomIncrOrDecrOperator(OK);
1842}
1843
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001844bool isDereferenceOperator(OverloadedOperatorKind OK) {
1845 return OK == OO_Star || OK == OO_Arrow || OK == OO_ArrowStar ||
1846 OK == OO_Subscript;
1847}
1848
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001849bool isIncrementOperator(OverloadedOperatorKind OK) {
1850 return OK == OO_PlusPlus;
1851}
1852
1853bool isDecrementOperator(OverloadedOperatorKind OK) {
1854 return OK == OO_MinusMinus;
1855}
1856
1857bool isRandomIncrOrDecrOperator(OverloadedOperatorKind OK) {
1858 return OK == OO_Plus || OK == OO_PlusEqual || OK == OO_Minus ||
1859 OK == OO_MinusEqual;
1860}
1861
Adam Balogh9a48ba62018-09-10 09:06:31 +00001862bool hasSubscriptOperator(ProgramStateRef State, const MemRegion *Reg) {
1863 const auto *CRD = getCXXRecordDecl(State, Reg);
1864 if (!CRD)
1865 return false;
1866
1867 for (const auto *Method : CRD->methods()) {
1868 if (!Method->isOverloadedOperator())
1869 continue;
1870 const auto OPK = Method->getOverloadedOperator();
1871 if (OPK == OO_Subscript) {
1872 return true;
1873 }
1874 }
1875 return false;
1876}
1877
1878bool frontModifiable(ProgramStateRef State, const MemRegion *Reg) {
1879 const auto *CRD = getCXXRecordDecl(State, Reg);
1880 if (!CRD)
1881 return false;
1882
1883 for (const auto *Method : CRD->methods()) {
1884 if (!Method->getDeclName().isIdentifier())
1885 continue;
1886 if (Method->getName() == "push_front" || Method->getName() == "pop_front") {
1887 return true;
1888 }
1889 }
1890 return false;
1891}
1892
1893bool backModifiable(ProgramStateRef State, const MemRegion *Reg) {
1894 const auto *CRD = getCXXRecordDecl(State, Reg);
1895 if (!CRD)
1896 return false;
1897
1898 for (const auto *Method : CRD->methods()) {
1899 if (!Method->getDeclName().isIdentifier())
1900 continue;
1901 if (Method->getName() == "push_back" || Method->getName() == "pop_back") {
1902 return true;
1903 }
1904 }
1905 return false;
1906}
1907
1908const CXXRecordDecl *getCXXRecordDecl(ProgramStateRef State,
1909 const MemRegion *Reg) {
1910 auto TI = getDynamicTypeInfo(State, Reg);
1911 if (!TI.isValid())
1912 return nullptr;
1913
1914 auto Type = TI.getType();
1915 if (const auto *RefT = Type->getAs<ReferenceType>()) {
1916 Type = RefT->getPointeeType();
1917 }
1918
1919 return Type->getUnqualifiedDesugaredType()->getAsCXXRecordDecl();
1920}
1921
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001922SymbolRef getContainerBegin(ProgramStateRef State, const MemRegion *Cont) {
1923 const auto *CDataPtr = getContainerData(State, Cont);
1924 if (!CDataPtr)
1925 return nullptr;
1926
1927 return CDataPtr->getBegin();
1928}
1929
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001930SymbolRef getContainerEnd(ProgramStateRef State, const MemRegion *Cont) {
1931 const auto *CDataPtr = getContainerData(State, Cont);
1932 if (!CDataPtr)
1933 return nullptr;
1934
1935 return CDataPtr->getEnd();
1936}
1937
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001938ProgramStateRef createContainerBegin(ProgramStateRef State,
Adam Balogh33160c42019-05-20 11:04:27 +00001939 const MemRegion *Cont, const Expr *E,
1940 QualType T, const LocationContext *LCtx,
1941 unsigned BlockCount) {
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001942 // Only create if it does not exist
1943 const auto *CDataPtr = getContainerData(State, Cont);
Adam Balogh33160c42019-05-20 11:04:27 +00001944 if (CDataPtr && CDataPtr->getBegin())
1945 return State;
1946
1947 auto &SymMgr = State->getSymbolManager();
1948 const SymbolConjured *Sym = SymMgr.conjureSymbol(E, LCtx, T, BlockCount,
1949 "begin");
1950 State = assumeNoOverflow(State, Sym, 4);
1951
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001952 if (CDataPtr) {
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001953 const auto CData = CDataPtr->newBegin(Sym);
1954 return setContainerData(State, Cont, CData);
1955 }
Adam Balogh33160c42019-05-20 11:04:27 +00001956
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001957 const auto CData = ContainerData::fromBegin(Sym);
1958 return setContainerData(State, Cont, CData);
1959}
1960
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001961ProgramStateRef createContainerEnd(ProgramStateRef State, const MemRegion *Cont,
Adam Balogh33160c42019-05-20 11:04:27 +00001962 const Expr *E, QualType T,
1963 const LocationContext *LCtx,
1964 unsigned BlockCount) {
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001965 // Only create if it does not exist
1966 const auto *CDataPtr = getContainerData(State, Cont);
Adam Balogh33160c42019-05-20 11:04:27 +00001967 if (CDataPtr && CDataPtr->getEnd())
1968 return State;
1969
1970 auto &SymMgr = State->getSymbolManager();
1971 const SymbolConjured *Sym = SymMgr.conjureSymbol(E, LCtx, T, BlockCount,
1972 "end");
1973 State = assumeNoOverflow(State, Sym, 4);
1974
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001975 if (CDataPtr) {
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001976 const auto CData = CDataPtr->newEnd(Sym);
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001977 return setContainerData(State, Cont, CData);
1978 }
Adam Balogh33160c42019-05-20 11:04:27 +00001979
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001980 const auto CData = ContainerData::fromEnd(Sym);
1981 return setContainerData(State, Cont, CData);
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001982}
1983
1984const ContainerData *getContainerData(ProgramStateRef State,
1985 const MemRegion *Cont) {
1986 return State->get<ContainerMap>(Cont);
1987}
1988
1989ProgramStateRef setContainerData(ProgramStateRef State, const MemRegion *Cont,
1990 const ContainerData &CData) {
1991 return State->set<ContainerMap>(Cont, CData);
1992}
1993
1994const IteratorPosition *getIteratorPosition(ProgramStateRef State,
1995 const SVal &Val) {
Adam Balogh42d241f2018-12-04 10:22:28 +00001996 if (auto Reg = Val.getAsRegion()) {
1997 Reg = Reg->getMostDerivedObjectRegion();
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001998 return State->get<IteratorRegionMap>(Reg);
1999 } else if (const auto Sym = Val.getAsSymbol()) {
2000 return State->get<IteratorSymbolMap>(Sym);
2001 } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
2002 return State->get<IteratorRegionMap>(LCVal->getRegion());
2003 }
2004 return nullptr;
2005}
2006
Artem Dergachev8fa639e2017-05-29 15:03:20 +00002007ProgramStateRef setIteratorPosition(ProgramStateRef State, const SVal &Val,
2008 const IteratorPosition &Pos) {
Adam Balogh42d241f2018-12-04 10:22:28 +00002009 if (auto Reg = Val.getAsRegion()) {
2010 Reg = Reg->getMostDerivedObjectRegion();
Artem Dergachev8fa639e2017-05-29 15:03:20 +00002011 return State->set<IteratorRegionMap>(Reg, Pos);
2012 } else if (const auto Sym = Val.getAsSymbol()) {
2013 return State->set<IteratorSymbolMap>(Sym, Pos);
2014 } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
2015 return State->set<IteratorRegionMap>(LCVal->getRegion(), Pos);
2016 }
2017 return nullptr;
2018}
2019
Artem Dergachev8fa639e2017-05-29 15:03:20 +00002020ProgramStateRef removeIteratorPosition(ProgramStateRef State, const SVal &Val) {
Adam Balogh42d241f2018-12-04 10:22:28 +00002021 if (auto Reg = Val.getAsRegion()) {
2022 Reg = Reg->getMostDerivedObjectRegion();
Artem Dergachev8fa639e2017-05-29 15:03:20 +00002023 return State->remove<IteratorRegionMap>(Reg);
2024 } else if (const auto Sym = Val.getAsSymbol()) {
2025 return State->remove<IteratorSymbolMap>(Sym);
2026 } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
2027 return State->remove<IteratorRegionMap>(LCVal->getRegion());
2028 }
2029 return nullptr;
2030}
2031
Adam Balogh54976e72019-04-23 07:15:55 +00002032ProgramStateRef relateSymbols(ProgramStateRef State, SymbolRef Sym1,
2033 SymbolRef Sym2, bool Equal) {
Artem Dergachev8fa639e2017-05-29 15:03:20 +00002034 auto &SVB = State->getStateManager().getSValBuilder();
Adam Balogh0a7592b2018-07-16 09:27:27 +00002035
2036 // FIXME: This code should be reworked as follows:
2037 // 1. Subtract the operands using evalBinOp().
2038 // 2. Assume that the result doesn't overflow.
2039 // 3. Compare the result to 0.
2040 // 4. Assume the result of the comparison.
Artem Dergachev8fa639e2017-05-29 15:03:20 +00002041 const auto comparison =
Adam Balogh54976e72019-04-23 07:15:55 +00002042 SVB.evalBinOp(State, BO_EQ, nonloc::SymbolVal(Sym1),
2043 nonloc::SymbolVal(Sym2), SVB.getConditionType());
Adam Baloghb03ed5e2018-06-28 10:58:53 +00002044
Adam Balogh0a7592b2018-07-16 09:27:27 +00002045 assert(comparison.getAs<DefinedSVal>() &&
2046 "Symbol comparison must be a `DefinedSVal`");
Adam Baloghb03ed5e2018-06-28 10:58:53 +00002047
Adam Balogh0a7592b2018-07-16 09:27:27 +00002048 auto NewState = State->assume(comparison.castAs<DefinedSVal>(), Equal);
Adam Balogh54976e72019-04-23 07:15:55 +00002049 if (!NewState)
2050 return nullptr;
2051
Adam Balogh0a7592b2018-07-16 09:27:27 +00002052 if (const auto CompSym = comparison.getAsSymbol()) {
2053 assert(isa<SymIntExpr>(CompSym) &&
2054 "Symbol comparison must be a `SymIntExpr`");
2055 assert(BinaryOperator::isComparisonOp(
2056 cast<SymIntExpr>(CompSym)->getOpcode()) &&
2057 "Symbol comparison must be a comparison");
2058 return assumeNoOverflow(NewState, cast<SymIntExpr>(CompSym)->getLHS(), 2);
Artem Dergachev8fa639e2017-05-29 15:03:20 +00002059 }
2060
Adam Balogh0a7592b2018-07-16 09:27:27 +00002061 return NewState;
Artem Dergachev8fa639e2017-05-29 15:03:20 +00002062}
2063
Adam Balogha6921202018-07-30 08:52:21 +00002064bool hasLiveIterators(ProgramStateRef State, const MemRegion *Cont) {
2065 auto RegionMap = State->get<IteratorRegionMap>();
2066 for (const auto Reg : RegionMap) {
2067 if (Reg.second.getContainer() == Cont)
2068 return true;
2069 }
2070
2071 auto SymbolMap = State->get<IteratorSymbolMap>();
2072 for (const auto Sym : SymbolMap) {
2073 if (Sym.second.getContainer() == Cont)
2074 return true;
2075 }
2076
2077 return false;
2078}
2079
Adam Balogh21583b72018-09-10 09:03:22 +00002080bool isBoundThroughLazyCompoundVal(const Environment &Env,
2081 const MemRegion *Reg) {
2082 for (const auto Binding: Env) {
2083 if (const auto LCVal = Binding.second.getAs<nonloc::LazyCompoundVal>()) {
2084 if (LCVal->getRegion() == Reg)
2085 return true;
2086 }
2087 }
2088
2089 return false;
2090}
2091
Adam Balogh54976e72019-04-23 07:15:55 +00002092// This function tells the analyzer's engine that symbols produced by our
2093// checker, most notably iterator positions, are relatively small.
2094// A distance between items in the container should not be very large.
2095// By assuming that it is within around 1/8 of the address space,
2096// we can help the analyzer perform operations on these symbols
2097// without being afraid of integer overflows.
2098// FIXME: Should we provide it as an API, so that all checkers could use it?
2099ProgramStateRef assumeNoOverflow(ProgramStateRef State, SymbolRef Sym,
2100 long Scale) {
2101 SValBuilder &SVB = State->getStateManager().getSValBuilder();
2102 BasicValueFactory &BV = SVB.getBasicValueFactory();
2103
2104 QualType T = Sym->getType();
2105 assert(T->isSignedIntegerOrEnumerationType());
2106 APSIntType AT = BV.getAPSIntType(T);
2107
2108 ProgramStateRef NewState = State;
2109
2110 llvm::APSInt Max = AT.getMaxValue() / AT.getValue(Scale);
2111 SVal IsCappedFromAbove =
2112 SVB.evalBinOpNN(State, BO_LE, nonloc::SymbolVal(Sym),
2113 nonloc::ConcreteInt(Max), SVB.getConditionType());
2114 if (auto DV = IsCappedFromAbove.getAs<DefinedSVal>()) {
2115 NewState = NewState->assume(*DV, true);
2116 if (!NewState)
2117 return State;
2118 }
2119
2120 llvm::APSInt Min = -Max;
2121 SVal IsCappedFromBelow =
2122 SVB.evalBinOpNN(State, BO_GE, nonloc::SymbolVal(Sym),
2123 nonloc::ConcreteInt(Min), SVB.getConditionType());
2124 if (auto DV = IsCappedFromBelow.getAs<DefinedSVal>()) {
2125 NewState = NewState->assume(*DV, true);
2126 if (!NewState)
2127 return State;
2128 }
2129
2130 return NewState;
2131}
2132
Adam Balogh2cfbe932018-08-28 08:41:15 +00002133template <typename Condition, typename Process>
2134ProgramStateRef processIteratorPositions(ProgramStateRef State, Condition Cond,
2135 Process Proc) {
2136 auto &RegionMapFactory = State->get_context<IteratorRegionMap>();
2137 auto RegionMap = State->get<IteratorRegionMap>();
2138 bool Changed = false;
2139 for (const auto Reg : RegionMap) {
2140 if (Cond(Reg.second)) {
2141 RegionMap = RegionMapFactory.add(RegionMap, Reg.first, Proc(Reg.second));
2142 Changed = true;
2143 }
2144 }
2145
2146 if (Changed)
2147 State = State->set<IteratorRegionMap>(RegionMap);
2148
2149 auto &SymbolMapFactory = State->get_context<IteratorSymbolMap>();
2150 auto SymbolMap = State->get<IteratorSymbolMap>();
2151 Changed = false;
2152 for (const auto Sym : SymbolMap) {
2153 if (Cond(Sym.second)) {
2154 SymbolMap = SymbolMapFactory.add(SymbolMap, Sym.first, Proc(Sym.second));
2155 Changed = true;
2156 }
2157 }
2158
2159 if (Changed)
2160 State = State->set<IteratorSymbolMap>(SymbolMap);
2161
2162 return State;
2163}
2164
2165ProgramStateRef invalidateAllIteratorPositions(ProgramStateRef State,
2166 const MemRegion *Cont) {
2167 auto MatchCont = [&](const IteratorPosition &Pos) {
2168 return Pos.getContainer() == Cont;
2169 };
2170 auto Invalidate = [&](const IteratorPosition &Pos) {
2171 return Pos.invalidate();
2172 };
2173 return processIteratorPositions(State, MatchCont, Invalidate);
2174}
2175
Adam Balogh2e7cb342018-09-10 09:07:47 +00002176ProgramStateRef
2177invalidateAllIteratorPositionsExcept(ProgramStateRef State,
2178 const MemRegion *Cont, SymbolRef Offset,
2179 BinaryOperator::Opcode Opc) {
2180 auto MatchContAndCompare = [&](const IteratorPosition &Pos) {
2181 return Pos.getContainer() == Cont &&
2182 !compare(State, Pos.getOffset(), Offset, Opc);
2183 };
2184 auto Invalidate = [&](const IteratorPosition &Pos) {
2185 return Pos.invalidate();
2186 };
2187 return processIteratorPositions(State, MatchContAndCompare, Invalidate);
2188}
2189
Adam Balogh9a48ba62018-09-10 09:06:31 +00002190ProgramStateRef invalidateIteratorPositions(ProgramStateRef State,
2191 SymbolRef Offset,
2192 BinaryOperator::Opcode Opc) {
2193 auto Compare = [&](const IteratorPosition &Pos) {
2194 return compare(State, Pos.getOffset(), Offset, Opc);
2195 };
2196 auto Invalidate = [&](const IteratorPosition &Pos) {
2197 return Pos.invalidate();
2198 };
2199 return processIteratorPositions(State, Compare, Invalidate);
2200}
2201
Adam Balogh2e7cb342018-09-10 09:07:47 +00002202ProgramStateRef invalidateIteratorPositions(ProgramStateRef State,
2203 SymbolRef Offset1,
2204 BinaryOperator::Opcode Opc1,
2205 SymbolRef Offset2,
2206 BinaryOperator::Opcode Opc2) {
2207 auto Compare = [&](const IteratorPosition &Pos) {
2208 return compare(State, Pos.getOffset(), Offset1, Opc1) &&
2209 compare(State, Pos.getOffset(), Offset2, Opc2);
2210 };
2211 auto Invalidate = [&](const IteratorPosition &Pos) {
2212 return Pos.invalidate();
2213 };
2214 return processIteratorPositions(State, Compare, Invalidate);
2215}
2216
Adam Balogh6b23b1a2018-09-10 09:04:27 +00002217ProgramStateRef reassignAllIteratorPositions(ProgramStateRef State,
2218 const MemRegion *Cont,
2219 const MemRegion *NewCont) {
2220 auto MatchCont = [&](const IteratorPosition &Pos) {
2221 return Pos.getContainer() == Cont;
2222 };
2223 auto ReAssign = [&](const IteratorPosition &Pos) {
2224 return Pos.reAssign(NewCont);
2225 };
2226 return processIteratorPositions(State, MatchCont, ReAssign);
2227}
2228
2229ProgramStateRef reassignAllIteratorPositionsUnless(ProgramStateRef State,
2230 const MemRegion *Cont,
2231 const MemRegion *NewCont,
2232 SymbolRef Offset,
2233 BinaryOperator::Opcode Opc) {
2234 auto MatchContAndCompare = [&](const IteratorPosition &Pos) {
2235 return Pos.getContainer() == Cont &&
2236 !compare(State, Pos.getOffset(), Offset, Opc);
2237 };
2238 auto ReAssign = [&](const IteratorPosition &Pos) {
2239 return Pos.reAssign(NewCont);
2240 };
2241 return processIteratorPositions(State, MatchContAndCompare, ReAssign);
2242}
2243
2244// This function rebases symbolic expression `OldSym + Int` to `NewSym + Int`,
2245// `OldSym - Int` to `NewSym - Int` and `OldSym` to `NewSym` in any iterator
2246// position offsets where `CondSym` is true.
2247ProgramStateRef rebaseSymbolInIteratorPositionsIf(
2248 ProgramStateRef State, SValBuilder &SVB, SymbolRef OldSym,
2249 SymbolRef NewSym, SymbolRef CondSym, BinaryOperator::Opcode Opc) {
2250 auto LessThanEnd = [&](const IteratorPosition &Pos) {
2251 return compare(State, Pos.getOffset(), CondSym, Opc);
2252 };
2253 auto RebaseSymbol = [&](const IteratorPosition &Pos) {
2254 return Pos.setTo(rebaseSymbol(State, SVB, Pos.getOffset(), OldSym,
2255 NewSym));
2256 };
2257 return processIteratorPositions(State, LessThanEnd, RebaseSymbol);
2258}
2259
2260// This function rebases symbolic expression `OldExpr + Int` to `NewExpr + Int`,
2261// `OldExpr - Int` to `NewExpr - Int` and `OldExpr` to `NewExpr` in expression
2262// `OrigExpr`.
2263SymbolRef rebaseSymbol(ProgramStateRef State, SValBuilder &SVB,
2264 SymbolRef OrigExpr, SymbolRef OldExpr,
2265 SymbolRef NewSym) {
2266 auto &SymMgr = SVB.getSymbolManager();
2267 auto Diff = SVB.evalBinOpNN(State, BO_Sub, nonloc::SymbolVal(OrigExpr),
2268 nonloc::SymbolVal(OldExpr),
2269 SymMgr.getType(OrigExpr));
2270
2271 const auto DiffInt = Diff.getAs<nonloc::ConcreteInt>();
2272 if (!DiffInt)
2273 return OrigExpr;
2274
2275 return SVB.evalBinOpNN(State, BO_Add, *DiffInt, nonloc::SymbolVal(NewSym),
2276 SymMgr.getType(OrigExpr)).getAsSymbol();
2277}
2278
Adam Baloghb03ed5e2018-06-28 10:58:53 +00002279bool isZero(ProgramStateRef State, const NonLoc &Val) {
2280 auto &BVF = State->getBasicVals();
2281 return compare(State, Val,
2282 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))),
2283 BO_EQ);
2284}
2285
Adam Baloghd5bd3f62018-12-04 10:27:27 +00002286bool isPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos) {
Artem Dergachev8fa639e2017-05-29 15:03:20 +00002287 const auto *Cont = Pos.getContainer();
2288 const auto *CData = getContainerData(State, Cont);
2289 if (!CData)
2290 return false;
2291
Adam Baloghd5bd3f62018-12-04 10:27:27 +00002292 const auto End = CData->getEnd();
2293 if (End) {
2294 if (isEqual(State, Pos.getOffset(), End)) {
2295 return true;
2296 }
2297 }
2298
2299 return false;
2300}
2301
2302bool isAheadOfRange(ProgramStateRef State, const IteratorPosition &Pos) {
2303 const auto *Cont = Pos.getContainer();
2304 const auto *CData = getContainerData(State, Cont);
2305 if (!CData)
2306 return false;
Artem Dergachev8fa639e2017-05-29 15:03:20 +00002307
Adam Baloghb03ed5e2018-06-28 10:58:53 +00002308 const auto Beg = CData->getBegin();
2309 if (Beg) {
2310 if (isLess(State, Pos.getOffset(), Beg)) {
2311 return true;
2312 }
2313 }
2314
Adam Baloghd5bd3f62018-12-04 10:27:27 +00002315 return false;
2316}
2317
2318bool isBehindPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos) {
2319 const auto *Cont = Pos.getContainer();
2320 const auto *CData = getContainerData(State, Cont);
2321 if (!CData)
2322 return false;
2323
Artem Dergachev8fa639e2017-05-29 15:03:20 +00002324 const auto End = CData->getEnd();
2325 if (End) {
Adam Baloghd5bd3f62018-12-04 10:27:27 +00002326 if (isGreater(State, Pos.getOffset(), End)) {
Artem Dergachev8fa639e2017-05-29 15:03:20 +00002327 return true;
2328 }
2329 }
2330
2331 return false;
2332}
2333
Adam Baloghb03ed5e2018-06-28 10:58:53 +00002334bool isLess(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) {
2335 return compare(State, Sym1, Sym2, BO_LT);
2336}
2337
Adam Baloghd5bd3f62018-12-04 10:27:27 +00002338bool isGreater(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) {
2339 return compare(State, Sym1, Sym2, BO_GT);
2340}
2341
2342bool isEqual(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) {
2343 return compare(State, Sym1, Sym2, BO_EQ);
Artem Dergachev8fa639e2017-05-29 15:03:20 +00002344}
2345
2346bool compare(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2,
2347 BinaryOperator::Opcode Opc) {
Adam Baloghb03ed5e2018-06-28 10:58:53 +00002348 return compare(State, nonloc::SymbolVal(Sym1), nonloc::SymbolVal(Sym2), Opc);
2349}
2350
2351bool compare(ProgramStateRef State, NonLoc NL1, NonLoc NL2,
2352 BinaryOperator::Opcode Opc) {
2353 auto &SVB = State->getStateManager().getSValBuilder();
Artem Dergachev8fa639e2017-05-29 15:03:20 +00002354
2355 const auto comparison =
Adam Balogh0a7592b2018-07-16 09:27:27 +00002356 SVB.evalBinOp(State, Opc, NL1, NL2, SVB.getConditionType());
Artem Dergachev8fa639e2017-05-29 15:03:20 +00002357
Adam Balogh0a7592b2018-07-16 09:27:27 +00002358 assert(comparison.getAs<DefinedSVal>() &&
2359 "Symbol comparison must be a `DefinedSVal`");
Artem Dergachev8fa639e2017-05-29 15:03:20 +00002360
Adam Balogh0a7592b2018-07-16 09:27:27 +00002361 return !State->assume(comparison.castAs<DefinedSVal>(), false);
Artem Dergachev8fa639e2017-05-29 15:03:20 +00002362}
2363
2364} // namespace
2365
Kristof Umann8fd74eb2019-01-26 20:06:54 +00002366void ento::registerIteratorModeling(CheckerManager &mgr) {
2367 mgr.registerChecker<IteratorChecker>();
2368}
2369
2370bool ento::shouldRegisterIteratorModeling(const LangOptions &LO) {
2371 return true;
2372}
2373
Artem Dergachev8fa639e2017-05-29 15:03:20 +00002374#define REGISTER_CHECKER(name) \
2375 void ento::register##name(CheckerManager &Mgr) { \
Kristof Umann204bf2b2019-01-26 21:41:50 +00002376 auto *checker = Mgr.getChecker<IteratorChecker>(); \
Artem Dergachev8fa639e2017-05-29 15:03:20 +00002377 checker->ChecksEnabled[IteratorChecker::CK_##name] = true; \
2378 checker->CheckNames[IteratorChecker::CK_##name] = \
2379 Mgr.getCurrentCheckName(); \
Kristof Umann058a7a42019-01-26 14:23:08 +00002380 } \
2381 \
2382 bool ento::shouldRegister##name(const LangOptions &LO) { \
2383 return true; \
Artem Dergachev8fa639e2017-05-29 15:03:20 +00002384 }
2385
2386REGISTER_CHECKER(IteratorRangeChecker)
Adam Balogh21583b72018-09-10 09:03:22 +00002387REGISTER_CHECKER(MismatchedIteratorChecker)
Adam Balogh2cfbe932018-08-28 08:41:15 +00002388REGISTER_CHECKER(InvalidatedIteratorChecker)