358 lines · cpp
1//===-- PipeWindows.cpp ---------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "lldb/Host/windows/PipeWindows.h"10 11#include "llvm/ADT/SmallString.h"12#include "llvm/Support/Process.h"13#include "llvm/Support/raw_ostream.h"14 15#include <fcntl.h>16#include <io.h>17#include <rpc.h>18 19#include <atomic>20#include <string>21 22using namespace lldb;23using namespace lldb_private;24 25static std::atomic<uint32_t> g_pipe_serial(0);26static constexpr llvm::StringLiteral g_pipe_name_prefix = "\\\\.\\Pipe\\";27 28PipeWindows::PipeWindows()29 : m_read(INVALID_HANDLE_VALUE), m_write(INVALID_HANDLE_VALUE),30 m_read_fd(PipeWindows::kInvalidDescriptor),31 m_write_fd(PipeWindows::kInvalidDescriptor) {32 ZeroMemory(&m_read_overlapped, sizeof(m_read_overlapped));33 ZeroMemory(&m_write_overlapped, sizeof(m_write_overlapped));34}35 36PipeWindows::PipeWindows(pipe_t read, pipe_t write)37 : m_read((HANDLE)read), m_write((HANDLE)write),38 m_read_fd(PipeWindows::kInvalidDescriptor),39 m_write_fd(PipeWindows::kInvalidDescriptor) {40 assert(read != LLDB_INVALID_PIPE || write != LLDB_INVALID_PIPE);41 42 // Don't risk in passing file descriptors and getting handles from them by43 // _get_osfhandle since the retrieved handles are highly likely unrecognized44 // in the current process and usually crashes the program. Pass handles45 // instead since the handle can be inherited.46 47 if (read != LLDB_INVALID_PIPE) {48 m_read_fd = _open_osfhandle((intptr_t)read, _O_RDONLY);49 // Make sure the fd and native handle are consistent.50 if (m_read_fd < 0)51 m_read = INVALID_HANDLE_VALUE;52 }53 54 if (write != LLDB_INVALID_PIPE) {55 m_write_fd = _open_osfhandle((intptr_t)write, _O_WRONLY);56 if (m_write_fd < 0)57 m_write = INVALID_HANDLE_VALUE;58 }59 60 ZeroMemory(&m_read_overlapped, sizeof(m_read_overlapped));61 m_read_overlapped.hEvent = ::CreateEventA(nullptr, TRUE, FALSE, nullptr);62 63 ZeroMemory(&m_write_overlapped, sizeof(m_write_overlapped));64 m_write_overlapped.hEvent = ::CreateEventA(nullptr, TRUE, FALSE, nullptr);65}66 67PipeWindows::~PipeWindows() { Close(); }68 69Status PipeWindows::CreateNew() {70 // Even for anonymous pipes, we open a named pipe. This is because you71 // cannot get overlapped i/o on Windows without using a named pipe. So we72 // synthesize a unique name.73 uint32_t serial = g_pipe_serial.fetch_add(1);74 std::string pipe_name = llvm::formatv(75 "lldb.pipe.{0}.{1}.{2}", GetCurrentProcessId(), &g_pipe_serial, serial);76 77 return CreateNew(pipe_name.c_str());78}79 80Status PipeWindows::CreateNew(llvm::StringRef name) {81 if (name.empty())82 return Status(ERROR_INVALID_PARAMETER, eErrorTypeWin32);83 84 if (CanRead() || CanWrite())85 return Status(ERROR_ALREADY_EXISTS, eErrorTypeWin32);86 87 std::string pipe_path = g_pipe_name_prefix.str();88 pipe_path.append(name.str());89 90 // We always create inheritable handles, but we won't pass them to a child91 // process unless explicitly requested (cf. ProcessLauncherWindows.cpp).92 SECURITY_ATTRIBUTES sa{sizeof(SECURITY_ATTRIBUTES), 0, TRUE};93 94 // Always open for overlapped i/o. We implement blocking manually in Read95 // and Write.96 DWORD read_mode = FILE_FLAG_OVERLAPPED;97 m_read =98 ::CreateNamedPipeA(pipe_path.c_str(), PIPE_ACCESS_INBOUND | read_mode,99 PIPE_TYPE_BYTE | PIPE_WAIT, /*nMaxInstances=*/1,100 /*nOutBufferSize=*/1024,101 /*nInBufferSize=*/1024,102 /*nDefaultTimeOut=*/0, &sa);103 if (INVALID_HANDLE_VALUE == m_read)104 return Status(::GetLastError(), eErrorTypeWin32);105 m_read_fd = _open_osfhandle((intptr_t)m_read, _O_RDONLY);106 ZeroMemory(&m_read_overlapped, sizeof(m_read_overlapped));107 m_read_overlapped.hEvent = ::CreateEvent(nullptr, TRUE, FALSE, nullptr);108 109 // Open the write end of the pipe. Note that closing either the read or 110 // write end of the pipe could directly close the pipe itself.111 Status result = OpenNamedPipe(name, false);112 if (!result.Success()) {113 CloseReadFileDescriptor();114 return result;115 }116 117 return result;118}119 120Status PipeWindows::CreateWithUniqueName(llvm::StringRef prefix,121 llvm::SmallVectorImpl<char> &name) {122 llvm::SmallString<128> pipe_name;123 Status error;124 ::UUID unique_id;125 RPC_CSTR unique_string;126 RPC_STATUS status = ::UuidCreate(&unique_id);127 if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY)128 status = ::UuidToStringA(&unique_id, &unique_string);129 if (status == RPC_S_OK) {130 pipe_name = prefix;131 pipe_name += "-";132 pipe_name += reinterpret_cast<char *>(unique_string);133 ::RpcStringFreeA(&unique_string);134 error = CreateNew(pipe_name);135 } else {136 error = Status(status, eErrorTypeWin32);137 }138 if (error.Success())139 name = pipe_name;140 return error;141}142 143Status PipeWindows::OpenAsReader(llvm::StringRef name) {144 if (CanRead())145 return Status(); // Note the name is ignored.146 147 return OpenNamedPipe(name, true);148}149 150llvm::Error PipeWindows::OpenAsWriter(llvm::StringRef name,151 const Timeout<std::micro> &timeout) {152 if (CanWrite())153 return llvm::Error::success(); // Note the name is ignored.154 155 return OpenNamedPipe(name, false).takeError();156}157 158Status PipeWindows::OpenNamedPipe(llvm::StringRef name, bool is_read) {159 if (name.empty())160 return Status(ERROR_INVALID_PARAMETER, eErrorTypeWin32);161 162 assert(is_read ? !CanRead() : !CanWrite());163 164 // We always create inheritable handles, but we won't pass them to a child165 // process unless explicitly requested (cf. ProcessLauncherWindows.cpp).166 SECURITY_ATTRIBUTES attributes{sizeof(SECURITY_ATTRIBUTES), 0, TRUE};167 168 std::string pipe_path = g_pipe_name_prefix.str();169 pipe_path.append(name.str());170 171 if (is_read) {172 m_read = ::CreateFileA(pipe_path.c_str(), GENERIC_READ, 0, &attributes,173 OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);174 if (INVALID_HANDLE_VALUE == m_read)175 return Status(::GetLastError(), eErrorTypeWin32);176 177 m_read_fd = _open_osfhandle((intptr_t)m_read, _O_RDONLY);178 179 ZeroMemory(&m_read_overlapped, sizeof(m_read_overlapped));180 m_read_overlapped.hEvent = ::CreateEvent(nullptr, TRUE, FALSE, nullptr);181 } else {182 m_write = ::CreateFileA(pipe_path.c_str(), GENERIC_WRITE, 0, &attributes,183 OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);184 if (INVALID_HANDLE_VALUE == m_write)185 return Status(::GetLastError(), eErrorTypeWin32);186 187 m_write_fd = _open_osfhandle((intptr_t)m_write, _O_WRONLY);188 189 ZeroMemory(&m_write_overlapped, sizeof(m_write_overlapped));190 m_write_overlapped.hEvent = ::CreateEventA(nullptr, TRUE, FALSE, nullptr);191 }192 193 return Status();194}195 196int PipeWindows::GetReadFileDescriptor() const { return m_read_fd; }197 198int PipeWindows::GetWriteFileDescriptor() const { return m_write_fd; }199 200int PipeWindows::ReleaseReadFileDescriptor() {201 if (!CanRead())202 return PipeWindows::kInvalidDescriptor;203 int result = m_read_fd;204 m_read_fd = PipeWindows::kInvalidDescriptor;205 if (m_read_overlapped.hEvent)206 ::CloseHandle(m_read_overlapped.hEvent);207 m_read = INVALID_HANDLE_VALUE;208 ZeroMemory(&m_read_overlapped, sizeof(m_read_overlapped));209 return result;210}211 212int PipeWindows::ReleaseWriteFileDescriptor() {213 if (!CanWrite())214 return PipeWindows::kInvalidDescriptor;215 int result = m_write_fd;216 m_write_fd = PipeWindows::kInvalidDescriptor;217 if (m_write_overlapped.hEvent)218 ::CloseHandle(m_write_overlapped.hEvent);219 m_write = INVALID_HANDLE_VALUE;220 ZeroMemory(&m_write_overlapped, sizeof(m_write_overlapped));221 return result;222}223 224void PipeWindows::CloseReadFileDescriptor() {225 if (!CanRead())226 return;227 228 if (m_read_overlapped.hEvent)229 ::CloseHandle(m_read_overlapped.hEvent);230 231 _close(m_read_fd);232 m_read = INVALID_HANDLE_VALUE;233 m_read_fd = PipeWindows::kInvalidDescriptor;234 ZeroMemory(&m_read_overlapped, sizeof(m_read_overlapped));235}236 237void PipeWindows::CloseWriteFileDescriptor() {238 if (!CanWrite())239 return;240 241 if (m_write_overlapped.hEvent)242 ::CloseHandle(m_write_overlapped.hEvent);243 244 _close(m_write_fd);245 m_write = INVALID_HANDLE_VALUE;246 m_write_fd = PipeWindows::kInvalidDescriptor;247 ZeroMemory(&m_write_overlapped, sizeof(m_write_overlapped));248}249 250void PipeWindows::Close() {251 CloseReadFileDescriptor();252 CloseWriteFileDescriptor();253}254 255Status PipeWindows::Delete(llvm::StringRef name) { return Status(); }256 257bool PipeWindows::CanRead() const { return (m_read != INVALID_HANDLE_VALUE); }258 259bool PipeWindows::CanWrite() const { return (m_write != INVALID_HANDLE_VALUE); }260 261HANDLE262PipeWindows::GetReadNativeHandle() { return m_read; }263 264HANDLE265PipeWindows::GetWriteNativeHandle() { return m_write; }266 267llvm::Expected<size_t> PipeWindows::Read(void *buf, size_t size,268 const Timeout<std::micro> &timeout) {269 if (!CanRead())270 return Status(ERROR_INVALID_HANDLE, eErrorTypeWin32).takeError();271 272 DWORD bytes_read = 0;273 BOOL result = ::ReadFile(m_read, buf, size, &bytes_read, &m_read_overlapped);274 if (result)275 return bytes_read;276 277 DWORD failure_error = ::GetLastError();278 if (failure_error != ERROR_IO_PENDING)279 return Status(failure_error, eErrorTypeWin32).takeError();280 281 DWORD timeout_msec =282 timeout ? std::chrono::ceil<std::chrono::milliseconds>(*timeout).count()283 : INFINITE;284 DWORD wait_result =285 ::WaitForSingleObject(m_read_overlapped.hEvent, timeout_msec);286 if (wait_result != WAIT_OBJECT_0) {287 // The operation probably failed. However, if it timed out, we need to288 // cancel the I/O. Between the time we returned from WaitForSingleObject289 // and the time we call CancelIoEx, the operation may complete. If that290 // hapens, CancelIoEx will fail and return ERROR_NOT_FOUND. If that291 // happens, the original operation should be considered to have been292 // successful.293 bool failed = true;294 failure_error = ::GetLastError();295 if (wait_result == WAIT_TIMEOUT) {296 BOOL cancel_result = ::CancelIoEx(m_read, &m_read_overlapped);297 if (!cancel_result && ::GetLastError() == ERROR_NOT_FOUND)298 failed = false;299 }300 if (failed)301 return Status(failure_error, eErrorTypeWin32).takeError();302 }303 304 // Now we call GetOverlappedResult setting bWait to false, since we've305 // already waited as long as we're willing to.306 if (!::GetOverlappedResult(m_read, &m_read_overlapped, &bytes_read, FALSE))307 return Status(::GetLastError(), eErrorTypeWin32).takeError();308 309 return bytes_read;310}311 312llvm::Expected<size_t> PipeWindows::Write(const void *buf, size_t size,313 const Timeout<std::micro> &timeout) {314 if (!CanWrite())315 return Status(ERROR_INVALID_HANDLE, eErrorTypeWin32).takeError();316 317 DWORD bytes_written = 0;318 BOOL result =319 ::WriteFile(m_write, buf, size, &bytes_written, &m_write_overlapped);320 if (result)321 return bytes_written;322 323 DWORD failure_error = ::GetLastError();324 if (failure_error != ERROR_IO_PENDING)325 return Status(failure_error, eErrorTypeWin32).takeError();326 327 DWORD timeout_msec =328 timeout ? std::chrono::ceil<std::chrono::milliseconds>(*timeout).count()329 : INFINITE;330 DWORD wait_result =331 ::WaitForSingleObject(m_write_overlapped.hEvent, timeout_msec);332 if (wait_result != WAIT_OBJECT_0) {333 // The operation probably failed. However, if it timed out, we need to334 // cancel the I/O. Between the time we returned from WaitForSingleObject335 // and the time we call CancelIoEx, the operation may complete. If that336 // hapens, CancelIoEx will fail and return ERROR_NOT_FOUND. If that337 // happens, the original operation should be considered to have been338 // successful.339 bool failed = true;340 failure_error = ::GetLastError();341 if (wait_result == WAIT_TIMEOUT) {342 BOOL cancel_result = ::CancelIoEx(m_write, &m_write_overlapped);343 if (!cancel_result && ::GetLastError() == ERROR_NOT_FOUND)344 failed = false;345 }346 if (failed)347 return Status(failure_error, eErrorTypeWin32).takeError();348 }349 350 // Now we call GetOverlappedResult setting bWait to false, since we've351 // already waited as long as we're willing to.352 if (!::GetOverlappedResult(m_write, &m_write_overlapped, &bytes_written,353 FALSE))354 return Status(::GetLastError(), eErrorTypeWin32).takeError();355 356 return bytes_written;357}358