[Lldb-commits] [lldb] [lldb] Ignore async notification packets while waiting for a response (PR #202556)

via lldb-commits lldb-commits at lists.llvm.org
Tue Jun 9 03:04:57 PDT 2026


https://github.com/dlgus8648 updated https://github.com/llvm/llvm-project/pull/202556

>From 3fc3e8f91128ad4f907e7f53ff41a50076c8c48e Mon Sep 17 00:00:00 2001
From: KIMRIHYEON <dlgus8648 at naver.com>
Date: Tue, 9 Jun 2026 18:07:43 +0900
Subject: [PATCH] [lldb] Ignore async notification packets while waiting for a
 response

OpenOCD's gdbserver sends an async notification packet
("%oocd_keepalive:XX#cc") roughly every 500ms while a long memory
read/write is in progress. WaitForPacketNoLock() treated any non-invalid
packet returned by CheckForPacket() -- including a PacketType::Notify --
as the response to the pending request, so a keepalive arriving during a
memory write produced:

  unexpected response to GDB server memory write packet
  'M2ffff8,4:54430000': 'oocd_keepalive:00'

GDB has silently dropped unknown notifications received while waiting for
a packet since 7.0 (2009). Match that behaviour: drop notification
packets and keep waiting for the actual response. The LLDB client does
not otherwise consume '%' notifications, so this is safe.

Adds a unit test covering single and multiple notifications preceding the
response.

Fixes #197944.

Assisted-by: Claude Code (Anthropic)
---
 .../gdb-remote/GDBRemoteCommunication.cpp     | 24 +++++++++++++++++--
 .../gdb-remote/GDBRemoteCommunicationTest.cpp | 19 +++++++++++++++
 2 files changed, 41 insertions(+), 2 deletions(-)

diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
index 04f486882e2c2..56d1d8bc09fb1 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
@@ -242,7 +242,17 @@ GDBRemoteCommunication::WaitForPacketNoLock(StringExtractorGDBRemote &packet,
   Log *log = GetLog(GDBRLog::Packets);
 
   // Check for a packet from our cache first without trying any reading...
-  if (CheckForPacket(nullptr, 0, packet) != PacketType::Invalid)
+  // Async notification packets (e.g. OpenOCD's "oocd_keepalive", sent during
+  // long memory operations) are not responses to our request. GDB silently
+  // drops such notifications while waiting for a packet; do the same and keep
+  // looking for the actual response.
+  PacketType packet_type = CheckForPacket(nullptr, 0, packet);
+  while (packet_type == PacketType::Notify) {
+    LLDB_LOGF(log, "GDBRemoteCommunication::%s ignoring notification packet",
+              __FUNCTION__);
+    packet_type = CheckForPacket(nullptr, 0, packet);
+  }
+  if (packet_type != PacketType::Invalid)
     return PacketResult::Success;
 
   bool timed_out = false;
@@ -258,7 +268,17 @@ GDBRemoteCommunication::WaitForPacketNoLock(StringExtractorGDBRemote &packet,
                      error, bytes_read);
 
     if (bytes_read > 0) {
-      if (CheckForPacket(buffer, bytes_read, packet) != PacketType::Invalid)
+      // Drop any async notification packets (see above) and keep waiting for
+      // the actual response. Once the freshly-read bytes have been consumed,
+      // re-check the cache for any further buffered packets.
+      packet_type = CheckForPacket(buffer, bytes_read, packet);
+      while (packet_type == PacketType::Notify) {
+        LLDB_LOGF(log,
+                  "GDBRemoteCommunication::%s ignoring notification packet",
+                  __FUNCTION__);
+        packet_type = CheckForPacket(nullptr, 0, packet);
+      }
+      if (packet_type != PacketType::Invalid)
         return PacketResult::Success;
     } else {
       switch (status) {
diff --git a/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationTest.cpp b/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationTest.cpp
index e96d587b10e25..2491ace98565b 100644
--- a/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationTest.cpp
+++ b/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationTest.cpp
@@ -75,6 +75,25 @@ TEST_F(GDBRemoteCommunicationTest, ReadPacket) {
   }
 }
 
+// Test that async notification packets received while waiting for a response
+// are silently dropped and that we keep looking for the actual response.
+// OpenOCD sends a "%oocd_keepalive:XX#cc" notification during long memory
+// operations; like GDB (since 7.0), LLDB must ignore it rather than mistake it
+// for the response. See https://github.com/llvm/llvm-project/issues/197944.
+TEST_F(GDBRemoteCommunicationTest, ReadPacketIgnoresNotifications) {
+  StringExtractorGDBRemote response;
+
+  // A single notification ahead of the response.
+  ASSERT_TRUE(Write("%oocd_keepalive:00#54$OK#9a"));
+  ASSERT_EQ(PacketResult::Success, client.ReadPacket(response));
+  EXPECT_EQ("OK", response.GetStringRef());
+
+  // Several notifications ahead of the response.
+  ASSERT_TRUE(Write("%oocd_keepalive:01#55%oocd_keepalive:02#56$OK#9a"));
+  ASSERT_EQ(PacketResult::Success, client.ReadPacket(response));
+  EXPECT_EQ("OK", response.GetStringRef());
+}
+
 // Test that packets with incorrect RLE sequences do not cause a crash and
 // reported as invalid.
 TEST_F(GDBRemoteCommunicationTest, CheckForPacket) {



More information about the lldb-commits mailing list