This is the mail archive of the
mailing list for the Archer project.
Re: [python] Crash when using generators with Python 2.4
- From: Jeffrey Yasskin <jyasskin at google dot com>
- To: Paul Pluzhnikov <ppluzhnikov at google dot com>
- Cc: archer at sourceware dot org
- Date: Fri, 16 Jan 2009 13:41:44 -0800
- Subject: Re: [python] Crash when using generators with Python 2.4
- References: <20090116184744.AEF2C3A6B56@localhost>
For completeness, the assertion in genobject.c is correct starting
from Python 2.5.0
although I haven't checked that gdb can run generators compiled
I checked with Brett Cannon (who's been hacking on Python internals
longer than I have), and he couldn't think of a third option either.
If you guys decide to manufacture a frame object, there's an example
of doing so at http://svn.python.org/view/python/tags/r246/Modules/pyexpat.c?rev=67853&view=markup.
They create a dummy code object in getcode() and create the dummy
frame with PyFrame_New() in call_with_frame().
On Fri, Jan 16, 2009 at 10:47 AM, Paul Pluzhnikov
> 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.
> Paul Pluzhnikov