On Tue, 4 Nov 2025 at 14:42, Tom Tromey <[email protected]> wrote:
>
> A user pointed out that, in DAP mode, gdb would hang while trying to
> display a certain vector.  See
>
>     https://sourceware.org/bugzilla/show_bug.cgi?id=33594
>
> This is caused by a combination of things: the vector is
> uninitialized, DAP requires a count of the number of children of a
> variable, and libstdc++ printers don't implement the 'num_children'
> method, so gdb tries to count children by iterating.
>
> In this case, the vector has a nonsensical size:
>
>     (gdb) p myVector
>     $1 = std::vector of length -34979931, capacity -33992726
>
> This patch adds a 'num_children' method to a subset of the
> pretty-printers, in particular ones where I thought the length might
> be arbitrarily large and susceptible to being garbage when the object
> isn't initialized.
>
> I've also specifically added a check to the vector printer for the
> case where the length is negative.
>
> These container printers could be further improved by adding the
> 'child' method, allowing random access to child objects.  However I
> haven't done that here.
>
> libstc++-v3/ChangeLog

s/libstc++/libstdc++/

OK with that change (which would probably be caught by the receive hook anyway).



>
>         * python/libstdcxx/v6/printers.py (StdVectorPrinter._bounds):
>         New method.
>         (StdVectorPrinter.to_string): Use it.
>         (StdVectorPrinter.num_children): New method.
>         (StdStackOrQueuePrinter.num_children): New method.
>         (StdMapPrinter.num_children): New method.
>         (StdSetPrinter.num_children): New method.
>         (StdDequePrinter._size): New method.
>         (StdDequePrinter.to_string): Use it.
>         (StdDequePrinter.num_children): New method.
>         (Tr1UnorderedSetPrinter.num_children): New method.
>         (Tr1UnorderedMapPrinter.num_children): New method.
>         (StdSpanPrinter.num_children): New method.
> ---
>  libstdc++-v3/python/libstdcxx/v6/printers.py | 62 ++++++++++++++++----
>  1 file changed, 52 insertions(+), 10 deletions(-)
>
> diff --git a/libstdc++-v3/python/libstdcxx/v6/printers.py 
> b/libstdc++-v3/python/libstdcxx/v6/printers.py
> index 7a5a627479f..f7f0489abf9 100644
> --- a/libstdc++-v3/python/libstdcxx/v6/printers.py
> +++ b/libstdc++-v3/python/libstdcxx/v6/printers.py
> @@ -572,7 +572,10 @@ class StdVectorPrinter(printer_base):
>                                self._val['_M_impl']['_M_finish'],
>                                self._is_bool)
>
> -    def to_string(self):
> +    # Helper to compute the bounds of the vector.
> +    # Returns a tuple: (length, capacity, suffix)
> +    # SUFFIX is a type-name suffix to print.
> +    def _bounds(self):
>          start = self._val['_M_impl']['_M_start']
>          finish = self._val['_M_impl']['_M_finish']
>          end = self._val['_M_impl']['_M_end_of_storage']
> @@ -582,13 +585,27 @@ class StdVectorPrinter(printer_base):
>              fo = self._val['_M_impl']['_M_finish']['_M_offset']
>              itype = start.dereference().type
>              bl = 8 * itype.sizeof
> -            length = bl * (finish - start) + fo
> -            capacity = bl * (end - start)
> -            return ('%s<bool> of length %d, capacity %d'
> -                    % (self._typename, int(length), int(capacity)))
> +            length = int(bl * (finish - start) + fo)
> +            capacity = int(bl * (end - start))
> +            suffix = '<bool>'
>          else:
> -            return ('%s of length %d, capacity %d'
> -                    % (self._typename, int(finish - start), int(end - 
> start)))
> +            length = int(finish - start)
> +            capacity = int(end - start)
> +            suffix = ''
> +        if length < 0:
> +            # Probably uninitialized.
> +            length = 0
> +            capacity = 0
> +        return (length, capacity, suffix)
> +
> +    def to_string(self):
> +        (length, capacity, suffix) = self._bounds()
> +        return ('%s%s of length %d, capacity %d'
> +                % (self._typename, suffix, length, capacity))
> +
> +    def num_children(self):
> +        (length, capacity, suffix) = self._bounds()
> +        return length
>
>      def display_hint(self):
>          return 'array'
> @@ -733,6 +750,11 @@ class StdStackOrQueuePrinter(printer_base):
>          return '%s wrapping: %s' % (self._typename,
>                                      self._visualizer.to_string())
>
> +    def num_children(self):
> +        if hasattr(self._visualizer, 'num_children'):
> +            return self._visualizer.num_children()
> +        return None
> +
>      def display_hint(self):
>          if hasattr(self._visualizer, 'display_hint'):
>              return self._visualizer.display_hint()
> @@ -876,6 +898,9 @@ class StdMapPrinter(printer_base):
>          node = lookup_node_type('_Rb_tree_node', self._val.type).pointer()
>          return self._iter(RbtreeIterator(self._val), node)
>
> +    def num_children(slf):
> +        return len(RbtreeIterator(self._val))
> +
>      def display_hint(self):
>          return 'map'
>
> @@ -915,6 +940,8 @@ class StdSetPrinter(printer_base):
>          node = lookup_node_type('_Rb_tree_node', self._val.type).pointer()
>          return self._iter(RbtreeIterator(self._val), node)
>
> +    def num_children(slf):
> +        return len(RbtreeIterator(self._val))
>
>  class StdBitsetPrinter(printer_base):
>      """Print a std::bitset."""
> @@ -1006,7 +1033,8 @@ class StdDequePrinter(printer_base):
>          else:
>              self._buffer_size = 1
>
> -    def to_string(self):
> +    # Helper to compute the size.
> +    def _size(self):
>          start = self._val['_M_impl']['_M_start']
>          end = self._val['_M_impl']['_M_finish']
>
> @@ -1014,9 +1042,11 @@ class StdDequePrinter(printer_base):
>          delta_s = start['_M_last'] - start['_M_cur']
>          delta_e = end['_M_cur'] - end['_M_first']
>
> -        size = self._buffer_size * delta_n + delta_s + delta_e
> +        return long(self._buffer_size * delta_n + delta_s + delta_e)
>
> -        return '%s with %s' % (self._typename, num_elements(long(size)))
> +    def to_string(self):
> +        size = self._size()
> +        return '%s with %s' % (self._typename, num_elements(size))
>
>      def children(self):
>          start = self._val['_M_impl']['_M_start']
> @@ -1024,6 +1054,9 @@ class StdDequePrinter(printer_base):
>          return self._iter(start['_M_node'], start['_M_cur'], 
> start['_M_last'],
>                            end['_M_cur'], self._buffer_size)
>
> +    def num_children(self):
> +        return self._size()
> +
>      def display_hint(self):
>          return 'array'
>
> @@ -1210,6 +1243,9 @@ class Tr1UnorderedSetPrinter(printer_base):
>              return izip(counter, Tr1HashtableIterator(self._hashtable()))
>          return izip(counter, StdHashtableIterator(self._hashtable()))
>
> +    def num_children(self):
> +        return int(self._hashtable()['_M_element_count'])
> +
>
>  class Tr1UnorderedMapPrinter(printer_base):
>      """Print a std::unordered_map or tr1::unordered_map."""
> @@ -1254,6 +1290,9 @@ class Tr1UnorderedMapPrinter(printer_base):
>          # Zip the two iterators together.
>          return izip(counter, data)
>
> +    def num_children(self):
> +        return int(self._hashtable()['_M_element_count'])
> +
>      def display_hint(self):
>          return 'map'
>
> @@ -1949,6 +1988,9 @@ class StdSpanPrinter(printer_base):
>      def children(self):
>          return self._iterator(self._val['_M_ptr'], self._size)
>
> +    def num_children(self):
> +        return int(self._size)
> +
>      def display_hint(self):
>          return 'array'
>
> --
> 2.51.0
>

Reply via email to