[PyQt] segfault with multiple inheritance and QGraphicsItems

Zach Pincus zpincus at gmail.com
Thu May 2 19:07:54 BST 2019


Thanks!

You're correct that the crash has nothing to do with the mixin: I
thought I had tested that aspect carefully, but apparently not. (My
apologies; it's a long story :) Furthermore, as you suggested,
importing QtWidgets instead of Qt solves the problem.

## THIS CRASHES ##
from PyQt5 import Qt
class MyItem(Qt.QGraphicsRectItem):
    def itemChange(self, change, value):
        return value
myitem = MyItem()
rect = Qt.QGraphicsRectItem(parent=myitem)

## THIS DOES NOT CRASH ##
from PyQt5 import QtWidgets
class MyItem(QtWidgets.QGraphicsRectItem):
    def itemChange(self, change, value):
        return value
myitem = MyItem()
rect = QtWidgets.QGraphicsRectItem(parent=myitem)

Is there a way to work around this issue (other than not importing
Qt)? I originally found this in a fairly large PyQt5 program that we
wrote and use extensively in my lab, and for which not importing Qt
would be a bit of a problem. Since the program is deployed on lots of
machines in the lab, we rely on the PyPI PyQt5 packages. So if there's
an easy workaround we'll use it; otherwise I'll disable the offending
feature until the next release of PyQt5 hits PyPI.

Thanks a ton for checking this out!
Zach



On Thu, May 2, 2019 at 12:40 PM Phil Thompson
<phil at riverbankcomputing.com> wrote:
>
> I get a crash running the test, but not the same one. I've fixed my
> crash in tonight's PyQt5 snapshot.
>
> I suspect it is the same cause but the code is wandering off to
> different places. I don't think it has anything to do with mixins.
>
> Can you change the test to import QGraphicsRectItem from QtWidgets
> instead of Qt? Don't import the Qt module at all. Does that fix it?
>
> Phil
>
> On 02/05/2019 04:47, Zach Pincus wrote:
> > Just to follow up a little on the below:
> >
> > (1) Since the order of the superclasses often matters for weird bugs
> > like this, I wanted to clarify that in this case it actually doesn't
> > matter. That is, the segfault occurs regardless of whether it's:
> > class MyItem(Mixin, Qt.QGraphicsRectItem):
> > or
> > class MyItem(Qt.QGraphicsRectItem, Mixin):
> >
> > (2) I have found that (using the PyQt5 builds available on PyPI) that
> > the segfault does not appear when my test case is run against PyQt5
> > versions 5.8.x or earlier. The segfault appears in the 5.9 series and
> > is present in every release thereafter, including the latest on PyPI,
> > version 5.12.1. This is true on both mac and linux. In contrast, the
> > version of python doesn't seem to matter much here.
> >
> > So my guess (based on the backtraces and this last finding) is that
> > this is the result of a super-weird corner-case bug introduced in SIP
> > a few releases back. It is a little odd that the exact location of the
> > segfault differs between mac and linux. Maybe this suggests an
> > unitialized memory error rather than dereferencing a null pointer? But
> > what do I know? :)
> >
> > Happy to run more tests and report back if it helps.
> >
> > Thanks again,
> > Zach
> >
> > On Wed, May 1, 2019 at 10:34 AM Zach Pincus <zpincus at gmail.com> wrote:
> >>
> >> Hello,
> >>
> >> I've traced a segfault in PyQt5 to multiple inheritance with
> >> QGraphicsItems. Below is a minimal example to reproduce this issue:
> >>
> >> #######
> >> from PyQt5 import Qt
> >>
> >> class Mixin:
> >>    pass
> >>
> >> class MyItem(Mixin, Qt.QGraphicsRectItem):
> >>    def itemChange(self, change, value):
> >>        return value
> >>
> >> myitem = MyItem()
> >> rect = Qt.QGraphicsRectItem(parent=myitem) # segfault here
> >> #######
> >>
> >> If MyItem doesn't inherit from Mixin, there's no problem. (The order
> >> of the superclasses doesn't matter, BTW.) If MyItem doesn't override
> >> itemChange, there's again no problem. (It can override other methods
> >> from QGraphicsItem just fine, as far as I can tell.) And if the parent
> >> of rect on the last line is None, there's no problem.
> >>
> >> This is tested with the latest PyQt5 from pip (5.12.1), but the issue
> >> reproduces across many versions of PyQt5. It happens on macOS and
> >> linux; I have not tested on windows. Below is an LLDB backtrace of the
> >> segfault on a mac, and a GDB backtrace from a Ubuntu install.
> >>
> >> Note also that the following works fine:
> >> myitem = MyItem()
> >> rect = Qt.QGraphicsRectItem(parent=None)
> >> rect.setParentItem(myItem)
> >>
> >> However, that workaround doesn't seem to apply to the larger Qt
> >> application that I'm working on, from which this example is extracted.
> >> In particular, the workaround creates some kind race condition that
> >> freezes the application. I don't fully understand that race, but I
> >> suspect it may well be related to the segfault here. So I'm hoping if
> >> I can fix the segfault in this simple example, I can get my
> >> application working properly.
> >>
> >> And obviously in the full application, there's a good reason to need
> >> to use a mixin class, even though it's just a placeholder here. (I'm
> >> trying to make it possible to add a set of behaviors to an arbitrary
> >> QGraphicsItem subclass, and inheritance of those behaviors via mixin
> >> seems like the most straightforward way to do this.)
> >>
> >> Any suggestions / workarounds would be welcome!
> >>
> >> Thanks,
> >> Zach
> >>
> >>
> >>
> >> *** GDB backtrace on up-to-date Ubuntu ***
> >>
> >> Program received signal SIGSEGV, Segmentation fault.
> >> 0x00007ffff5da743d in QObject::connect(QObject const*, char const*,
> >> QObject const*, char const*, Qt::ConnectionType) ()
> >>   from
> >> /usr/local/miniconda3/lib/python3.6/site-packages/PyQt5/Qt/lib/libQt5Core.so.5
> >> (gdb) bt
> >> #0  0x00007ffff5da743d in QObject::connect(QObject const*, char
> >> const*, QObject const*, char const*, Qt::ConnectionType) ()
> >>   from
> >> /usr/local/miniconda3/lib/python3.6/site-packages/PyQt5/Qt/lib/libQt5Core.so.5
> >> #1  0x00007ffff64429dc in PyQtMonitor::monitor(QObject*) () from
> >> /usr/local/miniconda3/lib/python3.6/site-packages/PyQt5/QtCore.so
> >> #2  0x00007ffff2d27c45 in sipSimpleWrapper_init () from
> >> /usr/local/miniconda3/lib/python3.6/site-packages/PyQt5/sip.so
> >> #3  0x00005555556f0f57 in type_call () at
> >> /tmp/build/80754af9/python_1540319457073/work/Objects/typeobject.c:915
> >> #4  0x00005555556671de in PyObject_Call () at
> >> /tmp/build/80754af9/python_1540319457073/work/Objects/abstract.c:2261
> >> #5  0x00007ffff2d296b6 in sipWrapInstance () from
> >> /usr/local/miniconda3/lib/python3.6/site-packages/PyQt5/sip.so
> >> #6  0x00007ffff2d1cafb in sip_api_convert_from_type () from
> >> /usr/local/miniconda3/lib/python3.6/site-packages/PyQt5/sip.so
> >> #7  0x00007ffff643e10b in Chimera::toPyObject(void*) const () from
> >> /usr/local/miniconda3/lib/python3.6/site-packages/PyQt5/QtCore.so
> >> #8  0x00007ffff643d8e3 in Chimera::toPyObject(QVariant const&) const
> >> () from
> >> /usr/local/miniconda3/lib/python3.6/site-packages/PyQt5/QtCore.so
> >> #9  0x00007ffff643dba8 in Chimera::toAnyPyObject(QVariant const&) ()
> >> from /usr/local/miniconda3/lib/python3.6/site-packages/PyQt5/QtCore.so
> >> #10 0x00007ffff2d25aa9 in sip_api_convert_from_new_type () from
> >> /usr/local/miniconda3/lib/python3.6/site-packages/PyQt5/sip.so
> >> #11 0x00007ffff2d260e8 in buildObject () from
> >> /usr/local/miniconda3/lib/python3.6/site-packages/PyQt5/sip.so
> >> #12 0x00007ffff2d26a09 in call_method () from
> >> /usr/local/miniconda3/lib/python3.6/site-packages/PyQt5/sip.so
> >> #13 0x00007ffff2d26c0c in sip_api_call_method () from
> >> /usr/local/miniconda3/lib/python3.6/site-packages/PyQt5/sip.so
> >> #14 0x00007fffeb73d10c in sipVH_QtWidgets_154(PyGILState_STATE, void
> >> (*)(_sipSimpleWrapper*, PyGILState_STATE), _sipSimpleWrapper*,
> >> _object*, QGraphicsItem::GraphicsItemChange, QVariant const&) () from
> >> /usr/local/miniconda3/lib/python3.6/site-packages/PyQt5/QtWidgets.so
> >> #15 0x00007fffeb848ddc in
> >> sipQGraphicsRectItem::itemChange(QGraphicsItem::GraphicsItemChange,
> >> QVariant const&) ()
> >>   from
> >> /usr/local/miniconda3/lib/python3.6/site-packages/PyQt5/QtWidgets.so
> >> #16 0x00007fffeb0f3034 in
> >> QGraphicsItemPrivate::setParentItemHelper(QGraphicsItem*, QVariant
> >> const*, QVariant const*) ()
> >>   from
> >> /usr/local/miniconda3/lib/python3.6/site-packages/PyQt5/Qt/lib/libQt5Widgets.so.5
> >> #17 0x00007fffeb0f3717 in QGraphicsItem::setParentItem(QGraphicsItem*)
> >> ()
> >>   from
> >> /usr/local/miniconda3/lib/python3.6/site-packages/PyQt5/Qt/lib/libQt5Widgets.so.5
> >> #18 0x00007fffeb0f3ca9 in
> >> QAbstractGraphicsShapeItem::QAbstractGraphicsShapeItem(QAbstractGraphicsShapeItemPrivate&,
> >> QGraphicsItem*) ()
> >>   from
> >> /usr/local/miniconda3/lib/python3.6/site-packages/PyQt5/Qt/lib/libQt5Widgets.so.5
> >> #19 0x00007fffeb0f40bd in
> >> QGraphicsRectItem::QGraphicsRectItem(QGraphicsItem*) ()
> >>   from
> >> /usr/local/miniconda3/lib/python3.6/site-packages/PyQt5/Qt/lib/libQt5Widgets.so.5
> >> #20 0x00007fffeb752409 in
> >> sipQGraphicsRectItem::sipQGraphicsRectItem(QGraphicsItem*) ()
> >>   from
> >> /usr/local/miniconda3/lib/python3.6/site-packages/PyQt5/QtWidgets.so
> >> #21 0x00007fffeb75270a in init_type_QGraphicsRectItem () from
> >> /usr/local/miniconda3/lib/python3.6/site-packages/PyQt5/QtWidgets.so
> >> #22 0x00007ffff2d27c94 in sipSimpleWrapper_init () from
> >> /usr/local/miniconda3/lib/python3.6/site-packages/PyQt5/sip.so
> >> #23 0x00005555556f0f57 in type_call () at
> >> /tmp/build/80754af9/python_1540319457073/work/Objects/typeobject.c:915
> >> #24 0x00005555556675bb in _PyObject_FastCallDict () at
> >> /tmp/build/80754af9/python_1540319457073/work/Objects/abstract.c:2331
> >> #25 0x00005555556eb2aa in _PyObject_FastCallKeywords () at
> >> /tmp/build/80754af9/python_1540319457073/work/Objects/abstract.c:2496
> >> #26 0x00005555556f0d6e in call_function () at
> >> /tmp/build/80754af9/python_1540319457073/work/Python/ceval.c:4861
> >> #27 0x00005555557144d8 in _PyEval_EvalFrameDefault () at
> >> /tmp/build/80754af9/python_1540319457073/work/Python/ceval.c:3351
> >> #28 0x00005555556ebad9 in _PyEval_EvalCodeWithName (qualname=0x0,
> >> name=<optimized out>, closure=0x0, kwdefs=0x0, defcount=0, defs=0x0,
> >>    kwstep=2, kwcount=<optimized out>, kwargs=0x0, kwnames=0x0,
> >> argcount=0, args=0x0, locals=0x7ffff7f422d0, globals=0x7ffff7f422d0,
> >>    _co=0x7ffff6ae25d0) at
> >> /tmp/build/80754af9/python_1540319457073/work/Python/ceval.c:4166
> >> #29 PyEval_EvalCodeEx () at
> >> /tmp/build/80754af9/python_1540319457073/work/Python/ceval.c:4187
> >> #30 0x00005555556ec87c in PyEval_EvalCode (co=co at entry=0x7ffff6ae25d0,
> >> globals=globals at entry=0x7ffff7f422d0,
> >> locals=locals at entry=0x7ffff7f422d0)
> >>    at /tmp/build/80754af9/python_1540319457073/work/Python/ceval.c:731
> >> #31 0x000055555576d074 in run_mod () at
> >> /tmp/build/80754af9/python_1540319457073/work/Python/pythonrun.c:1025
> >> #32 0x000055555576d471 in PyRun_FileExFlags () at
> >> /tmp/build/80754af9/python_1540319457073/work/Python/pythonrun.c:978
> >> #33 0x000055555576d673 in PyRun_SimpleFileExFlags () at
> >> /tmp/build/80754af9/python_1540319457073/work/Python/pythonrun.c:419
> >> #34 0x000055555576d77d in PyRun_AnyFileExFlags () at
> >> /tmp/build/80754af9/python_1540319457073/work/Python/pythonrun.c:81
> >> #35 0x00005555557711b0 in run_file (p_cf=0x7fffffffe8cc,
> >> filename=0x5555558ac690 L"foo.py", fp=0x55555593c900)
> >>    at /tmp/build/80754af9/python_1540319457073/work/Modules/main.c:340
> >> #36 Py_Main () at
> >> /tmp/build/80754af9/python_1540319457073/work/Modules/main.c:811
> >> #37 0x0000555555638b4e in main () at
> >> /tmp/build/80754af9/python_1540319457073/work/Programs/python.c:69
> >> #38 0x00007ffff77e6b97 in __libc_start_main (main=0x555555638a60
> >> <main>, argc=2, argv=0x7fffffffead8, init=<optimized out>,
> >>    fini=<optimized out>, rtld_fini=<optimized out>,
> >> stack_end=0x7fffffffeac8) at ../csu/libc-start.c:310
> >> #39 0x000055555571a1a8 in _start () at
> >> ../sysdeps/x86_64/elf/start.S:103
> >>
> >>
> >> *** LLDB backtrace on an up-to-date Mac ***
> >>
> >> * thread #1, queue = 'com.apple.main-thread', stop reason =
> >> EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
> >>  * frame #0: 0x0000000109908c41
> >> QtRemoteObjects.so`sipSubClass_QRemoteObjectNode(void**) + 49
> >>    frame #1: 0x00000001022ea61d sip.so`convertSubClass + 152
> >>    frame #2: 0x00000001022ea4dd sip.so`sip_api_convert_from_type + 225
> >>    frame #3: 0x0000000101b60ef8 QtCore.so`Chimera::toPyObject(void*)
> >> const + 760
> >>    frame #4: 0x0000000101b60b92 QtCore.so`Chimera::toPyObject(QVariant
> >> const&) const + 338
> >>    frame #5: 0x0000000101b61139
> >> QtCore.so`Chimera::toAnyPyObject(QVariant const&) + 217
> >>    frame #6: 0x00000001022ecec8 sip.so`sip_api_convert_from_new_type +
> >> 160
> >>    frame #7: 0x00000001022f0b8f sip.so`buildObject + 2598
> >>    frame #8: 0x00000001022f0edc sip.so`call_method + 58
> >>    frame #9: 0x00000001022ecc1c sip.so`sip_api_call_method + 136
> >>    frame #10: 0x00000001078e2c3a
> >> QtWidgets.so`sipQGraphicsRectItem::itemChange(QGraphicsItem::GraphicsItemChange,
> >> QVariant const&) + 202
> >>    frame #11: 0x000000010806e540
> >> QtWidgets`QGraphicsItemPrivate::setParentItemHelper(QGraphicsItem*,
> >> QVariant const*, QVariant const*) + 1456
> >>    frame #12: 0x0000000108071691
> >> QtWidgets`QGraphicsItem::setParentItem(QGraphicsItem*) + 513
> >>    frame #13: 0x0000000108081f2d
> >> QtWidgets`QGraphicsRectItem::QGraphicsRectItem(QGraphicsItem*) + 541
> >>    frame #14: 0x00000001078e3cbb
> >> QtWidgets.so`init_type_QGraphicsRectItem(_sipSimpleWrapper*, _object*,
> >> _object*, _object**, _object**, _object**) + 139
> >>    frame #15: 0x00000001022eaaa9 sip.so`sipSimpleWrapper_init + 175
> >>    frame #16: 0x00000001000b5af1 python`type_call + 241
> >>    frame #17: 0x0000000100008ef1 python`_PyObject_FastCallDict + 177
> >>    frame #18: 0x0000000100011137 python`_PyObject_FastCallKeywords +
> >> 327
> >>    frame #19: 0x000000010015f718 python`call_function + 392
> >>    frame #20: 0x000000010015d225 python`_PyEval_EvalFrameDefault +
> >> 47013
> >>    frame #21: 0x00000001001508c9 python`_PyEval_EvalCodeWithName + 425
> >>    frame #22: 0x00000001001a955c python`PyRun_FileExFlags + 252
> >>    frame #23: 0x00000001001a8a34 python`PyRun_SimpleFileExFlags + 372
> >>    frame #24: 0x00000001001cf7c6 python`Py_Main + 3734
> >>    frame #25: 0x0000000100000f59 python`main + 313
> >>    frame #26: 0x00007fff79e603d5 libdyld.dylib`start + 1
> >>    frame #27: 0x00007fff79e603d5 libdyld.dylib`start + 1
> > _______________________________________________
> > PyQt mailing list    PyQt at riverbankcomputing.com
> > https://www.riverbankcomputing.com/mailman/listinfo/pyqt
>


More information about the PyQt mailing list