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{{Iterator accessed outside of its range}}
27 }
28 
29 void simple_good_begin(const std::vector<int> &v) {
30   auto i = v.begin();
31   if (i != v.begin()) {
32     clang_analyzer_warnIfReached();
33     *--i; // no-warning
34   }
35 }
36 
37 void simple_good_begin_negated(const std::vector<int> &v) {
38   auto i = v.begin();
39   if (!(i == v.begin())) {
40     clang_analyzer_warnIfReached();
41     *--i; // no-warning
42   }
43 }
44 
45 void simple_bad_begin(const std::vector<int> &v) {
46   auto i = v.begin();
47   *--i; // expected-warning{{Iterator accessed outside of its range}}
48 }
49 
50 void copy(const std::vector<int> &v) {
51   auto i1 = v.end();
52   auto i2 = i1;
53   *i2; // expected-warning{{Iterator accessed outside of its range}}
54 }
55 
56 void decrease(const std::vector<int> &v) {
57   auto i = v.end();
58   --i;
59   *i; // no-warning
60 }
61 
62 void copy_and_decrease1(const std::vector<int> &v) {
63   auto i1 = v.end();
64   auto i2 = i1;
65   --i1;
66   *i1; // no-warning
67 }
68 
69 void copy_and_decrease2(const std::vector<int> &v) {
70   auto i1 = v.end();
71   auto i2 = i1;
72   --i1;
73   *i2; // expected-warning{{Iterator accessed outside of its range}}
74 }
75 
76 void copy_and_increase1(const std::vector<int> &v) {
77   auto i1 = v.begin();
78   auto i2 = i1;
79   ++i1;
80   if (i1 == v.end())
81     *i2; // no-warning
82 }
83 
84 void copy_and_increase2(const std::vector<int> &v) {
85   auto i1 = v.begin();
86   auto i2 = i1;
87   ++i1;
88   if (i2 == v.end())
89     *i2; // expected-warning{{Iterator accessed outside of its range}}
90 }
91 
92 void copy_and_increase3(const std::vector<int> &v) {
93   auto i1 = v.begin();
94   auto i2 = i1;
95   ++i1;
96   if (v.end() == i2)
97     *i2; // expected-warning{{Iterator accessed outside of its range}}
98 }
99 
100 template <class InputIterator, class T>
101 InputIterator nonStdFind(InputIterator first, InputIterator last,
102                          const T &val) {
103   for (auto i = first; i != last; ++i) {
104     if (*i == val) {
105       return i;
106     }
107   }
108   return last;
109 }
110 
111 void good_non_std_find(std::vector<int> &V, int e) {
112   auto first = nonStdFind(V.begin(), V.end(), e);
113   if (V.end() != first)
114     *first; // no-warning
115 }
116 
117 void bad_non_std_find(std::vector<int> &V, int e) {
118   auto first = nonStdFind(V.begin(), V.end(), e);
119   *first; // expected-warning{{Iterator accessed outside of its range}}
120 }
121 
122 void tricky(std::vector<int> &V, int e) {
123   const auto first = V.begin();
124   const auto comp1 = (first != V.end()), comp2 = (first == V.end());
125   if (comp1)
126     *first;
127 }
128 
129 void loop(std::vector<int> &V, int e) {
130   auto start = V.begin();
131   while (true) {
132     auto item = std::find(start, V.end(), e);
133     if (item == V.end())
134       break;
135     *item;          // no-warning
136     start = ++item; // no-warning
137   }
138 }
139 
140 void good_push_back(std::list<int> &L, int n) {
141   auto i0 = --L.cend();
142   L.push_back(n);
143   *++i0; // no-warning
144 }
145 
146 void bad_push_back(std::list<int> &L, int n) {
147   auto i0 = --L.cend();
148   L.push_back(n);
149   ++i0;
150   *++i0; // expected-warning{{Iterator accessed outside of its range}}
151 }
152 
153 void good_pop_back(std::list<int> &L, int n) {
154   auto i0 = --L.cend(); --i0;
155   L.pop_back();
156   *i0; // no-warning
157 }
158 
159 void bad_pop_back(std::list<int> &L, int n) {
160   auto i0 = --L.cend(); --i0;
161   L.pop_back();
162   *++i0; // expected-warning{{Iterator accessed outside of its range}}
163 }
164 
165 void good_push_front(std::list<int> &L, int n) {
166   auto i0 = L.cbegin();
167   L.push_front(n);
168   *--i0; // no-warning
169 }
170 
171 void bad_push_front(std::list<int> &L, int n) {
172   auto i0 = L.cbegin();
173   L.push_front(n);
174   --i0;
175   *--i0; // expected-warning{{Iterator accessed outside of its range}}
176 }
177 
178 void good_pop_front(std::list<int> &L, int n) {
179   auto i0 = ++L.cbegin();
180   L.pop_front();
181   *i0; // no-warning
182 }
183 
184 void bad_pop_front(std::list<int> &L, int n) {
185   auto i0 = ++L.cbegin();
186   L.pop_front();
187   *--i0; // expected-warning{{Iterator accessed outside of its range}}
188 }
189 
190 void bad_move(std::list<int> &L1, std::list<int> &L2) {
191   auto i0 = --L2.cend();
192   L1 = std::move(L2);
193   *++i0; // expected-warning{{Iterator accessed outside of its range}}
194 }
195 
196 void bad_move_push_back(std::list<int> &L1, std::list<int> &L2, int n) {
197   auto i0 = --L2.cend();
198   L2.push_back(n);
199   L1 = std::move(L2);
200   ++i0;
201   *++i0; // expected-warning{{Iterator accessed outside of its range}}
202 }
203