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