Skip to content

Commit 6e28700

Browse files
authored
[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.
1 parent c8f4c35 commit 6e28700

File tree

3 files changed

+87
-3
lines changed

3 files changed

+87
-3
lines changed
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
"""
2+
Test lldb-dap IO handling.
3+
"""
4+
5+
from lldbsuite.test.decorators import *
6+
import lldbdap_testcase
7+
import dap_server
8+
9+
10+
class TestDAP_io(lldbdap_testcase.DAPTestCaseBase):
11+
def launch(self):
12+
log_file_path = self.getBuildArtifact("dap.txt")
13+
process, _ = dap_server.DebugAdapterServer.launch(
14+
executable=self.lldbDAPExec, log_file=log_file_path
15+
)
16+
17+
def cleanup():
18+
# If the process is still alive, terminate it.
19+
if process.poll() is None:
20+
process.terminate()
21+
stdout_data = process.stdout.read()
22+
stderr_data = process.stderr.read()
23+
print("========= STDOUT =========")
24+
print(stdout_data)
25+
print("========= END =========")
26+
print("========= STDERR =========")
27+
print(stderr_data)
28+
print("========= END =========")
29+
print("========= DEBUG ADAPTER PROTOCOL LOGS =========")
30+
with open(log_file_path, "r") as file:
31+
print(file.read())
32+
print("========= END =========")
33+
34+
# Execute the cleanup function during test case tear down.
35+
self.addTearDownHook(cleanup)
36+
37+
return process
38+
39+
def test_eof_immediately(self):
40+
"""
41+
lldb-dap handles EOF without any other input.
42+
"""
43+
process = self.launch()
44+
process.stdin.close()
45+
self.assertEqual(process.wait(timeout=5.0), 0)
46+
47+
def test_partial_header(self):
48+
"""
49+
lldb-dap handles parital message headers.
50+
"""
51+
process = self.launch()
52+
process.stdin.write(b"Content-Length: ")
53+
process.stdin.close()
54+
self.assertEqual(process.wait(timeout=5.0), 0)
55+
56+
def test_incorrect_content_length(self):
57+
"""
58+
lldb-dap handles malformed content length headers.
59+
"""
60+
process = self.launch()
61+
process.stdin.write(b"Content-Length: abc")
62+
process.stdin.close()
63+
self.assertEqual(process.wait(timeout=5.0), 0)
64+
65+
def test_partial_content_length(self):
66+
"""
67+
lldb-dap handles partial messages.
68+
"""
69+
process = self.launch()
70+
process.stdin.write(b"Content-Length: 10{")
71+
process.stdin.close()
72+
self.assertEqual(process.wait(timeout=5.0), 0)

lldb/tools/lldb-dap/DAP.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -856,7 +856,11 @@ lldb::SBError DAP::Disconnect(bool terminateDebuggee) {
856856
}
857857

858858
llvm::Error DAP::Loop() {
859-
auto cleanup = llvm::make_scope_exit([this]() { StopEventHandlers(); });
859+
auto cleanup = llvm::make_scope_exit([this]() {
860+
if (output.descriptor)
861+
output.descriptor->Close();
862+
StopEventHandlers();
863+
});
860864
while (!disconnecting) {
861865
llvm::json::Object object;
862866
lldb_dap::PacketStatus status = GetNextObject(object);

lldb/tools/lldb-dap/IOStream.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,23 @@ bool InputStream::read_full(std::ofstream *log, size_t length,
3535
if (status.Fail())
3636
return false;
3737

38-
text += data;
38+
text += data.substr(0, length);
3939
return true;
4040
}
4141

4242
bool InputStream::read_line(std::ofstream *log, std::string &line) {
4343
line.clear();
4444
while (true) {
45-
if (!read_full(log, 1, line))
45+
std::string next;
46+
if (!read_full(log, 1, next))
4647
return false;
4748

49+
// If EOF is encoutnered, '' is returned, break out of this loop.
50+
if (next.empty())
51+
return false;
52+
53+
line += next;
54+
4855
if (llvm::StringRef(line).ends_with("\r\n"))
4956
break;
5057
}
@@ -60,6 +67,7 @@ bool InputStream::read_expected(std::ofstream *log, llvm::StringRef expected) {
6067
if (log)
6168
*log << "Warning: Expected '" << expected.str() << "', got '" << result
6269
<< "\n";
70+
return false;
6371
}
6472
return true;
6573
}

0 commit comments

Comments
 (0)