[PyQt] [BUG] Issues with overriding QSGMaterialShader::attributeNames()

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


On Thu, Jun 18, 2015 at 8:43 PM, Phil Thompson
<phil at riverbankcomputing.com> wrote:
> On 02/06/2015 11:47 am, Vladimir Rutsky wrote:
>>
>> Hello,
>>
>> 1. Overrided in Python QSGMaterialShader::attributeNames() always
>> returns NULL to Qt C++ code.
>>
>> In PyQt-gpl-5.4.1/sip/QtQuick/qsgmaterial.sip code for
>> attributeNames() method stores result in variable "result" and never
>> touches "sipRes" variable, which is returned at the end of function.
>>
>> Attached patch fixes this issue by assigning "sipRes" to "result" (I'm
>> not sure is this intented behavior in case of errors).
>>
>> 2. Calling overriden in Python QSGMaterialShader::attributeNames()
>> from Qt C++ code leads to memory leaks.
>>
>> Each call to attributeNames() creates copy of strings
>> (PyQt-gpl-5.4.1/sip/QtQuick/qsgmaterial.sip):
>>
>>                 // Note that the converted value will leak.  This
>> shouldn't matter
>>                 // because the data should be static anyway.
>>                 result = new char *[PyList_GET_SIZE(names) + 1];
>>                 result[PyList_GET_SIZE(names)] = 0;
>>
>> And attributeNames() is called e.g. in each
>> Renderer::renderUnmergedBatch(), which can lead to unlimited memory
>> leaks.
>
>
> (1) is fixed but is it possible you could produce a short script that
> demonstrates (2). I know it will leak but (as I'm not an OpenGL programmer)
> it would be really useful to see how this method is normally called.
>
> Thanks,
> Phil


I made example where attributeNames() are called approximately every
10 ms: https://gist.github.com/rutsky/380932afec27ff0f108e

Also I published there Valgrind log, that shows that issue is inside
attributeNames() (but looks like not only there :) ):

==15263== 1,730,683 (38,352 direct, 1,692,331 indirect) bytes in 1,598
blocks are definitely lost in loss record 7,800 of 7,800
==15263==    at 0x4C2B800: operator new[](unsigned long) (in
/usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==15263==    by 0xBD20C63: sipVH_QtQuick_7(PyGILState_STATE, void
(*)(_sipSimpleWrapper*, PyGILState_STATE), _sipSimpleWrapper*,
_object*, int) (qsgmaterial.sip:118)
==15263==    by 0xBD3856F: sipQSGMaterialShader::attributeNames()
const (sipQtQuickpart0.cpp:12346)
==15263==    by 0xC1719DF:
QSGBatchRenderer::Renderer::renderMergedBatch(QSGBatchRenderer::Batch
const*) (qsgbatchrenderer.cpp:2220)
==15263==    by 0xC173146: QSGBatchRenderer::Renderer::renderBatches()
(qsgbatchrenderer.cpp:2417)
==15263==    by 0xC1745B9: QSGBatchRenderer::Renderer::render()
(qsgbatchrenderer.cpp:2590)
==15263==    by 0xC189374: QSGRenderer::renderScene(QSGBindable
const&) (qsgrenderer.cpp:206)
==15263==    by 0xC1891B2: QSGRenderer::renderScene(unsigned int)
(qsgrenderer.cpp:168)
==15263==    by 0xC1A27A2:
QSGRenderContext::renderNextFrame(QSGRenderer*, unsigned int)
(qsgcontext.cpp:554)
==15263==    by 0xC201092: QQuickWindowPrivate::renderSceneGraph(QSize
const&) (qquickwindow.cpp:381)
==15263==    by 0xC1CCA07: QSGRenderThread::syncAndRender()
(qsgthreadedrenderloop.cpp:582)
==15263==    by 0xC1CD2F0: QSGRenderThread::run()
(qsgthreadedrenderloop.cpp:663)

Also you can find in Valgrind log stack trace of how attributeNames()
is being called.


Regards,

Vladimir Rutsky


More information about the PyQt mailing list