From 4ac25f8198aa1743f38f4e0b6de97bd7478b8f57 Mon Sep 17 00:00:00 2001 From: "seer-by-sentry[bot]" <157164994+seer-by-sentry[bot]@users.noreply.github.com> Date: Thu, 7 May 2026 22:08:26 +0000 Subject: [PATCH] bugfix(network): Prevent use-after-free during HTTP request cleanup on shutdown --- .../GeneralsOnline/HTTP/HTTPManager.cpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/GeneralsMD/Code/GameEngine/Source/GameNetwork/GeneralsOnline/HTTP/HTTPManager.cpp b/GeneralsMD/Code/GameEngine/Source/GameNetwork/GeneralsOnline/HTTP/HTTPManager.cpp index 7a3f38fe3f..0039ef29d4 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameNetwork/GeneralsOnline/HTTP/HTTPManager.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameNetwork/GeneralsOnline/HTTP/HTTPManager.cpp @@ -103,7 +103,12 @@ void HTTPManager::Shutdown() HTTPRequest* pRequest = *it; if (pRequest != nullptr && pRequest->EasyHandleMatches(pCurlHandle)) { - pRequest->Threaded_SetComplete(m->data.result); + // During shutdown, skip invoking the completion callback. The callback + // may reference objects (e.g. NGMP_OnlineServices_StatsInterface via + // captured 'this') that have already been or are being destroyed, + // leading to use-after-free memory corruption and crashes in unrelated + // destructors such as GameSpyMiscPreferences::~GameSpyMiscPreferences(). + // HTTPRequest::~HTTPRequest() handles all necessary curl handle cleanup. delete pRequest; m_vecRequestsInFlight.erase(it); break; @@ -122,6 +127,17 @@ void HTTPManager::Shutdown() NetworkLog(ELogVerbosity::LOG_RELEASE, "[HTTPManager] All in-flight requests completed"); + // Delete any remaining in-flight requests without invoking their callbacks. + // These are requests that completed via curl but were not matched above, or + // requests that are still pending completion. Invoking callbacks here is unsafe + // as the objects they reference may already be destroyed. + for (HTTPRequest* pRequest : m_vecRequestsInFlight) + { + if (pRequest != nullptr) + { + delete pRequest; + } + } m_vecRequestsInFlight.clear(); // Now safe to cleanup