llvm-project/clang/test/Analysis/iterator-range.cpp
Adam Balogh 12f5c7f0c3 [Analyzer] Iterator Checkers - Make range errors and invalidated access fatal
Range errors (dereferencing or incrementing the past-the-end iterator or
decrementing the iterator of the first element of the range) and access of
invalidated iterators lead to undefined behavior. There is no point to
continue the analysis after such an error on the same execution path, but
terminate it by a sink node (fatal error). This also improves the
performance and helps avoiding double reports (e.g. in case of nested
iterators).

Differential Revision: https://reviews.llvm.org/D62893

llvm-svn: 370314
2019-08-29 09:35:47 +00:00

245 lines
6.1 KiB
C++

// 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
// 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
#include "Inputs/system-header-simulator-cxx.h"
void clang_analyzer_warnIfReached();
void simple_good_end(const std::vector<int> &v) {
auto i = v.end();
if (i != v.end()) {
clang_analyzer_warnIfReached();
*i; // no-warning
}
}
void simple_good_end_negated(const std::vector<int> &v) {
auto i = v.end();
if (!(i == v.end())) {
clang_analyzer_warnIfReached();
*i; // no-warning
}
}
void simple_bad_end(const std::vector<int> &v) {
auto i = v.end();
*i; // expected-warning{{Past-the-end iterator dereferenced}}
clang_analyzer_warnIfReached();
}
void copy(const std::vector<int> &v) {
auto i1 = v.end();
auto i2 = i1;
*i2; // expected-warning{{Past-the-end iterator dereferenced}}
}
void decrease(const std::vector<int> &v) {
auto i = v.end();
--i;
*i; // no-warning
}
void copy_and_decrease1(const std::vector<int> &v) {
auto i1 = v.end();
auto i2 = i1;
--i1;
*i1; // no-warning
}
void copy_and_decrease2(const std::vector<int> &v) {
auto i1 = v.end();
auto i2 = i1;
--i1;
*i2; // expected-warning{{Past-the-end iterator dereferenced}}
}
void copy_and_increase1(const std::vector<int> &v) {
auto i1 = v.begin();
auto i2 = i1;
++i1;
if (i1 == v.end())
*i2; // no-warning
}
void copy_and_increase2(const std::vector<int> &v) {
auto i1 = v.begin();
auto i2 = i1;
++i1;
if (i2 == v.end())
*i2; // expected-warning{{Past-the-end iterator dereferenced}}
}
void copy_and_increase3(const std::vector<int> &v) {
auto i1 = v.begin();
auto i2 = i1;
++i1;
if (v.end() == i2)
*i2; // expected-warning{{Past-the-end iterator dereferenced}}
}
template <class InputIterator, class T>
InputIterator nonStdFind(InputIterator first, InputIterator last,
const T &val) {
for (auto i = first; i != last; ++i) {
if (*i == val) {
return i;
}
}
return last;
}
void good_non_std_find(std::vector<int> &V, int e) {
auto first = nonStdFind(V.begin(), V.end(), e);
if (V.end() != first)
*first; // no-warning
}
void bad_non_std_find(std::vector<int> &V, int e) {
auto first = nonStdFind(V.begin(), V.end(), e);
*first; // expected-warning{{Past-the-end iterator dereferenced}}
}
void tricky(std::vector<int> &V, int e) {
const auto first = V.begin();
const auto comp1 = (first != V.end()), comp2 = (first == V.end());
if (comp1)
*first; // no-warning
}
void loop(std::vector<int> &V, int e) {
auto start = V.begin();
while (true) {
auto item = std::find(start, V.end(), e);
if (item == V.end())
break;
*item; // no-warning
start = ++item; // no-warning
}
}
void good_push_back(std::list<int> &L, int n) {
auto i0 = --L.cend();
L.push_back(n);
*++i0; // no-warning
}
void bad_push_back(std::list<int> &L, int n) {
auto i0 = --L.cend();
L.push_back(n);
++i0;
*++i0; // expected-warning{{Past-the-end iterator dereferenced}}
}
void good_pop_back(std::list<int> &L, int n) {
auto i0 = --L.cend(); --i0;
L.pop_back();
*i0; // no-warning
}
void bad_pop_back(std::list<int> &L, int n) {
auto i0 = --L.cend(); --i0;
L.pop_back();
*++i0; // expected-warning{{Past-the-end iterator dereferenced}}
}
void good_push_front(std::list<int> &L, int n) {
auto i0 = L.cbegin();
L.push_front(n);
*--i0; // no-warning
}
void bad_push_front(std::list<int> &L, int n) {
auto i0 = L.cbegin();
L.push_front(n);
--i0;
--i0; // expected-warning{{Iterator decremented ahead of its valid range}}
}
void good_pop_front(std::list<int> &L, int n) {
auto i0 = ++L.cbegin();
L.pop_front();
*i0; // no-warning
}
void bad_pop_front(std::list<int> &L, int n) {
auto i0 = ++L.cbegin();
L.pop_front();
--i0; // expected-warning{{Iterator decremented ahead of its valid range}}
}
void bad_move(std::list<int> &L1, std::list<int> &L2) {
auto i0 = --L2.cend();
L1 = std::move(L2);
*++i0; // expected-warning{{Past-the-end iterator dereferenced}}
}
void bad_move_push_back(std::list<int> &L1, std::list<int> &L2, int n) {
auto i0 = --L2.cend();
L2.push_back(n);
L1 = std::move(L2);
++i0;
*++i0; // expected-warning{{Past-the-end iterator dereferenced}}
}
void good_incr_begin(const std::list<int> &L) {
auto i0 = L.begin();
++i0; // no-warning
}
void bad_decr_begin(const std::list<int> &L) {
auto i0 = L.begin();
--i0; // expected-warning{{Iterator decremented ahead of its valid range}}
}
void good_decr_end(const std::list<int> &L) {
auto i0 = L.end();
--i0; // no-warning
}
void bad_incr_end(const std::list<int> &L) {
auto i0 = L.end();
++i0; // expected-warning{{Iterator incremented behind the past-the-end iterator}}
}
struct simple_iterator_base {
simple_iterator_base();
simple_iterator_base(const simple_iterator_base& rhs);
simple_iterator_base &operator=(const simple_iterator_base& rhs);
virtual ~simple_iterator_base();
bool friend operator==(const simple_iterator_base &lhs,
const simple_iterator_base &rhs);
bool friend operator!=(const simple_iterator_base &lhs,
const simple_iterator_base &rhs);
private:
int *ptr;
};
struct simple_derived_iterator: public simple_iterator_base {
int& operator*();
int* operator->();
simple_iterator_base &operator++();
simple_iterator_base operator++(int);
simple_iterator_base &operator--();
simple_iterator_base operator--(int);
};
struct simple_container {
typedef simple_derived_iterator iterator;
iterator begin();
iterator end();
};
void good_derived(simple_container c) {
auto i0 = c.end();
if (i0 != c.end()) {
clang_analyzer_warnIfReached();
*i0; // no-warning
}
}
void iter_diff(std::vector<int> &V) {
auto i0 = V.begin(), i1 = V.end();
ptrdiff_t len = i1 - i0; // no-crash
}