Re: [PATCH] PR59170 make pretty printers check for singular iterators
On Fri, 16 Dec 2016 14:17:32 +0100, Jonathan Wakely wrote: > On 16/12/16 14:06 +0100, Jan Kratochvil wrote: > > (gdb) p bb.c.d > > $4 = (D &) @0x601028: {e = 0x601060 } > > Wat? > > bb.c.d is not a valid expression. > > B::c is a pointer, it should be bb.c->d > > Is it GDB policy to make invalid expressions like that "work"? Yes, this is a GDB extension from the times of plain C. In C++ it became a problem. That was not the topic of this example for the initial dereferencing operator. > I had no idea this even worked, I'd have used bb.c->d.e->i because > that's the correct expression for accessing that variable. There was a plan to make the 'compile' project backward compatible with these confusing GDB universal dot operators. Jan
Re: [PATCH] PR59170 make pretty printers check for singular iterators
On 16/12/16 14:06 +0100, Jan Kratochvil wrote: On Fri, 16 Dec 2016 13:33:52 +0100, Jonathan Wakely wrote: We don't do auto-deref for std::shared_ptr or std::unique_ptr, even though we know the object they point to definitely is live and safe to access, and that's because those types have pointer semantics not reference semantics. This is wrong std::shared_ptr or std::unique_ptr is not auto-dereferenced for GDB printing. But it may be more a GDB problem, not libstdc++ pretty printers problem. For example glib pretty printers already auto-dereference data structures: 5 GList* list = NULL; (gdb) p/r list $1 = (GList *) 0x607a00 (gdb) p list $2 = 0x607a00 = {0x400810} /usr/share/glib-2.0/gdb/glib.py if type.code == gdb.TYPE_CODE_PTR: type = type.target().unqualified() t = str(type) if t == "GList": return GListPrinter(val, "GList") But that is more a GDB bug that should be solved even for generic pointers. Currently while traversing through data structures one has to randomly add or remove '*' from the beginning of the GDB print expression: 1 class E { int a[1000]; int i=42; } ee; 2 class D { E *e= } dd; 3 class C { D =dd; } cc; 4 class B { C *c= } bb; 5 int main() {} (gdb) p bb $1 = {c = 0x601030 } (gdb) p bb.c $2 = (C *) 0x601030 Oops, I need to add a dereference: (gdb) p *bb.c $3 = {d = @0x601028} (gdb) p *bb.c.d No symbol "operator*" in current context. Oops, I need to remove a dereference: (gdb) p bb.c.d $4 = (D &) @0x601028: {e = 0x601060 } Wat? bb.c.d is not a valid expression. B::c is a pointer, it should be bb.c->d Is it GDB policy to make invalid expressions like that "work"? Because I'm not comfortable emulating that in the libstdc++ printers. (gdb) p bb.c.d.e $5 = (E *) 0x601060 Oops, I need to add a dereference: (gdb) p *bb.c.d.e $6 = {a = {0 }, i = 42} (gdb) p *bb.c.d.e.i Cannot access memory at address 0x2a Oops, I need to remove a dereference: (gdb) p bb.c.d.e.i $7 = 42 I had no idea this even worked, I'd have used bb.c->d.e->i because that's the correct expression for accessing that variable.
Re: [PATCH] PR59170 make pretty printers check for singular iterators
On Fri, 16 Dec 2016 13:33:52 +0100, Jonathan Wakely wrote: > We don't do auto-deref for std::shared_ptr or std::unique_ptr, even > though we know the object they point to definitely is live and safe to > access, and that's because those types have pointer semantics not > reference semantics. This is wrong std::shared_ptr or std::unique_ptr is not auto-dereferenced for GDB printing. But it may be more a GDB problem, not libstdc++ pretty printers problem. For example glib pretty printers already auto-dereference data structures: 5 GList* list = NULL; (gdb) p/r list $1 = (GList *) 0x607a00 (gdb) p list $2 = 0x607a00 = {0x400810} /usr/share/glib-2.0/gdb/glib.py if type.code == gdb.TYPE_CODE_PTR: type = type.target().unqualified() t = str(type) if t == "GList": return GListPrinter(val, "GList") But that is more a GDB bug that should be solved even for generic pointers. Currently while traversing through data structures one has to randomly add or remove '*' from the beginning of the GDB print expression: 1 class E { int a[1000]; int i=42; } ee; 2 class D { E *e= } dd; 3 class C { D =dd; } cc; 4 class B { C *c= } bb; 5 int main() {} (gdb) p bb $1 = {c = 0x601030 } (gdb) p bb.c $2 = (C *) 0x601030 Oops, I need to add a dereference: (gdb) p *bb.c $3 = {d = @0x601028} (gdb) p *bb.c.d No symbol "operator*" in current context. Oops, I need to remove a dereference: (gdb) p bb.c.d $4 = (D &) @0x601028: {e = 0x601060 } (gdb) p bb.c.d.e $5 = (E *) 0x601060 Oops, I need to add a dereference: (gdb) p *bb.c.d.e $6 = {a = {0 }, i = 42} (gdb) p *bb.c.d.e.i Cannot access memory at address 0x2a Oops, I need to remove a dereference: (gdb) p bb.c.d.e.i $7 = 42 This is probably solved in some clickable front-end interfaces. Jan
Re: [PATCH] PR59170 make pretty printers check for singular iterators
On 16/12/16 08:51 +0100, Jan Kratochvil wrote: On Fri, 16 Dec 2016 02:07:07 +0100, Jonathan Wakely wrote: On 15/12/16 22:19 +0100, Jan Kratochvil wrote: > Just with the GDB 'compile' project (libcc1) which is planned to be used for > all GDB expressions evalation the Xmethods will no longer work. But then *it can just get compiled, so it will still work, right? The only reason it doesn't work today is that the definition for operator* might not be in the executable, but if you can compile a new definition that doesn't matter. Currently it cannot as the source for gcc (via libcc1) is (re)generated from DWARF. Currently GDB does not provide original sources as a context for the compiled expression. Then maybe Xmethods should continue to work ;-) The reason I'm so strongly against auto-dereferencing iterators is that it's inconsistent, and dangerous. It only happens for *some* iterators, the small set of containers from the C++03 std::lib that we have printers for, and not for other iterators (such as pointers, or iterators from C++11 containers, or user-defined iterators). It's fundamentally wrong. An iterator is not the value it points at, because it might not even point at anything (it could have a garbage pointer that points to deallocated memory, or be past-the-end, which isn't detectable in general, or perform some additional work to obtain a value, like reverse_iterator does). We don't do auto-deref for std::shared_ptr or std::unique_ptr, even though we know the object they point to definitely is live and safe to access, and that's because those types have pointer semantics not reference semantics. Like iterators. And if we can make 'print *it' always work then we don't need that inconsistent auto-deref behaviour. It's up to the person driving GDB to decide whether to try and dereference an iterator, we don't make that decision for them. Besides that there is a C++17 modules feature which should solve that for LLDB as pointed out by Pedro before: http://lists.llvm.org/pipermail/lldb-dev/2016-August/010870.html Unaware if/when GDB 'compile' will handle C++ modules as a sources substitute or if/when it will do the original source recompilation. I think we're still a long way from being able to rely on that in the GNU toolchain.
Re: [PATCH] PR59170 make pretty printers check for singular iterators
On Fri, 16 Dec 2016 02:07:07 +0100, Jonathan Wakely wrote: > On 15/12/16 22:19 +0100, Jan Kratochvil wrote: > > Just with the GDB 'compile' project (libcc1) which is planned to be used for > > all GDB expressions evalation the Xmethods will no longer work. > > But then *it can just get compiled, so it will still work, right? > > The only reason it doesn't work today is that the definition for > operator* might not be in the executable, but if you can compile a new > definition that doesn't matter. Currently it cannot as the source for gcc (via libcc1) is (re)generated from DWARF. Currently GDB does not provide original sources as a context for the compiled expression. Besides that there is a C++17 modules feature which should solve that for LLDB as pointed out by Pedro before: http://lists.llvm.org/pipermail/lldb-dev/2016-August/010870.html Unaware if/when GDB 'compile' will handle C++ modules as a sources substitute or if/when it will do the original source recompilation. Jan
Re: [PATCH] PR59170 make pretty printers check for singular iterators
On 15/12/16 22:19 +0100, Jan Kratochvil wrote: On Thu, 15 Dec 2016 15:18:17 +0100, Jonathan Wakely wrote: 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. Just with the GDB 'compile' project (libcc1) which is planned to be used for all GDB expressions evalation the Xmethods will no longer work. Ah. But then *it can just get compiled, so it will still work, right? The only reason it doesn't work today is that the definition for operator* might not be in the executable, but if you can compile a new definition that doesn't matter.
Re: [PATCH] PR59170 make pretty printers check for singular iterators
On Thu, 15 Dec 2016 15:18:17 +0100, Jonathan Wakely wrote: > 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. Just with the GDB 'compile' project (libcc1) which is planned to be used for all GDB expressions evalation the Xmethods will no longer work. Jan
[PATCH] PR59170 make pretty printers check for singular iterators
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 WakelyDate: Thu Dec 15 14:05:24 2016 + 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 #include #include +#include #include int @@ -50,6 +51,9 @@ main() deq.push_back("two"); // { dg-final { note-test deq {std::deque with 2 elements = {"one", "two"}} } } + std::deque::iterator deqiter0; +// { dg-final { note-test deqiter0 {non-dereferenceable iterator for std::deque} } } + std::deque::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::iterator lstiter0; +// { dg-final { note-test lstiter0