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