| 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 | |