https://github.com/charles-zablit updated 
https://github.com/llvm/llvm-project/pull/180578

>From 43a81e2be21ec379f2d61bebf24116692cb063c2 Mon Sep 17 00:00:00 2001
From: Charles Zablit <[email protected]>
Date: Mon, 9 Feb 2026 18:23:59 +0000
Subject: [PATCH] [lldb-dap][windows] drain the ConPTY before attaching

---
 .../include/lldb/Host/windows/PseudoConsole.h | 10 +++
 lldb/source/Host/windows/PseudoConsole.cpp    | 66 +++++++++++++++++++
 2 files changed, 76 insertions(+)

diff --git a/lldb/include/lldb/Host/windows/PseudoConsole.h 
b/lldb/include/lldb/Host/windows/PseudoConsole.h
index a831c6028b252..996faf434585d 100644
--- a/lldb/include/lldb/Host/windows/PseudoConsole.h
+++ b/lldb/include/lldb/Host/windows/PseudoConsole.h
@@ -61,6 +61,16 @@ class PseudoConsole {
   ///     invalid.
   HANDLE GetSTDINHandle() const { return m_conpty_input; };
 
+  /// Drains initialization sequences from the ConPTY output pipe.
+  ///
+  /// When a process first attaches to a ConPTY, Windows emits VT100/ANSI 
escape
+  /// sequences (ESC[2J for clear screen, ESC[H for cursor home and more) as
+  /// part of the PseudoConsole initialization. To prevent these sequences from
+  /// appearing in the debugger output (and flushing lldb's shell for instance)
+  /// we launch a short-lived dummy process that triggers the initialization,
+  /// then drain all output before launching the actual debuggee.
+  llvm::Error DrainInitSequences();
+
 protected:
   HANDLE m_conpty_handle = ((HANDLE)(long long)-1);
   HANDLE m_conpty_output = ((HANDLE)(long long)-1);
diff --git a/lldb/source/Host/windows/PseudoConsole.cpp 
b/lldb/source/Host/windows/PseudoConsole.cpp
index b3314fd58bbb8..7f48290d18a6d 100644
--- a/lldb/source/Host/windows/PseudoConsole.cpp
+++ b/lldb/source/Host/windows/PseudoConsole.cpp
@@ -11,6 +11,7 @@
 #include <mutex>
 
 #include "lldb/Host/windows/PipeWindows.h"
+#include "lldb/Host/windows/ProcessLauncherWindows.h"
 #include "lldb/Host/windows/windows.h"
 #include "lldb/Utility/LLDBLog.h"
 
@@ -118,6 +119,12 @@ llvm::Error PseudoConsole::OpenPseudoConsole() {
   m_conpty_output = hOutputRead;
   m_conpty_input = hInputWrite;
 
+  if (auto error = DrainInitSequences()) {
+    Log *log = GetLog(LLDBLog::Host);
+    LLDB_LOG_ERROR(log, std::move(error),
+                   "failed to finalize ConPTY's setup: {0}");
+  }
+
   return llvm::Error::success();
 }
 
@@ -133,3 +140,62 @@ void PseudoConsole::Close() {
   m_conpty_input = INVALID_HANDLE_VALUE;
   m_conpty_output = INVALID_HANDLE_VALUE;
 }
+
+llvm::Error PseudoConsole::DrainInitSequences() {
+  STARTUPINFOEXW startupinfoex = {};
+  startupinfoex.StartupInfo.cb = sizeof(STARTUPINFOEXW);
+  startupinfoex.StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
+
+  auto attributelist_or_err = ProcThreadAttributeList::Create(startupinfoex);
+  if (!attributelist_or_err)
+    return llvm::errorCodeToError(attributelist_or_err.getError());
+  ProcThreadAttributeList attributelist = std::move(*attributelist_or_err);
+  if (auto error = attributelist.SetupPseudoConsole(m_conpty_handle))
+    return error;
+
+  PROCESS_INFORMATION pi = {};
+
+  wchar_t comspec[MAX_PATH];
+  DWORD comspecLen = GetEnvironmentVariableW(L"COMSPEC", comspec, MAX_PATH);
+  if (comspecLen == 0 || comspecLen >= MAX_PATH)
+    return llvm::createStringError(
+        std::error_code(GetLastError(), std::system_category()),
+        "Failed to get the 'COMSPEC' environment variable");
+
+  std::wstring cmdline_str = std::wstring(comspec) + L" /c 'echo foo && exit'";
+  std::vector<wchar_t> cmdline(cmdline_str.begin(), cmdline_str.end());
+  cmdline.push_back(L'\0');
+
+  if (!CreateProcessW(/*lpApplicationName=*/comspec, cmdline.data(),
+                      /*lpProcessAttributes=*/NULL, 
/*lpThreadAttributes=*/NULL,
+                      /*bInheritHandles=*/TRUE,
+                      /*dwCreationFlags=*/EXTENDED_STARTUPINFO_PRESENT |
+                          CREATE_UNICODE_ENVIRONMENT,
+                      /*lpEnvironment=*/NULL, /*lpCurrentDirectory=*/NULL,
+                      /*lpStartupInfo=*/
+                      reinterpret_cast<STARTUPINFOW *>(&startupinfoex),
+                      /*lpProcessInformation=*/&pi))
+    return llvm::errorCodeToError(
+        std::error_code(GetLastError(), std::system_category()));
+
+  char buf[4096];
+  OVERLAPPED ov = {};
+  ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+
+  DWORD read;
+  ReadFile(m_conpty_output, buf, sizeof(buf), &read, &ov);
+
+  WaitForSingleObject(pi.hProcess, INFINITE);
+
+  if (GetOverlappedResult(m_conpty_output, &ov, &read, FALSE) && read > 0) {
+    ResetEvent(ov.hEvent);
+    ReadFile(m_conpty_output, buf, sizeof(buf), &read, &ov);
+  }
+
+  CancelIo(m_conpty_output);
+  CloseHandle(ov.hEvent);
+  CloseHandle(pi.hProcess);
+  CloseHandle(pi.hThread);
+
+  return llvm::Error::success();
+}
\ No newline at end of file

_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to