diff options
author | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2023-06-26 11:02:56 +0200 |
---|---|---|
committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2023-06-28 07:19:38 +0000 |
commit | afffc5838523595ac1625c5e4ae27b99f7e24557 (patch) | |
tree | fce0733bfaf5712e6bc3f18ae40d5da2433d8456 | |
parent | 7222d8a0470eaa254128b3207a2c295025dd1819 (diff) |
PySide6/SignalManager: Fix memory leaks connecting free methods/lambdas
Change 1270a9e82e5bc3bd53a1131698ece60403da1192 changed the deletion
of global receivers from listening to QObject::destroyed() (which
caused thread issues) to using QPointer<> and purging the lists in
notify. What is missing was the deletion of global receivers that are
not tied by weak reference to a Python instance. Add a check in
notify() to clean out the empty global receivers.
Fixes: PYSIDE-2371
Fixes: PYSIDE-2299
Task-number: PYSIDE-2141
Change-Id: I39dca2a21088930c9a7f8e5eb7e948b3fff49b4b
Reviewed-by: Christian Tismer <tismer@stackless.com>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
(cherry picked from commit 46ab90a5f9493ba0687834e6fa83413ca2437ce5)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r-- | build_history/blacklist.txt | 4 | ||||
-rw-r--r-- | sources/pyside6/libpyside/signalmanager.cpp | 19 |
2 files changed, 19 insertions, 4 deletions
diff --git a/build_history/blacklist.txt b/build_history/blacklist.txt index 1da2b0ca0..475e5d40e 100644 --- a/build_history/blacklist.txt +++ b/build_history/blacklist.txt @@ -6,10 +6,6 @@ linux darwin win32 -[signals::anonymous_slot_leak_test] - linux - darwin - win32 [Qt3DExtras::qt3dextras_test] win32 ci linux diff --git a/sources/pyside6/libpyside/signalmanager.cpp b/sources/pyside6/libpyside/signalmanager.cpp index 753b50557..aa20c23d6 100644 --- a/sources/pyside6/libpyside/signalmanager.cpp +++ b/sources/pyside6/libpyside/signalmanager.cpp @@ -210,6 +210,7 @@ struct SignalManager::SignalManagerPrivate void deleteGobalReceiver(const QObject *gr); void clear(); + void purgeEmptyGobalReceivers(); GlobalReceiverV2Map m_globalReceivers; static SignalManager::QmlMetaCallErrorHandler m_qmlMetaCallErrorHandler; @@ -307,6 +308,7 @@ QObject *SignalManager::globalReceiver(QObject *sender, PyObject *callback, QObj void SignalManager::notifyGlobalReceiver(QObject *receiver) { reinterpret_cast<GlobalReceiverV2 *>(receiver)->notify(); + m_d->purgeEmptyGobalReceivers(); } void SignalManager::releaseGlobalReceiver(const QObject *source, QObject *receiver) @@ -342,6 +344,23 @@ void SignalManager::SignalManagerPrivate::clear() m_globalReceivers.erase(m_globalReceivers.cbegin()); } +static bool isEmptyGlobalReceiver(const GlobalReceiverV2Ptr &g) +{ + return g->isEmpty(); +} + +void SignalManager::SignalManagerPrivate::purgeEmptyGobalReceivers() +{ + // Delete repetitively (see comment in clear()). + while (true) { + auto it = std::find_if(m_globalReceivers.cbegin(), m_globalReceivers.cend(), + isEmptyGlobalReceiver); + if (it == m_globalReceivers.cend()) + break; + m_globalReceivers.erase(it); + } +} + int SignalManager::globalReceiverSlotIndex(QObject *receiver, const char *signature) const { return static_cast<GlobalReceiverV2 *>(receiver)->addSlot(signature); |