This is the mail archive of the
archer@sourceware.org
mailing list for the Archer project.
[python] Crash when using generators with Python 2.4
- From: ppluzhnikov at google dot com (Paul Pluzhnikov)
- To: archer at sourceware dot org
- Cc: Jeffrey Yasskin <jyasskin at google dot com>
- Date: Fri, 16 Jan 2009 10:47:44 -0800 (PST)
- Subject: [python] Crash when using generators with Python 2.4
Greetings,
One of my end-users wrote a pretty printer using Python generator,
and discovered that doing this crashes gdb+python.
Here is a test case: replace Tom's StdListPrinter with this one:
class StdListPrinter:
"Print a std::list"
def __init__(self, val):
self.val = val
def children(self):
itype = self.val.type().template_argument(0)
nodetype = gdb.Type('std::_List_node<%s>' % itype).pointer()
head = self.val['_M_impl']['_M_node']
base = head['_M_next']
head = head.address()
count = 0
while base != head:
elt = base.cast(self.nodetype).dereference()
base = elt['_M_next']
yield ('[%d]' % count, elt['_M_data'])
count += 1
def to_string(self):
if self.val['_M_impl']['_M_node'].address() == self.val['_M_impl']['_M_node']['_M_next']:
return 'empty std::list'
return 'std::list'
Configure gdb+python to use Python 2.4, print an instance of
std::list, and you'll see:
gdb: Objects/genobject.c:53: gen_iternext: Assertion `f->f_back != ((void *)0)' failed.
$1 = std::list
Program received signal SIGABRT, Aborted.
(top) bt
#0 0x00002aaaabbf1c75 in *__GI_raise (sig=<value optimized out>) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64
#1 0x00002aaaabbf3620 in *__GI_abort () at ../sysdeps/generic/abort.c:88
#2 0x00002aaaabbeb6d4 in *__GI___assert_fail (assertion=0x8deea9 "f->f_back != ((void *)0)", file=0x8dee3d "Objects/genobject.c", line=53, function=0x8dee67 "gen_iternext") at assert.c:83
#3 0x000000000077f3af in gen_iternext (gen=0x1608f90) at Objects/genobject.c:53
#4 0x00000000006ce090 in PyIter_Next (iter=0x1608f90) at Objects/abstract.c:2253
#5 0x000000000046a1d8 in print_children (printer=0x15cf360, hint=0x0, stream=0xb3bd80, recurse=0, options=0x7fffffffdd10, language=0x7f2260) at ../../gdb/python/python.c:1081
#6 0x000000000046a5e1 in apply_val_pretty_printer (type=0xe62bc8, valaddr=0xd98010 "À\220A", embedded_offset=0, address=140737488348304, stream=0xb3bd80, recurse=0, options=0x7fffffffdd10, language=0x7f2260) at ../../gdb/python/python.c:1238
#7 0x00000000004a9843 in value_print (val=0x136dbf0, stream=0xb3bd80, options=0x7fffffffdd10) at ../../gdb/valprint.c:353
#8 0x00000000004abed1 in print_formatted (val=0x136dbf0, size=0, options=0x7fffffffdd10, stream=0xb3bd80) at ../../gdb/printcmd.c:305
#9 0x00000000004ad078 in print_command_1 (exp=0xa120f2 "ls", inspect=0, voidprint=1) at ../../gdb/printcmd.c:914
...
"ls" in frame #9 is an instance of 'std::list<std::string>'
frames #3 and #4 are in Python
The actual crash happens inside Python, because it expects to have
a python frame above any routine which calls yield, and asserts so.
Python 2.6 removes that expectation/assertion, and the above pretty
printer produces expected:
(gdb) p ls
$1 = std::list
I see two ways to fix this:
A. somehow push a "dummy" Python frame before calling next() on
the iterator returned from children() [I don't know how exactly to
do that], or
B. disallow generators as return from children() if GDB was built
with Python 2.4 [I believe I know how to do that.]
A) has the advantage that the same pretty printers will work
regardless of which Python was used; but it is more of a hack.
Comments?
--
Paul Pluzhnikov