[PyQt] segfault using daily snapshot

Phil Thompson phil at riverbankcomputing.com
Sat Dec 18 12:26:21 GMT 2010


On Sat, 18 Dec 2010 11:40:07 +0100, Erik Janssens
<Erik.Janssens at conceptive.be> wrote:
> Hello Phil
> 
> Thank you for your assistance. Yes, threads are involved
> in my tests.  The segfault for sure happens during a
> 'deconstruction' phase, most of the time this is at the
> end of the tests, but not always.
> 
> I don't think there is any recursive behavior involved,
> our stress tests consist of generating a huge number of
> Camelot form and table views one after another.
> 
> I tried to change the code as you suggested to :
> 
> static void clear_access_func(sipSimpleWrapper *sw)
> {
>     sipAccessFunc old_access_func;
>     old_access_func = NULL;
>     if (sw->access_func != NULL)
>     {
>        old_access_func = sw->access_func;
>        sw->access_func = NULL;
>     }
>     if (old_access_func != NULL)
>     {
>        old_access_func(sw, ReleaseGuard);
>     }
>     sw->data = NULL;
> }
> 
> maybe a bit too much code, but I wanted to be sure.
> 
> but it didn't help, still the same effect, I also tried
> to put a SIP_BLOCK_THREADS around the code block, but it
> didn't help either.
> 
> would it be possible that a single QObject has multiple
> python wrappers, resulting in duplicate deletes ?

That shouldn't happen.

> what is for sure is that when I comment out the ReleaseGuard
> function, there are no segfaults.
> 
> what is the purpose of the ReleaseGuard step ?  I don't find
> any docs on it in the qt docs.

It just returns the QPointer to the heap. Without it you get a memory
leak.

> Maybe I should give a bit more background on the issue.  We
> have observed a number of segfaults with users of our application.
> What is strange is that this number is far higher with
> Windows 7 users.  Also, on Windows 7 the crashes seem more
> severe (push-the-button-time).  As this is the only segfault
> I'm able to produce with testing, I suspect it's this issue
> causing the Windows 7 segfaults, but that's not sure of course.
> 
> What I could do is deploy a number of apps with the ReleaseGuard
> line removed, to confirm this is the issue, but then I'd like
> to understand what the line is about ?
> 
> Another option would be to deploy debug-builds on Windows, but
> I'm really unfamiliar with doing such thing so I'd like to
> avoid it.
> 
> Regards,
> 
> Erik

I think we need to see if the race condition in Qt is the problem...

In qobject.cpp there is a method QMetaObject::removeGuard(). Can you move
the line...

    QMutexLocker locker(guardHashLock());

...so that it is the first line of the method.

Phil

> On Fri, 2010-12-17 at 18:47 +0000, Phil Thompson wrote:
>> On Fri, 17 Dec 2010 09:17:14 +0100, Erik Janssens
>> <Erik.Janssens at conceptive.be> wrote:
>> > Hello Phil,
>> > 
>> > please find enclosed a stack trace with a debug build
>> > of the last qt / pyqt releases.
>> > 
>> > apart from my stress-tests, I did not yet found an 
>> > easy way to reproduce it.  but I'm quite sure it affects
>> > our users as well during their daily use.
>> > 
>> > I do have a 60Mb core dump of it, but the whole debug
>> > build is more than 700Mb.
>> > 
>> > Should you have any hints for me on how to investigate
>> > this further...
>> 
>> Nothing looks obviously wrong.
>> 
>> Are threads involved in your tests?
>> 
>> Does the crash happen during normal execution, or only when the
>> interpreter terminates?
>> 
>> SIP gets the address of a C++ instance via an access function. PyQt
>> supplies qpointer_access_func() which uses a QPointer<QObject> so that
it
>> can detect when a QObject created internally by Qt gets deleted. (PyQt
>> can
>> detect when a QObject created by PyQt gets deleted by another
mechanism.)
>> The crash is happening when the resources used to implement the
QPointer
>> are being released when the Python object wrapping the C++ QObject is
>> being
>> garbage collected.
>> 
>> I will assume for the moment that QPointer works properly - although
I'm
>> not totally convinced as there seems to be a race condition in
>> QMetaObject::removeGuard().
>> 
>> Looking at the implementation of clear_access_func() in siplib.c you
can
>> see that it tries to make sure that the resources are not freed twice
by
>> resetting the the pointer to the access function.
>> 
>> Unless there is something fairly obvious that I am missing (which is
>> quite
>> possible) I would start to suspect timing issues - although the stack
>> trace
>> doesn't suggest any recursive behaviour.
>> 
>> You might want to try changing clear_access_func() so that it saves the
>> value of sw->access_func, clears it, then calls the access function
using
>> the saved pointer.
>> 
>> Phil
> 
> 
> _______________________________________________
> PyQt mailing list    PyQt at riverbankcomputing.com
> http://www.riverbankcomputing.com/mailman/listinfo/pyqt


More information about the PyQt mailing list