[PyKDE] PyQt4/win32 crash

K.S.Sreeram sreeram at tachyontech.net
Sun Sep 17 21:22:56 BST 2006


K.S.Sreeram wrote:
> Phil Thompson wrote:
>> On Friday 15 September 2006 9:58 pm, K.S.Sreeram wrote:
>>> [Qt-4.1.4, sip-4.4.5, PyQt-4.0.1, Python-2.4.3, MSVC-7.1]
>>>
>>> Hi all,
>>>
>>> I've been facing a random crash in my app for sometime, and i've got it
>>> down to a simple test program. Run the attached script, click "Click Me"
>>> and close the newly opened window, and it crashes!
>>>
>>> I used debug builds and poked around the code, and here's why i think
>>> its crashing...
>>>
>>> The crash happens when a top-level window is closed, and all python
>>> references to the window are lost in the 'closeEvent' method.
>>>
>>> When a window is closed using the close button at the right top of the
>>> window, the Qt function "QWidgetPrivate::close_helper(mode)" gets called
>>> with "mode == CloseWithSpontaneousEvent". This function is there in
>>> src/gui/kernel/qwidget.cpp line 4609.
>>>
>>> In this function, close event is sent to the widget if mode is
>>> CloseWithSpontaneousEvent, as in this case. By the time, the close event
>>> is handled by the widget, the widget is already deleted because of
>>> python's gc.
>>>
>>> The Qt code seems to check for this case using tests like
>>> "that.isNull()". But on line 4642, the check for null is not performed
>>> and the app crashes at that point.
>>>
>>> So this looks like it is a bug in Qt itself. But is there someway PyQt
>>> can workaround this bug?
>> What if you swap the two lines of MyWindow.closeEvent()?
> 
> That doesn't help. The last python reference is actually the 'self'
> parameter to the closeEvent. So the python gc kicks in only /after/ the
> return from closeEvent.
> 
> As a workaround, i'm currently just planning to use a single shot timer
> to keep a reference to the object until after the close fully completes.

Here's the actual workaround i'm using:

_delayed = []
_timer = None
def _onTimer() :
    global _timer
    del _delayed[:]
    _timer = None
def delaygc( obj ) :
    global _timer
    _delayed.append( obj )
    if _timer is not None :
        _timer.stop()
    _timer = QtCore.QTimer()
    _timer.setSingleShot( True )
    _timer.start( 1000 )
    QtCore.QObject.connect( _timer, QtCore.SIGNAL('timeout()'), _onTimer )

Just insert 'delaygc(self)' into 'closeEvent' methods and the app
doesn't crash anymore!

[sreeram;]

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 252 bytes
Desc: OpenPGP digital signature
Url : http://www.riverbankcomputing.com/pipermail/pyqt/attachments/20060917/871fc7ec/signature.bin


More information about the PyQt mailing list