This is another partial fix for PR 59170, this time adding checks for normal mode iterators that are default-constructed, so we don't try to dereference null pointers.
We still auto-dereference past-the-end iterators, and iterators that have been invalidated by container mutation. The former can be detected in debug mode (with some work to teach each iterator type how to compare itself to the container's end()) and the latter is already handled for debug mode. Neither case can be derected in normal mode. I feel quite strongly that we should disable the printers for iterators (the ones that make "print iter" automatically dereference the iterator and print what it points to ... or garbage ... or crash). I'm going to add Xmethods for all our iterator types so that it will always be possible to do "print *iter", so if GDB supports Xmethods then we don't need to register the iterator printers. PR libstdc++/59170 * python/libstdcxx/v6/printers.py (StdListIteratorPrinter.to_string) (StdSlistIteratorPrinter.to_string, StdVectorIteratorPrinter.to_string) (StdRbtreeIteratorPrinter.to_string) (StdDequeIteratorPrinter.to_string): Add check for value-initialized iterators. * testsuite/libstdc++-prettyprinters/simple.cc: Test them. * testsuite/libstdc++-prettyprinters/simple11.cc: Likewise. Tested x86_64-linux, committed to trunk.
commit 7b73bc563a5b4828b80e18d34cc06c0cbdae12ef Author: Jonathan Wakely <jwak...@redhat.com> Date: Thu Dec 15 14:05:24 2016 +0000 PR59170 make pretty printers check for singular iterators PR libstdc++/59170 * python/libstdcxx/v6/printers.py (StdListIteratorPrinter.to_string) (StdSlistIteratorPrinter.to_string, StdVectorIteratorPrinter.to_string) (StdRbtreeIteratorPrinter.to_string) (StdDequeIteratorPrinter.to_string): Add check for value-initialized iterators. * testsuite/libstdc++-prettyprinters/simple.cc: Test them. * testsuite/libstdc++-prettyprinters/simple11.cc: Likewise. diff --git a/libstdc++-v3/python/libstdcxx/v6/printers.py b/libstdc++-v3/python/libstdcxx/v6/printers.py index ab3592a..86de1ca 100644 --- a/libstdc++-v3/python/libstdcxx/v6/printers.py +++ b/libstdc++-v3/python/libstdcxx/v6/printers.py @@ -200,6 +200,8 @@ class StdListIteratorPrinter: self.typename = typename def to_string(self): + if not self.val['_M_node']: + return 'non-dereferenceable iterator for std::list' nodetype = find_type(self.val.type, '_Node') nodetype = nodetype.strip_typedefs().pointer() node = self.val['_M_node'].cast(nodetype).dereference() @@ -246,6 +248,8 @@ class StdSlistIteratorPrinter: self.val = val def to_string(self): + if not self.val['_M_node']: + return 'non-dereferenceable iterator for __gnu_cxx::slist' nodetype = find_type(self.val.type, '_Node') nodetype = nodetype.strip_typedefs().pointer() return str(self.val['_M_node'].cast(nodetype).dereference()['_M_data']) @@ -333,6 +337,8 @@ class StdVectorIteratorPrinter: self.val = val def to_string(self): + if not self.val['_M_current']: + return 'non-dereferenceable iterator for std::vector' return str(self.val['_M_current'].dereference()) class StdTuplePrinter: @@ -494,6 +500,8 @@ class StdRbtreeIteratorPrinter: self.link_type = nodetype.strip_typedefs().pointer() def to_string (self): + if not self.val['_M_node']: + return 'non-dereferenceable iterator for associative container' node = self.val['_M_node'].cast(self.link_type).dereference() return str(get_value_from_Rb_tree_node(node)) @@ -708,6 +716,8 @@ class StdDequeIteratorPrinter: self.val = val def to_string(self): + if not self.val['_M_cur']: + return 'non-dereferenceable iterator for std::deque' return str(self.val['_M_cur'].dereference()) class StdStringPrinter: diff --git a/libstdc++-v3/testsuite/libstdc++-prettyprinters/simple.cc b/libstdc++-v3/testsuite/libstdc++-prettyprinters/simple.cc index fb8e0d7..35fbb90 100644 --- a/libstdc++-v3/testsuite/libstdc++-prettyprinters/simple.cc +++ b/libstdc++-v3/testsuite/libstdc++-prettyprinters/simple.cc @@ -30,6 +30,7 @@ #include <list> #include <map> #include <set> +#include <vector> #include <ext/slist> int @@ -50,6 +51,9 @@ main() deq.push_back("two"); // { dg-final { note-test deq {std::deque with 2 elements = {"one", "two"}} } } + std::deque<int>::iterator deqiter0; +// { dg-final { note-test deqiter0 {non-dereferenceable iterator for std::deque} } } + std::deque<std::string>::iterator deqiter = deq.begin(); // { dg-final { note-test deqiter {"one"} } } @@ -58,6 +62,9 @@ main() lst.push_back("two"); // { dg-final { note-test lst {std::list = {[0] = "one", [1] = "two"}} } } + std::list<int>::iterator lstiter0; +// { dg-final { note-test lstiter0 {non-dereferenceable iterator for std::list} } } + std::list<std::string>::iterator lstiter = lst.begin(); tem = *lstiter; // { dg-final { note-test lstiter {"one"}} } @@ -73,6 +80,9 @@ main() std::map<std::string, int>::iterator mpiter = mp.begin(); // { dg-final { note-test mpiter {{first = "zardoz", second = 23}} } } + std::map<std::string, int>::iterator mpiter0; +// { dg-final { note-test mpiter0 {non-dereferenceable iterator for associative container} } } + // PR 67440 std::set<int> intset; intset.insert(2); @@ -88,6 +98,20 @@ main() std::set<std::string>::const_iterator spciter = sp.begin(); // { dg-final { note-test spciter {"barrel"} } } + std::set<int>::iterator spiter0; +// { dg-final { note-test spiter0 {non-dereferenceable iterator for associative container} } } + + std::vector<int> v; + v.push_back(1); + v.push_back(2); + v.erase(v.begin()); +// { dg-final { note-test v {std::vector of length 1, capacity 2 = {2}} } } + std::vector<int>::iterator viter3 = v.begin(); +// { dg-final { note-test viter3 {2} } } + + std::vector<int>::iterator viter0; +// { dg-final { note-test viter0 {non-dereferenceable iterator for std::vector} } } + __gnu_cxx::slist<int> sll; sll.push_front(23); sll.push_front(47); @@ -96,6 +120,9 @@ main() __gnu_cxx::slist<int>::iterator slliter = sll.begin(); // { dg-final { note-test slliter {47} } } + __gnu_cxx::slist<int>::iterator slliter0; +// { dg-final { note-test slliter0 {non-dereferenceable iterator for __gnu_cxx::slist} } } + std::cout << "\n"; return 0; // Mark SPOT } diff --git a/libstdc++-v3/testsuite/libstdc++-prettyprinters/simple11.cc b/libstdc++-v3/testsuite/libstdc++-prettyprinters/simple11.cc index 9e230e3..8efe00e 100644 --- a/libstdc++-v3/testsuite/libstdc++-prettyprinters/simple11.cc +++ b/libstdc++-v3/testsuite/libstdc++-prettyprinters/simple11.cc @@ -30,6 +30,7 @@ #include <list> #include <map> #include <set> +#include <vector> #include <ext/slist> int @@ -53,6 +54,9 @@ main() std::deque<std::string>::iterator deqiter = deq.begin(); // { dg-final { note-test deqiter {"one"} } } + std::deque<int>::iterator deqiter0; +// { dg-final { note-test deqiter0 {non-dereferenceable iterator for std::deque} } } + std::list<std::string> lst; lst.push_back("one"); lst.push_back("two"); @@ -66,6 +70,9 @@ main() tem = *lstciter; // { dg-final { note-test lstciter {"one"}} } + std::list<int>::iterator lstiter0; +// { dg-final { note-test lstiter0 {non-dereferenceable iterator for std::list} } } + std::map<std::string, int> mp; mp["zardoz"] = 23; // { dg-final { note-test mp {std::map with 1 element = {["zardoz"] = 23}} } } @@ -73,6 +80,9 @@ main() std::map<std::string, int>::iterator mpiter = mp.begin(); // { dg-final { note-test mpiter {{first = "zardoz", second = 23}} } } + std::map<std::string, int>::iterator mpiter0; +// { dg-final { note-test mpiter0 {non-dereferenceable iterator for associative container} } } + // PR 67440 const std::set<int> const_intset = {2, 3}; // { dg-final { note-test const_intset {std::set with 2 elements = {[0] = 2, [1] = 3}} } } @@ -85,6 +95,20 @@ main() std::set<std::string>::const_iterator spciter = sp.begin(); // { dg-final { note-test spciter {"barrel"} } } + std::set<int>::iterator spiter0; +// { dg-final { note-test spiter0 {non-dereferenceable iterator for associative container} } } + + std::vector<int> v; + v.push_back(1); + v.push_back(2); + v.erase(v.begin()); +// { dg-final { note-test v {std::vector of length 1, capacity 2 = {2}} } } + std::vector<int>::iterator viter3 = v.begin(); +// { dg-final { note-test viter3 {2} } } + + std::vector<int>::iterator viter0; +// { dg-final { note-test viter0 {non-dereferenceable iterator for std::vector} } } + __gnu_cxx::slist<int> sll; sll.push_front(23); sll.push_front(47); @@ -93,6 +117,9 @@ main() __gnu_cxx::slist<int>::iterator slliter = sll.begin(); // { dg-final { note-test slliter {47} } } + __gnu_cxx::slist<int>::iterator slliter0; +// { dg-final { note-test slliter0 {non-dereferenceable iterator for __gnu_cxx::slist} } } + std::cout << "\n"; return 0; // Mark SPOT }