From 5312b052e03225ffc593547c8af5596205657f29 Mon Sep 17 00:00:00 2001
From: Marc Mutz <marc.mutz@qt.io>
Date: Sun, 16 Jul 2023 14:22:37 +0200
Subject: [PATCH] wip: fix lookupHostImpl()'s mem-leak

Change-Id: I2d840e4b5f59616f35259f2048772eac8e206cff
---
 src/network/kernel/qhostinfo.cpp | 31 +++++++++++++++++--------------
 src/network/kernel/qhostinfo_p.h | 15 +++++++++------
 2 files changed, 26 insertions(+), 20 deletions(-)

diff --git a/src/network/kernel/qhostinfo.cpp b/src/network/kernel/qhostinfo.cpp
index ea2ffedd4c..3a0c33ae5d 100644
--- a/src/network/kernel/qhostinfo.cpp
+++ b/src/network/kernel/qhostinfo.cpp
@@ -107,8 +107,9 @@ void QHostInfoResult::postResultsReady(const QHostInfo &info)
     auto result = new QHostInfoResult(this);
     Q_CHECK_PTR(result);
 
-    auto metaCallEvent = QMetaCallEvent::create(slotObj, nullptr, signal_index, info);
+    auto metaCallEvent = QMetaCallEvent::create(slotObj.get(), nullptr, signal_index, info);
     Q_CHECK_PTR(metaCallEvent);
+    slotObj.release();
     qApp->postEvent(result, metaCallEvent);
 }
 
@@ -724,19 +725,20 @@ QString QHostInfo::localHostName()
     \internal
     Called by the various lookupHost overloads to perform the lookup.
 
-    Signals either the functor encapuslated in the \a slotObj in the context
+    Signals either the functor encapuslated in the \a rawSlotObj in the context
     of \a receiver, or the \a member slot of the \a receiver.
 
-    \a receiver might be the nullptr, but only if a \a slotObj is provided.
+    \a receiver might be the nullptr, but only if a \a rawSlotObj is provided.
 */
 int QHostInfo::lookupHostImpl(const QString &name,
                               const QObject *receiver,
-                              QtPrivate::QSlotObjectBase *slotObj,
+                              QtPrivate::QSlotObjectBase *rawSlotObj,
                               const char *member)
 {
+    auto slotObj = QtPrivate::SlotObjUniquePtr{rawSlotObj};
 #if defined QHOSTINFO_DEBUG
     qDebug("QHostInfo::lookupHostImpl(\"%s\", %p, %p, %s)",
-           name.toLatin1().constData(), receiver, slotObj, member ? member + 1 : 0);
+           name.toLatin1().constData(), receiver, slotObj.get(), member ? member + 1 : 0);
 #endif
     Q_ASSERT(!member != !slotObj); // one of these must be set, but not both
     Q_ASSERT(receiver || slotObj);
