xref: /llvm-project/lldb/source/Host/windows/PipeWindows.cpp (revision 3ea2b546a8d17014d3ecf05356ecfaadf26ed846)
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-exception
6 //
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 
22 using namespace lldb;
23 using namespace lldb_private;
24 
25 static std::atomic<uint32_t> g_pipe_serial(0);
26 static constexpr llvm::StringLiteral g_pipe_name_prefix = "\\\\.\\Pipe\\";
27 
28 PipeWindows::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 
36 PipeWindows::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 by
43   // _get_osfhandle since the retrieved handles are highly likely unrecognized
44   // in the current process and usually crashes the program.  Pass handles
45   // 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 
67 PipeWindows::~PipeWindows() { Close(); }
68 
69 Status PipeWindows::CreateNew(bool child_process_inherit) {
70   // Even for anonymous pipes, we open a named pipe.  This is because you
71   // cannot get overlapped i/o on Windows without using a named pipe.  So we
72   // 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(), child_process_inherit);
78 }
79 
80 Status PipeWindows::CreateNew(llvm::StringRef name,
81                               bool child_process_inherit) {
82   if (name.empty())
83     return Status(ERROR_INVALID_PARAMETER, eErrorTypeWin32);
84 
85   if (CanRead() || CanWrite())
86     return Status(ERROR_ALREADY_EXISTS, eErrorTypeWin32);
87 
88   std::string pipe_path = g_pipe_name_prefix.str();
89   pipe_path.append(name.str());
90 
91   SECURITY_ATTRIBUTES sa{sizeof(SECURITY_ATTRIBUTES), 0,
92                          child_process_inherit ? TRUE : FALSE};
93 
94   // Always open for overlapped i/o.  We implement blocking manually in Read
95   // 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, child_process_inherit, false);
112   if (!result.Success()) {
113     CloseReadFileDescriptor();
114     return result;
115   }
116 
117   return result;
118 }
119 
120 Status PipeWindows::CreateWithUniqueName(llvm::StringRef prefix,
121                                          bool child_process_inherit,
122                                          llvm::SmallVectorImpl<char> &name) {
123   llvm::SmallString<128> pipe_name;
124   Status error;
125   ::UUID unique_id;
126   RPC_CSTR unique_string;
127   RPC_STATUS status = ::UuidCreate(&unique_id);
128   if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY)
129     status = ::UuidToStringA(&unique_id, &unique_string);
130   if (status == RPC_S_OK) {
131     pipe_name = prefix;
132     pipe_name += "-";
133     pipe_name += reinterpret_cast<char *>(unique_string);
134     ::RpcStringFreeA(&unique_string);
135     error = CreateNew(pipe_name, child_process_inherit);
136   } else {
137     error = Status(status, eErrorTypeWin32);
138   }
139   if (error.Success())
140     name = pipe_name;
141   return error;
142 }
143 
144 Status PipeWindows::OpenAsReader(llvm::StringRef name,
145                                  bool child_process_inherit) {
146   if (CanRead())
147     return Status(); // Note the name is ignored.
148 
149   return OpenNamedPipe(name, child_process_inherit, true);
150 }
151 
152 Status
153 PipeWindows::OpenAsWriterWithTimeout(llvm::StringRef name,
154                                      bool child_process_inherit,
155                                      const std::chrono::microseconds &timeout) {
156   if (CanWrite())
157     return Status(); // Note the name is ignored.
158 
159   return OpenNamedPipe(name, child_process_inherit, false);
160 }
161 
162 Status PipeWindows::OpenNamedPipe(llvm::StringRef name,
163                                   bool child_process_inherit, bool is_read) {
164   if (name.empty())
165     return Status(ERROR_INVALID_PARAMETER, eErrorTypeWin32);
166 
167   assert(is_read ? !CanRead() : !CanWrite());
168 
169   SECURITY_ATTRIBUTES attributes{sizeof(SECURITY_ATTRIBUTES), 0,
170                                  child_process_inherit ? TRUE : FALSE};
171 
172   std::string pipe_path = g_pipe_name_prefix.str();
173   pipe_path.append(name.str());
174 
175   if (is_read) {
176     m_read = ::CreateFileA(pipe_path.c_str(), GENERIC_READ, 0, &attributes,
177                            OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
178     if (INVALID_HANDLE_VALUE == m_read)
179       return Status(::GetLastError(), eErrorTypeWin32);
180 
181     m_read_fd = _open_osfhandle((intptr_t)m_read, _O_RDONLY);
182 
183     ZeroMemory(&m_read_overlapped, sizeof(m_read_overlapped));
184     m_read_overlapped.hEvent = ::CreateEvent(nullptr, TRUE, FALSE, nullptr);
185   } else {
186     m_write = ::CreateFileA(pipe_path.c_str(), GENERIC_WRITE, 0, &attributes,
187                             OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
188     if (INVALID_HANDLE_VALUE == m_write)
189       return Status(::GetLastError(), eErrorTypeWin32);
190 
191     m_write_fd = _open_osfhandle((intptr_t)m_write, _O_WRONLY);
192 
193     ZeroMemory(&m_write_overlapped, sizeof(m_write_overlapped));
194     m_write_overlapped.hEvent = ::CreateEventA(nullptr, TRUE, FALSE, nullptr);
195   }
196 
197   return Status();
198 }
199 
200 int PipeWindows::GetReadFileDescriptor() const { return m_read_fd; }
201 
202 int PipeWindows::GetWriteFileDescriptor() const { return m_write_fd; }
203 
204 int PipeWindows::ReleaseReadFileDescriptor() {
205   if (!CanRead())
206     return PipeWindows::kInvalidDescriptor;
207   int result = m_read_fd;
208   m_read_fd = PipeWindows::kInvalidDescriptor;
209   if (m_read_overlapped.hEvent)
210     ::CloseHandle(m_read_overlapped.hEvent);
211   m_read = INVALID_HANDLE_VALUE;
212   ZeroMemory(&m_read_overlapped, sizeof(m_read_overlapped));
213   return result;
214 }
215 
216 int PipeWindows::ReleaseWriteFileDescriptor() {
217   if (!CanWrite())
218     return PipeWindows::kInvalidDescriptor;
219   int result = m_write_fd;
220   m_write_fd = PipeWindows::kInvalidDescriptor;
221   if (m_write_overlapped.hEvent)
222     ::CloseHandle(m_write_overlapped.hEvent);
223   m_write = INVALID_HANDLE_VALUE;
224   ZeroMemory(&m_write_overlapped, sizeof(m_write_overlapped));
225   return result;
226 }
227 
228 void PipeWindows::CloseReadFileDescriptor() {
229   if (!CanRead())
230     return;
231 
232   if (m_read_overlapped.hEvent)
233     ::CloseHandle(m_read_overlapped.hEvent);
234 
235   _close(m_read_fd);
236   m_read = INVALID_HANDLE_VALUE;
237   m_read_fd = PipeWindows::kInvalidDescriptor;
238   ZeroMemory(&m_read_overlapped, sizeof(m_read_overlapped));
239 }
240 
241 void PipeWindows::CloseWriteFileDescriptor() {
242   if (!CanWrite())
243     return;
244 
245   if (m_write_overlapped.hEvent)
246     ::CloseHandle(m_write_overlapped.hEvent);
247 
248   _close(m_write_fd);
249   m_write = INVALID_HANDLE_VALUE;
250   m_write_fd = PipeWindows::kInvalidDescriptor;
251   ZeroMemory(&m_write_overlapped, sizeof(m_write_overlapped));
252 }
253 
254 void PipeWindows::Close() {
255   CloseReadFileDescriptor();
256   CloseWriteFileDescriptor();
257 }
258 
259 Status PipeWindows::Delete(llvm::StringRef name) { return Status(); }
260 
261 bool PipeWindows::CanRead() const { return (m_read != INVALID_HANDLE_VALUE); }
262 
263 bool PipeWindows::CanWrite() const { return (m_write != INVALID_HANDLE_VALUE); }
264 
265 HANDLE
266 PipeWindows::GetReadNativeHandle() { return m_read; }
267 
268 HANDLE
269 PipeWindows::GetWriteNativeHandle() { return m_write; }
270 
271 Status PipeWindows::ReadWithTimeout(void *buf, size_t size,
272                                     const std::chrono::microseconds &duration,
273                                     size_t &bytes_read) {
274   if (!CanRead())
275     return Status(ERROR_INVALID_HANDLE, eErrorTypeWin32);
276 
277   bytes_read = 0;
278   DWORD sys_bytes_read = 0;
279   BOOL result =
280       ::ReadFile(m_read, buf, size, &sys_bytes_read, &m_read_overlapped);
281   if (result) {
282     bytes_read = sys_bytes_read;
283     return Status();
284   }
285 
286   DWORD failure_error = ::GetLastError();
287   if (failure_error != ERROR_IO_PENDING)
288     return Status(failure_error, eErrorTypeWin32);
289 
290   DWORD timeout = (duration == std::chrono::microseconds::zero())
291                       ? INFINITE
292                       : duration.count() / 1000;
293   DWORD wait_result = ::WaitForSingleObject(m_read_overlapped.hEvent, timeout);
294   if (wait_result != WAIT_OBJECT_0) {
295     // The operation probably failed.  However, if it timed out, we need to
296     // cancel the I/O. Between the time we returned from WaitForSingleObject
297     // and the time we call CancelIoEx, the operation may complete.  If that
298     // hapens, CancelIoEx will fail and return ERROR_NOT_FOUND. If that
299     // happens, the original operation should be considered to have been
300     // successful.
301     bool failed = true;
302     failure_error = ::GetLastError();
303     if (wait_result == WAIT_TIMEOUT) {
304       BOOL cancel_result = ::CancelIoEx(m_read, &m_read_overlapped);
305       if (!cancel_result && ::GetLastError() == ERROR_NOT_FOUND)
306         failed = false;
307     }
308     if (failed)
309       return Status(failure_error, eErrorTypeWin32);
310   }
311 
312   // Now we call GetOverlappedResult setting bWait to false, since we've
313   // already waited as long as we're willing to.
314   if (!::GetOverlappedResult(m_read, &m_read_overlapped, &sys_bytes_read,
315                              FALSE))
316     return Status(::GetLastError(), eErrorTypeWin32);
317 
318   bytes_read = sys_bytes_read;
319   return Status();
320 }
321 
322 Status PipeWindows::WriteWithTimeout(const void *buf, size_t size,
323                                      const std::chrono::microseconds &duration,
324                                      size_t &bytes_written) {
325   if (!CanWrite())
326     return Status(ERROR_INVALID_HANDLE, eErrorTypeWin32);
327 
328   bytes_written = 0;
329   DWORD sys_bytes_write = 0;
330   BOOL result =
331       ::WriteFile(m_write, buf, size, &sys_bytes_write, &m_write_overlapped);
332   if (result) {
333     bytes_written = sys_bytes_write;
334     return Status();
335   }
336 
337   DWORD failure_error = ::GetLastError();
338   if (failure_error != ERROR_IO_PENDING)
339     return Status(failure_error, eErrorTypeWin32);
340 
341   DWORD timeout = (duration == std::chrono::microseconds::zero())
342                       ? INFINITE
343                       : duration.count() / 1000;
344   DWORD wait_result = ::WaitForSingleObject(m_write_overlapped.hEvent, timeout);
345   if (wait_result != WAIT_OBJECT_0) {
346     // The operation probably failed.  However, if it timed out, we need to
347     // cancel the I/O. Between the time we returned from WaitForSingleObject
348     // and the time we call CancelIoEx, the operation may complete.  If that
349     // hapens, CancelIoEx will fail and return ERROR_NOT_FOUND. If that
350     // happens, the original operation should be considered to have been
351     // successful.
352     bool failed = true;
353     failure_error = ::GetLastError();
354     if (wait_result == WAIT_TIMEOUT) {
355       BOOL cancel_result = ::CancelIoEx(m_write, &m_write_overlapped);
356       if (!cancel_result && ::GetLastError() == ERROR_NOT_FOUND)
357         failed = false;
358     }
359     if (failed)
360       return Status(failure_error, eErrorTypeWin32);
361   }
362 
363   // Now we call GetOverlappedResult setting bWait to false, since we've
364   // already waited as long as we're willing to.
365   if (!::GetOverlappedResult(m_write, &m_write_overlapped, &sys_bytes_write,
366                              FALSE))
367     return Status(::GetLastError(), eErrorTypeWin32);
368 
369   bytes_written = sys_bytes_write;
370   return Status();
371 }
372