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