Skip to content

[lldb-dap] Ensure we do not print the close sentinel when closing stdout. #126833

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Feb 13, 2025

Conversation

ashgti
Copy link
Contributor

@ashgti ashgti commented Feb 12, 2025

If you have an lldb-dap log file you'll almost always see a final message like:

<-- 
Content-Length: 94

{
  "body": {
    "category": "stdout",
    "output": "\u0000\u0000"
  },
  "event": "output",
  "seq": 0,
  "type": "event"
}
<-- 
Content-Length: 94

{
  "body": {
    "category": "stderr",
    "output": "\u0000\u0000"
  },
  "event": "output",
  "seq": 0,
  "type": "event"
}

The OutputRedirect is always writing the "\0" byte as a final stdout message during shutdown. Instead, I adjusted this to detect the sentinel value and break out of the read loop as if we detected EOF.

…out.

The OutputRedirect is always writing the `"\0"` byte as a final stdout message during shutdown. Instead, I adjusted this to detect the sentinel value and break out of the read loop as if we detected EOF.
@llvmbot
Copy link
Member

llvmbot commented Feb 12, 2025

@llvm/pr-subscribers-lldb

Author: John Harrison (ashgti)

Changes

If you have an lldb-dap log file you'll almost always see a final message like:

&lt;-- 
Content-Length: 94

{
  "body": {
    "category": "stdout",
    "output": "\u0000\u0000"
  },
  "event": "output",
  "seq": 0,
  "type": "event"
}
&lt;-- 
Content-Length: 94

{
  "body": {
    "category": "stderr",
    "output": "\u0000\u0000"
  },
  "event": "output",
  "seq": 0,
  "type": "event"
}

The OutputRedirect is always writing the "\0" byte as a final stdout message during shutdown. Instead, I adjusted this to detect the sentinel value and break out of the read loop as if we detected EOF.


Full diff: https://github.com/llvm/llvm-project/pull/126833.diff

1 Files Affected:

  • (modified) lldb/tools/lldb-dap/OutputRedirector.cpp (+10-3)
diff --git a/lldb/tools/lldb-dap/OutputRedirector.cpp b/lldb/tools/lldb-dap/OutputRedirector.cpp
index a23572ab7ae04..c5090338cfd1c 100644
--- a/lldb/tools/lldb-dap/OutputRedirector.cpp
+++ b/lldb/tools/lldb-dap/OutputRedirector.cpp
@@ -10,6 +10,7 @@
 #include "DAP.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/Error.h"
+#include <cstring>
 #include <system_error>
 #if defined(_WIN32)
 #include <fcntl.h>
@@ -25,6 +26,10 @@ using llvm::Expected;
 using llvm::inconvertibleErrorCode;
 using llvm::StringRef;
 
