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