Skip to content

Commit de124ff

Browse files
committed
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.
1 parent f94a73e commit de124ff

File tree

1 file changed

+52
-10
lines changed

1 file changed

+52
-10
lines changed

libstdc++-v3/python/libstdcxx/v6/printers.py

Lines changed: 52 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -572,7 +572,10 @@ def children(self):
572572
self._val['_M_impl']['_M_finish'],
573573
self._is_bool)
574574

575-
def to_string(self):
575+
# Helper to compute the bounds of the vector.
576+
# Returns a tuple: (length, capacity, suffix)
577+
# SUFFIX is a type-name suffix to print.
578+
def _bounds(self):
576579
start = self._val['_M_impl']['_M_start']
577580
finish = self._val['_M_impl']['_M_finish']
578581
end = self._val['_M_impl']['_M_end_of_storage']
@@ -582,13 +585,27 @@ def to_string(self):
582585
fo = self._val['_M_impl']['_M_finish']['_M_offset']
583586
itype = start.dereference().type
584587
bl = 8 * itype.sizeof
585-
length = bl * (finish - start) + fo
586-
capacity = bl * (end - start)
587-
return ('%s<bool> of length %d, capacity %d'
588-
% (self._typename, int(length), int(capacity)))
588+
length = int(bl * (finish - start) + fo)
589+
capacity = int(bl * (end - start))
590+
suffix = '<bool>'
589591
else:
590-
return ('%s of length %d, capacity %d'
591-
% (self._typename, int(finish - start), int(end - start)))
592+
length = int(finish - start)
593+
capacity = int(end - start)
594+
suffix = ''
595+
if length < 0:
596+
# Probably uninitialized.
597+
length = 0
598+
capacity = 0
599+
return (length, capacity, suffix)
600+
601+
def to_string(self):
602+
(length, capacity, suffix) = self._bounds()
603+
return ('%s%s of length %d, capacity %d'
604+
% (self._typename, suffix, length, capacity))
605+
606+
def num_children(self):
607+
(length, capacity, suffix) = self._bounds()
608+
return length
592609

593610
def display_hint(self):
594611
return 'array'
@@ -733,6 +750,11 @@ def to_string(self):
733750
return '%s wrapping: %s' % (self._typename,
734751
self._visualizer.to_string())
735752

753+
def num_children(self):
754+
if hasattr(self._visualizer, 'num_children'):
755+
return self._visualizer.num_children()
756+
return None
757+
736758
def display_hint(self):
737759
if hasattr(self._visualizer, 'display_hint'):
738760
return self._visualizer.display_hint()
@@ -876,6 +898,9 @@ def children(self):
876898
node = lookup_node_type('_Rb_tree_node', self._val.type).pointer()
877899
return self._iter(RbtreeIterator(self._val), node)
878900

901+
def num_children(slf):
902+
return len(RbtreeIterator(self._val))
903+
879904
def display_hint(self):
880905
return 'map'
881906

@@ -915,6 +940,8 @@ def children(self):
915940
node = lookup_node_type('_Rb_tree_node', self._val.type).pointer()
916941
return self._iter(RbtreeIterator(self._val), node)
917942

943+
def num_children(slf):
944+
return len(RbtreeIterator(self._val))
918945

919946
class StdBitsetPrinter(printer_base):
920947
"""Print a std::bitset."""
@@ -1006,24 +1033,30 @@ def __init__(self, typename, val):
10061033
else:
10071034
self._buffer_size = 1
10081035

1009-
def to_string(self):
1036+
# Helper to compute the size.
1037+
def _size(self):
10101038
start = self._val['_M_impl']['_M_start']
10111039
end = self._val['_M_impl']['_M_finish']
10121040

10131041
delta_n = end['_M_node'] - start['_M_node'] - 1
10141042
delta_s = start['_M_last'] - start['_M_cur']
10151043
delta_e = end['_M_cur'] - end['_M_first']
10161044

1017-
size = self._buffer_size * delta_n + delta_s + delta_e
1045+
return long(self._buffer_size * delta_n + delta_s + delta_e)
10181046

1019-
return '%s with %s' % (self._typename, num_elements(long(size)))
1047+
def to_string(self):
1048+
size = self._size()
1049+
return '%s with %s' % (self._typename, num_elements(size))
10201050

10211051
def children(self):
10221052
start = self._val['_M_impl']['_M_start']
10231053
end = self._val['_M_impl']['_M_finish']
10241054
return self._iter(start['_M_node'], start['_M_cur'], start['_M_last'],
10251055
end['_M_cur'], self._buffer_size)
10261056

1057+
def num_children(self):
1058+
return self._size()
1059+
10271060
def display_hint(self):
10281061
return 'array'
10291062

@@ -1210,6 +1243,9 @@ def children(self):
12101243
return izip(counter, Tr1HashtableIterator(self._hashtable()))
12111244
return izip(counter, StdHashtableIterator(self._hashtable()))
12121245

1246+
def num_children(self):
1247+
return int(self._hashtable()['_M_element_count'])
1248+
12131249

12141250
class Tr1UnorderedMapPrinter(printer_base):
12151251
"""Print a std::unordered_map or tr1::unordered_map."""
@@ -1254,6 +1290,9 @@ def children(self):
12541290
# Zip the two iterators together.
12551291
return izip(counter, data)
12561292

1293+
def num_children(self):
1294+
return int(self._hashtable()['_M_element_count'])
1295+
12571296
def display_hint(self):
12581297
return 'map'
12591298

@@ -1949,6 +1988,9 @@ def to_string(self):
19491988
def children(self):
19501989
return self._iterator(self._val['_M_ptr'], self._size)
19511990

1991+
def num_children(self):
1992+
return int(self._size)
1993+
19521994
def display_hint(self):
19531995
return 'array'
19541996

0 commit comments

Comments
 (0)