[PyQt] [BUG] Class name collision

Vladimir Rutsky rutsky.vladimir at gmail.com
Wed Dec 9 13:21:45 GMT 2015


If Python class name is the same as some Qt class name PyQt metacast
machinery may try to access missing attribute of the class and
generate AttributeError.
This AttributeError is not explicitly catched and if Python
interpreter is built with enabled assertions (e.g. in debug mode)
Python interpreter aborts with failed assert.

Here is an example that reproduces this bug (only in debug Python):
https://gist.github.com/rutsky/0adfbb56a32b208ab28c

from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout

class QWindow(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setLayout(QVBoxLayout())
        self.layout().parentWidget()  # <-- uncaught exception is
generated and asserted here

qapp = QApplication([])
qwin = QWindow()
qwin.show()
qapp.exec()


Example generates following error:

python: ../Objects/abstract.c:2050: PyObject_Call: Assertion `(result
!= ((void *)0) && !PyErr_Occurred()) || (result == ((void *)0) &&
PyErr_Occurred())' failed.
Aborted (core dumped)


Exception is generated in this PyQt code of
qpycore_qobject_qt_metacast() function
(PyQt-gpl-5.5.1/qpy/QtCore/qpycore_qobject_helpers.cpp):

    for (SIP_SSIZE_T i = 0; i < PyTuple_GET_SIZE(mro); ++i)
    {
        PyTypeObject *pytype = (PyTypeObject *)PyTuple_GET_ITEM(mro, i);

        if (!PyObject_IsInstance((PyObject *)pytype, (PyObject
*)&qpycore_pyqtWrapperType_Type))
            continue;

        const sipTypeDef *td = ((sipWrapperType *)pytype)->type;

        if (qstrcmp(pytype->tp_name, _clname) == 0)
        {
            // The generated type definitions represent the C++ (rather than
            // Python) hierachy.  If the C++ hierachy doesn't match then the
            // super-type must be provided by a mixin.
            if (PyType_IsSubtype(base_pytype, pytype))
                *sipCpp = sipGetAddress(pySelf);
            else
                // ====================================
                // Attribute error is generated here, something like:
                // "AttributeError: 'QWindow' object has no attribute 'QWidget'"
                // ====================================
               *sipCpp = sipGetMixinAddress(pySelf, td);

            is_py_class = true;
            break;
        }

While whole attribute access thing looks unstable to me (what if not
only class name will collide, but also my class will have accessed
attribute?), adding explicit check for AttributeError here fixes this
issue. Attached patch workarounds (fixes?) this issue.


Regards,

Vladimir Rutsky
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not_catched_attribute_error_fix.patch
Type: text/x-patch
Size: 815 bytes
Desc: not available
URL: <https://www.riverbankcomputing.com/pipermail/pyqt/attachments/20151209/632bde85/attachment.bin>


More information about the PyQt mailing list