diff options
author | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2021-06-29 08:34:56 +0200 |
---|---|---|
committer | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2021-06-30 21:10:26 +0200 |
commit | 525aa59e3871dccc0ffe6b1cb6441605e3635132 (patch) | |
tree | 7390997caaac7a77a8611018b0843fa2c1fcb9ce /sources | |
parent | 8e81ff9bf06043713a0f5f3727d52bc7ddf29dba (diff) |
PySide6: Fix crashes in QObject.findChild()
For all objects encountered in findChild(), a wrapper
was created just to be able to retrieve its type object
and check against it. As there is a name lookup involved,
it happens that non-QObject wrappers are created for this
(in the specific case, an enum wrapper), which leads to
crashes later on.
Refactor the code, extracting a helper function to PySide
which finds the best-matching type object for a QObject
to check on that. Rearrange the check so that the name is
checked first.
Fixes: PYSIDE-1609
Change-Id: I026854201f3f6eca9e5905105127f0a4b4588fa9
Reviewed-by: Christian Tismer <tismer@stackless.com>
(cherry picked from commit 98aef951920641dcdf4c217a0c51626cdf82caf8)
Diffstat (limited to 'sources')
-rw-r--r-- | sources/pyside2/PySide2/glue/qtcore.cpp | 52 | ||||
-rw-r--r-- | sources/pyside2/libpyside/pyside.cpp | 16 | ||||
-rw-r--r-- | sources/pyside2/libpyside/pyside.h | 5 |
3 files changed, 51 insertions, 22 deletions
diff --git a/sources/pyside2/PySide2/glue/qtcore.cpp b/sources/pyside2/PySide2/glue/qtcore.cpp index 0c5d75695..902b76a40 100644 --- a/sources/pyside2/PySide2/glue/qtcore.cpp +++ b/sources/pyside2/PySide2/glue/qtcore.cpp @@ -775,12 +775,35 @@ qRegisterMetaType<QVector<int> >("QVector<int>"); // @snippet qobject-metaobject // @snippet qobject-findchild-1 +static bool _findChildTypeMatch(const QObject *child, PyTypeObject *desiredType) +{ + auto *pyChildType = PySide::getTypeForQObject(child); + return pyChildType != nullptr && PyType_IsSubtype(pyChildType, desiredType); +} + +static inline bool _findChildrenComparator(const QObject *child, + const QRegularExpression &name) +{ + return name.match(child->objectName()).hasMatch(); +} + +static inline bool _findChildrenComparator(const QObject *child, + const QString &name) +{ + return name.isNull() || name == child->objectName(); +} + +static inline bool _findChildrenComparator(const QObject *child, + const QRegExp &name) +{ + return name.indexIn(child->objectName()) != -1; +} + static QObject *_findChildHelper(const QObject *parent, const QString &name, PyTypeObject *desiredType) { for (auto *child : parent->children()) { - Shiboken::AutoDecRef pyChild(%CONVERTTOPYTHON[QObject *](child)); - if (PyType_IsSubtype(Py_TYPE(pyChild), desiredType) - && (name.isNull() || name == child->objectName())) { + if (_findChildrenComparator(child, name) + && _findChildTypeMatch(child, desiredType)) { return child; } } @@ -793,28 +816,15 @@ static QObject *_findChildHelper(const QObject *parent, const QString &name, PyT return nullptr; } -static inline bool _findChildrenComparator(const QObject *&child, const QRegExp &name) -{ - return name.indexIn(child->objectName()) != -1; -} - -static inline bool _findChildrenComparator(const QObject *&child, const QRegularExpression &name) -{ - return name.match(child->objectName()).hasMatch(); -} - -static inline bool _findChildrenComparator(const QObject *&child, const QString &name) -{ - return name.isNull() || name == child->objectName(); -} - -template<typename T> +template<typename T> // QString/QRegularExpression/QRegExp static void _findChildrenHelper(const QObject *parent, const T& name, PyTypeObject *desiredType, PyObject *result) { for (const auto *child : parent->children()) { - Shiboken::AutoDecRef pyChild(%CONVERTTOPYTHON[QObject *](child)); - if (PyType_IsSubtype(Py_TYPE(pyChild), desiredType) && _findChildrenComparator(child, name)) + if (_findChildrenComparator(child, name) + && _findChildTypeMatch(child, desiredType)) { + Shiboken::AutoDecRef pyChild(%CONVERTTOPYTHON[QObject *](child)); PyList_Append(result, pyChild); + } _findChildrenHelper(child, name, desiredType, result); } } diff --git a/sources/pyside2/libpyside/pyside.cpp b/sources/pyside2/libpyside/pyside.cpp index 6f15671a0..721529445 100644 --- a/sources/pyside2/libpyside/pyside.cpp +++ b/sources/pyside2/libpyside/pyside.cpp @@ -394,7 +394,7 @@ static const char invalidatePropertyName[] = "_PySideInvalidatePtr"; // PYSIDE-1214, when creating new wrappers for classes inheriting QObject but // not exposed to Python, try to find the best-matching (most-derived) Qt // class by walking up the meta objects. -static const char *typeName(QObject *cppSelf) +static const char *typeName(const QObject *cppSelf) { const char *typeName = typeid(*cppSelf).name(); if (!Shiboken::Conversions::getConverter(typeName)) { @@ -409,6 +409,20 @@ static const char *typeName(QObject *cppSelf) return typeName; } +PyTypeObject *getTypeForQObject(const QObject *cppSelf) +{ + // First check if there are any instances of Python implementations + // inheriting a PySide class. + auto *existing = Shiboken::BindingManager::instance().retrieveWrapper(cppSelf); + if (existing != nullptr) + return reinterpret_cast<PyObject *>(existing)->ob_type; + // Find the best match (will return a PySide type) + auto *sbkObjectType = Shiboken::ObjectType::typeForTypeName(typeName(cppSelf)); + if (sbkObjectType != nullptr) + return reinterpret_cast<PyTypeObject *>(sbkObjectType); + return nullptr; +} + PyObject *getWrapperForQObject(QObject *cppSelf, SbkObjectType *sbk_type) { PyObject *pyOut = reinterpret_cast<PyObject *>(Shiboken::BindingManager::instance().retrieveWrapper(cppSelf)); diff --git a/sources/pyside2/libpyside/pyside.h b/sources/pyside2/libpyside/pyside.h index c3dbe6bd3..8b4910f45 100644 --- a/sources/pyside2/libpyside/pyside.h +++ b/sources/pyside2/libpyside/pyside.h @@ -122,6 +122,11 @@ PYSIDE_API void setNextQObjectMemoryAddr(void *addr); PYSIDE_API PyObject *getWrapperForQObject(QObject *cppSelf, SbkObjectType *sbk_type); +/// Return the best-matching type for a QObject (Helper for QObject.findType()) +/// \param cppSelf QObject instance +/// \return type object +PYSIDE_API PyTypeObject *getTypeForQObject(const QObject *cppSelf); + #ifdef PYSIDE_QML_SUPPORT // Used by QtQuick module to notify QtQml that custom QtQuick items can be registered. typedef bool (*QuickRegisterItemFunction)(PyObject *pyObj, const char *uri, int versionMajor, |