[PyQt] [BUG] Return value of overriden QSGMaterial::createShader() impropely destroyed before use

Vladimir Rutsky rutsky.vladimir at gmail.com
Thu Jun 18 19:18:20 BST 2015


On Thu, Jun 18, 2015 at 8:27 PM, Phil Thompson
<phil at riverbankcomputing.com> wrote:
> On 16/06/2015 3:30 pm, Vladimir Rutsky wrote:
>>
>> On Mon, Jun 15, 2015 at 6:33 PM, Vladimir Rutsky
>> <rutsky.vladimir at gmail.com> wrote:
>>>
>>> Hello, Phil,
>>>
>>> I made an example that reproduces this bug:
>>> https://gist.github.com/rutsky/d6332e3354972997e938
>>>
>>> Plus it shows another bug: application hangs on exit on GNU/Linux.
>>>
>>> If I attach to it with GDB I can see, that application is waiting for
>>> some condition variable in QSGRenderLoop::cleanup().
>>>
>>>     0  pthread_cond_wait@@GLIBC_2.3.2 () at
>>> ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:185
>>>     1  0x00007f719d0f9cc3 in QWaitCondition::wait(QMutex*, unsigned
>>> long) () from /home/bob/Qt/5.4/gcc_64/lib/libQt5Core.so.5
>>>     2  0x00007f719e6f0acb in ?? () from
>>> /home/bob/Qt/5.4/gcc_64/lib/libQt5Quick.so.5
>>>     3  0x00007f719e6f12a0 in ?? () from
>>> /home/bob/Qt/5.4/gcc_64/lib/libQt5Quick.so.5
>>>     4  0x00007f719e6e7268 in QSGRenderLoop::cleanup() () from
>>> /home/bob/Qt/5.4/gcc_64/lib/libQt5Quick.so.5
>>>     5  0x00007f719d32e049 in qt_call_post_routines() () from
>>> /home/bob/Qt/5.4/gcc_64/lib/libQt5Core.so.5
>>>     6  0x00007f7197dc6a66 in QApplication::~QApplication() () from
>>> /home/bob/Qt/5.4/gcc_64/lib/libQt5Widgets.so.5
>>>     7  0x00007f7198892768 in sipQApplication::~sipQApplication
>>> (this=0x259ba90, __in_chrg=<optimized out>) at
>>> sipQtWidgetspart0.cpp:301912
>>>     8  0x00007f7198892798 in sipQApplication::~sipQApplication
>>> (this=0x259ba90, __in_chrg=<optimized out>) at
>>> sipQtWidgetspart0.cpp:301915
>>>     9  0x00007f7198895f31 in release_QApplication (sipCppV=0x259ba90)
>>> at sipQtWidgetspart0.cpp:303524
>>>     10 0x00007f7198895fca in dealloc_QApplication
>>> (sipSelf=0x7f7197809168) at sipQtWidgetspart0.cpp:303538
>>>     11 0x00007f7199d5b346 in ?? () from
>>> /home/bob/work/proplan/env/lib/python3.4/site-packages/sip.so
>>>     12 0x00007f7199d5c5e9 in ?? () from
>>> /home/bob/work/proplan/env/lib/python3.4/site-packages/sip.so
>>>     13 0x0000000000515c82 in ?? ()
>>>     14 0x00000000004fb938 in ?? ()
>>>     15 0x0000000000511820 in ?? ()
>>>     16 0x00000000005117fe in ?? ()
>>>     17 0x00000000005ae979 in ?? ()
>>>     18 0x00000000005972bd in PyErr_PrintEx ()
>>>     19 0x0000000000596331 in PyRun_SimpleFileExFlags ()
>>>     20 0x00000000004cb93a in Py_Main ()
>>>     21 0x00000000004cad1f in main ()
>>>
>>> (This issue is not reproduces in Windows, since Qt 5.4 still uses single
>>> threaded rendering there.)
>>>
>>>
>>> Regards,
>>>
>>> Vladimir Rutsky
>>
>>
>> I have updated the example:
>> https://gist.github.com/rutsky/d6332e3354972997e938
>>
>> As I see, when QQuickView is being destroyed it waits until render thread
>> clean ups all resources, which causes custom created QSGGeometryNode
>> to be destroyed,
>> which asks to lock GIL, which is still locked by main thread, so it's
>> deadlock.
>
>
> Both problems should be fixed in tonight's snapshot.
>
> I'd be interested to know how you think the ownership of the QSGNode
> returned from updatePaintNode() should be handled. Where in the docs does it
> say that Qt handles the lifetime of the node?
>
> Thanks,
> Phil
>

I made conclusion about ownership of QSGNode from example in
QQuickItem::updatePaintNode documentation:
http://doc.qt.io/qt-5/qquickitem.html#updatePaintNode

QSGNode *MyItem::updatePaintNode(QSGNode *node, UpdatePaintNodeData *)
{
    QSGSimpleRectNode *n = static_cast<QSGSimpleRectNode *>(node);
    if (!n) {
        n = new QSGSimpleRectNode();
        n->setColor(Qt::red);
    }
    n->setRect(boundingRect());
    return n;
}

QSGSimpleRectNode is created on heap and wasn't stored anywere, just
returned as QSGNode * pointer.

Now I see, that documentation has following information about QSGNode
ownership: http://doc.qt.io/qt-5/qquickitem.html#graphics-resource-handling

> A QSGNode returned from QQuickItem::updatePaintNode() is automatically deleted on the right thread at the right time.
> Trees of QSGNode instances are managed through the use of QSGNode::OwnedByParent, which is set by default.
> So, for the majority of custom scene graph items, no extra work will be required.


So I was not completely really correct about ownership of QSGNode:
it's defined by QSGNode::OwnedByParent flag which is set by default.


Regards,

Vladimir Rutsky


More information about the PyQt mailing list