From afffc5838523595ac1625c5e4ae27b99f7e24557 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 26 Jun 2023 11:02:56 +0200 Subject: 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 Reviewed-by: Qt CI Bot (cherry picked from commit 46ab90a5f9493ba0687834e6fa83413ca2437ce5) Reviewed-by: Qt Cherry-pick Bot --- build_history/blacklist.txt | 4 ---- 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(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(receiver)->addSlot(signature); -- cgit v1.2.3