1 // RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,alpha.cplusplus.IteratorRange -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=false %s -verify
2 // RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,alpha.cplusplus.IteratorRange -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=true -DINLINE=1 %s -verify
3
4 #include "Inputs/system-header-simulator-cxx.h"
5
6 void clang_analyzer_warnIfReached();
7
simple_good_end(const std::vector<int> & v)8 void simple_good_end(const std::vector<int> &v) {
9 auto i = v.end();
10 if (i != v.end()) {
11 clang_analyzer_warnIfReached();
12 *i; // no-warning
13 }
14 }
15
simple_good_end_negated(const std::vector<int> & v)16 void simple_good_end_negated(const std::vector<int> &v) {
17 auto i = v.end();
18 if (!(i == v.end())) {
19 clang_analyzer_warnIfReached();
20 *i; // no-warning
21 }
22 }
23
simple_bad_end(const std::vector<int> & v)24 void simple_bad_end(const std::vector<int> &v) {
25 auto i = v.end();
26 *i; // expected-warning{{Past-the-end iterator dereferenced}}
27 }
28
copy(const std::vector<int> & v)29 void copy(const std::vector<int> &v) {
30 auto i1 = v.end();
31 auto i2 = i1;
32 *i2; // expected-warning{{Past-the-end iterator dereferenced}}
33 }
34
decrease(const std::vector<int> & v)35 void decrease(const std::vector<int> &v) {
36 auto i = v.end();
37 --i;
38 *i; // no-warning
39 }
40
copy_and_decrease1(const std::vector<int> & v)41 void copy_and_decrease1(const std::vector<int> &v) {
42 auto i1 = v.end();
43 auto i2 = i1;
44 --i1;
45 *i1; // no-warning
46 }
47
copy_and_decrease2(const std::vector<int> & v)48 void copy_and_decrease2(const std::vector<int> &v) {
49 auto i1 = v.end();
50 auto i2 = i1;
51 --i1;
52 *i2; // expected-warning{{Past-the-end iterator dereferenced}}
53 }
54
copy_and_increase1(const std::vector<int> & v)55 void copy_and_increase1(const std::vector<int> &v) {
56 auto i1 = v.begin();
57 auto i2 = i1;
58 ++i1;
59 if (i1 == v.end())
60 *i2; // no-warning
61 }
62
copy_and_increase2(const std::vector<int> & v)63 void copy_and_increase2(const std::vector<int> &v) {
64 auto i1 = v.begin();
65 auto i2 = i1;
66 ++i1;
67 if (i2 == v.end())
68 *i2; // expected-warning{{Past-the-end iterator dereferenced}}
69 }
70
copy_and_increase3(const std::vector<int> & v)71 void copy_and_increase3(const std::vector<int> &v) {
72 auto i1 = v.begin();
73 auto i2 = i1;
74 ++i1;
75 if (v.end() == i2)
76 *i2; // expected-warning{{Past-the-end iterator dereferenced}}
77 }
78
79 template <class InputIterator, class T>
80 InputIterator nonStdFind(InputIterator first, InputIterator last,
81 const T &val) {
82 for (auto i = first; i != last; ++i) {
83 if (*i == val) {
84 return i;
85 }
86 }
87 return last;
88 }
89
good_non_std_find(std::vector<int> & V,int e)90 void good_non_std_find(std::vector<int> &V, int e) {
91 auto first = nonStdFind(V.begin(), V.end(), e);
92 if (V.end() != first)
93 *first; // no-warning
94 }
95
bad_non_std_find(std::vector<int> & V,int e)96 void bad_non_std_find(std::vector<int> &V, int e) {
97 auto first = nonStdFind(V.begin(), V.end(), e);
98 *first; // expected-warning{{Past-the-end iterator dereferenced}}
99 }
100
tricky(std::vector<int> & V,int e)101 void tricky(std::vector<int> &V, int e) {
102 const auto first = V.begin();
103 const auto comp1 = (first != V.end()), comp2 = (first == V.end());
104 if (comp1)
105 *first; // no-warning
106 }
107
loop(std::vector<int> & V,int e)108 void loop(std::vector<int> &V, int e) {
109 auto start = V.begin();
110 while (true) {
111 auto item = std::find(start, V.end(), e);
112 if (item == V.end())
113 break;
114 *item; // no-warning
115 start = ++item; // no-warning
116 }
117 }
118
good_push_back(std::list<int> & L,int n)119 void good_push_back(std::list<int> &L, int n) {
120 auto i0 = --L.cend();
121 L.push_back(n);
122 *++i0; // no-warning
123 }
124
bad_push_back(std::list<int> & L,int n)125 void bad_push_back(std::list<int> &L, int n) {
126 auto i0 = --L.cend();
127 L.push_back(n);
128 ++i0;
129 *++i0; // expected-warning{{Past-the-end iterator dereferenced}}
130 }
131
good_pop_back(std::list<int> & L,int n)132 void good_pop_back(std::list<int> &L, int n) {
133 auto i0 = --L.cend(); --i0;
134 L.pop_back();
135 *i0; // no-warning
136 }
137
bad_pop_back(std::list<int> & L,int n)138 void bad_pop_back(std::list<int> &L, int n) {
139 auto i0 = --L.cend(); --i0;
140 L.pop_back();
141 *++i0; // expected-warning{{Past-the-end iterator dereferenced}}
142 }
143
good_push_front(std::list<int> & L,int n)144 void good_push_front(std::list<int> &L, int n) {
145 auto i0 = L.cbegin();
146 L.push_front(n);
147 *--i0; // no-warning
148 }
149
bad_push_front(std::list<int> & L,int n)150 void bad_push_front(std::list<int> &L, int n) {
151 auto i0 = L.cbegin();
152 L.push_front(n);
153 --i0;
154 --i0; // expected-warning{{Iterator decremented ahead of its valid range}}
155 }
156
good_pop_front(std::list<int> & L,int n)157 void good_pop_front(std::list<int> &L, int n) {
158 auto i0 = ++L.cbegin();
159 L.pop_front();
160 *i0; // no-warning
161 }
162
bad_pop_front(std::list<int> & L,int n)163 void bad_pop_front(std::list<int> &L, int n) {
164 auto i0 = ++L.cbegin();
165 L.pop_front();
166 --i0; // expected-warning{{Iterator decremented ahead of its valid range}}
167 }
168
bad_move(std::list<int> & L1,std::list<int> & L2)169 void bad_move(std::list<int> &L1, std::list<int> &L2) {
170 auto i0 = --L2.cend();
171 L1 = std::move(L2);
172 *++i0; // expected-warning{{Past-the-end iterator dereferenced}}
173 }
174
bad_move_push_back(std::list<int> & L1,std::list<int> & L2,int n)175 void bad_move_push_back(std::list<int> &L1, std::list<int> &L2, int n) {
176 auto i0 = --L2.cend();
177 L2.push_back(n);
178 L1 = std::move(L2);
179 ++i0;
180 *++i0; // expected-warning{{Past-the-end iterator dereferenced}}
181 }
182
good_incr_begin(const std::list<int> & L)183 void good_incr_begin(const std::list<int> &L) {
184 auto i0 = L.begin();
185 ++i0; // no-warning
186 }
187
bad_decr_begin(const std::list<int> & L)188 void bad_decr_begin(const std::list<int> &L) {
189 auto i0 = L.begin();
190 --i0; // expected-warning{{Iterator decremented ahead of its valid range}}
191 }
192
good_decr_end(const std::list<int> & L)193 void good_decr_end(const std::list<int> &L) {
194 auto i0 = L.end();
195 --i0; // no-warning
196 }
197
bad_incr_end(const std::list<int> & L)198 void bad_incr_end(const std::list<int> &L) {
199 auto i0 = L.end();
200 ++i0; // expected-warning{{Iterator incremented behind the past-the-end iterator}}
201 }
202
203 struct simple_iterator_base {
204 simple_iterator_base();
205 simple_iterator_base(const simple_iterator_base& rhs);
206 simple_iterator_base &operator=(const simple_iterator_base& rhs);
207 virtual ~simple_iterator_base();
208 bool friend operator==(const simple_iterator_base &lhs,
209 const simple_iterator_base &rhs);
210 bool friend operator!=(const simple_iterator_base &lhs,
211 const simple_iterator_base &rhs);
212 private:
213 int *ptr;
214 };
215
216 struct simple_derived_iterator: public simple_iterator_base {
217 int& operator*();
218 int* operator->();
219 simple_iterator_base &operator++();
220 simple_iterator_base operator++(int);
221 simple_iterator_base &operator--();
222 simple_iterator_base operator--(int);
223 };
224
225 struct simple_container {
226 typedef simple_derived_iterator iterator;
227
228 iterator begin();
229 iterator end();
230 };
231
good_derived(simple_container c)232 void good_derived(simple_container c) {
233 auto i0 = c.end();
234 if (i0 != c.end()) {
235 clang_analyzer_warnIfReached();
236 *i0; // no-warning
237 }
238 }
239
iter_diff(std::vector<int> & V)240 void iter_diff(std::vector<int> &V) {
241 auto i0 = V.begin(), i1 = V.end();
242 ptrdiff_t len = i1 - i0; // no-crash
243 }
244