https://github.com/aokblast created https://github.com/llvm/llvm-project/pull/209019
transport::Binder::OnClosed() holds m_mutex (a recursive_mutex) while invoking m_disconnect_handler. In the MCP server, that handler removes the disconnected client, which owns the transport and therefore the Binder itself. As a result, the Binder -- and its m_mutex -- are destroyed while the scoped_lock in OnClosed still holds the lock. This is a use-after-free everywhere, as the lock guard later unlocks freed memory. Move the disconnect handler out of the critical section and release the lock before invoking it, so the Binder can be safely destroyed without holding or destroying a locked mutex. >From 1aa1cbd77b7b4391e151a484b21073f50e21d016 Mon Sep 17 00:00:00 2001 From: ShengYi Hung <[email protected]> Date: Sun, 12 Jul 2026 20:59:25 +0800 Subject: [PATCH] [LLDB] Fix use-after-free destroying a Binder from its OnClosed handler transport::Binder::OnClosed() holds m_mutex (a recursive_mutex) while invoking m_disconnect_handler. In the MCP server, that handler removes the disconnected client, which owns the transport and therefore the Binder itself. As a result, the Binder -- and its m_mutex -- are destroyed while the scoped_lock in OnClosed still holds the lock. This is a use-after-free everywhere, as the lock guard later unlocks freed memory. Move the disconnect handler out of the critical section and release the lock before invoking it, so the Binder can be safely destroyed without holding or destroying a locked mutex. --- lldb/include/lldb/Host/JSONTransport.h | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/lldb/include/lldb/Host/JSONTransport.h b/lldb/include/lldb/Host/JSONTransport.h index 0f58697e9f34d..df63a0845f3dd 100644 --- a/lldb/include/lldb/Host/JSONTransport.h +++ b/lldb/include/lldb/Host/JSONTransport.h @@ -587,9 +587,18 @@ class Binder : public JSONTransport<Proto>::MessageHandler { } void OnClosed() override { - std::scoped_lock<std::recursive_mutex> guard(m_mutex); - if (m_disconnect_handler) - m_disconnect_handler(); + // The disconnect handler may destroy this Binder -- e.g. the server + // removes the disconnected client, which owns the transport and, with it, + // this handler. Move the handler out and release the lock before invoking + // it, so we neither run the teardown while holding m_mutex nor destroy a + // still-locked mutex. + Callback<void()> disconnect_handler; + { + std::scoped_lock<std::recursive_mutex> guard(m_mutex); + disconnect_handler = std::move(m_disconnect_handler); + } + if (disconnect_handler) + disconnect_handler(); } private: _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
