This is the mail archive of the mailing list for the Archer project.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[python] Crash when using generators with Python 2.4


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

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]