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 } 28 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 35 void decrease(const std::vector<int> &v) { 36 auto i = v.end(); 37 --i; 38 *i; // no-warning 39 } 40 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 183 void good_incr_begin(const std::list<int> &L) { 184 auto i0 = L.begin(); 185 ++i0; // no-warning 186 } 187 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 193 void good_decr_end(const std::list<int> &L) { 194 auto i0 = L.end(); 195 --i0; // no-warning 196 } 197 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 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