[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