https://github.com/ashgti updated https://github.com/llvm/llvm-project/pull/129964
>From bcecf0c2aa0d398478734f24a9913cb398167e66 Mon Sep 17 00:00:00 2001 From: John Harrison <harj...@google.com> Date: Thu, 6 Mar 2025 02:05:46 +0100 Subject: [PATCH 1/2] [lldb-dap] Restore the override FD used by the output redirect on stop. While running lldb-dap over stdin/stdout the `stdout` and `stderr` FD's are replaced with a pipe that is reading the output to forward to the dap client. During shutdown we were not properly restoring those FDs, which means if any component attempted to write to stderr it would trigger a SIGPIPE due to the pipe being closed during the shutdown process. This can happen if we have an error reported from the `DAP::Loop` call that would then log to stderr, such as an error parsing a malformed DAP message or if lldb-dap crashed and it was trying to write the stack trace to stderr. There is one place we were not handling an `llvm::Error` if there was no logging setup that could trigger this condition. To address this, I updated the OutputRedirector to restore the FD to the prior state when `Stop` is called. --- lldb/test/API/tools/lldb-dap/io/TestDAP_io.py | 25 ++++++------ lldb/tools/lldb-dap/DAP.cpp | 40 ++++--------------- lldb/tools/lldb-dap/OutputRedirector.cpp | 31 +++++++++++++- lldb/tools/lldb-dap/OutputRedirector.h | 5 ++- 4 files changed, 53 insertions(+), 48 deletions(-) diff --git a/lldb/test/API/tools/lldb-dap/io/TestDAP_io.py b/lldb/test/API/tools/lldb-dap/io/TestDAP_io.py index a39bd17ceb3b3..04414cd7a3cdf 100644 --- a/lldb/test/API/tools/lldb-dap/io/TestDAP_io.py +++ b/lldb/test/API/tools/lldb-dap/io/TestDAP_io.py @@ -18,18 +18,19 @@ def cleanup(): # If the process is still alive, terminate it. if process.poll() is None: process.terminate() - stdout_data = process.stdout.read() - stderr_data = process.stderr.read() - print("========= STDOUT =========") - print(stdout_data) - print("========= END =========") - print("========= STDERR =========") - print(stderr_data) - print("========= END =========") - print("========= DEBUG ADAPTER PROTOCOL LOGS =========") - with open(log_file_path, "r") as file: - print(file.read()) - print("========= END =========") + process.wait() + stdout_data = process.stdout.read() + stderr_data = process.stderr.read() + print("========= STDOUT =========") + print(stdout_data) + print("========= END =========") + print("========= STDERR =========") + print(stderr_data) + print("========= END =========") + print("========= DEBUG ADAPTER PROTOCOL LOGS =========") + with open(log_file_path, "r") as file: + print(file.read()) + print("========= END =========") # Execute the cleanup function during test case tear down. self.addTearDownHook(cleanup) diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index b21b83a79aec7..1f7b25e7c5bcc 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -195,34 +195,16 @@ ExceptionBreakpoint *DAP::GetExceptionBreakpoint(const lldb::break_id_t bp_id) { llvm::Error DAP::ConfigureIO(std::FILE *overrideOut, std::FILE *overrideErr) { in = lldb::SBFile(std::fopen(DEV_NULL, "r"), /*transfer_ownership=*/true); - if (auto Error = out.RedirectTo([this](llvm::StringRef output) { + if (auto Error = out.RedirectTo(overrideOut, [this](llvm::StringRef output) { SendOutput(OutputType::Stdout, output); })) return Error; - if (overrideOut) { - auto fd = out.GetWriteFileDescriptor(); - if (auto Error = fd.takeError()) - return Error; - - if (dup2(*fd, fileno(overrideOut)) == -1) - return llvm::errorCodeToError(llvm::errnoAsErrorCode()); - } - - if (auto Error = err.RedirectTo([this](llvm::StringRef output) { + if (auto Error = err.RedirectTo(overrideErr, [this](llvm::StringRef output) { SendOutput(OutputType::Stderr, output); })) return Error; - if (overrideErr) { - auto fd = err.GetWriteFileDescriptor(); - if (auto Error = fd.takeError()) - return Error; - - if (dup2(*fd, fileno(overrideErr)) == -1) - return llvm::errorCodeToError(llvm::errnoAsErrorCode()); - } - return llvm::Error::success(); } @@ -729,15 +711,11 @@ PacketStatus DAP::GetNextObject(llvm::json::Object &object) { llvm::StringRef json_sref(json); llvm::Expected<llvm::json::Value> json_value = llvm::json::parse(json_sref); - if (!json_value) { - auto error = json_value.takeError(); - if (log) { - std::string error_str; - llvm::raw_string_ostream strm(error_str); - strm << error; + if (auto error = json_value.takeError()) { + std::string error_str = llvm::toString(std::move(error)); + if (log) *log << "error: failed to parse JSON: " << error_str << std::endl << json << std::endl; - } return PacketStatus::JSONMalformed; } @@ -848,10 +826,6 @@ lldb::SBError DAP::Disconnect(bool terminateDebuggee) { SendTerminatedEvent(); - // Stop forwarding the debugger output and error handles. - out.Stop(); - err.Stop(); - disconnecting = true; return error; @@ -859,8 +833,8 @@ lldb::SBError DAP::Disconnect(bool terminateDebuggee) { llvm::Error DAP::Loop() { auto cleanup = llvm::make_scope_exit([this]() { - if (output.descriptor) - output.descriptor->Close(); + out.Stop(); + err.Stop(); StopEventHandlers(); }); while (!disconnecting) { diff --git a/lldb/tools/lldb-dap/OutputRedirector.cpp b/lldb/tools/lldb-dap/OutputRedirector.cpp index 79321aebe9aac..5da3839973706 100644 --- a/lldb/tools/lldb-dap/OutputRedirector.cpp +++ b/lldb/tools/lldb-dap/OutputRedirector.cpp @@ -27,7 +27,9 @@ namespace lldb_dap { int OutputRedirector::kInvalidDescriptor = -1; -OutputRedirector::OutputRedirector() : m_fd(kInvalidDescriptor) {} +OutputRedirector::OutputRedirector() + : m_fd(kInvalidDescriptor), m_original_fd(kInvalidDescriptor), + m_restore_fd(kInvalidDescriptor) {} Expected<int> OutputRedirector::GetWriteFileDescriptor() { if (m_fd == kInvalidDescriptor) @@ -36,7 +38,8 @@ Expected<int> OutputRedirector::GetWriteFileDescriptor() { return m_fd; } -Error OutputRedirector::RedirectTo(std::function<void(StringRef)> callback) { +Error OutputRedirector::RedirectTo(std::FILE *override, + std::function<void(StringRef)> callback) { assert(m_fd == kInvalidDescriptor && "Output readirector already started."); int new_fd[2]; @@ -52,6 +55,19 @@ Error OutputRedirector::RedirectTo(std::function<void(StringRef)> callback) { int read_fd = new_fd[0]; m_fd = new_fd[1]; + + if (override) { + int override_fd = fileno(override); + + // Backup the FD to restore once redirection is complete. + m_original_fd = override_fd; + m_restore_fd = dup(override_fd); + + // Override the existing fd the new write end of the pipe. + if (::dup2(m_fd, override_fd) == -1) + return llvm::errorCodeToError(llvm::errnoAsErrorCode()); + } + m_forwarder = std::thread([this, callback, read_fd]() { char buffer[OutputBufferSize]; while (!m_stopped) { @@ -92,6 +108,17 @@ void OutputRedirector::Stop() { (void)::write(fd, kCloseSentinel.data(), kCloseSentinel.size()); ::close(fd); m_forwarder.join(); + + // Restore the fd back to its original state since we stopped the + // redirection. + if (m_restore_fd != kInvalidDescriptor && + m_original_fd != kInvalidDescriptor) { + int restore_fd = m_restore_fd; + m_restore_fd = kInvalidDescriptor; + int original_fd = m_original_fd; + m_original_fd = kInvalidDescriptor; + ::dup2(restore_fd, original_fd); + } } } diff --git a/lldb/tools/lldb-dap/OutputRedirector.h b/lldb/tools/lldb-dap/OutputRedirector.h index a47ea96f71f14..45571c0d5f344 100644 --- a/lldb/tools/lldb-dap/OutputRedirector.h +++ b/lldb/tools/lldb-dap/OutputRedirector.h @@ -27,7 +27,8 @@ class OutputRedirector { /// \return /// \a Error::success if the redirection was set up correctly, or an error /// otherwise. - llvm::Error RedirectTo(std::function<void(llvm::StringRef)> callback); + llvm::Error RedirectTo(std::FILE *overrideFile, + std::function<void(llvm::StringRef)> callback); llvm::Expected<int> GetWriteFileDescriptor(); void Stop(); @@ -41,6 +42,8 @@ class OutputRedirector { private: std::atomic<bool> m_stopped = false; int m_fd; + int m_original_fd; + int m_restore_fd; std::thread m_forwarder; }; >From 3becb4ff8d521267e61e6dc56e48176ecbef5a8f Mon Sep 17 00:00:00 2001 From: John Harrison <a...@greaterthaninfinity.com> Date: Thu, 6 Mar 2025 22:12:09 +0100 Subject: [PATCH 2/2] Update lldb/tools/lldb-dap/OutputRedirector.cpp Co-authored-by: Jonas Devlieghere <jo...@devlieghere.com> --- lldb/tools/lldb-dap/OutputRedirector.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/tools/lldb-dap/OutputRedirector.cpp b/lldb/tools/lldb-dap/OutputRedirector.cpp index 5da3839973706..44044a6849e0f 100644 --- a/lldb/tools/lldb-dap/OutputRedirector.cpp +++ b/lldb/tools/lldb-dap/OutputRedirector.cpp @@ -38,7 +38,7 @@ Expected<int> OutputRedirector::GetWriteFileDescriptor() { return m_fd; } -Error OutputRedirector::RedirectTo(std::FILE *override, +Error OutputRedirector::RedirectTo(std::FILE *file_override, std::function<void(StringRef)> callback) { assert(m_fd == kInvalidDescriptor && "Output readirector already started."); int new_fd[2]; _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits