https://github.com/charles-zablit updated https://github.com/llvm/llvm-project/pull/182302
>From e3cd4d04e29e28edff3ff04576a4a0ea1d16b7aa Mon Sep 17 00:00:00 2001 From: Charles Zablit <[email protected]> Date: Fri, 20 Feb 2026 16:46:39 +0000 Subject: [PATCH 1/6] [lldb][windows] fix a race condition when closing the ConPTY --- .../include/lldb/Core/ThreadedCommunication.h | 6 ++ lldb/include/lldb/Host/ProcessLaunchInfo.h | 2 + .../Host/windows/ConnectionConPTYWindows.h | 50 +++++++++++ .../include/lldb/Host/windows/PseudoConsole.h | 46 +++++++++- lldb/source/Core/ThreadedCommunication.cpp | 6 +- lldb/source/Host/CMakeLists.txt | 1 + lldb/source/Host/common/ProcessLaunchInfo.cpp | 11 ++- .../Host/windows/ConnectionConPTYWindows.cpp | 84 +++++++++++++++++++ .../Host/windows/ProcessLauncherWindows.cpp | 2 +- lldb/source/Host/windows/PseudoConsole.cpp | 24 ++++-- .../Process/Windows/Common/ProcessWindows.cpp | 9 +- 11 files changed, 227 insertions(+), 14 deletions(-) create mode 100644 lldb/include/lldb/Host/windows/ConnectionConPTYWindows.h create mode 100644 lldb/source/Host/windows/ConnectionConPTYWindows.cpp diff --git a/lldb/include/lldb/Core/ThreadedCommunication.h b/lldb/include/lldb/Core/ThreadedCommunication.h index 24412b2027932..352106d352a0d 100644 --- a/lldb/include/lldb/Core/ThreadedCommunication.h +++ b/lldb/include/lldb/Core/ThreadedCommunication.h @@ -216,6 +216,12 @@ class ThreadedCommunication : public Communication, public Broadcaster { /// void SynchronizeWithReadThread(); + /// Interrupts the current read. + /// + /// Unlike SynchronizeWithReadThread, this does not wait for the read loop to + /// finish processing outstanding data. + void InterruptRead(); + static llvm::StringRef GetStaticBroadcasterClass(); llvm::StringRef GetBroadcasterClass() const override { diff --git a/lldb/include/lldb/Host/ProcessLaunchInfo.h b/lldb/include/lldb/Host/ProcessLaunchInfo.h index e13eecc9463ea..7801662b244ad 100644 --- a/lldb/include/lldb/Host/ProcessLaunchInfo.h +++ b/lldb/include/lldb/Host/ProcessLaunchInfo.h @@ -136,6 +136,8 @@ class ProcessLaunchInfo : public ProcessInfo { /// always true on non Windows. bool ShouldUsePTY() const { #ifdef _WIN32 + if (!m_pty) + return false; return GetPTY().GetPseudoTerminalHandle() != ((HANDLE)(long long)-1) && GetNumFileActions() == 0; #else diff --git a/lldb/include/lldb/Host/windows/ConnectionConPTYWindows.h b/lldb/include/lldb/Host/windows/ConnectionConPTYWindows.h new file mode 100644 index 0000000000000..dc08833fc9d63 --- /dev/null +++ b/lldb/include/lldb/Host/windows/ConnectionConPTYWindows.h @@ -0,0 +1,50 @@ +//===-- ConnectionConPTY.h ------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_HOST_WINDOWS_CONNECTIONCONPTYWINDOWS_H +#define LLDB_HOST_WINDOWS_CONNECTIONCONPTYWINDOWS_H + +#include "lldb/Host/windows/ConnectionGenericFileWindows.h" +#include "lldb/Host/windows/PseudoConsole.h" +#include "lldb/Host/windows/windows.h" +#include "lldb/Utility/Connection.h" +#include "lldb/lldb-types.h" +#include <mutex> + +namespace lldb_private { + +/// A read only Connection implementation for the Windows ConPTY. +class ConnectionConPTY : public ConnectionGenericFile { +public: + ConnectionConPTY(std::shared_ptr<PseudoConsole> pty); + + ~ConnectionConPTY(); + + lldb::ConnectionStatus Connect(llvm::StringRef s, Status *error_ptr) override; + + lldb::ConnectionStatus Disconnect(Status *error_ptr) override; + + /// Read from the ConPTY's pipe. + /// + /// Before reading, check if the ConPTY is closing and wait for it to close + /// before reading. This prevents race conditions when closing the ConPTY + /// during a read. After reading, remove the ConPTY VT init sequence if + /// present. + size_t Read(void *dst, size_t dst_len, const Timeout<std::micro> &timeout, + lldb::ConnectionStatus &status, Status *error_ptr) override; + + size_t Write(const void *src, size_t src_len, lldb::ConnectionStatus &status, + Status *error_ptr) override; + +protected: + std::shared_ptr<PseudoConsole> m_pty; + bool m_pty_vt_sequence_was_stripped = false; +}; +} // namespace lldb_private + +#endif diff --git a/lldb/include/lldb/Host/windows/PseudoConsole.h b/lldb/include/lldb/Host/windows/PseudoConsole.h index 996faf434585d..c26ca12b9fc57 100644 --- a/lldb/include/lldb/Host/windows/PseudoConsole.h +++ b/lldb/include/lldb/Host/windows/PseudoConsole.h @@ -10,6 +10,7 @@ #define LIBLLDB_HOST_WINDOWS_PSEUDOCONSOLE_H_ #include "llvm/Support/Error.h" +#include <mutex> #include <string> #define PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE 0x20016 @@ -29,11 +30,31 @@ class PseudoConsole { PseudoConsole &operator=(const PseudoConsole &) = delete; PseudoConsole &operator=(PseudoConsole &&) = delete; + /// Creates and opens a new ConPTY instance with a default console size of + /// 80x25. Also sets up the associated STDIN/STDOUT pipes and drains any + /// initialization sequences emitted by Windows. + /// + /// \return + /// An llvm::Error if the ConPTY could not be created, or if ConPTY is + /// not available on this version of Windows, llvm::Error::success() + /// otherwise. llvm::Error OpenPseudoConsole(); - /// Close the ConPTY, its read/write handles and invalidate them. + /// Closes the ConPTY and invalidates its handle, without closing the STDIN + /// and STDOUT pipes. Closing the ConPTY signals EOF to any process currently + /// attached to it. void Close(); + /// Closes the STDIN and STDOUT pipe handles and invalidates them + void ClosePipes(); + + /// Returns whether the ConPTY and its pipes are currently open and valid. + /// + /// \return + /// True if the ConPTY handle, STDIN write handle, and STDOUT read handle + /// are all valid, false otherwise. + bool IsConnected() const; + /// The ConPTY HPCON handle accessor. /// /// This object retains ownership of the HPCON when this accessor is used. @@ -71,10 +92,33 @@ class PseudoConsole { /// then drain all output before launching the actual debuggee. llvm::Error DrainInitSequences(); + /// Returns a reference to the mutex used to synchronize access to the + /// ConPTY state. + std::mutex &GetMutex() { return m_mutex; }; + + /// Returns a reference to the condition variable used to signal state changes + /// to threads waiting on the ConPTY (e.g. waiting for output or shutdown). + std::condition_variable &GetCV() { return m_cv; }; + + /// Returns whether the ConPTY is in the process of shutting down. + /// + /// \return + /// A reference to the atomic bool that is set to true when the ConPTY + /// is stopping. Callers should check this in their read/write loops to + /// exit gracefully. + const std::atomic<bool> &IsStopping() const { return m_stopping; }; + + /// Sets the stopping flag to \p value, signalling to threads waiting on the + /// ConPTY that they should stop. + void SetStopping(bool value) { m_stopping = value; }; + protected: HANDLE m_conpty_handle = ((HANDLE)(long long)-1); HANDLE m_conpty_output = ((HANDLE)(long long)-1); HANDLE m_conpty_input = ((HANDLE)(long long)-1); + std::mutex m_mutex{}; + std::condition_variable m_cv{}; + std::atomic<bool> m_stopping = false; }; } // namespace lldb_private diff --git a/lldb/source/Core/ThreadedCommunication.cpp b/lldb/source/Core/ThreadedCommunication.cpp index 09f78f13f34d3..b24f953426afc 100644 --- a/lldb/source/Core/ThreadedCommunication.cpp +++ b/lldb/source/Core/ThreadedCommunication.cpp @@ -360,6 +360,10 @@ void ThreadedCommunication::SetReadThreadBytesReceivedCallback( m_callback_baton = callback_baton; } +void ThreadedCommunication::InterruptRead() { + m_connection_sp->InterruptRead(); +} + void ThreadedCommunication::SynchronizeWithReadThread() { // Only one thread can do the synchronization dance at a time. std::lock_guard<std::mutex> guard(m_synchronize_mutex); @@ -374,7 +378,7 @@ void ThreadedCommunication::SynchronizeWithReadThread() { return; // Notify the read thread. - m_connection_sp->InterruptRead(); + InterruptRead(); // Wait for the synchronization event. EventSP event_sp; diff --git a/lldb/source/Host/CMakeLists.txt b/lldb/source/Host/CMakeLists.txt index 8c198c655e0a6..651f3f09c471c 100644 --- a/lldb/source/Host/CMakeLists.txt +++ b/lldb/source/Host/CMakeLists.txt @@ -67,6 +67,7 @@ add_host_subdirectory(posix if (CMAKE_SYSTEM_NAME MATCHES "Windows") add_subdirectory(windows/PythonPathSetup) add_host_subdirectory(windows + windows/ConnectionConPTYWindows.cpp windows/ConnectionGenericFileWindows.cpp windows/FileSystem.cpp windows/Host.cpp diff --git a/lldb/source/Host/common/ProcessLaunchInfo.cpp b/lldb/source/Host/common/ProcessLaunchInfo.cpp index ea036d45e7c80..2f67a417996ac 100644 --- a/lldb/source/Host/common/ProcessLaunchInfo.cpp +++ b/lldb/source/Host/common/ProcessLaunchInfo.cpp @@ -33,7 +33,11 @@ using namespace lldb_private; ProcessLaunchInfo::ProcessLaunchInfo() : ProcessInfo(), m_working_dir(), m_plugin_name(), m_flags(0), - m_file_actions(), m_pty(new PTY), m_monitor_callback(nullptr) {} + m_file_actions(), m_monitor_callback(nullptr) { +#ifndef _WIN32 + m_pty = std::make_shared<PTY>(); +#endif +} ProcessLaunchInfo::ProcessLaunchInfo(const FileSpec &stdin_file_spec, const FileSpec &stdout_file_spec, @@ -41,7 +45,10 @@ ProcessLaunchInfo::ProcessLaunchInfo(const FileSpec &stdin_file_spec, const FileSpec &working_directory, uint32_t launch_flags) : ProcessInfo(), m_working_dir(), m_plugin_name(), m_flags(launch_flags), - m_file_actions(), m_pty(new PTY) { + m_file_actions() { +#ifndef _WIN32 + m_pty = std::make_shared<PTY>(); +#endif if (stdin_file_spec) { FileAction file_action; const bool read = true; diff --git a/lldb/source/Host/windows/ConnectionConPTYWindows.cpp b/lldb/source/Host/windows/ConnectionConPTYWindows.cpp new file mode 100644 index 0000000000000..c6959c8588af0 --- /dev/null +++ b/lldb/source/Host/windows/ConnectionConPTYWindows.cpp @@ -0,0 +1,84 @@ +//===-- ConnectionConPTY.cpp ----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "lldb/Host/windows/ConnectionConPTYWindows.h" +#include "lldb/Utility/Status.h" + +using namespace lldb; +using namespace lldb_private; + +/// Strips the ConPTY initialization sequences that Windows unconditionally +/// emits when a process is first attached to a pseudo console. +/// +/// These are emitted by ConPTY's host process (conhost.exe) at process attach +/// time, not by the debuggee. They are always the first bytes on the output +/// pipe and are always present as a contiguous prefix. +/// +/// \param dst Buffer containing the data read from the ConPTY output pipe. +/// Modified in place: if the initialization sequences are present +/// as a prefix, they are removed by shifting the remaining bytes +/// to the front of the buffer. +/// \param len On input, the number of valid bytes in \p dst. On output, +/// reduced by the number of bytes stripped. +/// \return +/// \p true if the sequence was found and stripped. +static bool StripConPTYInitSequences(void *dst, size_t &len) { + static const char sequences[] = "\x1b[?9001l\x1b[?1004l"; + static const size_t sequences_len = sizeof(sequences) - 1; + + char *buf = static_cast<char *>(dst); + if (len >= sequences_len && memcmp(buf, sequences, sequences_len) == 0) { + memmove(buf, buf + sequences_len, len - sequences_len); + len -= sequences_len; + return true; + } + return false; +} + +ConnectionConPTY::ConnectionConPTY(std::shared_ptr<PseudoConsole> pty) + : m_pty(pty), ConnectionGenericFile(pty->GetSTDOUTHandle(), false) {}; + +ConnectionConPTY::~ConnectionConPTY() {} + +lldb::ConnectionStatus ConnectionConPTY::Connect(llvm::StringRef s, + Status *error_ptr) { + if (m_pty->IsConnected()) + return eConnectionStatusSuccess; + return eConnectionStatusNoConnection; +} + +lldb::ConnectionStatus ConnectionConPTY::Disconnect(Status *error_ptr) { + m_pty->Close(); + return eConnectionStatusSuccess; +} + +size_t ConnectionConPTY::Read(void *dst, size_t dst_len, + const Timeout<std::micro> &timeout, + lldb::ConnectionStatus &status, + Status *error_ptr) { + std::unique_lock<std::mutex> guard(m_pty->GetMutex()); + if (m_pty->IsStopping().load()) { + m_pty->GetCV().wait(guard, [this] { return !m_pty->IsStopping().load(); }); + } + + size_t bytes_read = + ConnectionGenericFile::Read(dst, dst_len, timeout, status, error_ptr); + + if (bytes_read > 0 && !m_pty_vt_sequence_was_stripped) { + if (StripConPTYInitSequences(dst, bytes_read)) + m_pty_vt_sequence_was_stripped = true; + } + + return bytes_read; +} + +size_t ConnectionConPTY::Write(const void *src, size_t src_len, + lldb::ConnectionStatus &status, + Status *error_ptr) { + llvm_unreachable("not implemented"); +} diff --git a/lldb/source/Host/windows/ProcessLauncherWindows.cpp b/lldb/source/Host/windows/ProcessLauncherWindows.cpp index cfd84731f0eb6..f22e4739ca7b6 100644 --- a/lldb/source/Host/windows/ProcessLauncherWindows.cpp +++ b/lldb/source/Host/windows/ProcessLauncherWindows.cpp @@ -124,7 +124,6 @@ ProcessLauncherWindows::LaunchProcess(const ProcessLaunchInfo &launch_info, startupinfoex.StartupInfo.cb = sizeof(STARTUPINFOEXW); startupinfoex.StartupInfo.dwFlags |= STARTF_USESTDHANDLES; - HPCON hPC = launch_info.GetPTY().GetPseudoTerminalHandle(); bool use_pty = launch_info.ShouldUsePTY(); HANDLE stdin_handle = GetStdioHandle(launch_info, STDIN_FILENO); @@ -148,6 +147,7 @@ ProcessLauncherWindows::LaunchProcess(const ProcessLaunchInfo &launch_info, std::vector<HANDLE> inherited_handles; if (use_pty) { + HPCON hPC = launch_info.GetPTY().GetPseudoTerminalHandle(); if (auto err = attributelist.SetupPseudoConsole(hPC)) { error = Status::FromError(std::move(err)); return HostProcess(); diff --git a/lldb/source/Host/windows/PseudoConsole.cpp b/lldb/source/Host/windows/PseudoConsole.cpp index 15bc8fc9d32fe..da4b1310ea17c 100644 --- a/lldb/source/Host/windows/PseudoConsole.cpp +++ b/lldb/source/Host/windows/PseudoConsole.cpp @@ -65,7 +65,10 @@ struct Kernel32 { static Kernel32 kernel32; -PseudoConsole::~PseudoConsole() { Close(); } +PseudoConsole::~PseudoConsole() { + Close(); + ClosePipes(); +} llvm::Error PseudoConsole::OpenPseudoConsole() { if (!kernel32.IsConPTYAvailable()) @@ -128,19 +131,28 @@ llvm::Error PseudoConsole::OpenPseudoConsole() { return llvm::Error::success(); } +bool PseudoConsole::IsConnected() const { + return m_conpty_handle != INVALID_HANDLE_VALUE && + m_conpty_input != INVALID_HANDLE_VALUE && + m_conpty_output != INVALID_HANDLE_VALUE; +} + void PseudoConsole::Close() { - Sleep(50); // FIXME: This mitigates a race condition when closing the - // PseudoConsole. It's possible that there is still data in the - // pipe when we try to close it. We should wait until the data has - // been consumed. + SetStopping(true); + std::unique_lock<std::mutex> guard(m_mutex); if (m_conpty_handle != INVALID_HANDLE_VALUE) kernel32.ClosePseudoConsole(m_conpty_handle); + m_conpty_handle = INVALID_HANDLE_VALUE; + SetStopping(false); + m_cv.notify_all(); +} + +void PseudoConsole::ClosePipes() { if (m_conpty_input != INVALID_HANDLE_VALUE) CloseHandle(m_conpty_input); if (m_conpty_output != INVALID_HANDLE_VALUE) CloseHandle(m_conpty_output); - m_conpty_handle = INVALID_HANDLE_VALUE; m_conpty_input = INVALID_HANDLE_VALUE; m_conpty_output = INVALID_HANDLE_VALUE; } diff --git a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp index 8c1919eca7dda..2662e16090469 100644 --- a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp @@ -24,7 +24,7 @@ #include "lldb/Host/HostProcess.h" #include "lldb/Host/Pipe.h" #include "lldb/Host/PseudoTerminal.h" -#include "lldb/Host/windows/ConnectionGenericFileWindows.h" +#include "lldb/Host/windows/ConnectionConPTYWindows.h" #include "lldb/Host/windows/HostThreadWindows.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Target/DynamicLoader.h" @@ -651,8 +651,11 @@ void ProcessWindows::OnExitProcess(uint32_t exit_code) { Log *log = GetLog(WindowsLog::Process); LLDB_LOG(log, "Process {0} exited with code {1}", GetID(), exit_code); - if (m_pty) + if (m_pty) { + m_pty->SetStopping(true); + m_stdio_communication.InterruptRead(); m_pty->Close(); + } TargetSP target = CalculateTarget(); if (target) { @@ -1134,7 +1137,7 @@ void ProcessWindows::SetPseudoConsoleHandle() { if (m_pty == nullptr) return; m_stdio_communication.SetConnection( - std::make_unique<ConnectionGenericFile>(m_pty->GetSTDOUTHandle(), false)); + std::make_unique<ConnectionConPTY>(m_pty)); if (m_stdio_communication.IsConnected()) { m_stdio_communication.SetReadThreadBytesReceivedCallback( STDIOReadThreadBytesReceived, this); >From 41bf1e0eb5c785796433a11f4a1b546c046266b5 Mon Sep 17 00:00:00 2001 From: Charles Zablit <[email protected]> Date: Fri, 20 Feb 2026 17:46:10 +0000 Subject: [PATCH 2/6] Apply suggestions from code review Co-authored-by: Nerixyz <[email protected]> --- lldb/include/lldb/Host/windows/ConnectionConPTYWindows.h | 2 +- lldb/source/Host/windows/ConnectionConPTYWindows.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lldb/include/lldb/Host/windows/ConnectionConPTYWindows.h b/lldb/include/lldb/Host/windows/ConnectionConPTYWindows.h index dc08833fc9d63..7f1524445ae4c 100644 --- a/lldb/include/lldb/Host/windows/ConnectionConPTYWindows.h +++ b/lldb/include/lldb/Host/windows/ConnectionConPTYWindows.h @@ -1,4 +1,4 @@ -//===-- ConnectionConPTY.h ------------------------------------------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Host/windows/ConnectionConPTYWindows.cpp b/lldb/source/Host/windows/ConnectionConPTYWindows.cpp index c6959c8588af0..99805359e78ef 100644 --- a/lldb/source/Host/windows/ConnectionConPTYWindows.cpp +++ b/lldb/source/Host/windows/ConnectionConPTYWindows.cpp @@ -1,4 +1,4 @@ -//===-- ConnectionConPTY.cpp ----------------------------------------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. >From 5ccb38ce65c5faf0c2a9375bbc7ae8b8f41f8898 Mon Sep 17 00:00:00 2001 From: Charles Zablit <[email protected]> Date: Fri, 20 Feb 2026 17:46:39 +0000 Subject: [PATCH 3/6] Apply suggestion from @Nerixyz Co-authored-by: Nerixyz <[email protected]> --- lldb/include/lldb/Host/windows/PseudoConsole.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lldb/include/lldb/Host/windows/PseudoConsole.h b/lldb/include/lldb/Host/windows/PseudoConsole.h index c26ca12b9fc57..197e091aeb8c2 100644 --- a/lldb/include/lldb/Host/windows/PseudoConsole.h +++ b/lldb/include/lldb/Host/windows/PseudoConsole.h @@ -49,10 +49,6 @@ class PseudoConsole { void ClosePipes(); /// Returns whether the ConPTY and its pipes are currently open and valid. - /// - /// \return - /// True if the ConPTY handle, STDIN write handle, and STDOUT read handle - /// are all valid, false otherwise. bool IsConnected() const; /// The ConPTY HPCON handle accessor. >From c5b8d81e903a50a556ffc50269cd0ec4413e6ff2 Mon Sep 17 00:00:00 2001 From: Charles Zablit <[email protected]> Date: Fri, 20 Feb 2026 18:04:55 +0000 Subject: [PATCH 4/6] fixup! [lldb][windows] fix a race condition when closing the ConPTY --- lldb/include/lldb/Host/windows/PseudoConsole.h | 2 +- lldb/source/Host/windows/ConnectionConPTYWindows.cpp | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/lldb/include/lldb/Host/windows/PseudoConsole.h b/lldb/include/lldb/Host/windows/PseudoConsole.h index 197e091aeb8c2..12d21a567958b 100644 --- a/lldb/include/lldb/Host/windows/PseudoConsole.h +++ b/lldb/include/lldb/Host/windows/PseudoConsole.h @@ -102,7 +102,7 @@ class PseudoConsole { /// A reference to the atomic bool that is set to true when the ConPTY /// is stopping. Callers should check this in their read/write loops to /// exit gracefully. - const std::atomic<bool> &IsStopping() const { return m_stopping; }; + const bool &IsStopping() const { return m_stopping; }; /// Sets the stopping flag to \p value, signalling to threads waiting on the /// ConPTY that they should stop. diff --git a/lldb/source/Host/windows/ConnectionConPTYWindows.cpp b/lldb/source/Host/windows/ConnectionConPTYWindows.cpp index 99805359e78ef..f3dc0aef1a105 100644 --- a/lldb/source/Host/windows/ConnectionConPTYWindows.cpp +++ b/lldb/source/Host/windows/ConnectionConPTYWindows.cpp @@ -23,14 +23,17 @@ using namespace lldb_private; /// Modified in place: if the initialization sequences are present /// as a prefix, they are removed by shifting the remaining bytes /// to the front of the buffer. +/// \param dst_len The size of \p dst. /// \param len On input, the number of valid bytes in \p dst. On output, /// reduced by the number of bytes stripped. /// \return /// \p true if the sequence was found and stripped. -static bool StripConPTYInitSequences(void *dst, size_t &len) { +static bool StripConPTYInitSequences(void *dst, size_t dst_len, size_t &len) { static const char sequences[] = "\x1b[?9001l\x1b[?1004l"; static const size_t sequences_len = sizeof(sequences) - 1; + assert(dst_len >= len - sequences_len); + char *buf = static_cast<char *>(dst); if (len >= sequences_len && memcmp(buf, sequences, sequences_len) == 0) { memmove(buf, buf + sequences_len, len - sequences_len); @@ -62,15 +65,15 @@ size_t ConnectionConPTY::Read(void *dst, size_t dst_len, lldb::ConnectionStatus &status, Status *error_ptr) { std::unique_lock<std::mutex> guard(m_pty->GetMutex()); - if (m_pty->IsStopping().load()) { - m_pty->GetCV().wait(guard, [this] { return !m_pty->IsStopping().load(); }); + if (m_pty->IsStopping()) { + m_pty->GetCV().wait(guard, [this] { return !m_pty->IsStopping(); }); } size_t bytes_read = ConnectionGenericFile::Read(dst, dst_len, timeout, status, error_ptr); if (bytes_read > 0 && !m_pty_vt_sequence_was_stripped) { - if (StripConPTYInitSequences(dst, bytes_read)) + if (StripConPTYInitSequences(dst, dst_len, bytes_read)) m_pty_vt_sequence_was_stripped = true; } >From ad8b501edbfa5e8246ccef9407aef80c243dae3a Mon Sep 17 00:00:00 2001 From: Charles Zablit <[email protected]> Date: Fri, 20 Feb 2026 18:22:23 +0000 Subject: [PATCH 5/6] fixup! [lldb][windows] fix a race condition when closing the ConPTY --- .../Host/windows/ConnectionConPTYWindows.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lldb/source/Host/windows/ConnectionConPTYWindows.cpp b/lldb/source/Host/windows/ConnectionConPTYWindows.cpp index f3dc0aef1a105..7d6fed56044c8 100644 --- a/lldb/source/Host/windows/ConnectionConPTYWindows.cpp +++ b/lldb/source/Host/windows/ConnectionConPTYWindows.cpp @@ -31,14 +31,14 @@ using namespace lldb_private; static bool StripConPTYInitSequences(void *dst, size_t dst_len, size_t &len) { static const char sequences[] = "\x1b[?9001l\x1b[?1004l"; static const size_t sequences_len = sizeof(sequences) - 1; - - assert(dst_len >= len - sequences_len); - char *buf = static_cast<char *>(dst); - if (len >= sequences_len && memcmp(buf, sequences, sequences_len) == 0) { - memmove(buf, buf + sequences_len, len - sequences_len); - len -= sequences_len; - return true; + if (len >= sequences_len) { + assert(dst_len >= len - sequences_len); + if (memcmp(buf, sequences, sequences_len) == 0) { + memmove(buf, buf + sequences_len, len - sequences_len); + len -= sequences_len; + return true; + } } return false; } >From 87f9e7cb2d6e377466ece0c4901c54104b8acb71 Mon Sep 17 00:00:00 2001 From: Charles Zablit <[email protected]> Date: Mon, 23 Feb 2026 16:35:57 +0000 Subject: [PATCH 6/6] Update lldb/include/lldb/Host/windows/PseudoConsole.h Co-authored-by: Nerixyz <[email protected]> --- lldb/include/lldb/Host/windows/PseudoConsole.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/include/lldb/Host/windows/PseudoConsole.h b/lldb/include/lldb/Host/windows/PseudoConsole.h index 12d21a567958b..a1967fc85188c 100644 --- a/lldb/include/lldb/Host/windows/PseudoConsole.h +++ b/lldb/include/lldb/Host/windows/PseudoConsole.h @@ -102,7 +102,7 @@ class PseudoConsole { /// A reference to the atomic bool that is set to true when the ConPTY /// is stopping. Callers should check this in their read/write loops to /// exit gracefully. - const bool &IsStopping() const { return m_stopping; }; + bool IsStopping() const { return m_stopping.load(); }; /// Sets the stopping flag to \p value, signalling to threads waiting on the /// ConPTY that they should stop. _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
