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 1/2] [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 >From 1cf7a8eedab7b53054a5ce91f1763d15aec0673c Mon Sep 17 00:00:00 2001 From: Charles Zablit <[email protected]> Date: Wed, 11 Feb 2026 15:12:15 +0100 Subject: [PATCH 2/2] Update lldb/source/Host/windows/PseudoConsole.cpp Co-authored-by: Nerixyz <[email protected]> --- lldb/source/Host/windows/PseudoConsole.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/source/Host/windows/PseudoConsole.cpp b/lldb/source/Host/windows/PseudoConsole.cpp index 7f48290d18a6d..413c8a3328445 100644 --- a/lldb/source/Host/windows/PseudoConsole.cpp +++ b/lldb/source/Host/windows/PseudoConsole.cpp @@ -198,4 +198,4 @@ llvm::Error PseudoConsole::DrainInitSequences() { 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