+namespace {
+char kCloseSentinel[] = "\0";
+} // namespace
+
 namespace lldb_dap {
 
 int OutputRedirector::kInvalidDescriptor = -1;
@@ -59,7 +64,10 @@ Error OutputRedirector::RedirectTo(std::function<void(StringRef)> callback) {
     while (!m_stopped) {
       ssize_t bytes_count = ::read(read_fd, &buffer, sizeof(buffer));
       // EOF detected.
-      if (bytes_count == 0)
+      if (bytes_count == 0 ||
+          (bytes_count == sizeof(kCloseSentinel) &&
+           std::memcmp(buffer, kCloseSentinel, sizeof(kCloseSentinel)) == 0 &&
+           m_fd == kInvalidDescriptor))
         break;
       if (bytes_count == -1) {
         // Skip non-fatal errors.
@@ -85,8 +93,7 @@ void OutputRedirector::Stop() {
     // Closing the pipe may not be sufficient to wake up the thread in case the
     // write descriptor is duplicated (to stdout/err or to another process).
     // Write a null byte to ensure the read call returns.
-    char buf[] = "\0";
-    (void)::write(fd, buf, sizeof(buf));
+    (void)::write(fd, kCloseSentinel, sizeof(kCloseSentinel));
     ::close(fd);
     m_forwarder.join();
   }

@@ -59,7 +64,10 @@ Error OutputRedirector::RedirectTo(std::function<void(StringRef)> callback) {
while (!m_stopped) {
ssize_t bytes_count = ::read(read_fd, &buffer, sizeof(buffer));
// EOF detected.
if (bytes_count == 0)
if (bytes_count == 0 ||
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't make this an inline suggestion, but this would flow better if you replaced this with the following code after the -1 check:

StringRef data(buffer, bytes_count);
if (data.empty() || (m_stopped && data == kCloseSentinel)) break;

I'm also noting this will not always remove the sentinel as it can end up attached to some other output. That could be handled by something like

if (m_stopped) data = data.consume_back(kCloseSentinel);
if (data.empty()); break;

.. but that has the potential to remove an unrelated piece of text. Since neither of them is perfect, I'll leave it up to you to choose.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I used the second suggestion and added some tests to try to validate we don't incorrectly consume any null bytes produced by the debuggee.

…re output produced by the debuggee is not affected by the output redirection.
@ashgti ashgti merged commit c2e9677 into llvm:main Feb 13, 2025
5 of 6 checks passed
joaosaffran pushed a commit to joaosaffran/llvm-project that referenced this pull request Feb 14, 2025
…out. (llvm#126833)

If you have an lldb-dap log file you'll almost always see a final
message like:

```
<-- 
Content-Length: 94

{
  "body": {
    "category": "stdout",
    "output": "\u0000\u0000"
  },
  "event": "output",
  "seq": 0,
  "type": "event"
}
<-- 
Content-Length: 94

{
  "body": {
    "category": "stderr",
    "output": "\u0000\u0000"
  },
  "event": "output",
  "seq": 0,
  "type": "event"
}
```

The OutputRedirect is always writing the `"\0"` byte as a final stdout
message during shutdown. Instead, I adjusted this to detect the sentinel
value and break out of the read loop as if we detected EOF.

---------

Co-authored-by: Pavel Labath <[email protected]>
sivan-shani pushed a commit to sivan-shani/llvm-project that referenced this pull request Feb 24, 2025
…out. (llvm#126833)

If you have an lldb-dap log file you'll almost always see a final
message like:

```
<-- 
Content-Length: 94

{
  "body": {
    "category": "stdout",
    "output": "\u0000\u0000"
  },
  "event": "output",
  "seq": 0,
  "type": "event"
}
<-- 
Content-Length: 94

{
  "body": {
    "category": "stderr",
    "output": "\u0000\u0000"
  },
  "event": "output",
  "seq": 0,
  "type": "event"
}
```

The OutputRedirect is always writing the `"\0"` byte as a final stdout
message during shutdown. Instead, I adjusted this to detect the sentinel
value and break out of the read loop as if we detected EOF.

---------

Co-authored-by: Pavel Labath <[email protected]>
JDevlieghere pushed a commit to swiftlang/llvm-project that referenced this pull request Feb 25, 2025
…out. (llvm#126833)

If you have an lldb-dap log file you'll almost always see a final
message like:

```
<--
Content-Length: 94

{
  "body": {
    "category": "stdout",
    "output": "\u0000\u0000"
  },
  "event": "output",
  "seq": 0,
  "type": "event"
}
<--
Content-Length: 94

{
  "body": {
    "category": "stderr",
    "output": "\u0000\u0000"
  },
  "event": "output",
  "seq": 0,
  "type": "event"
}
```

The OutputRedirect is always writing the `"\0"` byte as a final stdout
message during shutdown. Instead, I adjusted this to detect the sentinel
value and break out of the read loop as if we detected EOF.

---------

Co-authored-by: Pavel Labath <[email protected]>
(cherry picked from commit c2e9677)
SquallATF pushed a commit to SquallATF/llvm-project that referenced this pull request Mar 8, 2025
…out. (llvm#126833)

If you have an lldb-dap log file you'll almost always see a final
message like:

```
<-- 
Content-Length: 94

{
  "body": {
    "category": "stdout",
    "output": "\u0000\u0000"
  },
  "event": "output",
  "seq": 0,
  "type": "event"
}
<-- 
Content-Length: 94

{
  "body": {
    "category": "stderr",
    "output": "\u0000\u0000"
  },
  "event": "output",
  "seq": 0,
  "type": "event"
}
```

The OutputRedirect is always writing the `"\0"` byte as a final stdout
message during shutdown. Instead, I adjusted this to detect the sentinel
value and break out of the read loop as if we detected EOF.

---------

Co-authored-by: Pavel Labath <[email protected]>
SquallATF pushed a commit to SquallATF/llvm-project that referenced this pull request Mar 20, 2025
…out. (llvm#126833)

If you have an lldb-dap log file you'll almost always see a final
message like:

```
<-- 
Content-Length: 94

{
  "body": {
    "category": "stdout",
    "output": "\u0000\u0000"
  },
  "event": "output",
  "seq": 0,
  "type": "event"
}
<-- 
Content-Length: 94

{
  "body": {
    "category": "stderr",
    "output": "\u0000\u0000"
  },
  "event": "output",
  "seq": 0,
  "type": "event"
}
```

The OutputRedirect is always writing the `"\0"` byte as a final stdout
message during shutdown. Instead, I adjusted this to detect the sentinel
value and break out of the read loop as if we detected EOF.

---------

Co-authored-by: Pavel Labath <[email protected]>
SquallATF pushed a commit to SquallATF/llvm-project that referenced this pull request Apr 2, 2025
…out. (llvm#126833)

If you have an lldb-dap log file you'll almost always see a final
message like:

```
<-- 
Content-Length: 94

{
  "body": {
    "category": "stdout",
    "output": "\u0000\u0000"
  },
  "event": "output",
  "seq": 0,
  "type": "event"
}
<-- 
Content-Length: 94

{
  "body": {
    "category": "stderr",
    "output": "\u0000\u0000"
  },
  "event": "output",
  "seq": 0,
  "type": "event"
}
```

The OutputRedirect is always writing the `"\0"` byte as a final stdout
message during shutdown. Instead, I adjusted this to detect the sentinel
value and break out of the read loop as if we detected EOF.

---------

Co-authored-by: Pavel Labath <[email protected]>
SquallATF pushed a commit to SquallATF/llvm-project that referenced this pull request Apr 17, 2025
…out. (llvm#126833)

If you have an lldb-dap log file you'll almost always see a final
message like:

```
<-- 
Content-Length: 94

{
  "body": {
    "category": "stdout",
    "output": "\u0000\u0000"
  },
  "event": "output",
  "seq": 0,
  "type": "event"
}
<-- 
Content-Length: 94

{
  "body": {
    "category": "stderr",
    "output": "\u0000\u0000"
  },
  "event": "output",
  "seq": 0,
  "type": "event"
}
```

The OutputRedirect is always writing the `"\0"` byte as a final stdout
message during shutdown. Instead, I adjusted this to detect the sentinel
value and break out of the read loop as if we detected EOF.

---------

Co-authored-by: Pavel Labath <[email protected]>
SquallATF pushed a commit to SquallATF/llvm-project that referenced this pull request Apr 30, 2025
…out. (llvm#126833)

If you have an lldb-dap log file you'll almost always see a final
message like:

```
<-- 
Content-Length: 94

{
  "body": {
    "category": "stdout",
    "output": "\u0000\u0000"
  },
  "event": "output",
  "seq": 0,
  "type": "event"
}
<-- 
Content-Length: 94

{
  "body": {
    "category": "stderr",
    "output": "\u0000\u0000"
  },
  "event": "output",
  "seq": 0,
  "type": "event"
}
```

The OutputRedirect is always writing the `"\0"` byte as a final stdout
message during shutdown. Instead, I adjusted this to detect the sentinel
value and break out of the read loop as if we detected EOF.

---------

Co-authored-by: Pavel Labath <[email protected]>
SquallATF pushed a commit to SquallATF/llvm-project that referenced this pull request May 15, 2025
…out. (llvm#126833)

If you have an lldb-dap log file you'll almost always see a final
message like:

```
<-- 
Content-Length: 94

{
  "body": {
    "category": "stdout",
    "output": "\u0000\u0000"
  },
  "event": "output",
  "seq": 0,
  "type": "event"
}
<-- 
Content-Length: 94

{
  "body": {
    "category": "stderr",
    "output": "\u0000\u0000"
  },
  "event": "output",
  "seq": 0,
  "type": "event"
}
```

The OutputRedirect is always writing the `"\0"` byte as a final stdout
message during shutdown. Instead, I adjusted this to detect the sentinel
value and break out of the read loop as if we detected EOF.

---------

Co-authored-by: Pavel Labath <[email protected]>
SquallATF pushed a commit to SquallATF/llvm-project that referenced this pull request May 29, 2025
…out. (llvm#126833)

If you have an lldb-dap log file you'll almost always see a final
message like:

```
<-- 
Content-Length: 94

{
  "body": {
    "category": "stdout",
    "output": "\u0000\u0000"
  },
  "event": "output",
  "seq": 0,
  "type": "event"
}
<-- 
Content-Length: 94

{
  "body": {
    "category": "stderr",
    "output": "\u0000\u0000"
  },
  "event": "output",
  "seq": 0,
  "type": "event"
}
```

The OutputRedirect is always writing the `"\0"` byte as a final stdout
message during shutdown. Instead, I adjusted this to detect the sentinel
value and break out of the read loop as if we detected EOF.

---------

Co-authored-by: Pavel Labath <[email protected]>
SquallATF pushed a commit to SquallATF/llvm-project that referenced this pull request Jun 13, 2025
…out. (llvm#126833)

If you have an lldb-dap log file you'll almost always see a final
message like:

```
<-- 
Content-Length: 94

{
  "body": {
    "category": "stdout",
    "output": "\u0000\u0000"
  },
  "event": "output",
  "seq": 0,
  "type": "event"
}
<-- 
Content-Length: 94

{
  "body": {
    "category": "stderr",
    "output": "\u0000\u0000"
  },
  "event": "output",
  "seq": 0,
  "type": "event"
}
```

The OutputRedirect is always writing the `"\0"` byte as a final stdout
message during shutdown. Instead, I adjusted this to detect the sentinel
value and break out of the read loop as if we detected EOF.

---------

Co-authored-by: Pavel Labath <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants