[PyQt] Segmentation faults

Luke Campagnola lcampagn at email.unc.edu
Thu Aug 5 19:08:37 BST 2010


On Thu, Aug 5, 2010 at 03:43, Phil Thompson <phil at riverbankcomputing.com>wrote:

> On Thu, 5 Aug 2010 03:10:50 -0400, Luke Campagnola
> <lcampagn at email.unc.edu>
> wrote:
> > I believe I have run into a class of bugs in PyQt4. I originally found
> that
> > QSpinBox.lineEdit() returns a QLineEdit instance which does not maintain
> > its
> > reference count properly after the original QSpinBox is deleted. Thus it
> is
> > possible to either 1) have uncollectable LineEdits lingering in memory,
> or
> > 2) crash the program by accessing the LineEdit (see example below).
> >
> > The same bug also applies to:
> >  - QAbstractSpinBox.lineEdit
> >  - QComboBox.lineEdit,
> >  - QAbstractScrollArea.horizontalScrollBar
> >  - QAbstractScrollArea.verticalScrollBar
> >  - QTreeView.header
> >  - QSplitter.handle
> >
> > .. and likely many others. In the best case, this bug causes minor
> memory
> > leaks that few people are likely to notice. In the worst case, it causes
> > crashes which are very difficult to debug if you don't have easy access
> to
> > debugging symbols (ie using windows binaries).
> >
> > $ python
> >>>> from PyQt4.QtGui import *
> >>>> a = QApplication([])
> >>>> s = QSpinBox()
> >>>> l = s.lineEdit()
> >>>> del s
> >>>> l.text()
> > Segmentation fault
>
> These are refer to objects created (and still owned) by C++. They are
> destroyed by C++ when (for example) the QSpinBox is deleted. There is
> nothing that can be done about that.
>

Agreed; Qt may delete objects whenever it pleases. The real issue is that 1)
the reference count for these objects is incorrect, causing memory leaks,
and 2) the object is not informed when it's underlying C++ object is
deleted, which raises the possibility of crashes (raising an exception would
be perfectly acceptable). The former issue is unavoidable, and the latter
(in my opinion) is a serious problem affecting the usability of PyQt. There
are a few rare instances when I think a segmentation fault through python is
acceptable; this is not one of them.

Because they are created by C++, PyQt cannot (easily) work out when they
> get deleted. If it could then you would get an exception about the C++
> object no longer existing instead of a crash.


Given that the original SpinBox object had the correct reference count and
knew when the underlying object had been deleted, there should be a way to
accomplish the same behavior with the LineEdit. I am not familiar with sip
internals, but it seems this could be done by wrapping the SpinBox.lineEdit
function to ensure that the returned object is configured properly, or the
SpinBox itself could call sip.setdeleted on the LineEdit as soon as the
underlying object is deleted. My current workaround is to call
sip.setdeleted from within SpinBox.__del__, but this is obviously not
guaranteed to be called after the underlying object is deleted.

Luke
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.riverbankcomputing.com/pipermail/pyqt/attachments/20100805/cf47c879/attachment.html>


More information about the PyQt mailing list