https://gcc.gnu.org/g:de124ffe1439d63e4531f8aaf3641bb8f4260c33
commit r16-5284-gde124ffe1439d63e4531f8aaf3641bb8f4260c33 Author: Tom Tromey <[email protected]> Date: Mon Nov 3 14:02:22 2025 -0700 Add 'num_children' method to relevant pretty-printers 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. libstdc++-v3/ChangeLog * 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. Diff: --- 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 7a5a627479fd..f7f0489abf9a 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'