@@ -755,7 +757,7 @@ int QHostInfo::lookupHostImpl(const QString &name,
         hostInfo.setError(QHostInfo::HostNotFound);
         hostInfo.setErrorString(QCoreApplication::translate("QHostInfo", "No host name given"));
 
-        QHostInfoResult result(receiver, slotObj);
+        QHostInfoResult result(receiver, std::move(slotObj));
         if (receiver && member)
             QObject::connect(&result, SIGNAL(resultsReady(QHostInfo)),
                             receiver, member, Qt::QueuedConnection);
@@ -772,7 +774,7 @@ int QHostInfo::lookupHostImpl(const QString &name,
     QHostInfo hostInfo = QHostInfoAgent::lookup(name);
     hostInfo.setLookupId(id);
 
-    QHostInfoResult result(receiver, slotObj);
+    QHostInfoResult result(receiver, std::move(slotObj));
     if (receiver && member)
         QObject::connect(&result, SIGNAL(resultsReady(QHostInfo)),
                         receiver, member, Qt::QueuedConnection);
@@ -788,7 +790,7 @@ int QHostInfo::lookupHostImpl(const QString &name,
             QHostInfo info = manager->cache.get(name, &valid);
             if (valid) {
                 info.setLookupId(id);
-                QHostInfoResult result(receiver, slotObj);
+                QHostInfoResult result(receiver, std::move(slotObj));
                 if (receiver && member)
                     QObject::connect(&result, SIGNAL(resultsReady(QHostInfo)),
                                     receiver, member, Qt::QueuedConnection);
@@ -798,19 +800,19 @@ int QHostInfo::lookupHostImpl(const QString &name,
         }
 
         // cache is not enabled or it was not in the cache, do normal lookup
-        QHostInfoRunnable *runnable = new QHostInfoRunnable(name, id, receiver, slotObj);
+        auto runnable = std::make_unique<QHostInfoRunnable>(name, id, receiver, std::move(slotObj));
         if (receiver && member)
             QObject::connect(&runnable->resultEmitter, SIGNAL(resultsReady(QHostInfo)),
                                 receiver, member, Qt::QueuedConnection);
-        manager->scheduleLookup(runnable);
+        manager->scheduleLookup(std::move(runnable));
     }
 #endif // Q_OS_WASM
     return id;
 }
 
 QHostInfoRunnable::QHostInfoRunnable(const QString &hn, int i, const QObject *receiver,
-                                     QtPrivate::QSlotObjectBase *slotObj) :
-    toBeLookedUp(hn), id(i), resultEmitter(receiver, slotObj)
+                                     QtPrivate::SlotObjUniquePtr slotObj)
+    : toBeLookedUp(hn), id(i), resultEmitter(receiver, std::move(slotObj))
 {
     setAutoDelete(true);
 }
@@ -971,14 +973,15 @@ void QHostInfoLookupManager::rescheduleWithMutexHeld()
 }
 
 // called by QHostInfo
-void QHostInfoLookupManager::scheduleLookup(QHostInfoRunnable *r)
+void QHostInfoLookupManager::scheduleLookup(std::unique_ptr<QHostInfoRunnable> r)
 {
     QMutexLocker locker(&this->mutex);
 
     if (wasDeleted)
         return;
 
-    scheduledLookups.enqueue(r);
+    scheduledLookups.enqueue(r.get());
+    r.release();
     rescheduleWithMutexHeld();
 }
 
diff --git a/src/network/kernel/qhostinfo_p.h b/src/network/kernel/qhostinfo_p.h
index 2176b464ae..75a6fed716 100644
--- a/src/network/kernel/qhostinfo_p.h
+++ b/src/network/kernel/qhostinfo_p.h
@@ -43,8 +43,8 @@ class QHostInfoResult : public QObject
 {
     Q_OBJECT
 public:
-    QHostInfoResult(const QObject *receiver, QtPrivate::QSlotObjectBase *slotObj)
-        : receiver(receiver), slotObj(slotObj),
+    QHostInfoResult(const QObject *receiver, QtPrivate::SlotObjUniquePtr slotObj)
+        : receiver(receiver), slotObj(std::move(slotObj)),
           withContextObject(slotObj && receiver)
     {
         if (receiver)
@@ -61,9 +61,11 @@ protected:
 
 private:
     QHostInfoResult(const QHostInfoResult *other)
-        : receiver(other->receiver), slotObj(other->slotObj),
+        : receiver(other->receiver), slotObj(other->slotObj.get()),
           withContextObject(other->withContextObject)
     {
+        if (slotObj)
+            slotObj->ref();
         // cleanup if the application terminates before results are delivered
         connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit,
                 this, &QObject::deleteLater);
@@ -71,8 +73,9 @@ private:
         moveToThread(other->thread());
     }
 
+
     QPointer<const QObject> receiver = nullptr;
-    QtPrivate::QSlotObjectBase *slotObj = nullptr;
+    QtPrivate::SlotObjUniquePtr slotObj;
     const bool withContextObject = false;
 };
 
@@ -142,7 +145,7 @@ class QHostInfoRunnable : public QRunnable
 {
 public:
     QHostInfoRunnable(const QString &hn, int i, const QObject *receiver,
-                      QtPrivate::QSlotObjectBase *slotObj);
+                      QtPrivate::SlotObjUniquePtr slotObj);
     void run() override;
 
     QString toBeLookedUp;
@@ -160,7 +163,7 @@ public:
     void clear();
 
     // called from QHostInfo
-    void scheduleLookup(QHostInfoRunnable *r);
+    void scheduleLookup(std::unique_ptr<QHostInfoRunnable> r);
     void abortLookup(int id);
 
     // called from QHostInfoRunnable
-- 
2.25.1

