[Lldb-commits] [lldb] 6e28700 - [lldb-dap] Improving EOF handling on stream input and adding new unit tests (#129581)

via lldb-commits lldb-commits at lists.llvm.org
Tue Mar 4 10:09:31 PST 2025


Author: John Harrison
Date: 2025-03-04T10:09:28-08:00
New Revision: 6e28700ab1d876a9b01647782ce3c0ed4d8e0bb4

URL: https://github.com/llvm/llvm-project/commit/6e28700ab1d876a9b01647782ce3c0ed4d8e0bb4
DIFF: https://github.com/llvm/llvm-project/commit/6e28700ab1d876a9b01647782ce3c0ed4d8e0bb4.diff

LOG: [lldb-dap] Improving EOF handling on stream input and adding new unit tests (#129581)

This should improve the handling of EOF on stdin and adding some new
unit tests to malformed requests.

Added: 
    lldb/test/API/tools/lldb-dap/io/TestDAP_io.py

Modified: 
    lldb/tools/lldb-dap/DAP.cpp
    lldb/tools/lldb-dap/IOStream.cpp

Removed: 
    


################################################################################
diff  --git a/lldb/test/API/tools/lldb-dap/io/TestDAP_io.py b/lldb/test/API/tools/lldb-dap/io/TestDAP_io.py
new file mode 100644
index 0000000000000..a39bd17ceb3b3
--- /dev/null
+++ b/lldb/test/API/tools/lldb-dap/io/TestDAP_io.py
@@ -0,0 +1,72 @@
+"""
+Test lldb-dap IO handling.
+"""
+
+from lldbsuite.test.decorators import *
+import lldbdap_testcase
+import dap_server
+
+
+class TestDAP_io(lldbdap_testcase.DAPTestCaseBase):
+    def launch(self):
+        log_file_path = self.getBuildArtifact("dap.txt")
+        process, _ = dap_server.DebugAdapterServer.launch(
+            executable=self.lldbDAPExec, log_file=log_file_path
+        )
+
+        def cleanup():
+            # If the process is still alive, terminate it.
+            if process.poll() is None:
+                process.terminate()
+                stdout_data = process.stdout.read()
+                stderr_data = process.stderr.read()
+                print("========= STDOUT =========")
+                print(stdout_data)
+                print("========= END =========")
+                print("========= STDERR =========")
+                print(stderr_data)
+                print("========= END =========")
+                print("========= DEBUG ADAPTER PROTOCOL LOGS =========")
+                with open(log_file_path, "r") as file:
+                    print(file.read())
+                print("========= END =========")
+
+        # Execute the cleanup function during test case tear down.
+        self.addTearDownHook(cleanup)
+
+        return process
+
+    def test_eof_immediately(self):
+        """
+        lldb-dap handles EOF without any other input.
+        """
+        process = self.launch()
+        process.stdin.close()
+        self.assertEqual(process.wait(timeout=5.0), 0)
+
+    def test_partial_header(self):
+        """
+        lldb-dap handles parital message headers.
+        """
+        process = self.launch()
+        process.stdin.write(b"Content-Length: ")
+        process.stdin.close()
+        self.assertEqual(process.wait(timeout=5.0), 0)
+
+    def test_incorrect_content_length(self):
+        """
+        lldb-dap handles malformed content length headers.
+        """
+        process = self.launch()
+        process.stdin.write(b"Content-Length: abc")
+        process.stdin.close()
+        self.assertEqual(process.wait(timeout=5.0), 0)
+
+    def test_partial_content_length(self):
+        """
+        lldb-dap handles partial messages.
+        """
+        process = self.launch()
+        process.stdin.write(b"Content-Length: 10{")
+        process.stdin.close()
+        self.assertEqual(process.wait(timeout=5.0), 0)

diff  --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp
index 53c514b790f38..3dc9d6f5ca0a4 100644
--- a/lldb/tools/lldb-dap/DAP.cpp
+++ b/lldb/tools/lldb-dap/DAP.cpp
@@ -856,7 +856,11 @@ lldb::SBError DAP::Disconnect(bool terminateDebuggee) {
 }
 
 llvm::Error DAP::Loop() {
-  auto cleanup = llvm::make_scope_exit([this]() { StopEventHandlers(); });
+  auto cleanup = llvm::make_scope_exit([this]() {
+    if (output.descriptor)
+      output.descriptor->Close();
+    StopEventHandlers();
+  });
   while (!disconnecting) {
     llvm::json::Object object;
     lldb_dap::PacketStatus status = GetNextObject(object);

diff  --git a/lldb/tools/lldb-dap/IOStream.cpp b/lldb/tools/lldb-dap/IOStream.cpp
index c6f1bfaf3b799..ee22a297ec248 100644
--- a/lldb/tools/lldb-dap/IOStream.cpp
+++ b/lldb/tools/lldb-dap/IOStream.cpp
@@ -35,16 +35,23 @@ bool InputStream::read_full(std::ofstream *log, size_t length,
   if (status.Fail())
     return false;
 
-  text += data;
+  text += data.substr(0, length);
   return true;
 }
 
 bool InputStream::read_line(std::ofstream *log, std::string &line) {
   line.clear();
   while (true) {
-    if (!read_full(log, 1, line))
+    std::string next;
+    if (!read_full(log, 1, next))
       return false;
 
+    // If EOF is encoutnered, '' is returned, break out of this loop.
+    if (next.empty())
+      return false;
+
+    line += next;
+
     if (llvm::StringRef(line).ends_with("\r\n"))
       break;
   }
@@ -60,6 +67,7 @@ bool InputStream::read_expected(std::ofstream *log, llvm::StringRef expected) {
     if (log)
       *log << "Warning: Expected '" << expected.str() << "', got '" << result
            << "\n";
+    return false;
   }
   return true;
 }


        


More information about the lldb-commits mailing list