Index: include/clang/StaticAnalyzer/Checkers/Checkers.td =================================================================== --- include/clang/StaticAnalyzer/Checkers/Checkers.td +++ include/clang/StaticAnalyzer/Checkers/Checkers.td @@ -284,6 +284,10 @@ HelpText<"Check iterators used past end">, DescFile<"IteratorPastEndChecker.cpp">; +def MismatchedIteratorChecker : Checker<"MismatchedIterator">, + HelpText<"Check iterators used for the wrong container">, + DescFile<"MismatchedIteratorChecker.cpp">; + } // end: "alpha.cplusplus" Index: test/Analysis/Inputs/system-header-simulator-cxx.h =================================================================== --- test/Analysis/Inputs/system-header-simulator-cxx.h +++ test/Analysis/Inputs/system-header-simulator-cxx.h @@ -14,7 +14,8 @@ typedef __iterator iterator; typedef __iterator const_iterator; - __iterator(const Ptr p) : ptr(p) {} + __iterator(const Ptr p): ptr(p) {} + __iterator(const iterator &rhs): ptr(rhs.base()) {} __iterator operator++() { return *this; } __iterator operator++(int) { return *this; } @@ -29,6 +30,7 @@ bool operator!=(const iterator &rhs) const { return ptr != rhs.ptr; } bool operator!=(const const_iterator &rhs) const { return ptr != rhs.ptr; } + const Ptr& base() const { return ptr; } private: Ptr ptr; }; @@ -47,9 +49,13 @@ }; typedef __typeof__(sizeof(int)) size_t; + + template class initializer_list; template class vector { + typedef T value_type; + typedef size_t size_type; typedef __iterator iterator; typedef __iterator const_iterator; @@ -58,6 +64,8 @@ T *_end_of_storage; public: vector() : _start(0), _finish(0), _end_of_storage(0) {} + template + vector(InputIterator first, InputIterator last); ~vector(); size_t size() const { @@ -67,6 +75,22 @@ void push_back(); T pop_back(); + iterator insert(const_iterator position, const value_type& val); + iterator insert(const_iterator position, size_type n, + const value_type& val); + template + iterator insert(const_iterator position, InputIterator first, + InputIterator last); + iterator insert(const_iterator position, value_type&& val); + iterator insert(const_iterator position, initializer_list il); + + iterator erase(const_iterator position); + iterator erase(const_iterator first, const_iterator last); + + template + iterator emplace(const_iterator position, Args&&... args); + + T &operator[](size_t n) { return _start[n]; } @@ -77,8 +101,10 @@ iterator begin() { return iterator(_start); } const_iterator begin() const { return const_iterator(_start); } + const_iterator cbegin() const { return const_iterator(_start); } iterator end() { return iterator(_finish); } const_iterator end() const { return const_iterator(_finish); } + const_iterator cend() const { return const_iterator(_finish); } }; class exception { Index: test/Analysis/diagnostics/explicit-suppression.cpp =================================================================== --- test/Analysis/diagnostics/explicit-suppression.cpp +++ test/Analysis/diagnostics/explicit-suppression.cpp @@ -18,6 +18,6 @@ void testCopyNull(C *I, C *E) { std::copy(I, E, (C *)0); #ifndef SUPPRESSED - // expected-warning@../Inputs/system-header-simulator-cxx.h:191 {{Called C++ object pointer is null}} + // expected-warning@../Inputs/system-header-simulator-cxx.h:217 {{Called C++ object pointer is null}} #endif } Index: test/Analysis/mismatched-iterator.cpp =================================================================== --- /dev/null +++ test/Analysis/mismatched-iterator.cpp @@ -0,0 +1,121 @@ +// RUN: %clang_cc1 -std=c++11 -analyze -analyzer-checker=core,cplusplus,alpha.cplusplus.MismatchedIterator -analyzer-eagerly-assume %s -verify + +#include "Inputs/system-header-simulator-cxx.h" + +void good_insert1(std::vector &v, int n) { + v.insert(v.cbegin(), n); // no-warning +} + + +void good_insert2(std::vector &v, int len, int n) { + v.insert(v.cbegin(), len, n); // no-warning +} + +void good_insert3(std::vector &v1, std::vector &v2) { + v1.insert(v1.cbegin(), v2.cbegin(), v2.cend()); // no-warning +} + +void good_insert4(std::vector &v, int len, int n) { + v.insert(v.cbegin(), {n-1, n, n+1}); // no-warning +} + +void good_insert_find(std::vector &v, int n, int m) { + auto i = std::find(v.begin(), v.end(), n); + v.insert(i, m); // no-warning +} + +void good_erase1(std::vector &v) { + v.erase(v.cbegin()); // no-warning +} + +void good_erase2(std::vector &v) { + v.erase(v.cbegin(), v.cend()); // no-warning +} + +void good_emplace(std::vector &v, int n) { + v.emplace(v.cbegin(), n); // no-warning +} + +void good_ctor(std::vector &v) { + std::vector new_v(v.begin(), v.end()); // no-warning +} + +void good_find(std::vector &v, int n) { + std::find(v.begin(), v.end(), n); // no-warning +} + +void good_find_first_of(std::vector &v1, std::vector &v2) { + std::find_first_of(v1.begin(), v1.end(), v2.begin(), v2.end()); // no-warning +} + +void good_comparison(std::vector &v) { + if (v.begin() == v.end()) {} // no-warning +} + +void bad_insert1(std::vector &v1, std::vector &v2, int n) { + v2.insert(v1.cbegin(), n); // expected-warning{{Iterator access mismatched}} +} + +void bad_insert2(std::vector &v1, std::vector &v2, int len, int n) { + v2.insert(v1.cbegin(), len, n); // expected-warning{{Iterator access mismatched}} +} + +void bad_insert3(std::vector &v1, std::vector &v2) { + v2.insert(v1.cbegin(), v2.cbegin(), v2.cend()); // expected-warning{{Iterator access mismatched}} + v1.insert(v1.cbegin(), v1.cbegin(), v2.cend()); // expected-warning{{Iterator access mismatched}} + v1.insert(v1.cbegin(), v2.cbegin(), v1.cend()); // expected-warning{{Iterator access mismatched}} +} + +void bad_insert4(std::vector &v1, std::vector &v2, int len, int n) { + v2.insert(v1.cbegin(), {n-1, n, n+1}); // expected-warning{{Iterator access mismatched}} +} + +void bad_erase1(std::vector &v1, std::vector &v2) { + v2.erase(v1.cbegin()); // expected-warning{{Iterator access mismatched}} +} + +void bad_erase2(std::vector &v1, std::vector &v2) { + v2.erase(v2.cbegin(), v1.cend()); // expected-warning{{Iterator access mismatched}} + v2.erase(v1.cbegin(), v2.cend()); // expected-warning{{Iterator access mismatched}} + v2.erase(v1.cbegin(), v1.cend()); // expected-warning{{Iterator access mismatched}} +} + +void bad_emplace(std::vector &v1, std::vector &v2, int n) { + v2.emplace(v1.cbegin(), n); // expected-warning{{Iterator access mismatched}} +} + +void bad_ctor(std::vector &v1, std::vector &v2) { + std::vector new_v(v1.begin(), v2.end()); // expected-warning{{Iterator access mismatched}} +} + +void bad_find(std::vector &v1, std::vector &v2, int n) { + std::find(v1.begin(), v2.end(), n); // expected-warning{{Iterator access mismatched}} +} + +void bad_find_first_of(std::vector &v1, std::vector &v2) { + std::find_first_of(v1.begin(), v2.end(), v2.begin(), v2.end()); // expected-warning{{Iterator access mismatched}} + std::find_first_of(v1.begin(), v1.end(), v2.begin(), v1.end()); // expected-warning{{Iterator access mismatched}} +} + +void bad_comparison(std::vector &v1, std::vector &v2) { + if (v1.begin() != v2.end()) { // expected-warning{{Iterator access mismatched}} + *v1.begin(); + } +} + +void bad_insert_find(std::vector &v1, std::vector &v2, int n, int m) { + auto i = std::find(v1.begin(), v1.end(), n); + v2.insert(i, m); // expected-warning{{Iterator access mismatched}} +} + +void good_overwrite(std::vector &v1, std::vector &v2, int n) { + auto i = v1.cbegin(); + i = v2.cbegin(); + v2.insert(i, n); // no-warning +} + +void bad_overwrite(std::vector &v1, std::vector &v2, int n) { + auto i = v1.cbegin(); + i = v2.cbegin(); + v1.insert(i, n); // expected-warning{{Iterator access mismatched}} +}