From 189d87b6ae0bad96efa77992f001c7be8b9a7ed7 Mon Sep 17 00:00:00 2001 From: PA Dev Bot <344001113+pa-devbot@users.noreply.github.com> Date: Sun, 1 Nov 2026 20:08:17 +0000 Subject: [PATCH] ClientSocket_Qt: give signal completions shared ownership The 5 s completion wait in send() was only safe while the queued call ran within the window: the completion object was stack-local, so if the wait expired and the event thread delivered the queued internal_send() later, the slot wrote through a dead stack pointer (stack-use-after-return) - the same issue ServerSocket_Qt had, fixed the same way in the ServerSocket_Qt work. The signal now passes QSharedPointer by value: the queued call's own copy keeps the payload alive until it runs (or is discarded with the socket), so the wait's expiry is safe. --- Common/Cpp/Sockets/ClientSocket_Qt.cpp | 21 ++++++++++++--------- Common/Cpp/Sockets/ClientSocket_Qt.h | 3 ++- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/Common/Cpp/Sockets/ClientSocket_Qt.cpp b/Common/Cpp/Sockets/ClientSocket_Qt.cpp index 7fbdc75abf..62f933d034 100644 --- a/Common/Cpp/Sockets/ClientSocket_Qt.cpp +++ b/Common/Cpp/Sockets/ClientSocket_Qt.cpp @@ -5,6 +5,7 @@ */ #include +#include #include #include #include "Common/Qt/QtThreadPool.h" @@ -93,25 +94,27 @@ size_t ClientSocket_Qt::send(const void* data, size_t bytes){ return 0; } - SendData send_data; - send_data.packet.assign((const char*)data, bytes); + QSharedPointer send_data = QSharedPointer::create(); + send_data->packet.assign((const char*)data, bytes); - emit internal_send(&send_data); + emit internal_send(send_data); // Wait for the socket's event thread to finish writing the packet. // The timeout covers the case where "close()" destroys the socket // before the queued call ever runs, in which case it will never - // complete on its own. + // complete on its own. The shared ownership makes the timeout + // safe: if it expires, the queued call's own copy keeps the + // payload alive until it runs. { - std::unique_lock lg(send_data.lock); - send_data.cv.wait_for( + std::unique_lock lg(send_data->lock); + send_data->cv.wait_for( lg, std::chrono::seconds(5), - [&send_data]{ return send_data.done; } + [&send_data]{ return send_data->done; } ); } - return send_data.bytes_sent; + return send_data->bytes_sent; } void ClientSocket_Qt::connection_failed(const std::string& error_message){ @@ -238,7 +241,7 @@ std::unique_ptr ClientSocket_Qt::make_socket(){ ); QObject::connect( this, &ClientSocket_Qt::internal_send, - socket.get(), [this, sock = socket.get()](SendData* send_data){ + socket.get(), [this, sock = socket.get()](QSharedPointer send_data){ { std::lock_guard lg(m_lock); m_sends_in_flight.fetch_add(1, std::memory_order_acq_rel); diff --git a/Common/Cpp/Sockets/ClientSocket_Qt.h b/Common/Cpp/Sockets/ClientSocket_Qt.h index c944ec2b6f..f03f9b59b4 100644 --- a/Common/Cpp/Sockets/ClientSocket_Qt.h +++ b/Common/Cpp/Sockets/ClientSocket_Qt.h @@ -10,6 +10,7 @@ #include #include #include +#include #include "Common/Cpp/Concurrency/Mutex.h" #include "Common/Cpp/Concurrency/ConditionVariable.h" #include "AbstractClientSocket.h" @@ -60,7 +61,7 @@ class ClientSocket_Qt final : public QObject, public AbstractClientSocket{ signals: void internal_connect(const std::string& address, uint16_t port); - void internal_send(SendData* send_data); + void internal_send(QSharedPointer send_data); private: