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

Reply via email to