aboutsummaryrefslogtreecommitdiffstats
path: root/sources
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@qt.io>2021-06-29 08:34:56 +0200
committerFriedemann Kleint <Friedemann.Kleint@qt.io>2021-06-30 21:10:26 +0200
commit525aa59e3871dccc0ffe6b1cb6441605e3635132 (patch)
tree7390997caaac7a77a8611018b0843fa2c1fcb9ce /sources
parent8e81ff9bf06043713a0f5f3727d52bc7ddf29dba (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.cpp52
-rw-r--r--sources/pyside2/libpyside/pyside.cpp16
-rw-r--r--sources/pyside2/libpyside/pyside.h5
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,