From: Tom Tromey Date: Mon, 3 Nov 2025 21:02:22 +0000 (-0700) Subject: Add 'num_children' method to relevant pretty-printers X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=de124ffe1439d63e4531f8aaf3641bb8f4260c33;p=thirdparty%2Fgcc.git 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 --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 of length %d, capacity %d' - % (self._typename, int(length), int(capacity))) + length = int(bl * (finish - start) + fo) + capacity = int(bl * (end - start)) + suffix = '' 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'