blob: 557bc04268b0e02a203f70dd74af05da7ae06b77 [file] [log] [blame]
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001//===-- IteratorChecker.cpp ---------------------------------------*- C++ -*--//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// Defines a checker for using iterators outside their range (past end). Usage
11// means here dereferencing, incrementing etc.
12//
13//===----------------------------------------------------------------------===//
14//
15// In the code, iterator can be represented as a:
16// * type-I: typedef-ed pointer. Operations over such iterator, such as
17// comparisons or increments, are modeled straightforwardly by the
18// analyzer.
19// * type-II: structure with its method bodies available. Operations over such
20// iterator are inlined by the analyzer, and results of modeling
21// these operations are exposing implementation details of the
22// iterators, which is not necessarily helping.
23// * type-III: completely opaque structure. Operations over such iterator are
24// modeled conservatively, producing conjured symbols everywhere.
25//
26// To handle all these types in a common way we introduce a structure called
27// IteratorPosition which is an abstraction of the position the iterator
28// represents using symbolic expressions. The checker handles all the
29// operations on this structure.
30//
31// Additionally, depending on the circumstances, operators of types II and III
32// can be represented as:
33// * type-IIa, type-IIIa: conjured structure symbols - when returned by value
34// from conservatively evaluated methods such as
35// `.begin()`.
36// * type-IIb, type-IIIb: memory regions of iterator-typed objects, such as
37// variables or temporaries, when the iterator object is
38// currently treated as an lvalue.
39// * type-IIc, type-IIIc: compound values of iterator-typed objects, when the
40// iterator object is treated as an rvalue taken of a
41// particular lvalue, eg. a copy of "type-a" iterator
42// object, or an iterator that existed before the
43// analysis has started.
44//
45// To handle any of these three different representations stored in an SVal we
46// use setter and getters functions which separate the three cases. To store
47// them we use a pointer union of symbol and memory region.
48//
Adam Baloghb03ed5e2018-06-28 10:58:53 +000049// The checker works the following way: We record the begin and the
50// past-end iterator for all containers whenever their `.begin()` and `.end()`
51// are called. Since the Constraint Manager cannot handle such SVals we need
52// to take over its role. We post-check equality and non-equality comparisons
53// and record that the two sides are equal if we are in the 'equal' branch
54// (true-branch for `==` and false-branch for `!=`).
Artem Dergachev8fa639e2017-05-29 15:03:20 +000055//
56// In case of type-I or type-II iterators we get a concrete integer as a result
57// of the comparison (1 or 0) but in case of type-III we only get a Symbol. In
58// this latter case we record the symbol and reload it in evalAssume() and do
59// the propagation there. We also handle (maybe double) negated comparisons
Adam Baloghb03ed5e2018-06-28 10:58:53 +000060// which are represented in the form of (x == 0 or x != 0) where x is the
Artem Dergachev8fa639e2017-05-29 15:03:20 +000061// comparison itself.
Adam Baloghb03ed5e2018-06-28 10:58:53 +000062//
63// Since `SimpleConstraintManager` cannot handle complex symbolic expressions
64// we only use expressions of the format S, S+n or S-n for iterator positions
65// where S is a conjured symbol and n is an unsigned concrete integer. When
66// making an assumption e.g. `S1 + n == S2 + m` we store `S1 - S2 == m - n` as
67// a constraint which we later retrieve when doing an actual comparison.
Artem Dergachev8fa639e2017-05-29 15:03:20 +000068
69#include "ClangSACheckers.h"
Adam Balogh2cfbe932018-08-28 08:41:15 +000070#include "clang/AST/DeclTemplate.h"
Artem Dergachev8fa639e2017-05-29 15:03:20 +000071#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
72#include "clang/StaticAnalyzer/Core/Checker.h"
73#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
74#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
Adam Balogh9a48ba62018-09-10 09:06:31 +000075#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h"
Artem Dergachev8fa639e2017-05-29 15:03:20 +000076
Adam Balogh2cfbe932018-08-28 08:41:15 +000077#include <utility>
78
Artem Dergachev8fa639e2017-05-29 15:03:20 +000079using namespace clang;
80using namespace ento;
81
82namespace {
83
84// Abstract position of an iterator. This helps to handle all three kinds
85// of operators in a common way by using a symbolic position.
86struct IteratorPosition {
87private:
88
89 // Container the iterator belongs to
90 const MemRegion *Cont;
91
Adam Balogh2cfbe932018-08-28 08:41:15 +000092 // Whether iterator is valid
93 const bool Valid;
94
Artem Dergachev8fa639e2017-05-29 15:03:20 +000095 // Abstract offset
Adam Baloghb03ed5e2018-06-28 10:58:53 +000096 const SymbolRef Offset;
Artem Dergachev8fa639e2017-05-29 15:03:20 +000097
Adam Balogh2cfbe932018-08-28 08:41:15 +000098 IteratorPosition(const MemRegion *C, bool V, SymbolRef Of)
99 : Cont(C), Valid(V), Offset(Of) {}
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000100
101public:
102 const MemRegion *getContainer() const { return Cont; }
Adam Balogh2cfbe932018-08-28 08:41:15 +0000103 bool isValid() const { return Valid; }
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000104 SymbolRef getOffset() const { return Offset; }
105
Adam Balogh2cfbe932018-08-28 08:41:15 +0000106 IteratorPosition invalidate() const {
107 return IteratorPosition(Cont, false, Offset);
108 }
109
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000110 static IteratorPosition getPosition(const MemRegion *C, SymbolRef Of) {
Adam Balogh2cfbe932018-08-28 08:41:15 +0000111 return IteratorPosition(C, true, Of);
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000112 }
113
114 IteratorPosition setTo(SymbolRef NewOf) const {
Adam Balogh2cfbe932018-08-28 08:41:15 +0000115 return IteratorPosition(Cont, Valid, NewOf);
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000116 }
117
Adam Balogh6b23b1a2018-09-10 09:04:27 +0000118 IteratorPosition reAssign(const MemRegion *NewCont) const {
119 return IteratorPosition(NewCont, Valid, Offset);
120 }
121
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000122 bool operator==(const IteratorPosition &X) const {
Adam Balogh2cfbe932018-08-28 08:41:15 +0000123 return Cont == X.Cont && Valid == X.Valid && Offset == X.Offset;
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000124 }
125
126 bool operator!=(const IteratorPosition &X) const {
Adam Balogh2cfbe932018-08-28 08:41:15 +0000127 return Cont != X.Cont || Valid != X.Valid || Offset != X.Offset;
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000128 }
129
130 void Profile(llvm::FoldingSetNodeID &ID) const {
131 ID.AddPointer(Cont);
Adam Balogh2cfbe932018-08-28 08:41:15 +0000132 ID.AddInteger(Valid);
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000133 ID.Add(Offset);
134 }
135};
136
137typedef llvm::PointerUnion<const MemRegion *, SymbolRef> RegionOrSymbol;
138
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000139// Structure to record the symbolic begin and end position of a container
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000140struct ContainerData {
141private:
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000142 const SymbolRef Begin, End;
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000143
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000144 ContainerData(SymbolRef B, SymbolRef E) : Begin(B), End(E) {}
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000145
146public:
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000147 static ContainerData fromBegin(SymbolRef B) {
148 return ContainerData(B, nullptr);
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000149 }
150
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000151 static ContainerData fromEnd(SymbolRef E) {
152 return ContainerData(nullptr, E);
153 }
154
155 SymbolRef getBegin() const { return Begin; }
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000156 SymbolRef getEnd() const { return End; }
157
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000158 ContainerData newBegin(SymbolRef B) const { return ContainerData(B, End); }
159
160 ContainerData newEnd(SymbolRef E) const { return ContainerData(Begin, E); }
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000161
162 bool operator==(const ContainerData &X) const {
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000163 return Begin == X.Begin && End == X.End;
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000164 }
165
166 bool operator!=(const ContainerData &X) const {
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000167 return Begin != X.Begin || End != X.End;
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000168 }
169
170 void Profile(llvm::FoldingSetNodeID &ID) const {
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000171 ID.Add(Begin);
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000172 ID.Add(End);
173 }
174};
175
176// Structure fo recording iterator comparisons. We needed to retrieve the
177// original comparison expression in assumptions.
178struct IteratorComparison {
179private:
180 RegionOrSymbol Left, Right;
181 bool Equality;
182
183public:
184 IteratorComparison(RegionOrSymbol L, RegionOrSymbol R, bool Eq)
185 : Left(L), Right(R), Equality(Eq) {}
186
187 RegionOrSymbol getLeft() const { return Left; }
188 RegionOrSymbol getRight() const { return Right; }
189 bool isEquality() const { return Equality; }
190 bool operator==(const IteratorComparison &X) const {
191 return Left == X.Left && Right == X.Right && Equality == X.Equality;
192 }
193 bool operator!=(const IteratorComparison &X) const {
194 return Left != X.Left || Right != X.Right || Equality != X.Equality;
195 }
196 void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(Equality); }
197};
198
199class IteratorChecker
200 : public Checker<check::PreCall, check::PostCall,
Adam Balogh2e7cb342018-09-10 09:07:47 +0000201 check::PostStmt<MaterializeTemporaryExpr>, check::Bind,
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000202 check::LiveSymbols, check::DeadSymbols,
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000203 eval::Assume> {
204
205 std::unique_ptr<BugType> OutOfRangeBugType;
Adam Balogh21583b72018-09-10 09:03:22 +0000206 std::unique_ptr<BugType> MismatchedBugType;
Adam Balogh2cfbe932018-08-28 08:41:15 +0000207 std::unique_ptr<BugType> InvalidatedBugType;
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000208
209 void handleComparison(CheckerContext &C, const SVal &RetVal, const SVal &LVal,
210 const SVal &RVal, OverloadedOperatorKind Op) const;
Adam Balogh2cfbe932018-08-28 08:41:15 +0000211 void verifyAccess(CheckerContext &C, const SVal &Val) const;
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000212 void verifyDereference(CheckerContext &C, const SVal &Val) const;
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000213 void handleIncrement(CheckerContext &C, const SVal &RetVal, const SVal &Iter,
214 bool Postfix) const;
215 void handleDecrement(CheckerContext &C, const SVal &RetVal, const SVal &Iter,
216 bool Postfix) const;
217 void handleRandomIncrOrDecr(CheckerContext &C, OverloadedOperatorKind Op,
218 const SVal &RetVal, const SVal &LHS,
219 const SVal &RHS) const;
220 void handleBegin(CheckerContext &C, const Expr *CE, const SVal &RetVal,
221 const SVal &Cont) const;
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000222 void handleEnd(CheckerContext &C, const Expr *CE, const SVal &RetVal,
223 const SVal &Cont) const;
224 void assignToContainer(CheckerContext &C, const Expr *CE, const SVal &RetVal,
225 const MemRegion *Cont) const;
Adam Balogh6b23b1a2018-09-10 09:04:27 +0000226 void handleAssign(CheckerContext &C, const SVal &Cont,
227 const Expr *CE = nullptr,
228 const SVal &OldCont = UndefinedVal()) const;
Adam Balogh2e7cb342018-09-10 09:07:47 +0000229 void handleClear(CheckerContext &C, const SVal &Cont) const;
Adam Balogh9a48ba62018-09-10 09:06:31 +0000230 void handlePushBack(CheckerContext &C, const SVal &Cont) const;
231 void handlePopBack(CheckerContext &C, const SVal &Cont) const;
232 void handlePushFront(CheckerContext &C, const SVal &Cont) const;
233 void handlePopFront(CheckerContext &C, const SVal &Cont) const;
Adam Balogh2e7cb342018-09-10 09:07:47 +0000234 void handleInsert(CheckerContext &C, const SVal &Iter) const;
235 void handleErase(CheckerContext &C, const SVal &Iter) const;
236 void handleErase(CheckerContext &C, const SVal &Iter1,
237 const SVal &Iter2) const;
238 void handleEraseAfter(CheckerContext &C, const SVal &Iter) const;
239 void handleEraseAfter(CheckerContext &C, const SVal &Iter1,
240 const SVal &Iter2) const;
Adam Baloghd5bd3f62018-12-04 10:27:27 +0000241 void verifyIncrement(CheckerContext &C, const SVal &Iter) const;
242 void verifyDecrement(CheckerContext &C, const SVal &Iter) const;
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000243 void verifyRandomIncrOrDecr(CheckerContext &C, OverloadedOperatorKind Op,
Adam Baloghd5bd3f62018-12-04 10:27:27 +0000244 const SVal &LHS, const SVal &RHS) const;
Adam Balogh2e7cb342018-09-10 09:07:47 +0000245 void verifyMatch(CheckerContext &C, const SVal &Iter,
246 const MemRegion *Cont) const;
Adam Balogh21583b72018-09-10 09:03:22 +0000247 void verifyMatch(CheckerContext &C, const SVal &Iter1,
248 const SVal &Iter2) const;
Adam Baloghd5bd3f62018-12-04 10:27:27 +0000249 IteratorPosition advancePosition(CheckerContext &C, OverloadedOperatorKind Op,
250 const IteratorPosition &Pos,
251 const SVal &Distance) const;
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000252 void reportOutOfRangeBug(const StringRef &Message, const SVal &Val,
253 CheckerContext &C, ExplodedNode *ErrNode) const;
Adam Balogh21583b72018-09-10 09:03:22 +0000254 void reportMismatchedBug(const StringRef &Message, const SVal &Val1,
255 const SVal &Val2, CheckerContext &C,
256 ExplodedNode *ErrNode) const;
Adam Balogh3659f7a2018-09-10 09:05:31 +0000257 void reportMismatchedBug(const StringRef &Message, const SVal &Val,
258 const MemRegion *Reg, CheckerContext &C,
259 ExplodedNode *ErrNode) const;
Adam Balogh2cfbe932018-08-28 08:41:15 +0000260 void reportInvalidatedBug(const StringRef &Message, const SVal &Val,
261 CheckerContext &C, ExplodedNode *ErrNode) const;
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000262
263public:
264 IteratorChecker();
265
266 enum CheckKind {
267 CK_IteratorRangeChecker,
Adam Balogh21583b72018-09-10 09:03:22 +0000268 CK_MismatchedIteratorChecker,
Adam Balogh2cfbe932018-08-28 08:41:15 +0000269 CK_InvalidatedIteratorChecker,
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000270 CK_NumCheckKinds
271 };
272
273 DefaultBool ChecksEnabled[CK_NumCheckKinds];
274 CheckName CheckNames[CK_NumCheckKinds];
275
276 void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
277 void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
Adam Balogh2e7cb342018-09-10 09:07:47 +0000278 void checkBind(SVal Loc, SVal Val, const Stmt *S, CheckerContext &C) const;
279 void checkPostStmt(const CXXConstructExpr *CCE, CheckerContext &C) const;
280 void checkPostStmt(const DeclStmt *DS, CheckerContext &C) const;
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000281 void checkPostStmt(const MaterializeTemporaryExpr *MTE,
282 CheckerContext &C) const;
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000283 void checkLiveSymbols(ProgramStateRef State, SymbolReaper &SR) const;
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000284 void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
285 ProgramStateRef evalAssume(ProgramStateRef State, SVal Cond,
286 bool Assumption) const;
287};
288} // namespace
289
290REGISTER_MAP_WITH_PROGRAMSTATE(IteratorSymbolMap, SymbolRef, IteratorPosition)
291REGISTER_MAP_WITH_PROGRAMSTATE(IteratorRegionMap, const MemRegion *,
292 IteratorPosition)
293
294REGISTER_MAP_WITH_PROGRAMSTATE(ContainerMap, const MemRegion *, ContainerData)
295
296REGISTER_MAP_WITH_PROGRAMSTATE(IteratorComparisonMap, const SymExpr *,
297 IteratorComparison)
298
299namespace {
300
301bool isIteratorType(const QualType &Type);
302bool isIterator(const CXXRecordDecl *CRD);
Adam Balogh3659f7a2018-09-10 09:05:31 +0000303bool isComparisonOperator(OverloadedOperatorKind OK);
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000304bool isBeginCall(const FunctionDecl *Func);
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000305bool isEndCall(const FunctionDecl *Func);
Adam Balogh2e7cb342018-09-10 09:07:47 +0000306bool isAssignCall(const FunctionDecl *Func);
307bool isClearCall(const FunctionDecl *Func);
Adam Balogh9a48ba62018-09-10 09:06:31 +0000308bool isPushBackCall(const FunctionDecl *Func);
309bool isEmplaceBackCall(const FunctionDecl *Func);
310bool isPopBackCall(const FunctionDecl *Func);
311bool isPushFrontCall(const FunctionDecl *Func);
312bool isEmplaceFrontCall(const FunctionDecl *Func);
313bool isPopFrontCall(const FunctionDecl *Func);
Adam Balogh2e7cb342018-09-10 09:07:47 +0000314bool isInsertCall(const FunctionDecl *Func);
315bool isEraseCall(const FunctionDecl *Func);
316bool isEraseAfterCall(const FunctionDecl *Func);
317bool isEmplaceCall(const FunctionDecl *Func);
Adam Balogh2cfbe932018-08-28 08:41:15 +0000318bool isAssignmentOperator(OverloadedOperatorKind OK);
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000319bool isSimpleComparisonOperator(OverloadedOperatorKind OK);
Adam Balogh2cfbe932018-08-28 08:41:15 +0000320bool isAccessOperator(OverloadedOperatorKind OK);
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000321bool isDereferenceOperator(OverloadedOperatorKind OK);
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000322bool isIncrementOperator(OverloadedOperatorKind OK);
323bool isDecrementOperator(OverloadedOperatorKind OK);
324bool isRandomIncrOrDecrOperator(OverloadedOperatorKind OK);
Adam Balogh9a48ba62018-09-10 09:06:31 +0000325bool hasSubscriptOperator(ProgramStateRef State, const MemRegion *Reg);
326bool frontModifiable(ProgramStateRef State, const MemRegion *Reg);
327bool backModifiable(ProgramStateRef State, const MemRegion *Reg);
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000328BinaryOperator::Opcode getOpcode(const SymExpr *SE);
329const RegionOrSymbol getRegionOrSymbol(const SVal &Val);
330const ProgramStateRef processComparison(ProgramStateRef State,
331 RegionOrSymbol LVal,
332 RegionOrSymbol RVal, bool Equal);
333const ProgramStateRef saveComparison(ProgramStateRef State,
334 const SymExpr *Condition, const SVal &LVal,
335 const SVal &RVal, bool Eq);
336const IteratorComparison *loadComparison(ProgramStateRef State,
337 const SymExpr *Condition);
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000338SymbolRef getContainerBegin(ProgramStateRef State, const MemRegion *Cont);
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000339SymbolRef getContainerEnd(ProgramStateRef State, const MemRegion *Cont);
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000340ProgramStateRef createContainerBegin(ProgramStateRef State,
341 const MemRegion *Cont,
342 const SymbolRef Sym);
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000343ProgramStateRef createContainerEnd(ProgramStateRef State, const MemRegion *Cont,
344 const SymbolRef Sym);
345const IteratorPosition *getIteratorPosition(ProgramStateRef State,
346 const SVal &Val);
347const IteratorPosition *getIteratorPosition(ProgramStateRef State,
348 RegionOrSymbol RegOrSym);
349ProgramStateRef setIteratorPosition(ProgramStateRef State, const SVal &Val,
350 const IteratorPosition &Pos);
351ProgramStateRef setIteratorPosition(ProgramStateRef State,
352 RegionOrSymbol RegOrSym,
353 const IteratorPosition &Pos);
354ProgramStateRef removeIteratorPosition(ProgramStateRef State, const SVal &Val);
355ProgramStateRef adjustIteratorPosition(ProgramStateRef State,
356 RegionOrSymbol RegOrSym,
357 const IteratorPosition &Pos, bool Equal);
358ProgramStateRef relateIteratorPositions(ProgramStateRef State,
359 const IteratorPosition &Pos1,
360 const IteratorPosition &Pos2,
361 bool Equal);
Adam Balogh2cfbe932018-08-28 08:41:15 +0000362ProgramStateRef invalidateAllIteratorPositions(ProgramStateRef State,
363 const MemRegion *Cont);
Adam Balogh2e7cb342018-09-10 09:07:47 +0000364ProgramStateRef
365invalidateAllIteratorPositionsExcept(ProgramStateRef State,
366 const MemRegion *Cont, SymbolRef Offset,
367 BinaryOperator::Opcode Opc);
Adam Balogh9a48ba62018-09-10 09:06:31 +0000368ProgramStateRef invalidateIteratorPositions(ProgramStateRef State,
369 SymbolRef Offset,
370 BinaryOperator::Opcode Opc);
Adam Balogh2e7cb342018-09-10 09:07:47 +0000371ProgramStateRef invalidateIteratorPositions(ProgramStateRef State,
372 SymbolRef Offset1,
373 BinaryOperator::Opcode Opc1,
374 SymbolRef Offset2,
375 BinaryOperator::Opcode Opc2);
Adam Balogh6b23b1a2018-09-10 09:04:27 +0000376ProgramStateRef reassignAllIteratorPositions(ProgramStateRef State,
377 const MemRegion *Cont,
378 const MemRegion *NewCont);
379ProgramStateRef reassignAllIteratorPositionsUnless(ProgramStateRef State,
380 const MemRegion *Cont,
381 const MemRegion *NewCont,
382 SymbolRef Offset,
383 BinaryOperator::Opcode Opc);
384ProgramStateRef rebaseSymbolInIteratorPositionsIf(
385 ProgramStateRef State, SValBuilder &SVB, SymbolRef OldSym,
386 SymbolRef NewSym, SymbolRef CondSym, BinaryOperator::Opcode Opc);
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000387const ContainerData *getContainerData(ProgramStateRef State,
388 const MemRegion *Cont);
389ProgramStateRef setContainerData(ProgramStateRef State, const MemRegion *Cont,
390 const ContainerData &CData);
Adam Balogha6921202018-07-30 08:52:21 +0000391bool hasLiveIterators(ProgramStateRef State, const MemRegion *Cont);
Adam Balogh21583b72018-09-10 09:03:22 +0000392bool isBoundThroughLazyCompoundVal(const Environment &Env,
393 const MemRegion *Reg);
Adam Baloghd5bd3f62018-12-04 10:27:27 +0000394bool isPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos);
395bool isAheadOfRange(ProgramStateRef State, const IteratorPosition &Pos);
396bool isBehindPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos);
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000397bool isZero(ProgramStateRef State, const NonLoc &Val);
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000398} // namespace
399
400IteratorChecker::IteratorChecker() {
401 OutOfRangeBugType.reset(
402 new BugType(this, "Iterator out of range", "Misuse of STL APIs"));
403 OutOfRangeBugType->setSuppressOnSink(true);
Adam Balogh21583b72018-09-10 09:03:22 +0000404 MismatchedBugType.reset(
405 new BugType(this, "Iterator(s) mismatched", "Misuse of STL APIs"));
406 MismatchedBugType->setSuppressOnSink(true);
Adam Balogh2cfbe932018-08-28 08:41:15 +0000407 InvalidatedBugType.reset(
408 new BugType(this, "Iterator invalidated", "Misuse of STL APIs"));
409 InvalidatedBugType->setSuppressOnSink(true);
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000410}
411
412void IteratorChecker::checkPreCall(const CallEvent &Call,
413 CheckerContext &C) const {
Adam Balogh2cfbe932018-08-28 08:41:15 +0000414 // Check for out of range access or access of invalidated position and
415 // iterator mismatches
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000416 const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
417 if (!Func)
418 return;
419
420 if (Func->isOverloadedOperator()) {
Adam Balogh2cfbe932018-08-28 08:41:15 +0000421 if (ChecksEnabled[CK_InvalidatedIteratorChecker] &&
422 isAccessOperator(Func->getOverloadedOperator())) {
423 // Check for any kind of access of invalidated iterator positions
424 if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
425 verifyAccess(C, InstCall->getCXXThisVal());
426 } else {
427 verifyAccess(C, Call.getArgSVal(0));
428 }
429 }
Adam Baloghd5bd3f62018-12-04 10:27:27 +0000430 if (ChecksEnabled[CK_IteratorRangeChecker]) {
431 if (isIncrementOperator(Func->getOverloadedOperator())) {
432 // Check for out-of-range incrementions
433 if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
434 verifyIncrement(C, InstCall->getCXXThisVal());
435 } else {
436 if (Call.getNumArgs() >= 1) {
437 verifyIncrement(C, Call.getArgSVal(0));
438 }
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000439 }
Adam Baloghd5bd3f62018-12-04 10:27:27 +0000440 } else if (isDecrementOperator(Func->getOverloadedOperator())) {
441 // Check for out-of-range decrementions
442 if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
443 verifyDecrement(C, InstCall->getCXXThisVal());
444 } else {
445 if (Call.getNumArgs() >= 1) {
446 verifyDecrement(C, Call.getArgSVal(0));
447 }
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000448 }
Adam Baloghd5bd3f62018-12-04 10:27:27 +0000449 } else if (isRandomIncrOrDecrOperator(Func->getOverloadedOperator())) {
450 if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
451 // Check for out-of-range incrementions and decrementions
452 if (Call.getNumArgs() >= 1) {
453 verifyRandomIncrOrDecr(C, Func->getOverloadedOperator(),
454 InstCall->getCXXThisVal(),
455 Call.getArgSVal(0));
456 }
457 } else {
458 if (Call.getNumArgs() >= 2) {
459 verifyRandomIncrOrDecr(C, Func->getOverloadedOperator(),
460 Call.getArgSVal(0), Call.getArgSVal(1));
461 }
462 }
463 } else if (isDereferenceOperator(Func->getOverloadedOperator())) {
464 // Check for dereference of out-of-range iterators
465 if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
466 verifyDereference(C, InstCall->getCXXThisVal());
467 } else {
468 verifyDereference(C, Call.getArgSVal(0));
469 }
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000470 }
Adam Balogh3659f7a2018-09-10 09:05:31 +0000471 } else if (ChecksEnabled[CK_MismatchedIteratorChecker] &&
472 isComparisonOperator(Func->getOverloadedOperator())) {
473 // Check for comparisons of iterators of different containers
474 if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
475 if (Call.getNumArgs() < 1)
476 return;
477
478 if (!isIteratorType(InstCall->getCXXThisExpr()->getType()) ||
479 !isIteratorType(Call.getArgExpr(0)->getType()))
480 return;
481
482 verifyMatch(C, InstCall->getCXXThisVal(), Call.getArgSVal(0));
483 } else {
484 if (Call.getNumArgs() < 2)
485 return;
486
487 if (!isIteratorType(Call.getArgExpr(0)->getType()) ||
488 !isIteratorType(Call.getArgExpr(1)->getType()))
489 return;
490
491 verifyMatch(C, Call.getArgSVal(0), Call.getArgSVal(1));
492 }
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000493 }
Adam Balogh2e7cb342018-09-10 09:07:47 +0000494 } else if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
495 if (!ChecksEnabled[CK_MismatchedIteratorChecker])
496 return;
497
498 const auto *ContReg = InstCall->getCXXThisVal().getAsRegion();
499 if (!ContReg)
500 return;
501 // Check for erase, insert and emplace using iterator of another container
502 if (isEraseCall(Func) || isEraseAfterCall(Func)) {
503 verifyMatch(C, Call.getArgSVal(0),
504 InstCall->getCXXThisVal().getAsRegion());
505 if (Call.getNumArgs() == 2) {
506 verifyMatch(C, Call.getArgSVal(1),
507 InstCall->getCXXThisVal().getAsRegion());
508 }
509 } else if (isInsertCall(Func)) {
510 verifyMatch(C, Call.getArgSVal(0),
511 InstCall->getCXXThisVal().getAsRegion());
512 if (Call.getNumArgs() == 3 &&
513 isIteratorType(Call.getArgExpr(1)->getType()) &&
514 isIteratorType(Call.getArgExpr(2)->getType())) {
515 verifyMatch(C, Call.getArgSVal(1), Call.getArgSVal(2));
516 }
517 } else if (isEmplaceCall(Func)) {
518 verifyMatch(C, Call.getArgSVal(0),
519 InstCall->getCXXThisVal().getAsRegion());
520 }
Adam Balogh3659f7a2018-09-10 09:05:31 +0000521 } else if (isa<CXXConstructorCall>(&Call)) {
522 // Check match of first-last iterator pair in a constructor of a container
523 if (Call.getNumArgs() < 2)
524 return;
525
526 const auto *Ctr = cast<CXXConstructorDecl>(Call.getDecl());
527 if (Ctr->getNumParams() < 2)
528 return;
529
530 if (Ctr->getParamDecl(0)->getName() != "first" ||
531 Ctr->getParamDecl(1)->getName() != "last")
532 return;
533
534 if (!isIteratorType(Call.getArgExpr(0)->getType()) ||
535 !isIteratorType(Call.getArgExpr(1)->getType()))
536 return;
537
538 verifyMatch(C, Call.getArgSVal(0), Call.getArgSVal(1));
539 } else {
Adam Balogh21583b72018-09-10 09:03:22 +0000540 // The main purpose of iterators is to abstract away from different
541 // containers and provide a (maybe limited) uniform access to them.
542 // This implies that any correctly written template function that
543 // works on multiple containers using iterators takes different
544 // template parameters for different containers. So we can safely
545 // assume that passing iterators of different containers as arguments
546 // whose type replaces the same template parameter is a bug.
547 //
548 // Example:
549 // template<typename I1, typename I2>
550 // void f(I1 first1, I1 last1, I2 first2, I2 last2);
551 //
552 // In this case the first two arguments to f() must be iterators must belong
553 // to the same container and the last to also to the same container but
554 // not neccessarily to the same as the first two.
555
556 if (!ChecksEnabled[CK_MismatchedIteratorChecker])
557 return;
558
559 const auto *Templ = Func->getPrimaryTemplate();
560 if (!Templ)
561 return;
562
563 const auto *TParams = Templ->getTemplateParameters();
564 const auto *TArgs = Func->getTemplateSpecializationArgs();
565
566 // Iterate over all the template parameters
567 for (size_t I = 0; I < TParams->size(); ++I) {
568 const auto *TPDecl = dyn_cast<TemplateTypeParmDecl>(TParams->getParam(I));
569 if (!TPDecl)
570 continue;
571
572 if (TPDecl->isParameterPack())
573 continue;
574
575 const auto TAType = TArgs->get(I).getAsType();
576 if (!isIteratorType(TAType))
577 continue;
578
579 SVal LHS = UndefinedVal();
580
581 // For every template parameter which is an iterator type in the
582 // instantiation look for all functions' parameters' type by it and
583 // check whether they belong to the same container
584 for (auto J = 0U; J < Func->getNumParams(); ++J) {
585 const auto *Param = Func->getParamDecl(J);
586 const auto *ParamType =
587 Param->getType()->getAs<SubstTemplateTypeParmType>();
588 if (!ParamType ||
589 ParamType->getReplacedParameter()->getDecl() != TPDecl)
590 continue;
591 if (LHS.isUndef()) {
592 LHS = Call.getArgSVal(J);
593 } else {
594 verifyMatch(C, LHS, Call.getArgSVal(J));
595 }
596 }
597 }
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000598 }
599}
600
601void IteratorChecker::checkPostCall(const CallEvent &Call,
602 CheckerContext &C) const {
603 // Record new iterator positions and iterator position changes
604 const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
605 if (!Func)
606 return;
607
608 if (Func->isOverloadedOperator()) {
609 const auto Op = Func->getOverloadedOperator();
Adam Balogh2cfbe932018-08-28 08:41:15 +0000610 if (isAssignmentOperator(Op)) {
611 const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call);
Adam Balogh6b23b1a2018-09-10 09:04:27 +0000612 if (Func->getParamDecl(0)->getType()->isRValueReferenceType()) {
613 handleAssign(C, InstCall->getCXXThisVal(), Call.getOriginExpr(),
614 Call.getArgSVal(0));
615 } else {
616 handleAssign(C, InstCall->getCXXThisVal());
617 }
Adam Balogh2cfbe932018-08-28 08:41:15 +0000618 } else if (isSimpleComparisonOperator(Op)) {
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000619 if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
620 handleComparison(C, Call.getReturnValue(), InstCall->getCXXThisVal(),
621 Call.getArgSVal(0), Op);
622 } else {
623 handleComparison(C, Call.getReturnValue(), Call.getArgSVal(0),
624 Call.getArgSVal(1), Op);
625 }
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000626 } else if (isRandomIncrOrDecrOperator(Func->getOverloadedOperator())) {
627 if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
628 if (Call.getNumArgs() >= 1) {
629 handleRandomIncrOrDecr(C, Func->getOverloadedOperator(),
630 Call.getReturnValue(),
631 InstCall->getCXXThisVal(), Call.getArgSVal(0));
632 }
633 } else {
634 if (Call.getNumArgs() >= 2) {
635 handleRandomIncrOrDecr(C, Func->getOverloadedOperator(),
636 Call.getReturnValue(), Call.getArgSVal(0),
637 Call.getArgSVal(1));
638 }
639 }
640 } else if (isIncrementOperator(Func->getOverloadedOperator())) {
641 if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
642 handleIncrement(C, Call.getReturnValue(), InstCall->getCXXThisVal(),
643 Call.getNumArgs());
644 } else {
645 handleIncrement(C, Call.getReturnValue(), Call.getArgSVal(0),
646 Call.getNumArgs());
647 }
648 } else if (isDecrementOperator(Func->getOverloadedOperator())) {
649 if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
650 handleDecrement(C, Call.getReturnValue(), InstCall->getCXXThisVal(),
651 Call.getNumArgs());
652 } else {
653 handleDecrement(C, Call.getReturnValue(), Call.getArgSVal(0),
654 Call.getNumArgs());
655 }
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000656 }
657 } else {
Adam Balogh9a48ba62018-09-10 09:06:31 +0000658 if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
Adam Balogh2e7cb342018-09-10 09:07:47 +0000659 if (isAssignCall(Func)) {
660 handleAssign(C, InstCall->getCXXThisVal());
661 } else if (isClearCall(Func)) {
662 handleClear(C, InstCall->getCXXThisVal());
663 } else if (isPushBackCall(Func) || isEmplaceBackCall(Func)) {
Adam Balogh9a48ba62018-09-10 09:06:31 +0000664 handlePushBack(C, InstCall->getCXXThisVal());
665 } else if (isPopBackCall(Func)) {
666 handlePopBack(C, InstCall->getCXXThisVal());
667 } else if (isPushFrontCall(Func) || isEmplaceFrontCall(Func)) {
668 handlePushFront(C, InstCall->getCXXThisVal());
669 } else if (isPopFrontCall(Func)) {
670 handlePopFront(C, InstCall->getCXXThisVal());
Adam Balogh2e7cb342018-09-10 09:07:47 +0000671 } else if (isInsertCall(Func) || isEmplaceCall(Func)) {
672 handleInsert(C, Call.getArgSVal(0));
673 } else if (isEraseCall(Func)) {
674 if (Call.getNumArgs() == 1) {
675 handleErase(C, Call.getArgSVal(0));
676 } else if (Call.getNumArgs() == 2) {
677 handleErase(C, Call.getArgSVal(0), Call.getArgSVal(1));
678 }
679 } else if (isEraseAfterCall(Func)) {
680 if (Call.getNumArgs() == 1) {
681 handleEraseAfter(C, Call.getArgSVal(0));
682 } else if (Call.getNumArgs() == 2) {
683 handleEraseAfter(C, Call.getArgSVal(0), Call.getArgSVal(1));
684 }
Adam Balogh9a48ba62018-09-10 09:06:31 +0000685 }
686 }
687
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000688 const auto *OrigExpr = Call.getOriginExpr();
689 if (!OrigExpr)
690 return;
691
692 if (!isIteratorType(Call.getResultType()))
693 return;
694
695 auto State = C.getState();
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000696
697 if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000698 if (isBeginCall(Func)) {
699 handleBegin(C, OrigExpr, Call.getReturnValue(),
700 InstCall->getCXXThisVal());
701 return;
702 }
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000703 if (isEndCall(Func)) {
704 handleEnd(C, OrigExpr, Call.getReturnValue(),
705 InstCall->getCXXThisVal());
706 return;
707 }
708 }
709
Adam Balogh6b23b1a2018-09-10 09:04:27 +0000710 // Already bound to container?
711 if (getIteratorPosition(State, Call.getReturnValue()))
712 return;
713
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000714 // Copy-like and move constructors
715 if (isa<CXXConstructorCall>(&Call) && Call.getNumArgs() == 1) {
716 if (const auto *Pos = getIteratorPosition(State, Call.getArgSVal(0))) {
717 State = setIteratorPosition(State, Call.getReturnValue(), *Pos);
718 if (cast<CXXConstructorDecl>(Func)->isMoveConstructor()) {
719 State = removeIteratorPosition(State, Call.getArgSVal(0));
720 }
721 C.addTransition(State);
722 return;
723 }
724 }
725
726 // Assumption: if return value is an iterator which is not yet bound to a
727 // container, then look for the first iterator argument, and
728 // bind the return value to the same container. This approach
729 // works for STL algorithms.
730 // FIXME: Add a more conservative mode
731 for (unsigned i = 0; i < Call.getNumArgs(); ++i) {
732 if (isIteratorType(Call.getArgExpr(i)->getType())) {
733 if (const auto *Pos = getIteratorPosition(State, Call.getArgSVal(i))) {
734 assignToContainer(C, OrigExpr, Call.getReturnValue(),
735 Pos->getContainer());
736 return;
737 }
738 }
739 }
740 }
741}
742
Adam Balogh2e7cb342018-09-10 09:07:47 +0000743void IteratorChecker::checkBind(SVal Loc, SVal Val, const Stmt *S,
744 CheckerContext &C) const {
745 auto State = C.getState();
746 const auto *Pos = getIteratorPosition(State, Val);
747 if (Pos) {
748 State = setIteratorPosition(State, Loc, *Pos);
749 C.addTransition(State);
750 } else {
751 const auto *OldPos = getIteratorPosition(State, Loc);
752 if (OldPos) {
753 State = removeIteratorPosition(State, Loc);
754 C.addTransition(State);
755 }
756 }
757}
758
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000759void IteratorChecker::checkPostStmt(const MaterializeTemporaryExpr *MTE,
760 CheckerContext &C) const {
761 /* Transfer iterator state to temporary objects */
762 auto State = C.getState();
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000763 const auto *Pos =
George Karpenkovd703ec92018-01-17 20:27:29 +0000764 getIteratorPosition(State, C.getSVal(MTE->GetTemporaryExpr()));
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000765 if (!Pos)
766 return;
George Karpenkovd703ec92018-01-17 20:27:29 +0000767 State = setIteratorPosition(State, C.getSVal(MTE), *Pos);
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000768 C.addTransition(State);
769}
770
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000771void IteratorChecker::checkLiveSymbols(ProgramStateRef State,
772 SymbolReaper &SR) const {
773 // Keep symbolic expressions of iterator positions, container begins and ends
774 // alive
775 auto RegionMap = State->get<IteratorRegionMap>();
776 for (const auto Reg : RegionMap) {
Adam Balogh0a7592b2018-07-16 09:27:27 +0000777 const auto Offset = Reg.second.getOffset();
778 for (auto i = Offset->symbol_begin(); i != Offset->symbol_end(); ++i)
779 if (isa<SymbolData>(*i))
780 SR.markLive(*i);
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000781 }
782
783 auto SymbolMap = State->get<IteratorSymbolMap>();
784 for (const auto Sym : SymbolMap) {
Adam Balogh0a7592b2018-07-16 09:27:27 +0000785 const auto Offset = Sym.second.getOffset();
786 for (auto i = Offset->symbol_begin(); i != Offset->symbol_end(); ++i)
787 if (isa<SymbolData>(*i))
788 SR.markLive(*i);
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000789 }
790
791 auto ContMap = State->get<ContainerMap>();
792 for (const auto Cont : ContMap) {
793 const auto CData = Cont.second;
794 if (CData.getBegin()) {
795 SR.markLive(CData.getBegin());
Adam Balogh9a48ba62018-09-10 09:06:31 +0000796 if(const auto *SIE = dyn_cast<SymIntExpr>(CData.getBegin()))
797 SR.markLive(SIE->getLHS());
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000798 }
799 if (CData.getEnd()) {
800 SR.markLive(CData.getEnd());
Adam Balogh9a48ba62018-09-10 09:06:31 +0000801 if(const auto *SIE = dyn_cast<SymIntExpr>(CData.getEnd()))
802 SR.markLive(SIE->getLHS());
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000803 }
804 }
805}
806
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000807void IteratorChecker::checkDeadSymbols(SymbolReaper &SR,
808 CheckerContext &C) const {
809 // Cleanup
810 auto State = C.getState();
811
812 auto RegionMap = State->get<IteratorRegionMap>();
813 for (const auto Reg : RegionMap) {
814 if (!SR.isLiveRegion(Reg.first)) {
Adam Balogh21583b72018-09-10 09:03:22 +0000815 // The region behind the `LazyCompoundVal` is often cleaned up before
816 // the `LazyCompoundVal` itself. If there are iterator positions keyed
817 // by these regions their cleanup must be deferred.
818 if (!isBoundThroughLazyCompoundVal(State->getEnvironment(), Reg.first)) {
819 State = State->remove<IteratorRegionMap>(Reg.first);
820 }
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000821 }
822 }
823
824 auto SymbolMap = State->get<IteratorSymbolMap>();
825 for (const auto Sym : SymbolMap) {
826 if (!SR.isLive(Sym.first)) {
827 State = State->remove<IteratorSymbolMap>(Sym.first);
828 }
829 }
830
831 auto ContMap = State->get<ContainerMap>();
832 for (const auto Cont : ContMap) {
833 if (!SR.isLiveRegion(Cont.first)) {
Adam Balogha6921202018-07-30 08:52:21 +0000834 // We must keep the container data while it has live iterators to be able
835 // to compare them to the begin and the end of the container.
836 if (!hasLiveIterators(State, Cont.first)) {
837 State = State->remove<ContainerMap>(Cont.first);
838 }
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000839 }
840 }
841
842 auto ComparisonMap = State->get<IteratorComparisonMap>();
843 for (const auto Comp : ComparisonMap) {
844 if (!SR.isLive(Comp.first)) {
845 State = State->remove<IteratorComparisonMap>(Comp.first);
846 }
847 }
Reka Kovacse48ea892018-07-30 16:14:59 +0000848
849 C.addTransition(State);
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000850}
851
852ProgramStateRef IteratorChecker::evalAssume(ProgramStateRef State, SVal Cond,
853 bool Assumption) const {
854 // Load recorded comparison and transfer iterator state between sides
855 // according to comparison operator and assumption
856 const auto *SE = Cond.getAsSymExpr();
857 if (!SE)
858 return State;
859
860 auto Opc = getOpcode(SE);
861 if (Opc != BO_EQ && Opc != BO_NE)
862 return State;
863
864 bool Negated = false;
865 const auto *Comp = loadComparison(State, SE);
866 if (!Comp) {
867 // Try negated comparison, which is a SymExpr to 0 integer comparison
868 const auto *SIE = dyn_cast<SymIntExpr>(SE);
869 if (!SIE)
870 return State;
871
872 if (SIE->getRHS() != 0)
873 return State;
874
875 SE = SIE->getLHS();
876 Negated = SIE->getOpcode() == BO_EQ; // Equal to zero means negation
877 Opc = getOpcode(SE);
878 if (Opc != BO_EQ && Opc != BO_NE)
879 return State;
880
881 Comp = loadComparison(State, SE);
882 if (!Comp)
883 return State;
884 }
885
886 return processComparison(State, Comp->getLeft(), Comp->getRight(),
887 (Comp->isEquality() == Assumption) != Negated);
888}
889
890void IteratorChecker::handleComparison(CheckerContext &C, const SVal &RetVal,
891 const SVal &LVal, const SVal &RVal,
892 OverloadedOperatorKind Op) const {
893 // Record the operands and the operator of the comparison for the next
894 // evalAssume, if the result is a symbolic expression. If it is a concrete
895 // value (only one branch is possible), then transfer the state between
896 // the operands according to the operator and the result
897 auto State = C.getState();
898 if (const auto *Condition = RetVal.getAsSymbolicExpression()) {
899 const auto *LPos = getIteratorPosition(State, LVal);
900 const auto *RPos = getIteratorPosition(State, RVal);
901 if (!LPos && !RPos)
902 return;
903 State = saveComparison(State, Condition, LVal, RVal, Op == OO_EqualEqual);
904 C.addTransition(State);
905 } else if (const auto TruthVal = RetVal.getAs<nonloc::ConcreteInt>()) {
906 if ((State = processComparison(
907 State, getRegionOrSymbol(LVal), getRegionOrSymbol(RVal),
908 (Op == OO_EqualEqual) == (TruthVal->getValue() != 0)))) {
909 C.addTransition(State);
910 } else {
911 C.generateSink(State, C.getPredecessor());
912 }
913 }
914}
915
916void IteratorChecker::verifyDereference(CheckerContext &C,
917 const SVal &Val) const {
918 auto State = C.getState();
919 const auto *Pos = getIteratorPosition(State, Val);
Adam Baloghd5bd3f62018-12-04 10:27:27 +0000920 if (Pos && isPastTheEnd(State, *Pos)) {
Adam Balogh2cfbe932018-08-28 08:41:15 +0000921 auto *N = C.generateNonFatalErrorNode(State);
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000922 if (!N)
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000923 return;
Adam Baloghd5bd3f62018-12-04 10:27:27 +0000924 reportOutOfRangeBug("Past-the-end iterator dereferenced.", Val, C, N);
925 return;
Artem Dergachev8fa639e2017-05-29 15:03:20 +0000926 }
927}
928
Adam Balogh2cfbe932018-08-28 08:41:15 +0000929void IteratorChecker::verifyAccess(CheckerContext &C, const SVal &Val) const {
930 auto State = C.getState();
931 const auto *Pos = getIteratorPosition(State, Val);
932 if (Pos && !Pos->isValid()) {
933 auto *N = C.generateNonFatalErrorNode(State);
934 if (!N) {
935 return;
936 }
937 reportInvalidatedBug("Invalidated iterator accessed.", Val, C, N);
938 }
939}
940
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000941void IteratorChecker::handleIncrement(CheckerContext &C, const SVal &RetVal,
942 const SVal &Iter, bool Postfix) const {
943 // Increment the symbolic expressions which represents the position of the
944 // iterator
945 auto State = C.getState();
946 const auto *Pos = getIteratorPosition(State, Iter);
947 if (Pos) {
948 auto &SymMgr = C.getSymbolManager();
949 auto &BVF = SymMgr.getBasicVals();
Adam Baloghd5bd3f62018-12-04 10:27:27 +0000950 const auto NewPos =
951 advancePosition(C, OO_Plus, *Pos,
952 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000953 State = setIteratorPosition(State, Iter, NewPos);
954 State = setIteratorPosition(State, RetVal, Postfix ? *Pos : NewPos);
955 C.addTransition(State);
956 }
957}
958
959void IteratorChecker::handleDecrement(CheckerContext &C, const SVal &RetVal,
960 const SVal &Iter, bool Postfix) const {
961 // Decrement the symbolic expressions which represents the position of the
962 // iterator
963 auto State = C.getState();
964 const auto *Pos = getIteratorPosition(State, Iter);
965 if (Pos) {
966 auto &SymMgr = C.getSymbolManager();
967 auto &BVF = SymMgr.getBasicVals();
Adam Baloghd5bd3f62018-12-04 10:27:27 +0000968 const auto NewPos =
969 advancePosition(C, OO_Minus, *Pos,
970 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
Adam Baloghb03ed5e2018-06-28 10:58:53 +0000971 State = setIteratorPosition(State, Iter, NewPos);
972 State = setIteratorPosition(State, RetVal, Postfix ? *Pos : NewPos);
973 C.addTransition(State);
974 }
975}
976
977// This function tells the analyzer's engine that symbols produced by our
978// checker, most notably iterator positions, are relatively small.
979// A distance between items in the container should not be very large.
980// By assuming that it is within around 1/8 of the address space,
981// we can help the analyzer perform operations on these symbols
982// without being afraid of integer overflows.
983// FIXME: Should we provide it as an API, so that all checkers could use it?
984static ProgramStateRef assumeNoOverflow(ProgramStateRef State, SymbolRef Sym,
985 long Scale) {
986 SValBuilder &SVB = State->getStateManager().getSValBuilder();
987 BasicValueFactory &BV = SVB.getBasicValueFactory();
988
989 QualType T = Sym->getType();
990 assert(T->isSignedIntegerOrEnumerationType());
991 APSIntType AT = BV.getAPSIntType(T);
992
993 ProgramStateRef NewState = State;
994
995 llvm::APSInt Max = AT.getMaxValue() / AT.getValue(Scale);
996 SVal IsCappedFromAbove =
997 SVB.evalBinOpNN(State, BO_LE, nonloc::SymbolVal(Sym),
998 nonloc::ConcreteInt(Max), SVB.getConditionType());
999 if (auto DV = IsCappedFromAbove.getAs<DefinedSVal>()) {
1000 NewState = NewState->assume(*DV, true);
1001 if (!NewState)
1002 return State;
1003 }
1004
1005 llvm::APSInt Min = -Max;
1006 SVal IsCappedFromBelow =
1007 SVB.evalBinOpNN(State, BO_GE, nonloc::SymbolVal(Sym),
1008 nonloc::ConcreteInt(Min), SVB.getConditionType());
1009 if (auto DV = IsCappedFromBelow.getAs<DefinedSVal>()) {
1010 NewState = NewState->assume(*DV, true);
1011 if (!NewState)
1012 return State;
1013 }
1014
1015 return NewState;
1016}
1017
1018void IteratorChecker::handleRandomIncrOrDecr(CheckerContext &C,
1019 OverloadedOperatorKind Op,
1020 const SVal &RetVal,
1021 const SVal &LHS,
1022 const SVal &RHS) const {
1023 // Increment or decrement the symbolic expressions which represents the
1024 // position of the iterator
1025 auto State = C.getState();
1026 const auto *Pos = getIteratorPosition(State, LHS);
1027 if (!Pos)
1028 return;
1029
1030 const auto *value = &RHS;
1031 if (auto loc = RHS.getAs<Loc>()) {
1032 const auto val = State->getRawSVal(*loc);
1033 value = &val;
1034 }
1035
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001036 auto &TgtVal = (Op == OO_PlusEqual || Op == OO_MinusEqual) ? LHS : RetVal;
Adam Baloghd5bd3f62018-12-04 10:27:27 +00001037 State =
1038 setIteratorPosition(State, TgtVal, advancePosition(C, Op, *Pos, *value));
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001039 C.addTransition(State);
1040}
1041
Adam Baloghd5bd3f62018-12-04 10:27:27 +00001042void IteratorChecker::verifyIncrement(CheckerContext &C,
1043 const SVal &Iter) const {
1044 auto &BVF = C.getSValBuilder().getBasicValueFactory();
1045 verifyRandomIncrOrDecr(C, OO_Plus, Iter,
1046 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
1047}
1048
1049void IteratorChecker::verifyDecrement(CheckerContext &C,
1050 const SVal &Iter) const {
1051 auto &BVF = C.getSValBuilder().getBasicValueFactory();
1052 verifyRandomIncrOrDecr(C, OO_Minus, Iter,
1053 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
1054}
1055
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001056void IteratorChecker::verifyRandomIncrOrDecr(CheckerContext &C,
1057 OverloadedOperatorKind Op,
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001058 const SVal &LHS,
1059 const SVal &RHS) const {
1060 auto State = C.getState();
1061
1062 // If the iterator is initially inside its range, then the operation is valid
1063 const auto *Pos = getIteratorPosition(State, LHS);
Adam Baloghd5bd3f62018-12-04 10:27:27 +00001064 if (!Pos)
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001065 return;
1066
Adam Baloghd5bd3f62018-12-04 10:27:27 +00001067 auto Value = RHS;
1068 if (auto ValAsLoc = RHS.getAs<Loc>()) {
1069 Value = State->getRawSVal(*ValAsLoc);
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001070 }
1071
Adam Baloghd5bd3f62018-12-04 10:27:27 +00001072 if (Value.isUnknown())
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001073 return;
1074
Adam Baloghd5bd3f62018-12-04 10:27:27 +00001075 // Incremention or decremention by 0 is never a bug.
1076 if (isZero(State, Value.castAs<NonLoc>()))
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001077 return;
1078
Adam Baloghd5bd3f62018-12-04 10:27:27 +00001079 // The result may be the past-end iterator of the container, but any other
1080 // out of range position is undefined behaviour
1081 if (isAheadOfRange(State, advancePosition(C, Op, *Pos, Value))) {
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001082 auto *N = C.generateNonFatalErrorNode(State);
1083 if (!N)
1084 return;
Adam Baloghd5bd3f62018-12-04 10:27:27 +00001085 reportOutOfRangeBug("Iterator decremented ahead of its valid range.", LHS,
1086 C, N);
1087 }
1088 if (isBehindPastTheEnd(State, advancePosition(C, Op, *Pos, Value))) {
1089 auto *N = C.generateNonFatalErrorNode(State);
1090 if (!N)
1091 return;
1092 reportOutOfRangeBug("Iterator incremented behind the past-the-end "
1093 "iterator.", LHS, C, N);
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001094 }
1095}
1096
Adam Balogh2e7cb342018-09-10 09:07:47 +00001097void IteratorChecker::verifyMatch(CheckerContext &C, const SVal &Iter,
1098 const MemRegion *Cont) const {
1099 // Verify match between a container and the container of an iterator
Adam Balogh42d241f2018-12-04 10:22:28 +00001100 Cont = Cont->getMostDerivedObjectRegion();
Adam Balogh2e7cb342018-09-10 09:07:47 +00001101
1102 auto State = C.getState();
1103 const auto *Pos = getIteratorPosition(State, Iter);
1104 if (Pos && Pos->getContainer() != Cont) {
1105 auto *N = C.generateNonFatalErrorNode(State);
1106 if (!N) {
1107 return;
1108 }
1109 reportMismatchedBug("Container accessed using foreign iterator argument.", Iter, Cont, C, N);
1110 }
1111}
1112
Adam Balogh21583b72018-09-10 09:03:22 +00001113void IteratorChecker::verifyMatch(CheckerContext &C, const SVal &Iter1,
1114 const SVal &Iter2) const {
1115 // Verify match between the containers of two iterators
1116 auto State = C.getState();
1117 const auto *Pos1 = getIteratorPosition(State, Iter1);
1118 const auto *Pos2 = getIteratorPosition(State, Iter2);
1119 if (Pos1 && Pos2 && Pos1->getContainer() != Pos2->getContainer()) {
1120 auto *N = C.generateNonFatalErrorNode(State);
1121 if (!N)
1122 return;
1123 reportMismatchedBug("Iterators of different containers used where the "
1124 "same container is expected.", Iter1, Iter2, C, N);
1125 }
1126}
1127
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001128void IteratorChecker::handleBegin(CheckerContext &C, const Expr *CE,
1129 const SVal &RetVal, const SVal &Cont) const {
1130 const auto *ContReg = Cont.getAsRegion();
1131 if (!ContReg)
1132 return;
1133
Adam Balogh42d241f2018-12-04 10:22:28 +00001134 ContReg = ContReg->getMostDerivedObjectRegion();
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001135
1136 // If the container already has a begin symbol then use it. Otherwise first
1137 // create a new one.
1138 auto State = C.getState();
1139 auto BeginSym = getContainerBegin(State, ContReg);
1140 if (!BeginSym) {
1141 auto &SymMgr = C.getSymbolManager();
1142 BeginSym = SymMgr.conjureSymbol(CE, C.getLocationContext(),
1143 C.getASTContext().LongTy, C.blockCount());
1144 State = assumeNoOverflow(State, BeginSym, 4);
1145 State = createContainerBegin(State, ContReg, BeginSym);
1146 }
1147 State = setIteratorPosition(State, RetVal,
1148 IteratorPosition::getPosition(ContReg, BeginSym));
1149 C.addTransition(State);
1150}
1151
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001152void IteratorChecker::handleEnd(CheckerContext &C, const Expr *CE,
1153 const SVal &RetVal, const SVal &Cont) const {
1154 const auto *ContReg = Cont.getAsRegion();
1155 if (!ContReg)
1156 return;
1157
Adam Balogh42d241f2018-12-04 10:22:28 +00001158 ContReg = ContReg->getMostDerivedObjectRegion();
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001159
1160 // If the container already has an end symbol then use it. Otherwise first
1161 // create a new one.
1162 auto State = C.getState();
1163 auto EndSym = getContainerEnd(State, ContReg);
1164 if (!EndSym) {
1165 auto &SymMgr = C.getSymbolManager();
1166 EndSym = SymMgr.conjureSymbol(CE, C.getLocationContext(),
1167 C.getASTContext().LongTy, C.blockCount());
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001168 State = assumeNoOverflow(State, EndSym, 4);
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001169 State = createContainerEnd(State, ContReg, EndSym);
1170 }
1171 State = setIteratorPosition(State, RetVal,
1172 IteratorPosition::getPosition(ContReg, EndSym));
1173 C.addTransition(State);
1174}
1175
1176void IteratorChecker::assignToContainer(CheckerContext &C, const Expr *CE,
1177 const SVal &RetVal,
1178 const MemRegion *Cont) const {
Adam Balogh42d241f2018-12-04 10:22:28 +00001179 Cont = Cont->getMostDerivedObjectRegion();
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001180
1181 auto State = C.getState();
1182 auto &SymMgr = C.getSymbolManager();
1183 auto Sym = SymMgr.conjureSymbol(CE, C.getLocationContext(),
1184 C.getASTContext().LongTy, C.blockCount());
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001185 State = assumeNoOverflow(State, Sym, 4);
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001186 State = setIteratorPosition(State, RetVal,
1187 IteratorPosition::getPosition(Cont, Sym));
1188 C.addTransition(State);
1189}
1190
Adam Balogh6b23b1a2018-09-10 09:04:27 +00001191void IteratorChecker::handleAssign(CheckerContext &C, const SVal &Cont,
1192 const Expr *CE, const SVal &OldCont) const {
Adam Balogh2cfbe932018-08-28 08:41:15 +00001193 const auto *ContReg = Cont.getAsRegion();
1194 if (!ContReg)
1195 return;
1196
Adam Balogh42d241f2018-12-04 10:22:28 +00001197 ContReg = ContReg->getMostDerivedObjectRegion();
Adam Balogh2cfbe932018-08-28 08:41:15 +00001198
1199 // Assignment of a new value to a container always invalidates all its
1200 // iterators
1201 auto State = C.getState();
1202 const auto CData = getContainerData(State, ContReg);
1203 if (CData) {
1204 State = invalidateAllIteratorPositions(State, ContReg);
1205 }
1206
Adam Balogh6b23b1a2018-09-10 09:04:27 +00001207 // In case of move, iterators of the old container (except the past-end
1208 // iterators) remain valid but refer to the new container
1209 if (!OldCont.isUndef()) {
1210 const auto *OldContReg = OldCont.getAsRegion();
1211 if (OldContReg) {
Adam Balogh42d241f2018-12-04 10:22:28 +00001212 OldContReg = OldContReg->getMostDerivedObjectRegion();
Adam Balogh6b23b1a2018-09-10 09:04:27 +00001213 const auto OldCData = getContainerData(State, OldContReg);
1214 if (OldCData) {
1215 if (const auto OldEndSym = OldCData->getEnd()) {
1216 // If we already assigned an "end" symbol to the old conainer, then
1217 // first reassign all iterator positions to the new container which
1218 // are not past the container (thus not greater or equal to the
1219 // current "end" symbol).
1220 State = reassignAllIteratorPositionsUnless(State, OldContReg, ContReg,
1221 OldEndSym, BO_GE);
1222 auto &SymMgr = C.getSymbolManager();
1223 auto &SVB = C.getSValBuilder();
1224 // Then generate and assign a new "end" symbol for the new container.
1225 auto NewEndSym =
1226 SymMgr.conjureSymbol(CE, C.getLocationContext(),
1227 C.getASTContext().LongTy, C.blockCount());
1228 State = assumeNoOverflow(State, NewEndSym, 4);
1229 if (CData) {
1230 State = setContainerData(State, ContReg, CData->newEnd(NewEndSym));
1231 } else {
1232 State = setContainerData(State, ContReg,
1233 ContainerData::fromEnd(NewEndSym));
1234 }
1235 // Finally, replace the old "end" symbol in the already reassigned
1236 // iterator positions with the new "end" symbol.
1237 State = rebaseSymbolInIteratorPositionsIf(
1238 State, SVB, OldEndSym, NewEndSym, OldEndSym, BO_LT);
1239 } else {
1240 // There was no "end" symbol assigned yet to the old container,
1241 // so reassign all iterator positions to the new container.
1242 State = reassignAllIteratorPositions(State, OldContReg, ContReg);
1243 }
1244 if (const auto OldBeginSym = OldCData->getBegin()) {
1245 // If we already assigned a "begin" symbol to the old container, then
1246 // assign it to the new container and remove it from the old one.
1247 if (CData) {
1248 State =
1249 setContainerData(State, ContReg, CData->newBegin(OldBeginSym));
1250 } else {
1251 State = setContainerData(State, ContReg,
1252 ContainerData::fromBegin(OldBeginSym));
1253 }
1254 State =
1255 setContainerData(State, OldContReg, OldCData->newEnd(nullptr));
1256 }
1257 } else {
1258 // There was neither "begin" nor "end" symbol assigned yet to the old
1259 // container, so reassign all iterator positions to the new container.
1260 State = reassignAllIteratorPositions(State, OldContReg, ContReg);
1261 }
1262 }
1263 }
Adam Balogh2cfbe932018-08-28 08:41:15 +00001264 C.addTransition(State);
1265}
1266
Adam Balogh2e7cb342018-09-10 09:07:47 +00001267void IteratorChecker::handleClear(CheckerContext &C, const SVal &Cont) const {
1268 const auto *ContReg = Cont.getAsRegion();
1269 if (!ContReg)
1270 return;
1271
Adam Balogh42d241f2018-12-04 10:22:28 +00001272 ContReg = ContReg->getMostDerivedObjectRegion();
Adam Balogh2e7cb342018-09-10 09:07:47 +00001273
1274 // The clear() operation invalidates all the iterators, except the past-end
1275 // iterators of list-like containers
1276 auto State = C.getState();
1277 if (!hasSubscriptOperator(State, ContReg) ||
1278 !backModifiable(State, ContReg)) {
1279 const auto CData = getContainerData(State, ContReg);
1280 if (CData) {
1281 if (const auto EndSym = CData->getEnd()) {
1282 State =
1283 invalidateAllIteratorPositionsExcept(State, ContReg, EndSym, BO_GE);
1284 C.addTransition(State);
1285 return;
1286 }
1287 }
1288 }
1289 State = invalidateAllIteratorPositions(State, ContReg);
1290 C.addTransition(State);
1291}
1292
Adam Balogh9a48ba62018-09-10 09:06:31 +00001293void IteratorChecker::handlePushBack(CheckerContext &C,
1294 const SVal &Cont) const {
1295 const auto *ContReg = Cont.getAsRegion();
1296 if (!ContReg)
1297 return;
1298
Adam Balogh42d241f2018-12-04 10:22:28 +00001299 ContReg = ContReg->getMostDerivedObjectRegion();
Adam Balogh9a48ba62018-09-10 09:06:31 +00001300
1301 // For deque-like containers invalidate all iterator positions
1302 auto State = C.getState();
1303 if (hasSubscriptOperator(State, ContReg) && frontModifiable(State, ContReg)) {
1304 State = invalidateAllIteratorPositions(State, ContReg);
1305 C.addTransition(State);
1306 return;
1307 }
1308
1309 const auto CData = getContainerData(State, ContReg);
1310 if (!CData)
1311 return;
1312
1313 // For vector-like containers invalidate the past-end iterator positions
1314 if (const auto EndSym = CData->getEnd()) {
1315 if (hasSubscriptOperator(State, ContReg)) {
1316 State = invalidateIteratorPositions(State, EndSym, BO_GE);
1317 }
1318 auto &SymMgr = C.getSymbolManager();
1319 auto &BVF = SymMgr.getBasicVals();
1320 auto &SVB = C.getSValBuilder();
1321 const auto newEndSym =
1322 SVB.evalBinOp(State, BO_Add,
1323 nonloc::SymbolVal(EndSym),
1324 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
1325 SymMgr.getType(EndSym)).getAsSymbol();
1326 State = setContainerData(State, ContReg, CData->newEnd(newEndSym));
1327 }
1328 C.addTransition(State);
1329}
1330
1331void IteratorChecker::handlePopBack(CheckerContext &C, const SVal &Cont) const {
1332 const auto *ContReg = Cont.getAsRegion();
1333 if (!ContReg)
1334 return;
1335
Adam Balogh42d241f2018-12-04 10:22:28 +00001336 ContReg = ContReg->getMostDerivedObjectRegion();
Adam Balogh9a48ba62018-09-10 09:06:31 +00001337
1338 auto State = C.getState();
1339 const auto CData = getContainerData(State, ContReg);
1340 if (!CData)
1341 return;
1342
1343 if (const auto EndSym = CData->getEnd()) {
1344 auto &SymMgr = C.getSymbolManager();
1345 auto &BVF = SymMgr.getBasicVals();
1346 auto &SVB = C.getSValBuilder();
1347 const auto BackSym =
1348 SVB.evalBinOp(State, BO_Sub,
1349 nonloc::SymbolVal(EndSym),
1350 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
1351 SymMgr.getType(EndSym)).getAsSymbol();
1352 // For vector-like and deque-like containers invalidate the last and the
1353 // past-end iterator positions. For list-like containers only invalidate
1354 // the last position
1355 if (hasSubscriptOperator(State, ContReg) &&
1356 backModifiable(State, ContReg)) {
1357 State = invalidateIteratorPositions(State, BackSym, BO_GE);
1358 State = setContainerData(State, ContReg, CData->newEnd(nullptr));
1359 } else {
1360 State = invalidateIteratorPositions(State, BackSym, BO_EQ);
1361 }
1362 auto newEndSym = BackSym;
1363 State = setContainerData(State, ContReg, CData->newEnd(newEndSym));
1364 C.addTransition(State);
1365 }
1366}
1367
1368void IteratorChecker::handlePushFront(CheckerContext &C,
1369 const SVal &Cont) const {
1370 const auto *ContReg = Cont.getAsRegion();
1371 if (!ContReg)
1372 return;
1373
Adam Balogh42d241f2018-12-04 10:22:28 +00001374 ContReg = ContReg->getMostDerivedObjectRegion();
Adam Balogh9a48ba62018-09-10 09:06:31 +00001375
1376 // For deque-like containers invalidate all iterator positions
1377 auto State = C.getState();
1378 if (hasSubscriptOperator(State, ContReg)) {
1379 State = invalidateAllIteratorPositions(State, ContReg);
1380 C.addTransition(State);
1381 } else {
1382 const auto CData = getContainerData(State, ContReg);
1383 if (!CData)
1384 return;
1385
1386 if (const auto BeginSym = CData->getBegin()) {
1387 auto &SymMgr = C.getSymbolManager();
1388 auto &BVF = SymMgr.getBasicVals();
1389 auto &SVB = C.getSValBuilder();
1390 const auto newBeginSym =
1391 SVB.evalBinOp(State, BO_Sub,
1392 nonloc::SymbolVal(BeginSym),
1393 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
1394 SymMgr.getType(BeginSym)).getAsSymbol();
1395 State = setContainerData(State, ContReg, CData->newBegin(newBeginSym));
1396 C.addTransition(State);
1397 }
1398 }
1399}
1400
1401void IteratorChecker::handlePopFront(CheckerContext &C,
1402 const SVal &Cont) const {
1403 const auto *ContReg = Cont.getAsRegion();
1404 if (!ContReg)
1405 return;
1406
Adam Balogh42d241f2018-12-04 10:22:28 +00001407 ContReg = ContReg->getMostDerivedObjectRegion();
Adam Balogh9a48ba62018-09-10 09:06:31 +00001408
1409 auto State = C.getState();
1410 const auto CData = getContainerData(State, ContReg);
1411 if (!CData)
1412 return;
1413
1414 // For deque-like containers invalidate all iterator positions. For list-like
1415 // iterators only invalidate the first position
1416 if (const auto BeginSym = CData->getBegin()) {
1417 if (hasSubscriptOperator(State, ContReg)) {
1418 State = invalidateIteratorPositions(State, BeginSym, BO_LE);
1419 } else {
1420 State = invalidateIteratorPositions(State, BeginSym, BO_EQ);
1421 }
1422 auto &SymMgr = C.getSymbolManager();
1423 auto &BVF = SymMgr.getBasicVals();
1424 auto &SVB = C.getSValBuilder();
1425 const auto newBeginSym =
1426 SVB.evalBinOp(State, BO_Add,
1427 nonloc::SymbolVal(BeginSym),
1428 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
1429 SymMgr.getType(BeginSym)).getAsSymbol();
1430 State = setContainerData(State, ContReg, CData->newBegin(newBeginSym));
1431 C.addTransition(State);
1432 }
1433}
1434
Adam Balogh2e7cb342018-09-10 09:07:47 +00001435void IteratorChecker::handleInsert(CheckerContext &C, const SVal &Iter) const {
1436 auto State = C.getState();
1437 const auto *Pos = getIteratorPosition(State, Iter);
1438 if (!Pos)
1439 return;
1440
1441 // For deque-like containers invalidate all iterator positions. For
1442 // vector-like containers invalidate iterator positions after the insertion.
1443 const auto *Cont = Pos->getContainer();
1444 if (hasSubscriptOperator(State, Cont) && backModifiable(State, Cont)) {
1445 if (frontModifiable(State, Cont)) {
1446 State = invalidateAllIteratorPositions(State, Cont);
1447 } else {
1448 State = invalidateIteratorPositions(State, Pos->getOffset(), BO_GE);
1449 }
1450 if (const auto *CData = getContainerData(State, Cont)) {
1451 if (const auto EndSym = CData->getEnd()) {
1452 State = invalidateIteratorPositions(State, EndSym, BO_GE);
1453 State = setContainerData(State, Cont, CData->newEnd(nullptr));
1454 }
1455 }
1456 C.addTransition(State);
1457 }
1458}
1459
1460void IteratorChecker::handleErase(CheckerContext &C, const SVal &Iter) const {
1461 auto State = C.getState();
1462 const auto *Pos = getIteratorPosition(State, Iter);
1463 if (!Pos)
1464 return;
1465
1466 // For deque-like containers invalidate all iterator positions. For
1467 // vector-like containers invalidate iterator positions at and after the
1468 // deletion. For list-like containers only invalidate the deleted position.
1469 const auto *Cont = Pos->getContainer();
1470 if (hasSubscriptOperator(State, Cont) && backModifiable(State, Cont)) {
1471 if (frontModifiable(State, Cont)) {
1472 State = invalidateAllIteratorPositions(State, Cont);
1473 } else {
1474 State = invalidateIteratorPositions(State, Pos->getOffset(), BO_GE);
1475 }
1476 if (const auto *CData = getContainerData(State, Cont)) {
1477 if (const auto EndSym = CData->getEnd()) {
1478 State = invalidateIteratorPositions(State, EndSym, BO_GE);
1479 State = setContainerData(State, Cont, CData->newEnd(nullptr));
1480 }
1481 }
1482 } else {
1483 State = invalidateIteratorPositions(State, Pos->getOffset(), BO_EQ);
1484 }
1485 C.addTransition(State);
1486}
1487
1488void IteratorChecker::handleErase(CheckerContext &C, const SVal &Iter1,
1489 const SVal &Iter2) const {
1490 auto State = C.getState();
1491 const auto *Pos1 = getIteratorPosition(State, Iter1);
1492 const auto *Pos2 = getIteratorPosition(State, Iter2);
1493 if (!Pos1 || !Pos2)
1494 return;
1495
1496 // For deque-like containers invalidate all iterator positions. For
1497 // vector-like containers invalidate iterator positions at and after the
1498 // deletion range. For list-like containers only invalidate the deleted
1499 // position range [first..last].
1500 const auto *Cont = Pos1->getContainer();
1501 if (hasSubscriptOperator(State, Cont) && backModifiable(State, Cont)) {
1502 if (frontModifiable(State, Cont)) {
1503 State = invalidateAllIteratorPositions(State, Cont);
1504 } else {
1505 State = invalidateIteratorPositions(State, Pos1->getOffset(), BO_GE);
1506 }
1507 if (const auto *CData = getContainerData(State, Cont)) {
1508 if (const auto EndSym = CData->getEnd()) {
1509 State = invalidateIteratorPositions(State, EndSym, BO_GE);
1510 State = setContainerData(State, Cont, CData->newEnd(nullptr));
1511 }
1512 }
1513 } else {
1514 State = invalidateIteratorPositions(State, Pos1->getOffset(), BO_GE,
1515 Pos2->getOffset(), BO_LT);
1516 }
1517 C.addTransition(State);
1518}
1519
1520void IteratorChecker::handleEraseAfter(CheckerContext &C,
1521 const SVal &Iter) const {
1522 auto State = C.getState();
1523 const auto *Pos = getIteratorPosition(State, Iter);
1524 if (!Pos)
1525 return;
1526
1527 // Invalidate the deleted iterator position, which is the position of the
1528 // parameter plus one.
1529 auto &SymMgr = C.getSymbolManager();
1530 auto &BVF = SymMgr.getBasicVals();
1531 auto &SVB = C.getSValBuilder();
1532 const auto NextSym =
1533 SVB.evalBinOp(State, BO_Add,
1534 nonloc::SymbolVal(Pos->getOffset()),
1535 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
1536 SymMgr.getType(Pos->getOffset())).getAsSymbol();
1537 State = invalidateIteratorPositions(State, NextSym, BO_EQ);
1538 C.addTransition(State);
1539}
1540
1541void IteratorChecker::handleEraseAfter(CheckerContext &C, const SVal &Iter1,
1542 const SVal &Iter2) const {
1543 auto State = C.getState();
1544 const auto *Pos1 = getIteratorPosition(State, Iter1);
1545 const auto *Pos2 = getIteratorPosition(State, Iter2);
1546 if (!Pos1 || !Pos2)
1547 return;
1548
1549 // Invalidate the deleted iterator position range (first..last)
1550 State = invalidateIteratorPositions(State, Pos1->getOffset(), BO_GT,
1551 Pos2->getOffset(), BO_LT);
1552 C.addTransition(State);
1553}
1554
Adam Baloghd5bd3f62018-12-04 10:27:27 +00001555IteratorPosition IteratorChecker::advancePosition(CheckerContext &C,
1556 OverloadedOperatorKind Op,
1557 const IteratorPosition &Pos,
1558 const SVal &Distance) const {
1559 auto State = C.getState();
1560 auto &SymMgr = C.getSymbolManager();
1561 auto &SVB = C.getSValBuilder();
1562
1563 assert ((Op == OO_Plus || Op == OO_PlusEqual ||
1564 Op == OO_Minus || Op == OO_MinusEqual) &&
1565 "Advance operator must be one of +, -, += and -=.");
1566 auto BinOp = (Op == OO_Plus || Op == OO_PlusEqual) ? BO_Add : BO_Sub;
1567 if (const auto IntDist = Distance.getAs<nonloc::ConcreteInt>()) {
1568 // For concrete integers we can calculate the new position
1569 return Pos.setTo(SVB.evalBinOp(State, BinOp,
1570 nonloc::SymbolVal(Pos.getOffset()), *IntDist,
1571 SymMgr.getType(Pos.getOffset()))
1572 .getAsSymbol());
1573 } else {
1574 // For other symbols create a new symbol to keep expressions simple
1575 const auto &LCtx = C.getLocationContext();
1576 const auto NewPosSym = SymMgr.conjureSymbol(nullptr, LCtx,
1577 SymMgr.getType(Pos.getOffset()),
1578 C.blockCount());
1579 State = assumeNoOverflow(State, NewPosSym, 4);
1580 return Pos.setTo(NewPosSym);
1581 }
1582}
1583
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001584void IteratorChecker::reportOutOfRangeBug(const StringRef &Message,
1585 const SVal &Val, CheckerContext &C,
1586 ExplodedNode *ErrNode) const {
1587 auto R = llvm::make_unique<BugReport>(*OutOfRangeBugType, Message, ErrNode);
1588 R->markInteresting(Val);
1589 C.emitReport(std::move(R));
1590}
1591
Adam Balogh21583b72018-09-10 09:03:22 +00001592void IteratorChecker::reportMismatchedBug(const StringRef &Message,
1593 const SVal &Val1, const SVal &Val2,
1594 CheckerContext &C,
1595 ExplodedNode *ErrNode) const {
1596 auto R = llvm::make_unique<BugReport>(*MismatchedBugType, Message, ErrNode);
1597 R->markInteresting(Val1);
1598 R->markInteresting(Val2);
1599 C.emitReport(std::move(R));
1600}
1601
Adam Balogh3659f7a2018-09-10 09:05:31 +00001602void IteratorChecker::reportMismatchedBug(const StringRef &Message,
1603 const SVal &Val, const MemRegion *Reg,
1604 CheckerContext &C,
1605 ExplodedNode *ErrNode) const {
1606 auto R = llvm::make_unique<BugReport>(*MismatchedBugType, Message, ErrNode);
1607 R->markInteresting(Val);
1608 R->markInteresting(Reg);
1609 C.emitReport(std::move(R));
1610}
1611
Adam Balogh2cfbe932018-08-28 08:41:15 +00001612void IteratorChecker::reportInvalidatedBug(const StringRef &Message,
1613 const SVal &Val, CheckerContext &C,
1614 ExplodedNode *ErrNode) const {
1615 auto R = llvm::make_unique<BugReport>(*InvalidatedBugType, Message, ErrNode);
1616 R->markInteresting(Val);
1617 C.emitReport(std::move(R));
1618}
1619
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001620namespace {
1621
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001622bool isLess(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2);
Adam Baloghd5bd3f62018-12-04 10:27:27 +00001623bool isGreater(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2);
1624bool isEqual(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2);
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001625bool compare(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2,
1626 BinaryOperator::Opcode Opc);
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001627bool compare(ProgramStateRef State, NonLoc NL1, NonLoc NL2,
1628 BinaryOperator::Opcode Opc);
Adam Balogh9a48ba62018-09-10 09:06:31 +00001629const CXXRecordDecl *getCXXRecordDecl(ProgramStateRef State,
1630 const MemRegion *Reg);
Adam Balogh6b23b1a2018-09-10 09:04:27 +00001631SymbolRef rebaseSymbol(ProgramStateRef State, SValBuilder &SVB, SymbolRef Expr,
1632 SymbolRef OldSym, SymbolRef NewSym);
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001633
1634bool isIteratorType(const QualType &Type) {
1635 if (Type->isPointerType())
1636 return true;
1637
1638 const auto *CRD = Type->getUnqualifiedDesugaredType()->getAsCXXRecordDecl();
1639 return isIterator(CRD);
1640}
1641
1642bool isIterator(const CXXRecordDecl *CRD) {
1643 if (!CRD)
1644 return false;
1645
1646 const auto Name = CRD->getName();
1647 if (!(Name.endswith_lower("iterator") || Name.endswith_lower("iter") ||
1648 Name.endswith_lower("it")))
1649 return false;
1650
1651 bool HasCopyCtor = false, HasCopyAssign = true, HasDtor = false,
1652 HasPreIncrOp = false, HasPostIncrOp = false, HasDerefOp = false;
1653 for (const auto *Method : CRD->methods()) {
1654 if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(Method)) {
1655 if (Ctor->isCopyConstructor()) {
1656 HasCopyCtor = !Ctor->isDeleted() && Ctor->getAccess() == AS_public;
1657 }
1658 continue;
1659 }
1660 if (const auto *Dtor = dyn_cast<CXXDestructorDecl>(Method)) {
1661 HasDtor = !Dtor->isDeleted() && Dtor->getAccess() == AS_public;
1662 continue;
1663 }
1664 if (Method->isCopyAssignmentOperator()) {
1665 HasCopyAssign = !Method->isDeleted() && Method->getAccess() == AS_public;
1666 continue;
1667 }
1668 if (!Method->isOverloadedOperator())
1669 continue;
1670 const auto OPK = Method->getOverloadedOperator();
1671 if (OPK == OO_PlusPlus) {
1672 HasPreIncrOp = HasPreIncrOp || (Method->getNumParams() == 0);
1673 HasPostIncrOp = HasPostIncrOp || (Method->getNumParams() == 1);
1674 continue;
1675 }
1676 if (OPK == OO_Star) {
1677 HasDerefOp = (Method->getNumParams() == 0);
1678 continue;
1679 }
1680 }
1681
1682 return HasCopyCtor && HasCopyAssign && HasDtor && HasPreIncrOp &&
1683 HasPostIncrOp && HasDerefOp;
1684}
1685
Adam Balogh3659f7a2018-09-10 09:05:31 +00001686bool isComparisonOperator(OverloadedOperatorKind OK) {
1687 return OK == OO_EqualEqual || OK == OO_ExclaimEqual || OK == OO_Less ||
1688 OK == OO_LessEqual || OK == OO_Greater || OK == OO_GreaterEqual;
1689}
1690
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001691bool isBeginCall(const FunctionDecl *Func) {
1692 const auto *IdInfo = Func->getIdentifier();
1693 if (!IdInfo)
1694 return false;
1695 return IdInfo->getName().endswith_lower("begin");
1696}
1697
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001698bool isEndCall(const FunctionDecl *Func) {
1699 const auto *IdInfo = Func->getIdentifier();
1700 if (!IdInfo)
1701 return false;
1702 return IdInfo->getName().endswith_lower("end");
1703}
1704
Adam Balogh2e7cb342018-09-10 09:07:47 +00001705bool isAssignCall(const FunctionDecl *Func) {
1706 const auto *IdInfo = Func->getIdentifier();
1707 if (!IdInfo)
1708 return false;
1709 if (Func->getNumParams() > 2)
1710 return false;
1711 return IdInfo->getName() == "assign";
1712}
1713
1714bool isClearCall(const FunctionDecl *Func) {
1715 const auto *IdInfo = Func->getIdentifier();
1716 if (!IdInfo)
1717 return false;
1718 if (Func->getNumParams() > 0)
1719 return false;
1720 return IdInfo->getName() == "clear";
1721}
1722
Adam Balogh9a48ba62018-09-10 09:06:31 +00001723bool isPushBackCall(const FunctionDecl *Func) {
1724 const auto *IdInfo = Func->getIdentifier();
1725 if (!IdInfo)
1726 return false;
1727 if (Func->getNumParams() != 1)
1728 return false;
1729 return IdInfo->getName() == "push_back";
1730}
1731
1732bool isEmplaceBackCall(const FunctionDecl *Func) {
1733 const auto *IdInfo = Func->getIdentifier();
1734 if (!IdInfo)
1735 return false;
1736 if (Func->getNumParams() < 1)
1737 return false;
1738 return IdInfo->getName() == "emplace_back";
1739}
1740
1741bool isPopBackCall(const FunctionDecl *Func) {
1742 const auto *IdInfo = Func->getIdentifier();
1743 if (!IdInfo)
1744 return false;
1745 if (Func->getNumParams() > 0)
1746 return false;
1747 return IdInfo->getName() == "pop_back";
1748}
1749
1750bool isPushFrontCall(const FunctionDecl *Func) {
1751 const auto *IdInfo = Func->getIdentifier();
1752 if (!IdInfo)
1753 return false;
1754 if (Func->getNumParams() != 1)
1755 return false;
1756 return IdInfo->getName() == "push_front";
1757}
1758
1759bool isEmplaceFrontCall(const FunctionDecl *Func) {
1760 const auto *IdInfo = Func->getIdentifier();
1761 if (!IdInfo)
1762 return false;
1763 if (Func->getNumParams() < 1)
1764 return false;
1765 return IdInfo->getName() == "emplace_front";
1766}
1767
1768bool isPopFrontCall(const FunctionDecl *Func) {
1769 const auto *IdInfo = Func->getIdentifier();
1770 if (!IdInfo)
1771 return false;
1772 if (Func->getNumParams() > 0)
1773 return false;
1774 return IdInfo->getName() == "pop_front";
1775}
1776
Adam Balogh2e7cb342018-09-10 09:07:47 +00001777bool isInsertCall(const FunctionDecl *Func) {
1778 const auto *IdInfo = Func->getIdentifier();
1779 if (!IdInfo)
1780 return false;
1781 if (Func->getNumParams() < 2 || Func->getNumParams() > 3)
1782 return false;
1783 if (!isIteratorType(Func->getParamDecl(0)->getType()))
1784 return false;
1785 return IdInfo->getName() == "insert";
1786}
1787
1788bool isEmplaceCall(const FunctionDecl *Func) {
1789 const auto *IdInfo = Func->getIdentifier();
1790 if (!IdInfo)
1791 return false;
1792 if (Func->getNumParams() < 2)
1793 return false;
1794 if (!isIteratorType(Func->getParamDecl(0)->getType()))
1795 return false;
1796 return IdInfo->getName() == "emplace";
1797}
1798
1799bool isEraseCall(const FunctionDecl *Func) {
1800 const auto *IdInfo = Func->getIdentifier();
1801 if (!IdInfo)
1802 return false;
1803 if (Func->getNumParams() < 1 || Func->getNumParams() > 2)
1804 return false;
1805 if (!isIteratorType(Func->getParamDecl(0)->getType()))
1806 return false;
1807 if (Func->getNumParams() == 2 &&
1808 !isIteratorType(Func->getParamDecl(1)->getType()))
1809 return false;
1810 return IdInfo->getName() == "erase";
1811}
1812
1813bool isEraseAfterCall(const FunctionDecl *Func) {
1814 const auto *IdInfo = Func->getIdentifier();
1815 if (!IdInfo)
1816 return false;
1817 if (Func->getNumParams() < 1 || Func->getNumParams() > 2)
1818 return false;
1819 if (!isIteratorType(Func->getParamDecl(0)->getType()))
1820 return false;
1821 if (Func->getNumParams() == 2 &&
1822 !isIteratorType(Func->getParamDecl(1)->getType()))
1823 return false;
1824 return IdInfo->getName() == "erase_after";
1825}
1826
Adam Balogh2cfbe932018-08-28 08:41:15 +00001827bool isAssignmentOperator(OverloadedOperatorKind OK) { return OK == OO_Equal; }
1828
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001829bool isSimpleComparisonOperator(OverloadedOperatorKind OK) {
1830 return OK == OO_EqualEqual || OK == OO_ExclaimEqual;
1831}
1832
Adam Balogh2cfbe932018-08-28 08:41:15 +00001833bool isAccessOperator(OverloadedOperatorKind OK) {
1834 return isDereferenceOperator(OK) || isIncrementOperator(OK) ||
1835 isDecrementOperator(OK) || isRandomIncrOrDecrOperator(OK);
1836}
1837
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001838bool isDereferenceOperator(OverloadedOperatorKind OK) {
1839 return OK == OO_Star || OK == OO_Arrow || OK == OO_ArrowStar ||
1840 OK == OO_Subscript;
1841}
1842
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001843bool isIncrementOperator(OverloadedOperatorKind OK) {
1844 return OK == OO_PlusPlus;
1845}
1846
1847bool isDecrementOperator(OverloadedOperatorKind OK) {
1848 return OK == OO_MinusMinus;
1849}
1850
1851bool isRandomIncrOrDecrOperator(OverloadedOperatorKind OK) {
1852 return OK == OO_Plus || OK == OO_PlusEqual || OK == OO_Minus ||
1853 OK == OO_MinusEqual;
1854}
1855
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001856BinaryOperator::Opcode getOpcode(const SymExpr *SE) {
1857 if (const auto *BSE = dyn_cast<BinarySymExpr>(SE)) {
1858 return BSE->getOpcode();
1859 } else if (const auto *SC = dyn_cast<SymbolConjured>(SE)) {
Henry Wong073d5f02018-03-20 09:27:02 +00001860 const auto *COE = dyn_cast_or_null<CXXOperatorCallExpr>(SC->getStmt());
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001861 if (!COE)
1862 return BO_Comma; // Extremal value, neither EQ nor NE
1863 if (COE->getOperator() == OO_EqualEqual) {
1864 return BO_EQ;
1865 } else if (COE->getOperator() == OO_ExclaimEqual) {
1866 return BO_NE;
1867 }
1868 return BO_Comma; // Extremal value, neither EQ nor NE
1869 }
1870 return BO_Comma; // Extremal value, neither EQ nor NE
1871}
1872
Adam Balogh9a48ba62018-09-10 09:06:31 +00001873bool hasSubscriptOperator(ProgramStateRef State, const MemRegion *Reg) {
1874 const auto *CRD = getCXXRecordDecl(State, Reg);
1875 if (!CRD)
1876 return false;
1877
1878 for (const auto *Method : CRD->methods()) {
1879 if (!Method->isOverloadedOperator())
1880 continue;
1881 const auto OPK = Method->getOverloadedOperator();
1882 if (OPK == OO_Subscript) {
1883 return true;
1884 }
1885 }
1886 return false;
1887}
1888
1889bool frontModifiable(ProgramStateRef State, const MemRegion *Reg) {
1890 const auto *CRD = getCXXRecordDecl(State, Reg);
1891 if (!CRD)
1892 return false;
1893
1894 for (const auto *Method : CRD->methods()) {
1895 if (!Method->getDeclName().isIdentifier())
1896 continue;
1897 if (Method->getName() == "push_front" || Method->getName() == "pop_front") {
1898 return true;
1899 }
1900 }
1901 return false;
1902}
1903
1904bool backModifiable(ProgramStateRef State, const MemRegion *Reg) {
1905 const auto *CRD = getCXXRecordDecl(State, Reg);
1906 if (!CRD)
1907 return false;
1908
1909 for (const auto *Method : CRD->methods()) {
1910 if (!Method->getDeclName().isIdentifier())
1911 continue;
1912 if (Method->getName() == "push_back" || Method->getName() == "pop_back") {
1913 return true;
1914 }
1915 }
1916 return false;
1917}
1918
1919const CXXRecordDecl *getCXXRecordDecl(ProgramStateRef State,
1920 const MemRegion *Reg) {
1921 auto TI = getDynamicTypeInfo(State, Reg);
1922 if (!TI.isValid())
1923 return nullptr;
1924
1925 auto Type = TI.getType();
1926 if (const auto *RefT = Type->getAs<ReferenceType>()) {
1927 Type = RefT->getPointeeType();
1928 }
1929
1930 return Type->getUnqualifiedDesugaredType()->getAsCXXRecordDecl();
1931}
1932
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001933const RegionOrSymbol getRegionOrSymbol(const SVal &Val) {
1934 if (const auto Reg = Val.getAsRegion()) {
1935 return Reg;
1936 } else if (const auto Sym = Val.getAsSymbol()) {
1937 return Sym;
1938 } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
1939 return LCVal->getRegion();
1940 }
1941 return RegionOrSymbol();
1942}
1943
1944const ProgramStateRef processComparison(ProgramStateRef State,
1945 RegionOrSymbol LVal,
1946 RegionOrSymbol RVal, bool Equal) {
1947 const auto *LPos = getIteratorPosition(State, LVal);
1948 const auto *RPos = getIteratorPosition(State, RVal);
1949 if (LPos && !RPos) {
1950 State = adjustIteratorPosition(State, RVal, *LPos, Equal);
1951 } else if (!LPos && RPos) {
1952 State = adjustIteratorPosition(State, LVal, *RPos, Equal);
1953 } else if (LPos && RPos) {
1954 State = relateIteratorPositions(State, *LPos, *RPos, Equal);
1955 }
1956 return State;
1957}
1958
1959const ProgramStateRef saveComparison(ProgramStateRef State,
1960 const SymExpr *Condition, const SVal &LVal,
1961 const SVal &RVal, bool Eq) {
1962 const auto Left = getRegionOrSymbol(LVal);
1963 const auto Right = getRegionOrSymbol(RVal);
1964 if (!Left || !Right)
1965 return State;
1966 return State->set<IteratorComparisonMap>(Condition,
1967 IteratorComparison(Left, Right, Eq));
1968}
1969
1970const IteratorComparison *loadComparison(ProgramStateRef State,
1971 const SymExpr *Condition) {
1972 return State->get<IteratorComparisonMap>(Condition);
1973}
1974
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001975SymbolRef getContainerBegin(ProgramStateRef State, const MemRegion *Cont) {
1976 const auto *CDataPtr = getContainerData(State, Cont);
1977 if (!CDataPtr)
1978 return nullptr;
1979
1980 return CDataPtr->getBegin();
1981}
1982
Artem Dergachev8fa639e2017-05-29 15:03:20 +00001983SymbolRef getContainerEnd(ProgramStateRef State, const MemRegion *Cont) {
1984 const auto *CDataPtr = getContainerData(State, Cont);
1985 if (!CDataPtr)
1986 return nullptr;
1987
1988 return CDataPtr->getEnd();
1989}
1990
Adam Baloghb03ed5e2018-06-28 10:58:53 +00001991ProgramStateRef createContainerBegin(ProgramStateRef State,
1992 const MemRegion *Cont,
1993 const SymbolRef Sym) {
1994 // Only create if it does not exist
1995 const auto *CDataPtr = getContainerData(State, Cont);
1996 if (CDataPtr) {
1997 if (CDataPtr->getBegin()) {
1998 return State;
1999 }
2000 const auto CData = CDataPtr->newBegin(Sym);
2001 return setContainerData(State, Cont, CData);
2002 }
2003 const auto CData = ContainerData::fromBegin(Sym);
2004 return setContainerData(State, Cont, CData);
2005}
2006
Artem Dergachev8fa639e2017-05-29 15:03:20 +00002007ProgramStateRef createContainerEnd(ProgramStateRef State, const MemRegion *Cont,
2008 const SymbolRef Sym) {
2009 // Only create if it does not exist
2010 const auto *CDataPtr = getContainerData(State, Cont);
2011 if (CDataPtr) {
2012 if (CDataPtr->getEnd()) {
2013 return State;
Artem Dergachev8fa639e2017-05-29 15:03:20 +00002014 }
Adam Baloghb03ed5e2018-06-28 10:58:53 +00002015 const auto CData = CDataPtr->newEnd(Sym);
Artem Dergachev8fa639e2017-05-29 15:03:20 +00002016 return setContainerData(State, Cont, CData);
2017 }
Adam Baloghb03ed5e2018-06-28 10:58:53 +00002018 const auto CData = ContainerData::fromEnd(Sym);
2019 return setContainerData(State, Cont, CData);
Artem Dergachev8fa639e2017-05-29 15:03:20 +00002020}
2021
2022const ContainerData *getContainerData(ProgramStateRef State,
2023 const MemRegion *Cont) {
2024 return State->get<ContainerMap>(Cont);
2025}
2026
2027ProgramStateRef setContainerData(ProgramStateRef State, const MemRegion *Cont,
2028 const ContainerData &CData) {
2029 return State->set<ContainerMap>(Cont, CData);
2030}
2031
2032const IteratorPosition *getIteratorPosition(ProgramStateRef State,
2033 const SVal &Val) {
Adam Balogh42d241f2018-12-04 10:22:28 +00002034 if (auto Reg = Val.getAsRegion()) {
2035 Reg = Reg->getMostDerivedObjectRegion();
Artem Dergachev8fa639e2017-05-29 15:03:20 +00002036 return State->get<IteratorRegionMap>(Reg);
2037 } else if (const auto Sym = Val.getAsSymbol()) {
2038 return State->get<IteratorSymbolMap>(Sym);
2039 } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
2040 return State->get<IteratorRegionMap>(LCVal->getRegion());
2041 }
2042 return nullptr;
2043}
2044
2045const IteratorPosition *getIteratorPosition(ProgramStateRef State,
2046 RegionOrSymbol RegOrSym) {
2047 if (RegOrSym.is<const MemRegion *>()) {
Adam Balogh42d241f2018-12-04 10:22:28 +00002048 auto Reg = RegOrSym.get<const MemRegion *>()->getMostDerivedObjectRegion();
2049 return State->get<IteratorRegionMap>(Reg);
Artem Dergachev8fa639e2017-05-29 15:03:20 +00002050 } else if (RegOrSym.is<SymbolRef>()) {
2051 return State->get<IteratorSymbolMap>(RegOrSym.get<SymbolRef>());
2052 }
2053 return nullptr;
2054}
2055
2056ProgramStateRef setIteratorPosition(ProgramStateRef State, const SVal &Val,
2057 const IteratorPosition &Pos) {
Adam Balogh42d241f2018-12-04 10:22:28 +00002058 if (auto Reg = Val.getAsRegion()) {
2059 Reg = Reg->getMostDerivedObjectRegion();
Artem Dergachev8fa639e2017-05-29 15:03:20 +00002060 return State->set<IteratorRegionMap>(Reg, Pos);
2061 } else if (const auto Sym = Val.getAsSymbol()) {
2062 return State->set<IteratorSymbolMap>(Sym, Pos);
2063 } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
2064 return State->set<IteratorRegionMap>(LCVal->getRegion(), Pos);
2065 }
2066 return nullptr;
2067}
2068
2069ProgramStateRef setIteratorPosition(ProgramStateRef State,
2070 RegionOrSymbol RegOrSym,
2071 const IteratorPosition &Pos) {
2072 if (RegOrSym.is<const MemRegion *>()) {
Adam Balogh42d241f2018-12-04 10:22:28 +00002073 auto Reg = RegOrSym.get<const MemRegion *>()->getMostDerivedObjectRegion();
2074 return State->set<IteratorRegionMap>(Reg, Pos);
Artem Dergachev8fa639e2017-05-29 15:03:20 +00002075 } else if (RegOrSym.is<SymbolRef>()) {
2076 return State->set<IteratorSymbolMap>(RegOrSym.get<SymbolRef>(), Pos);
2077 }
2078 return nullptr;
2079}
2080
2081ProgramStateRef removeIteratorPosition(ProgramStateRef State, const SVal &Val) {
Adam Balogh42d241f2018-12-04 10:22:28 +00002082 if (auto Reg = Val.getAsRegion()) {
2083 Reg = Reg->getMostDerivedObjectRegion();
Artem Dergachev8fa639e2017-05-29 15:03:20 +00002084 return State->remove<IteratorRegionMap>(Reg);
2085 } else if (const auto Sym = Val.getAsSymbol()) {
2086 return State->remove<IteratorSymbolMap>(Sym);
2087 } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
2088 return State->remove<IteratorRegionMap>(LCVal->getRegion());
2089 }
2090 return nullptr;
2091}
2092
2093ProgramStateRef adjustIteratorPosition(ProgramStateRef State,
2094 RegionOrSymbol RegOrSym,
2095 const IteratorPosition &Pos,
2096 bool Equal) {
2097 if (Equal) {
2098 return setIteratorPosition(State, RegOrSym, Pos);
2099 } else {
2100 return State;
2101 }
2102}
2103
2104ProgramStateRef relateIteratorPositions(ProgramStateRef State,
2105 const IteratorPosition &Pos1,
2106 const IteratorPosition &Pos2,
2107 bool Equal) {
Artem Dergachev8fa639e2017-05-29 15:03:20 +00002108 auto &SVB = State->getStateManager().getSValBuilder();
Adam Balogh0a7592b2018-07-16 09:27:27 +00002109
2110 // FIXME: This code should be reworked as follows:
2111 // 1. Subtract the operands using evalBinOp().
2112 // 2. Assume that the result doesn't overflow.
2113 // 3. Compare the result to 0.
2114 // 4. Assume the result of the comparison.
Artem Dergachev8fa639e2017-05-29 15:03:20 +00002115 const auto comparison =
2116 SVB.evalBinOp(State, BO_EQ, nonloc::SymbolVal(Pos1.getOffset()),
Adam Balogh0a7592b2018-07-16 09:27:27 +00002117 nonloc::SymbolVal(Pos2.getOffset()),
2118 SVB.getConditionType());
Adam Baloghb03ed5e2018-06-28 10:58:53 +00002119
Adam Balogh0a7592b2018-07-16 09:27:27 +00002120 assert(comparison.getAs<DefinedSVal>() &&
2121 "Symbol comparison must be a `DefinedSVal`");
Adam Baloghb03ed5e2018-06-28 10:58:53 +00002122
Adam Balogh0a7592b2018-07-16 09:27:27 +00002123 auto NewState = State->assume(comparison.castAs<DefinedSVal>(), Equal);
2124 if (const auto CompSym = comparison.getAsSymbol()) {
2125 assert(isa<SymIntExpr>(CompSym) &&
2126 "Symbol comparison must be a `SymIntExpr`");
2127 assert(BinaryOperator::isComparisonOp(
2128 cast<SymIntExpr>(CompSym)->getOpcode()) &&
2129 "Symbol comparison must be a comparison");
2130 return assumeNoOverflow(NewState, cast<SymIntExpr>(CompSym)->getLHS(), 2);
Artem Dergachev8fa639e2017-05-29 15:03:20 +00002131 }
2132
Adam Balogh0a7592b2018-07-16 09:27:27 +00002133 return NewState;
Artem Dergachev8fa639e2017-05-29 15:03:20 +00002134}
2135
Adam Balogha6921202018-07-30 08:52:21 +00002136bool hasLiveIterators(ProgramStateRef State, const MemRegion *Cont) {
2137 auto RegionMap = State->get<IteratorRegionMap>();
2138 for (const auto Reg : RegionMap) {
2139 if (Reg.second.getContainer() == Cont)
2140 return true;
2141 }
2142
2143 auto SymbolMap = State->get<IteratorSymbolMap>();
2144 for (const auto Sym : SymbolMap) {
2145 if (Sym.second.getContainer() == Cont)
2146 return true;
2147 }
2148
2149 return false;
2150}
2151
Adam Balogh21583b72018-09-10 09:03:22 +00002152bool isBoundThroughLazyCompoundVal(const Environment &Env,
2153 const MemRegion *Reg) {
2154 for (const auto Binding: Env) {
2155 if (const auto LCVal = Binding.second.getAs<nonloc::LazyCompoundVal>()) {
2156 if (LCVal->getRegion() == Reg)
2157 return true;
2158 }
2159 }
2160
2161 return false;
2162}
2163
Adam Balogh2cfbe932018-08-28 08:41:15 +00002164template <typename Condition, typename Process>
2165ProgramStateRef processIteratorPositions(ProgramStateRef State, Condition Cond,
2166 Process Proc) {
2167 auto &RegionMapFactory = State->get_context<IteratorRegionMap>();
2168 auto RegionMap = State->get<IteratorRegionMap>();
2169 bool Changed = false;
2170 for (const auto Reg : RegionMap) {
2171 if (Cond(Reg.second)) {
2172 RegionMap = RegionMapFactory.add(RegionMap, Reg.first, Proc(Reg.second));
2173 Changed = true;
2174 }
2175 }
2176
2177 if (Changed)
2178 State = State->set<IteratorRegionMap>(RegionMap);
2179
2180 auto &SymbolMapFactory = State->get_context<IteratorSymbolMap>();
2181 auto SymbolMap = State->get<IteratorSymbolMap>();
2182 Changed = false;
2183 for (const auto Sym : SymbolMap) {
2184 if (Cond(Sym.second)) {
2185 SymbolMap = SymbolMapFactory.add(SymbolMap, Sym.first, Proc(Sym.second));
2186 Changed = true;
2187 }
2188 }
2189
2190 if (Changed)
2191 State = State->set<IteratorSymbolMap>(SymbolMap);
2192
2193 return State;
2194}
2195
2196ProgramStateRef invalidateAllIteratorPositions(ProgramStateRef State,
2197 const MemRegion *Cont) {
2198 auto MatchCont = [&](const IteratorPosition &Pos) {
2199 return Pos.getContainer() == Cont;
2200 };
2201 auto Invalidate = [&](const IteratorPosition &Pos) {
2202 return Pos.invalidate();
2203 };
2204 return processIteratorPositions(State, MatchCont, Invalidate);
2205}
2206
Adam Balogh2e7cb342018-09-10 09:07:47 +00002207ProgramStateRef
2208invalidateAllIteratorPositionsExcept(ProgramStateRef State,
2209 const MemRegion *Cont, SymbolRef Offset,
2210 BinaryOperator::Opcode Opc) {
2211 auto MatchContAndCompare = [&](const IteratorPosition &Pos) {
2212 return Pos.getContainer() == Cont &&
2213 !compare(State, Pos.getOffset(), Offset, Opc);
2214 };
2215 auto Invalidate = [&](const IteratorPosition &Pos) {
2216 return Pos.invalidate();
2217 };
2218 return processIteratorPositions(State, MatchContAndCompare, Invalidate);
2219}
2220
Adam Balogh9a48ba62018-09-10 09:06:31 +00002221ProgramStateRef invalidateIteratorPositions(ProgramStateRef State,
2222 SymbolRef Offset,
2223 BinaryOperator::Opcode Opc) {
2224 auto Compare = [&](const IteratorPosition &Pos) {
2225 return compare(State, Pos.getOffset(), Offset, Opc);
2226 };
2227 auto Invalidate = [&](const IteratorPosition &Pos) {
2228 return Pos.invalidate();
2229 };
2230 return processIteratorPositions(State, Compare, Invalidate);
2231}
2232
Adam Balogh2e7cb342018-09-10 09:07:47 +00002233ProgramStateRef invalidateIteratorPositions(ProgramStateRef State,
2234 SymbolRef Offset1,
2235 BinaryOperator::Opcode Opc1,
2236 SymbolRef Offset2,
2237 BinaryOperator::Opcode Opc2) {
2238 auto Compare = [&](const IteratorPosition &Pos) {
2239 return compare(State, Pos.getOffset(), Offset1, Opc1) &&
2240 compare(State, Pos.getOffset(), Offset2, Opc2);
2241 };
2242 auto Invalidate = [&](const IteratorPosition &Pos) {
2243 return Pos.invalidate();
2244 };
2245 return processIteratorPositions(State, Compare, Invalidate);
2246}
2247
Adam Balogh6b23b1a2018-09-10 09:04:27 +00002248ProgramStateRef reassignAllIteratorPositions(ProgramStateRef State,
2249 const MemRegion *Cont,
2250 const MemRegion *NewCont) {
2251 auto MatchCont = [&](const IteratorPosition &Pos) {
2252 return Pos.getContainer() == Cont;
2253 };
2254 auto ReAssign = [&](const IteratorPosition &Pos) {
2255 return Pos.reAssign(NewCont);
2256 };
2257 return processIteratorPositions(State, MatchCont, ReAssign);
2258}
2259
2260ProgramStateRef reassignAllIteratorPositionsUnless(ProgramStateRef State,
2261 const MemRegion *Cont,
2262 const MemRegion *NewCont,
2263 SymbolRef Offset,
2264 BinaryOperator::Opcode Opc) {
2265 auto MatchContAndCompare = [&](const IteratorPosition &Pos) {
2266 return Pos.getContainer() == Cont &&
2267 !compare(State, Pos.getOffset(), Offset, Opc);
2268 };
2269 auto ReAssign = [&](const IteratorPosition &Pos) {
2270 return Pos.reAssign(NewCont);
2271 };
2272 return processIteratorPositions(State, MatchContAndCompare, ReAssign);
2273}
2274
2275// This function rebases symbolic expression `OldSym + Int` to `NewSym + Int`,
2276// `OldSym - Int` to `NewSym - Int` and `OldSym` to `NewSym` in any iterator
2277// position offsets where `CondSym` is true.
2278ProgramStateRef rebaseSymbolInIteratorPositionsIf(
2279 ProgramStateRef State, SValBuilder &SVB, SymbolRef OldSym,
2280 SymbolRef NewSym, SymbolRef CondSym, BinaryOperator::Opcode Opc) {
2281 auto LessThanEnd = [&](const IteratorPosition &Pos) {
2282 return compare(State, Pos.getOffset(), CondSym, Opc);
2283 };
2284 auto RebaseSymbol = [&](const IteratorPosition &Pos) {
2285 return Pos.setTo(rebaseSymbol(State, SVB, Pos.getOffset(), OldSym,
2286 NewSym));
2287 };
2288 return processIteratorPositions(State, LessThanEnd, RebaseSymbol);
2289}
2290
2291// This function rebases symbolic expression `OldExpr + Int` to `NewExpr + Int`,
2292// `OldExpr - Int` to `NewExpr - Int` and `OldExpr` to `NewExpr` in expression
2293// `OrigExpr`.
2294SymbolRef rebaseSymbol(ProgramStateRef State, SValBuilder &SVB,
2295 SymbolRef OrigExpr, SymbolRef OldExpr,
2296 SymbolRef NewSym) {
2297 auto &SymMgr = SVB.getSymbolManager();
2298 auto Diff = SVB.evalBinOpNN(State, BO_Sub, nonloc::SymbolVal(OrigExpr),
2299 nonloc::SymbolVal(OldExpr),
2300 SymMgr.getType(OrigExpr));
2301
2302 const auto DiffInt = Diff.getAs<nonloc::ConcreteInt>();
2303 if (!DiffInt)
2304 return OrigExpr;
2305
2306 return SVB.evalBinOpNN(State, BO_Add, *DiffInt, nonloc::SymbolVal(NewSym),
2307 SymMgr.getType(OrigExpr)).getAsSymbol();
2308}
2309
Adam Baloghb03ed5e2018-06-28 10:58:53 +00002310bool isZero(ProgramStateRef State, const NonLoc &Val) {
2311 auto &BVF = State->getBasicVals();
2312 return compare(State, Val,
2313 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))),
2314 BO_EQ);
2315}
2316
Adam Baloghd5bd3f62018-12-04 10:27:27 +00002317bool isPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos) {
Artem Dergachev8fa639e2017-05-29 15:03:20 +00002318 const auto *Cont = Pos.getContainer();
2319 const auto *CData = getContainerData(State, Cont);
2320 if (!CData)
2321 return false;
2322
Adam Baloghd5bd3f62018-12-04 10:27:27 +00002323 const auto End = CData->getEnd();
2324 if (End) {
2325 if (isEqual(State, Pos.getOffset(), End)) {
2326 return true;
2327 }
2328 }
2329
2330 return false;
2331}
2332
2333bool isAheadOfRange(ProgramStateRef State, const IteratorPosition &Pos) {
2334 const auto *Cont = Pos.getContainer();
2335 const auto *CData = getContainerData(State, Cont);
2336 if (!CData)
2337 return false;
Artem Dergachev8fa639e2017-05-29 15:03:20 +00002338
Adam Baloghb03ed5e2018-06-28 10:58:53 +00002339 const auto Beg = CData->getBegin();
2340 if (Beg) {
2341 if (isLess(State, Pos.getOffset(), Beg)) {
2342 return true;
2343 }
2344 }
2345
Adam Baloghd5bd3f62018-12-04 10:27:27 +00002346 return false;
2347}
2348
2349bool isBehindPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos) {
2350 const auto *Cont = Pos.getContainer();
2351 const auto *CData = getContainerData(State, Cont);
2352 if (!CData)
2353 return false;
2354
Artem Dergachev8fa639e2017-05-29 15:03:20 +00002355 const auto End = CData->getEnd();
2356 if (End) {
Adam Baloghd5bd3f62018-12-04 10:27:27 +00002357 if (isGreater(State, Pos.getOffset(), End)) {
Artem Dergachev8fa639e2017-05-29 15:03:20 +00002358 return true;
2359 }
2360 }
2361
2362 return false;
2363}
2364
Adam Baloghb03ed5e2018-06-28 10:58:53 +00002365bool isLess(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) {
2366 return compare(State, Sym1, Sym2, BO_LT);
2367}
2368
Adam Baloghd5bd3f62018-12-04 10:27:27 +00002369bool isGreater(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) {
2370 return compare(State, Sym1, Sym2, BO_GT);
2371}
2372
2373bool isEqual(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) {
2374 return compare(State, Sym1, Sym2, BO_EQ);
Artem Dergachev8fa639e2017-05-29 15:03:20 +00002375}
2376
2377bool compare(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2,
2378 BinaryOperator::Opcode Opc) {
Adam Baloghb03ed5e2018-06-28 10:58:53 +00002379 return compare(State, nonloc::SymbolVal(Sym1), nonloc::SymbolVal(Sym2), Opc);
2380}
2381
Adam Balogh9a48ba62018-09-10 09:06:31 +00002382
Adam Baloghb03ed5e2018-06-28 10:58:53 +00002383bool compare(ProgramStateRef State, NonLoc NL1, NonLoc NL2,
2384 BinaryOperator::Opcode Opc) {
2385 auto &SVB = State->getStateManager().getSValBuilder();
Artem Dergachev8fa639e2017-05-29 15:03:20 +00002386
2387 const auto comparison =
Adam Balogh0a7592b2018-07-16 09:27:27 +00002388 SVB.evalBinOp(State, Opc, NL1, NL2, SVB.getConditionType());
Artem Dergachev8fa639e2017-05-29 15:03:20 +00002389
Adam Balogh0a7592b2018-07-16 09:27:27 +00002390 assert(comparison.getAs<DefinedSVal>() &&
2391 "Symbol comparison must be a `DefinedSVal`");
Artem Dergachev8fa639e2017-05-29 15:03:20 +00002392
Adam Balogh0a7592b2018-07-16 09:27:27 +00002393 return !State->assume(comparison.castAs<DefinedSVal>(), false);
Artem Dergachev8fa639e2017-05-29 15:03:20 +00002394}
2395
2396} // namespace
2397
2398#define REGISTER_CHECKER(name) \
2399 void ento::register##name(CheckerManager &Mgr) { \
2400 auto *checker = Mgr.registerChecker<IteratorChecker>(); \
2401 checker->ChecksEnabled[IteratorChecker::CK_##name] = true; \
2402 checker->CheckNames[IteratorChecker::CK_##name] = \
2403 Mgr.getCurrentCheckName(); \
2404 }
2405
2406REGISTER_CHECKER(IteratorRangeChecker)
Adam Balogh21583b72018-09-10 09:03:22 +00002407REGISTER_CHECKER(MismatchedIteratorChecker)
Adam Balogh2cfbe932018-08-28 08:41:15 +00002408REGISTER_CHECKER(InvalidatedIteratorChecker)