### Bug Summary

File: | builds/wireshark/wireshark/wsutil/ws_pipe.c
Warning: | line 682, column 18 Potential leak of memory pointed to by 'argv'

### Annotated Source Code

Press '?' to see keyboard shortcuts

Show analyzer invocation
clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name ws_pipe.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -fno-delete-null-pointer-checks -mframe-pointer=all -relaxed-aliasing -fmath-errno -ffp-contract=on -fno-rounding-math -ffloat16-excess-precision=fast -fbfloat16-excess-precision=fast -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/builds/wireshark/wireshark/build -fcoverage-compilation-dir=/builds/wireshark/wireshark/build -resource-dir /usr/lib/llvm-22/lib/clang/22 -isystem /usr/include/glib-2.0 -isystem /usr/lib/x86_64-linux-gnu/glib-2.0/include -D BUILD_WSUTIL -D CARES_NO_DEPRECATED -D G_DISABLE_DEPRECATED -D G_DISABLE_SINGLE_INCLUDES -D WS_BUILD_DLL -D WS_DEBUG -D WS_DEBUG_UTF_8 -D wsutil_EXPORTS -I /builds/wireshark/wireshark/build -I /builds/wireshark/wireshark -I /builds/wireshark/wireshark/include -I /builds/wireshark/wireshark/build/wsutil -D _GLIBCXX_ASSERTIONS -internal-isystem /usr/lib/llvm-22/lib/clang/22/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fmacro-prefix-map=/builds/wireshark/wireshark/= -fmacro-prefix-map=/builds/wireshark/wireshark/build/= -fmacro-prefix-map=../= -Wno-format-nonliteral -std=gnu17 -ferror-limit 19 -fvisibility=hidden -fwrapv -fwrapv-pointer -fstrict-flex-arrays=3 -stack-protector 2 -fstack-clash-protection -fcf-protection=full -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fexceptions -fcolor-diagnostics -analyzer-output=html -faddrsig -fdwarf2-cfi-asm -o /builds/wireshark/wireshark/sbout/2026-09-02-100927-3660-1 -x c /builds/wireshark/wireshark/wsutil/ws_pipe.c

Keyboard shortcuts:

- Use 'j/k' keys for keyboard navigation
- Use 'Shift+S' to show/hide relevant lines
- Use '?' to toggle this window

Close
Show only relevant lines Show control flow arrows

1 | /* ws_pipe.c
2 | *
3 | * Routines for handling pipes.
4 | *
5 | * Wireshark - Network traffic analyzer
6 | * By Gerald Combs <gerald@wireshark.org>
7 | * Copyright 1998 Gerald Combs
8 | *
9 | * SPDX-License-Identifier: GPL-2.0-or-later
10 | */
11 |
12 | #include "config.h"
13 | #define WS_LOG_DOMAIN"Capture" LOG_DOMAIN_CAPTURE"Capture"
14 | #include "wsutil/ws_pipe.h"
15 |
16 | #include <stdio.h>
17 | #include <stdlib.h>
18 | #include <string.h>
19 |
20 | #ifdef _WIN32
21 | #include <windows.h>
22 | #include <io.h>
23 | #include <fcntl.h> /* for _O_BINARY */
24 | #include <wsutil/win32-utils.h>
25 | #else
26 | #include <unistd.h>
27 | #ifdef HAVE_SYS_SELECT_H
28 | #include <sys/select.h>
29 | #endif
30 | #endif
31 |
32 | #if !GLIB_CHECK_VERSION(2, 58, 2)(2 > (2) || (2 == (2) && 88 > (58)) || (2 == (2 ) && 88 == (58) && 0 >= (2)))
33 | #ifdef __linux__1
34 | #define HAS_G_SPAWN_LINUX_THREAD_SAFETY_BUG
35 | #include <fcntl.h>
36 | #include <sys/syscall.h> /* for syscall and SYS_getdents64 */
37 | #include <wsutil/file_util.h> /* for ws_open -> open to pacify checkAPIs.pl */
38 | #endif
39 | #endif
40 |
41 | #include "wsutil/filesystem.h"
42 | #include "wsutil/wslog.h"
43 |
44 | #ifdef HAS_G_SPAWN_LINUX_THREAD_SAFETY_BUG
45 | struct linux_dirent64 {
46 | uint64_t d_ino; /* 64-bit inode number */
47 | uint64_t d_off; /* 64-bit offset to next structure */
48 | unsigned short d_reclen; /* Size of this dirent */
49 | unsigned char d_type; /* File type */
50 | char d_name[]; /* Filename (null-terminated) */
51 | };
52 |
53 | /* Async-signal-safe string to integer conversion. */
54 | static int
55 | filename_to_fd(const char *p)
56 | {
57 | char c;
58 | int fd = 0;
59 | const int cutoff = INT_MAX2147483647 / 10;
60 | const int cutlim = INT_MAX2147483647 % 10;
61 |
62 | if (*p == '\0')
63 | return -1;
64 |
65 | while ((c = *p++) != '\0') {
66 | if (!g_ascii_isdigit(c)((g_ascii_table[(guchar) (c)] & G_ASCII_DIGIT) != 0))
67 | return -1;
68 | c -= '0';
69 |
70 | /* Check for overflow. */
71 | if (fd > cutoff || (fd == cutoff && c > cutlim))
72 | return -1;
73 |
74 | fd = fd * 10 + c;
75 | }
76 |
77 | return fd;
78 | }
79 |
80 | static void
81 | close_non_standard_fds_linux(void * user_data _U___attribute__((unused)))
82 | {
83 | /*
84 | * GLib 2.14.2 and newer (up to at least GLib 2.58.1) on Linux with multiple
85 | * threads can deadlock in the child process due to use of opendir (which
86 | * is not async-signal-safe). To avoid this, disable the broken code path
87 | * and manually close file descriptors using async-signal-safe code only.
88 | * Use CLOEXEC to allow reporting of execve errors to the parent via a pipe.
89 | * https://gitlab.gnome.org/GNOME/glib/issues/1014
90 | * https://gitlab.gnome.org/GNOME/glib/merge_requests/490
91 | */
92 | int dir_fd = ws_open("/proc/self/fd", O_RDONLY | O_DIRECTORY);
93 | if (dir_fd >= 0) {
94 | char buf[4096];
95 | int nread, fd;
96 | struct linux_dirent64 *de;
97 |
98 | while ((nread = (int) syscall(SYS_getdents64, dir_fd, buf, sizeof(buf))) > 0) {
99 | for (int pos = 0; pos < nread; pos += de->d_reclen) {
100 | de = (struct linux_dirent64 *)(buf + pos);
101 | fd = filename_to_fd(de->d_name);
102 | if (fd > STDERR_FILENO2 && fd != dir_fd) {
103 | /* Close all other (valid) file descriptors above stderr. */
104 | fcntl(fd, F_SETFD, FD_CLOEXEC);
105 | }
106 | }
107 | }
108 |
109 | close(dir_fd);
110 | } else {
111 | /* Slow fallback in case /proc is not mounted */
112 | for (int fd = STDERR_FILENO2 + 1; fd < getdtablesize(); fd++) {
113 | fcntl(fd, F_SETFD, FD_CLOEXEC);
114 | }
115 | }
116 | }
117 | #endif
118 |
119 | #ifdef _WIN32
120 | static ULONG pipe_serial_number;
121 |
122 | /* Alternative for CreatePipe() where read handle is opened with FILE_FLAG_OVERLAPPED */
123 | static bool_Bool
124 | ws_pipe_create_overlapped_read(HANDLE *read_pipe_handle, HANDLE *write_pipe_handle,
125 | SECURITY_ATTRIBUTES *sa, DWORD suggested_buffer_size)
126 | {
127 | HANDLE read_pipe, write_pipe;
128 | char *name = ws_strdup_printf("\\\\.\\Pipe\\WiresharkWsPipe.%08lx.%08lx",wmem_strdup_printf(((void*)0), "\\\\.\\Pipe\\WiresharkWsPipe.%08lx.%08lx" , GetCurrentProcessId(), InterlockedIncrement((LONG*)&pipe_serial_number ))
129 | GetCurrentProcessId(),wmem_strdup_printf(((void*)0), "\\\\.\\Pipe\\WiresharkWsPipe.%08lx.%08lx" , GetCurrentProcessId(), InterlockedIncrement((LONG*)&pipe_serial_number ))
130 | InterlockedIncrement((LONG*)&pipe_serial_number))wmem_strdup_printf(((void*)0), "\\\\.\\Pipe\\WiresharkWsPipe.%08lx.%08lx" , GetCurrentProcessId(), InterlockedIncrement((LONG*)&pipe_serial_number ));
131 | gunichar2 *wname = g_utf8_to_utf16(name, -1, NULL((void*)0), NULL((void*)0), NULL((void*)0));
132 |
133 | g_free(name)(__builtin_object_size ((name), 0) != ((size_t) - 1)) ? g_free_sized (name, __builtin_object_size ((name), 0)) : (g_free) (name);
134 |
135 | read_pipe = CreateNamedPipe(wname, PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
136 | PIPE_TYPE_BYTE | PIPE_WAIT, 1,
137 | suggested_buffer_size, suggested_buffer_size,
138 | 0, sa);
139 | if (INVALID_HANDLE_VALUE == read_pipe)
140 | {
141 | g_free(wname)(__builtin_object_size ((wname), 0) != ((size_t) - 1)) ? g_free_sized (wname, __builtin_object_size ((wname), 0)) : (g_free) (wname );
142 | return false0;
143 | }
144 |
145 | write_pipe = CreateFile(wname, GENERIC_WRITE, 0, sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL((void*)0));
146 | if (INVALID_HANDLE_VALUE == write_pipe)
147 | {
148 | DWORD error = GetLastError();
149 | CloseHandle(read_pipe);
150 | SetLastError(error);
151 | g_free(wname)(__builtin_object_size ((wname), 0) != ((size_t) - 1)) ? g_free_sized (wname, __builtin_object_size ((wname), 0)) : (g_free) (wname );
152 | return false0;
153 | }
154 |
155 | *read_pipe_handle = read_pipe;
156 | *write_pipe_handle = write_pipe;
157 | g_free(wname)(__builtin_object_size ((wname), 0) != ((size_t) - 1)) ? g_free_sized (wname, __builtin_object_size ((wname), 0)) : (g_free) (wname );
158 | return true1;
159 | }
160 | #endif
161 |
162 | /**
163 | * Helper to convert a command and argument list to an NULL-terminated 'argv'
164 | * array, suitable for g_spawn_sync and friends. Free with g_strfreev.
165 | */
166 | static char **
167 | convert_to_argv(const char *command, unsigned args_count, char *const *args)
168 | {
169 | char **argv = g_new(char *, (size_t)args_count + 2)((char * *) g_malloc_n (((size_t)args_count + 2), sizeof (char *)));
10 | ← | Memory is allocated | →
170 | // The caller does not seem to modify this, but g_spawn_sync uses 'char **'
171 | // as opposed to 'const char **', so just to be sure clone it.
172 | argv[0] = g_strdup(command)g_strdup_inline (command);
173 | for (unsigned i = 0; i < args_count; i++) {
11 | ← | Assuming 'i' is >= 'args_count' | →
12 | ← | Loop condition is false. Execution continues on line 183 | →
174 | // Empty arguments may indicate a bug in Wireshark. Extcap for example
175 | // omits arguments when their string value is empty. On Windows, empty
176 | // arguments would silently be ignored because protect_arg returns an
177 | // empty string, therefore we print a warning here.
178 | if (!*args[i]) {
179 | ws_warning("Empty argument %u in arguments list", i)do { if (1) { ws_log_full("Capture", LOG_LEVEL_WARNING, "wsutil/ws_pipe.c" , 179, __func__, "Empty argument %u in arguments list", i); } } while (0);
180 | }
181 | argv[1 + i] = g_strdup(args[i])g_strdup_inline (args[i]);
182 | }
183 | argv[args_count + 1] = NULL((void*)0);
184 | return argv;
185 | }
186 |
187 | /**
188 | * Convert a non-empty NULL-terminated array of command and arguments to a
189 | * string for displaying purposes. On Windows, the returned string is properly
190 | * escaped and can be executed directly.
191 | */
192 | static char *
193 | convert_to_command_line(char **argv)
194 | {
195 | GString *command_line = g_string_sized_new(200);
196 | #ifdef _WIN32
197 | const char *basename = get_basename(argv[0]);
198 | const char *dot = strrchr(basename, '.');
199 | char *quoted_arg;
200 | if (dot && dot != basename) {
201 | char *interpreter = win32_command_for_ext(dot);
202 | if (interpreter) {
203 | ws_debug("interpreter command for extension: %s", interpreter)do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "wsutil/ws_pipe.c" , 203, __func__, "interpreter command for extension: %s", interpreter ); } } while (0);
204 | // Already quoted, we just need to substitute argv[0] for %1.
205 | g_string_append(command_line, interpreter)(__builtin_constant_p (interpreter) ? __extension__ ({ const char * const __val = (interpreter); g_string_append_len_inline (command_line , __val, (__val != ((void*)0)) ? (gssize) strlen (((__val) + ! (__val))) : (gssize) -1); }) : g_string_append_len_inline (command_line , interpreter, (gssize) -1));
206 | if (g_str_has_suffix(interpreter, "%*")(__builtin_constant_p ("%*")? __extension__ ({ const char * const __str = (interpreter); const char * const __suffix = ("%*"); gboolean __result = (0); if (__str == ((void*)0) || __suffix == ((void*)0)) __result = (g_str_has_suffix) (__str, __suffix ); else { const size_t __str_len = strlen (((__str) + !(__str ))); const size_t __suffix_len = strlen (((__suffix) + !(__suffix ))); if (__str_len >= __suffix_len) __result = memcmp (__str + __str_len - __suffix_len, ((__suffix) + !(__suffix)), __suffix_len ) == 0; } __result; }) : (g_str_has_suffix) (interpreter, "%*" ) )) {
207 | // I am not sure why this has to be removed in some situations
208 | // but not others.
209 | g_string_truncate(command_line, command_line->len - 2)g_string_truncate_inline (command_line, command_line->len - 2);
210 | }
211 | g_free(interpreter)(__builtin_object_size ((interpreter), 0) != ((size_t) - 1)) ? g_free_sized (interpreter, __builtin_object_size ((interpreter ), 0)) : (g_free) (interpreter);
212 | }
213 | }
214 | // g_string_replace is available since GLib 2.68.
215 | // We've been using newer than that on official Windows releases since
216 | // at least 4.0. We might just want to bump the minimum GLib in general.
217 | if (!g_string_replace(command_line, "%1", argv[0], 1)) {
218 | // This is expected to fail if we didn't find an interpreter.
219 | // What if we did and it still failed?
220 | if (command_line->len) {
221 | // We returned a interpreter command, but it didn't have "%1".
222 | // That's unexpected. As a fallback, add a space and then append
223 | // the original command at the end.
224 | ws_info("Interpreter command didn't have \"%%1\", fallback to append.")do { if (1) { ws_log_full("Capture", LOG_LEVEL_INFO, ((void*) 0), -1, ((void*)0), "Interpreter command didn't have \"%%1\", fallback to append." ); } } while (0);
225 | g_string_append_c(command_line, ' ')g_string_append_c_inline (command_line, ' ');
226 | }
227 | // The first argument must always be quoted even if it does not contain
228 | // special characters or else CreateProcess might consider arguments as part
229 | // of the executable.
230 | quoted_arg = protect_arg(argv[0]);
231 | if (quoted_arg[0] != '"') {
232 | g_string_append_c(command_line, '"')g_string_append_c_inline (command_line, '"');
233 | g_string_append(command_line, quoted_arg)(__builtin_constant_p (quoted_arg) ? __extension__ ({ const char * const __val = (quoted_arg); g_string_append_len_inline (command_line , __val, (__val != ((void*)0)) ? (gssize) strlen (((__val) + ! (__val))) : (gssize) -1); }) : g_string_append_len_inline (command_line , quoted_arg, (gssize) -1));
234 | g_string_append_c(command_line, '"')g_string_append_c_inline (command_line, '"');
235 | } else {
236 | g_string_append(command_line, quoted_arg)(__builtin_constant_p (quoted_arg) ? __extension__ ({ const char * const __val = (quoted_arg); g_string_append_len_inline (command_line , __val, (__val != ((void*)0)) ? (gssize) strlen (((__val) + ! (__val))) : (gssize) -1); }) : g_string_append_len_inline (command_line , quoted_arg, (gssize) -1));
237 | }
238 | g_free(quoted_arg)(__builtin_object_size ((quoted_arg), 0) != ((size_t) - 1)) ? g_free_sized (quoted_arg, __builtin_object_size ((quoted_arg ), 0)) : (g_free) (quoted_arg);
239 | }
240 |
241 | for (int i = 1; argv[i]; i++) {
242 | quoted_arg = protect_arg(argv[i]);
243 | g_string_append_c(command_line, ' ')g_string_append_c_inline (command_line, ' ');
244 | g_string_append(command_line, quoted_arg)(__builtin_constant_p (quoted_arg) ? __extension__ ({ const char * const __val = (quoted_arg); g_string_append_len_inline (command_line , __val, (__val != ((void*)0)) ? (gssize) strlen (((__val) + ! (__val))) : (gssize) -1); }) : g_string_append_len_inline (command_line , quoted_arg, (gssize) -1));
245 | g_free(quoted_arg)(__builtin_object_size ((quoted_arg), 0) != ((size_t) - 1)) ? g_free_sized (quoted_arg, __builtin_object_size ((quoted_arg ), 0)) : (g_free) (quoted_arg);
246 | }
247 | #else
248 | for (int i = 0; argv[i]; i++) {
249 | char *quoted_arg = g_shell_quote(argv[i]);
250 | if (i != 0) {
251 | g_string_append_c(command_line, ' ')g_string_append_c_inline (command_line, ' ');
252 | }
253 | g_string_append(command_line, quoted_arg)(__builtin_constant_p (quoted_arg) ? __extension__ ({ const char * const __val = (quoted_arg); g_string_append_len_inline (command_line , __val, (__val != ((void*)0)) ? (gssize) strlen (((__val) + ! (__val))) : (gssize) -1); }) : g_string_append_len_inline (command_line , quoted_arg, (gssize) -1));
254 | g_free(quoted_arg)(__builtin_object_size ((quoted_arg), 0) != ((size_t) - 1)) ? g_free_sized (quoted_arg, __builtin_object_size ((quoted_arg ), 0)) : (g_free) (quoted_arg);
255 | }
256 | #endif
257 | return g_string_free(command_line, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((command_line ), ((0))) : g_string_free_and_steal (command_line)) : (g_string_free ) ((command_line), ((0))));
15 | ← | Loop condition is false. Execution continues on line 257 | →
16 | ← | '?' condition is false | →
17 | ← | Returning without deallocating memory or storing the pointer for later deallocation | →
258 | }
259 |
260 | bool_Bool ws_pipe_spawn_sync(const char *working_directory, const char *command, unsigned argc, char **args, char **command_output)
261 | {
262 | bool_Bool status = false0;
263 | bool_Bool result = false0;
264 | char *local_output = NULL((void*)0);
265 | #ifdef _WIN32
266 |
267 | #define BUFFER_SIZE 16384
268 |
269 | STARTUPINFO info;
270 | PROCESS_INFORMATION processInfo;
271 |
272 | SECURITY_ATTRIBUTES sa;
273 | HANDLE child_stdout_rd = NULL((void*)0);
274 | HANDLE child_stdout_wr = NULL((void*)0);
275 | HANDLE child_stderr_rd = NULL((void*)0);
276 | HANDLE child_stderr_wr = NULL((void*)0);
277 | HANDLE inherit_handles[2];
278 |
279 | OVERLAPPED stdout_overlapped;
280 | OVERLAPPED stderr_overlapped;
281 | #else
282 | int exit_status = 0;
283 | #endif
284 |
285 | char **argv = convert_to_argv(command, argc, args);
286 | char *command_line = convert_to_command_line(argv);
287 |
288 | ws_debug("command line: %s", command_line)do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "wsutil/ws_pipe.c" , 288, __func__, "command line: %s", command_line); } } while (0);
289 |
290 | int64_t start_time = g_get_monotonic_time();
291 |
292 | #ifdef _WIN32
293 | /* Setup overlapped structures. Create Manual Reset events, initially not signalled */
294 | memset(&stdout_overlapped, 0, sizeof(OVERLAPPED));
295 | memset(&stderr_overlapped, 0, sizeof(OVERLAPPED));
296 | stdout_overlapped.hEvent = CreateEvent(NULL((void*)0), true1, false0, NULL((void*)0));
297 | if (!stdout_overlapped.hEvent)
298 | {
299 | g_free(command_line)(__builtin_object_size ((command_line), 0) != ((size_t) - 1)) ? g_free_sized (command_line, __builtin_object_size ((command_line ), 0)) : (g_free) (command_line);
300 | g_strfreev(argv);
301 | ws_debug("Could not create stdout overlapped event")do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "wsutil/ws_pipe.c" , 301, __func__, "Could not create stdout overlapped event"); } } while (0);
302 | return false0;
303 | }
304 | stderr_overlapped.hEvent = CreateEvent(NULL((void*)0), true1, false0, NULL((void*)0));
305 | if (!stderr_overlapped.hEvent)
306 | {
307 | CloseHandle(stdout_overlapped.hEvent);
308 | g_free(command_line)(__builtin_object_size ((command_line), 0) != ((size_t) - 1)) ? g_free_sized (command_line, __builtin_object_size ((command_line ), 0)) : (g_free) (command_line);
309 | g_strfreev(argv);
310 | ws_debug("Could not create stderr overlapped event")do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "wsutil/ws_pipe.c" , 310, __func__, "Could not create stderr overlapped event"); } } while (0);
311 | return false0;
312 | }
313 |
314 | memset(&sa, 0, sizeof(SECURITY_ATTRIBUTES));
315 | sa.nLength = sizeof(SECURITY_ATTRIBUTES);
316 | sa.bInheritHandle = false0;
317 | sa.lpSecurityDescriptor = NULL((void*)0);
318 |
319 | if (!ws_pipe_create_overlapped_read(&child_stdout_rd, &child_stdout_wr, &sa, 0))
320 | {
321 | CloseHandle(stdout_overlapped.hEvent);
322 | CloseHandle(stderr_overlapped.hEvent);
323 | g_free(command_line)(__builtin_object_size ((command_line), 0) != ((size_t) - 1)) ? g_free_sized (command_line, __builtin_object_size ((command_line ), 0)) : (g_free) (command_line);
324 | g_strfreev(argv);
325 | ws_debug("Could not create stdout handle")do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "wsutil/ws_pipe.c" , 325, __func__, "Could not create stdout handle"); } } while (0);
326 | return false0;
327 | }
328 |
329 | if (!ws_pipe_create_overlapped_read(&child_stderr_rd, &child_stderr_wr, &sa, 0))
330 | {
331 | CloseHandle(stdout_overlapped.hEvent);
332 | CloseHandle(stderr_overlapped.hEvent);
333 | CloseHandle(child_stdout_rd);
334 | CloseHandle(child_stdout_wr);
335 | g_free(command_line)(__builtin_object_size ((command_line), 0) != ((size_t) - 1)) ? g_free_sized (command_line, __builtin_object_size ((command_line ), 0)) : (g_free) (command_line);
336 | g_strfreev(argv);
337 | ws_debug("Could not create stderr handle")do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "wsutil/ws_pipe.c" , 337, __func__, "Could not create stderr handle"); } } while (0);
338 | return false0;
339 | }
340 |
341 | inherit_handles[0] = child_stderr_wr;
342 | inherit_handles[1] = child_stdout_wr;
343 |
344 | memset(&processInfo, 0, sizeof(PROCESS_INFORMATION));
345 | memset(&info, 0, sizeof(STARTUPINFO));
346 |
347 | info.cb = sizeof(STARTUPINFO);
348 | info.hStdError = child_stderr_wr;
349 | info.hStdOutput = child_stdout_wr;
350 | info.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
351 | info.wShowWindow = SW_HIDE;
352 |
353 | if (win32_create_process(NULL((void*)0), command_line, NULL((void*)0), NULL((void*)0), G_N_ELEMENTS(inherit_handles)(sizeof (inherit_handles) / sizeof ((inherit_handles)[0])), inherit_handles,
354 | CREATE_NEW_CONSOLE, NULL((void*)0), working_directory, &info, &processInfo))
355 | {
356 | char* stdout_buffer = (char*)g_malloc(BUFFER_SIZE);
357 | char* stderr_buffer = (char*)g_malloc(BUFFER_SIZE);
358 | DWORD dw;
359 | DWORD bytes_read;
360 | GString *output_string = g_string_new(NULL((void*)0));
361 | bool_Bool process_finished = false0;
362 | bool_Bool pending_stdout = true1;
363 | bool_Bool pending_stderr = true1;
364 |
365 | /* Start asynchronous reads from child process stdout and stderr */
366 | if (!ReadFile(child_stdout_rd, stdout_buffer, BUFFER_SIZE, NULL((void*)0), &stdout_overlapped))
367 | {
368 | if (GetLastError() != ERROR_IO_PENDING)
369 | {
370 | ws_debug("ReadFile on child stdout pipe failed. Error %ld", GetLastError())do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "wsutil/ws_pipe.c" , 370, __func__, "ReadFile on child stdout pipe failed. Error %ld" , GetLastError()); } } while (0);
371 | pending_stdout = false0;
372 | }
373 | }
374 |
375 | if (!ReadFile(child_stderr_rd, stderr_buffer, BUFFER_SIZE, NULL((void*)0), &stderr_overlapped))
376 | {
377 | if (GetLastError() != ERROR_IO_PENDING)
378 | {
379 | ws_debug("ReadFile on child stderr pipe failed. Error %ld", GetLastError())do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "wsutil/ws_pipe.c" , 379, __func__, "ReadFile on child stderr pipe failed. Error %ld" , GetLastError()); } } while (0);
380 | pending_stderr = false0;
381 | }
382 | }
383 |
384 | for (;;)
385 | {
386 | HANDLE handles[3];
387 | DWORD n_handles = 0;
388 | if (!process_finished)
389 | {
390 | handles[n_handles++] = processInfo.hProcess;
391 | }
392 | if (pending_stdout)
393 | {
394 | handles[n_handles++] = stdout_overlapped.hEvent;
395 | }
396 | if (pending_stderr)
397 | {
398 | handles[n_handles++] = stderr_overlapped.hEvent;
399 | }
400 |
401 | if (!n_handles)
402 | {
403 | /* No more things to wait */
404 | break;
405 | }
406 |
407 | dw = WaitForMultipleObjects(n_handles, handles, false0, INFINITE);
408 | if (dw < (WAIT_OBJECT_0 + n_handles))
409 | {
410 | int i = dw - WAIT_OBJECT_0;
411 | if (handles[i] == processInfo.hProcess)
412 | {
413 | /* Process finished but there might still be unread data in the pipe.
414 | * Close the write pipes, so ReadFile does not wait indefinitely.
415 | */
416 | CloseHandle(child_stdout_wr);
417 | CloseHandle(child_stderr_wr);
418 | process_finished = true1;
419 | }
420 | else if (handles[i] == stdout_overlapped.hEvent)
421 | {
422 | bytes_read = 0;
423 | if (!GetOverlappedResult(child_stdout_rd, &stdout_overlapped, &bytes_read, true1))
424 | {
425 | if (GetLastError() == ERROR_BROKEN_PIPE)
426 | {
427 | pending_stdout = false0;
428 | continue;
429 | }
430 | ws_debug("GetOverlappedResult on stdout failed. Error %ld", GetLastError())do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "wsutil/ws_pipe.c" , 430, __func__, "GetOverlappedResult on stdout failed. Error %ld" , GetLastError()); } } while (0);
431 | }
432 | if (process_finished && (bytes_read == 0))
433 | {
434 | /* We have drained the pipe and there isn't any process that holds active write handle to the pipe. */
435 | pending_stdout = false0;
436 | continue;
437 | }
438 | g_string_append_len(output_string, stdout_buffer, bytes_read)g_string_append_len_inline (output_string, stdout_buffer, bytes_read );
439 | if (!ReadFile(child_stdout_rd, stdout_buffer, BUFFER_SIZE, NULL((void*)0), &stdout_overlapped))
440 | {
441 | if (GetLastError() != ERROR_IO_PENDING)
442 | {
443 | ws_debug("ReadFile on child stdout pipe failed. Error %ld", GetLastError())do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "wsutil/ws_pipe.c" , 443, __func__, "ReadFile on child stdout pipe failed. Error %ld" , GetLastError()); } } while (0);
444 | pending_stdout = false0;
445 | }
446 | }
447 | }
448 | else if (handles[i] == stderr_overlapped.hEvent)
449 | {
450 | /* Discard the stderr data just like non-windows version of this function does. */
451 | bytes_read = 0;
452 | if (!GetOverlappedResult(child_stderr_rd, &stderr_overlapped, &bytes_read, true1))
453 | {
454 | if (GetLastError() == ERROR_BROKEN_PIPE)
455 | {
456 | pending_stderr = false0;
457 | continue;
458 | }
459 | ws_debug("GetOverlappedResult on stderr failed. Error %ld", GetLastError())do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "wsutil/ws_pipe.c" , 459, __func__, "GetOverlappedResult on stderr failed. Error %ld" , GetLastError()); } } while (0);
460 | }
461 | if (process_finished && (bytes_read == 0))
462 | {
463 | pending_stderr = false0;
464 | continue;
465 | }
466 | if (!ReadFile(child_stderr_rd, stderr_buffer, BUFFER_SIZE, NULL((void*)0), &stderr_overlapped))
467 | {
468 | if (GetLastError() != ERROR_IO_PENDING)
469 | {
470 | ws_debug("ReadFile on child stderr pipe failed. Error %ld", GetLastError())do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "wsutil/ws_pipe.c" , 470, __func__, "ReadFile on child stderr pipe failed. Error %ld" , GetLastError()); } } while (0);
471 | pending_stderr = false0;
472 | }
473 | }
474 | }
475 | }
476 | else
477 | {
478 | ws_debug("WaitForMultipleObjects returned 0x%08lX. Error %ld", dw, GetLastError())do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "wsutil/ws_pipe.c" , 478, __func__, "WaitForMultipleObjects returned 0x%08lX. Error %ld" , dw, GetLastError()); } } while (0);
479 | }
480 | }
481 |
482 | g_free(stdout_buffer)(__builtin_object_size ((stdout_buffer), 0) != ((size_t) - 1) ) ? g_free_sized (stdout_buffer, __builtin_object_size ((stdout_buffer ), 0)) : (g_free) (stdout_buffer);
483 | g_free(stderr_buffer)(__builtin_object_size ((stderr_buffer), 0) != ((size_t) - 1) ) ? g_free_sized (stderr_buffer, __builtin_object_size ((stderr_buffer ), 0)) : (g_free) (stderr_buffer);
484 |
485 | status = GetExitCodeProcess(processInfo.hProcess, &dw);
486 | if (status && dw != 0)
487 | {
488 | status = false0;
489 | }
490 |
491 | local_output = g_string_free(output_string, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((output_string ), ((0))) : g_string_free_and_steal (output_string)) : (g_string_free ) ((output_string), ((0))));
492 |
493 | CloseHandle(child_stdout_rd);
494 | CloseHandle(child_stderr_rd);
495 |
496 | CloseHandle(processInfo.hProcess);
497 | CloseHandle(processInfo.hThread);
498 | }
499 | else
500 | {
501 | status = false0;
502 |
503 | CloseHandle(child_stdout_rd);
504 | CloseHandle(child_stdout_wr);
505 | CloseHandle(child_stderr_rd);
506 | CloseHandle(child_stderr_wr);
507 | }
508 |
509 | CloseHandle(stdout_overlapped.hEvent);
510 | CloseHandle(stderr_overlapped.hEvent);
511 | #else
512 |
513 | GSpawnFlags flags = (GSpawnFlags)0;
514 | GSpawnChildSetupFunc child_setup = NULL((void*)0);
515 | #ifdef HAS_G_SPAWN_LINUX_THREAD_SAFETY_BUG
516 | flags = (GSpawnFlags)(flags | G_SPAWN_LEAVE_DESCRIPTORS_OPEN);
517 | child_setup = close_non_standard_fds_linux;
518 | #endif
519 | status = g_spawn_sync(working_directory, argv, NULL((void*)0),
520 | flags, child_setup, NULL((void*)0), &local_output, NULL((void*)0), &exit_status, NULL((void*)0));
521 |
522 | if (status && exit_status != 0)
523 | status = false0;
524 | #endif
525 |
526 | ws_debug("%s finished in %.3fms", argv[0], (g_get_monotonic_time() - start_time) / 1000.0)do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "wsutil/ws_pipe.c" , 526, __func__, "%s finished in %.3fms", argv[0], (g_get_monotonic_time () - start_time) / 1000.0); } } while (0);
527 |
528 | if (status)
529 | {
530 | if (local_output != NULL((void*)0)) {
531 | ws_noisy("spawn output: %s", local_output)do { if (1) { ws_log_full("Capture", LOG_LEVEL_NOISY, "wsutil/ws_pipe.c" , 531, __func__, "spawn output: %s", local_output); } } while (0);
532 | if (command_output != NULL((void*)0))
533 | *command_output = g_strdup(local_output)g_strdup_inline (local_output);
534 | }
535 | result = true1;
536 | }
537 |
538 | g_free(local_output)(__builtin_object_size ((local_output), 0) != ((size_t) - 1)) ? g_free_sized (local_output, __builtin_object_size ((local_output ), 0)) : (g_free) (local_output);
539 | g_free(command_line)(__builtin_object_size ((command_line), 0) != ((size_t) - 1)) ? g_free_sized (command_line, __builtin_object_size ((command_line ), 0)) : (g_free) (command_line);
540 | g_strfreev(argv);
541 |
542 | return result;
543 | }
544 |
545 | void ws_pipe_init(ws_pipe_t *ws_pipe)
546 | {
547 | if (!ws_pipe) return;
548 | memset(ws_pipe, 0, sizeof(ws_pipe_t));
549 | ws_pipe->pid = WS_INVALID_PID-1;
550 | }
551 |
552 | GPid ws_pipe_spawn_async(ws_pipe_t *ws_pipe, GPtrArray *args)
553 | {
554 | GPid pid = WS_INVALID_PID-1;
555 | int stdin_fd, stdout_fd, stderr_fd;
556 | #ifdef _WIN32
557 | STARTUPINFO info;
558 | PROCESS_INFORMATION processInfo;
559 |
560 | SECURITY_ATTRIBUTES sa;
561 | HANDLE child_stdin_rd = NULL((void*)0);
562 | HANDLE child_stdin_wr = NULL((void*)0);
563 | HANDLE child_stdout_rd = NULL((void*)0);
564 | HANDLE child_stdout_wr = NULL((void*)0);
565 | HANDLE child_stderr_rd = NULL((void*)0);
566 | HANDLE child_stderr_wr = NULL((void*)0);
567 | HANDLE inherit_handles[3];
568 | #endif
569 |
570 | // XXX harmonize handling of command arguments for the sync/async functions
571 | // and make them const? This array ends with a trailing NULL by the way.
572 | char **args_array = (char **)args->pdata;
573 |
574 | // args must include command itself
575 | ws_return_val_if(args->len < 1, WS_INVALID_PID)do { if (1 && (args->len < 1)) { ws_log_full("InvalidArg" , LOG_LEVEL_WARNING, "wsutil/ws_pipe.c", 575, __func__, "invalid argument: %s" , "args->len < 1"); return (-1); } } while (0);
1 | Assuming field 'len' is >= 1 | →
2 | ← | Taking false branch | →
576 | ws_return_val_if(!args_array[0], WS_INVALID_PID)do { if (1 && (!args_array[0])) { ws_log_full("InvalidArg" , LOG_LEVEL_WARNING, "wsutil/ws_pipe.c", 576, __func__, "invalid argument: %s" , "!args_array[0]"); return (-1); } } while (0);
3 | ← | Loop condition is false. Exiting loop | →
4 | ← | Assuming the condition is false | →
5 | ← | Taking false branch | →
6 | ← | Loop condition is false. Exiting loop | →
577 |
578 | unsigned args_count = args->len - 2;
579 | if (args_array[args->len - 1] != NULL((void*)0)) {
7 | ← | Assuming the condition is false | →
8 | ← | Taking false branch | →
580 | ws_warning("args should be NULL-terminated")do { if (1) { ws_log_full("Capture", LOG_LEVEL_WARNING, "wsutil/ws_pipe.c" , 580, __func__, "args should be NULL-terminated"); } } while (0);
581 | args_count = args->len - 1;
582 | }
583 | char **argv = convert_to_argv(args_array[0], args_count, args_array + 1);
9 | ← | Calling 'convert_to_argv' | →
13 | ← | Returned allocated memory | →
584 | char *command_line = convert_to_command_line(argv);
14 | ← | Calling 'convert_to_command_line' | →
18 | ← | Returning from 'convert_to_command_line' | →
585 |
586 | ws_debug("command line: %s", command_line)do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "wsutil/ws_pipe.c" , 586, __func__, "command line: %s", command_line); } } while (0);
19 | ← | Taking true branch | →
20 | ← | Loop condition is false. Exiting loop | →
587 |
588 | #ifdef _WIN32
589 | sa.nLength = sizeof(SECURITY_ATTRIBUTES);
590 | sa.bInheritHandle = false0;
591 | sa.lpSecurityDescriptor = NULL((void*)0);
592 |
593 | if (!CreatePipe(&child_stdin_rd, &child_stdin_wr, &sa, 0))
594 | {
595 | g_free(command_line)(__builtin_object_size ((command_line), 0) != ((size_t) - 1)) ? g_free_sized (command_line, __builtin_object_size ((command_line ), 0)) : (g_free) (command_line);
596 | g_strfreev(argv);
597 | ws_debug("Could not create stdin handle")do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "wsutil/ws_pipe.c" , 597, __func__, "Could not create stdin handle"); } } while ( 0);
598 | return WS_INVALID_PID-1;
599 | }
600 |
601 | if (!CreatePipe(&child_stdout_rd, &child_stdout_wr, &sa, 0))
602 | {
603 | CloseHandle(child_stdin_rd);
604 | CloseHandle(child_stdin_wr);
605 | g_free(command_line)(__builtin_object_size ((command_line), 0) != ((size_t) - 1)) ? g_free_sized (command_line, __builtin_object_size ((command_line ), 0)) : (g_free) (command_line);
606 | g_strfreev(argv);
607 | ws_debug("Could not create stdout handle")do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "wsutil/ws_pipe.c" , 607, __func__, "Could not create stdout handle"); } } while (0);
608 | return WS_INVALID_PID-1;
609 | }
610 |
611 | if (!CreatePipe(&child_stderr_rd, &child_stderr_wr, &sa, 0))
612 | {
613 | CloseHandle(child_stdin_rd);
614 | CloseHandle(child_stdin_wr);
615 | CloseHandle(child_stdout_rd);
616 | CloseHandle(child_stdout_wr);
617 | g_free(command_line)(__builtin_object_size ((command_line), 0) != ((size_t) - 1)) ? g_free_sized (command_line, __builtin_object_size ((command_line ), 0)) : (g_free) (command_line);
618 | g_strfreev(argv);
619 | ws_debug("Could not create stderr handle")do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "wsutil/ws_pipe.c" , 619, __func__, "Could not create stderr handle"); } } while (0);
620 | return WS_INVALID_PID-1;
621 | }
622 |
623 | inherit_handles[0] = child_stdin_rd;
624 | inherit_handles[1] = child_stderr_wr;
625 | inherit_handles[2] = child_stdout_wr;
626 |
627 | memset(&processInfo, 0, sizeof(PROCESS_INFORMATION));
628 | memset(&info, 0, sizeof(STARTUPINFO));
629 |
630 | info.cb = sizeof(STARTUPINFO);
631 | info.hStdInput = child_stdin_rd;
632 | info.hStdError = child_stderr_wr;
633 | info.hStdOutput = child_stdout_wr;
634 | info.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
635 | info.wShowWindow = SW_HIDE;
636 |
637 | if (win32_create_process(NULL((void*)0), command_line, NULL((void*)0), NULL((void*)0), G_N_ELEMENTS(inherit_handles)(sizeof (inherit_handles) / sizeof ((inherit_handles)[0])), inherit_handles,
638 | CREATE_NEW_CONSOLE, NULL((void*)0), NULL((void*)0), &info, &processInfo))
639 | {
640 | stdin_fd = _open_osfhandle((intptr_t)(child_stdin_wr), _O_BINARY);
641 | stdout_fd = _open_osfhandle((intptr_t)(child_stdout_rd), _O_BINARY);
642 | stderr_fd = _open_osfhandle((intptr_t)(child_stderr_rd), _O_BINARY);
643 | pid = processInfo.hProcess;
644 | CloseHandle(processInfo.hThread);
645 | }
646 | else
647 | {
648 | CloseHandle(child_stdin_wr);
649 | CloseHandle(child_stdout_rd);
650 | CloseHandle(child_stderr_rd);
651 | }
652 |
653 | /* We no longer need other (child) end of pipes. The child process holds
654 | * its own handles that will be closed on process exit. However, we have
655 | * to close *our* handles as otherwise read() on stdout_fd and stderr_fd
656 | * will block indefinitely after the process exits.
657 | */
658 | CloseHandle(child_stdin_rd);
659 | CloseHandle(child_stdout_wr);
660 | CloseHandle(child_stderr_wr);
661 | #else
662 |
663 | GError *error = NULL((void*)0);
664 | GSpawnFlags flags = G_SPAWN_DO_NOT_REAP_CHILD;
665 | GSpawnChildSetupFunc child_setup = NULL((void*)0);
666 | #ifdef HAS_G_SPAWN_LINUX_THREAD_SAFETY_BUG
667 | flags = (GSpawnFlags)(flags | G_SPAWN_LEAVE_DESCRIPTORS_OPEN);
668 | child_setup = close_non_standard_fds_linux;
669 | #endif
670 | bool_Bool spawned = g_spawn_async_with_pipes(NULL((void*)0), argv, NULL((void*)0),
671 | flags, child_setup, NULL((void*)0),
672 | &pid, &stdin_fd, &stdout_fd, &stderr_fd, &error);
673 | if (!spawned) {
21 | ← | Assuming 'spawned' is true | →
674 | ws_debug("Error creating async pipe: %s", error->message)do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "wsutil/ws_pipe.c" , 674, __func__, "Error creating async pipe: %s", error->message ); } } while (0);
675 | g_free(error->message)(__builtin_object_size ((error->message), 0) != ((size_t) - 1)) ? g_free_sized (error->message, __builtin_object_size ((error->message), 0)) : (g_free) (error->message);
676 | }
677 | #endif
678 |
679 | g_free(command_line)(__builtin_object_size ((command_line), 0) != ((size_t) - 1)) ? g_free_sized (command_line, __builtin_object_size ((command_line ), 0)) : (g_free) (command_line);
22 | ← | Taking false branch | →
23 | ← | Assuming the condition is false | →
24 | ← | '?' condition is false | →
680 | g_strfreev(argv);
681 |
682 | ws_pipe->pid = pid;
25 | ← | Potential leak of memory pointed to by 'argv'
683 |
684 | if (pid != WS_INVALID_PID-1) {
685 | #ifdef _WIN32
686 | ws_pipe->stdin_io = g_io_channel_win32_new_fd(stdin_fd);
687 | ws_pipe->stdout_io = g_io_channel_win32_new_fd(stdout_fd);
688 | ws_pipe->stderr_io = g_io_channel_win32_new_fd(stderr_fd);
689 | #else
690 | ws_pipe->stdin_io = g_io_channel_unix_new(stdin_fd);
691 | ws_pipe->stdout_io = g_io_channel_unix_new(stdout_fd);
692 | ws_pipe->stderr_io = g_io_channel_unix_new(stderr_fd);
693 | #endif
694 | g_io_channel_set_encoding(ws_pipe->stdin_io, NULL((void*)0), NULL((void*)0));
695 | g_io_channel_set_encoding(ws_pipe->stdout_io, NULL((void*)0), NULL((void*)0));
696 | g_io_channel_set_encoding(ws_pipe->stderr_io, NULL((void*)0), NULL((void*)0));
697 | g_io_channel_set_buffered(ws_pipe->stdin_io, false0);
698 | g_io_channel_set_buffered(ws_pipe->stdout_io, false0);
699 | g_io_channel_set_buffered(ws_pipe->stderr_io, false0);
700 | g_io_channel_set_close_on_unref(ws_pipe->stdin_io, true1);
701 | g_io_channel_set_close_on_unref(ws_pipe->stdout_io, true1);
702 | g_io_channel_set_close_on_unref(ws_pipe->stderr_io, true1);
703 | }
704 |
705 | return pid;
706 | }
707 |
708 | #ifdef _WIN32
709 |
710 | typedef struct
711 | {
712 | HANDLE pipeHandle;
713 | OVERLAPPED ol;
714 | BOOL pendingIO;
715 | } PIPEINTS;
716 |
717 | bool_Bool
718 | ws_pipe_wait_for_pipe(HANDLE * pipe_handles, int num_pipe_handles, HANDLE pid)
719 | {
720 | PIPEINTS pipeinsts[3];
721 | HANDLE handles[4];
722 | bool_Bool result = true1;
723 |
724 | SecureZeroMemory(pipeinsts, sizeof(pipeinsts));
725 |
726 | if (num_pipe_handles == 0 || num_pipe_handles > 3)
727 | {
728 | ws_debug("Invalid number of pipes given as argument.")do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "wsutil/ws_pipe.c" , 728, __func__, "Invalid number of pipes given as argument." ); } } while (0);
729 | return false0;
730 | }
731 |
732 | for (int i = 0; i < num_pipe_handles; ++i)
733 | {
734 | pipeinsts[i].ol.hEvent = CreateEvent(NULL((void*)0), true1, false0, NULL((void*)0));
735 | if (!pipeinsts[i].ol.hEvent)
736 | {
737 | ws_debug("Could not create overlapped event")do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "wsutil/ws_pipe.c" , 737, __func__, "Could not create overlapped event"); } } while (0);
738 | for (int j = 0; j < i; j++)
739 | {
740 | CloseHandle(pipeinsts[j].ol.hEvent);
741 | }
742 | return false0;
743 | }
744 | }
745 |
746 | for (int i = 0; i < num_pipe_handles; ++i)
747 | {
748 | pipeinsts[i].pipeHandle = pipe_handles[i];
749 | pipeinsts[i].ol.Pointer = 0;
750 | pipeinsts[i].pendingIO = false0;
751 | if (!ConnectNamedPipe(pipeinsts[i].pipeHandle, &pipeinsts[i].ol))
752 | {
753 | DWORD error = GetLastError();
754 | switch (error)
755 | {
756 | case ERROR_IO_PENDING:
757 | pipeinsts[i].pendingIO = true1;
758 | break;
759 |
760 | case ERROR_PIPE_CONNECTED:
761 | SetEvent(pipeinsts[i].ol.hEvent);
762 | break;
763 |
764 | default:
765 | ws_debug("ConnectNamedPipe failed with %ld\n.", error)do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "wsutil/ws_pipe.c" , 765, __func__, "ConnectNamedPipe failed with %ld\n.", error ); } } while (0);
766 | result = false0;
767 | }
768 | }
769 | }
770 |
771 | while (result)
772 | {
773 | DWORD dw;
774 | int num_handles = 0;
775 | for (int i = 0; i < num_pipe_handles; ++i)
776 | {
777 | if (pipeinsts[i].pendingIO)
778 | {
779 | handles[num_handles] = pipeinsts[i].ol.hEvent;
780 | num_handles++;
781 | }
782 | }
783 | if (num_handles == 0)
784 | {
785 | /* All pipes have been successfully connected */
786 | break;
787 | }
788 | /* Wait for process in case it exits before the pipes have connected */
789 | handles[num_handles] = pid;
790 | num_handles++;
791 |
792 | dw = WaitForMultipleObjects(num_handles, handles, false0, 30000);
793 | int handle_idx = dw - WAIT_OBJECT_0;
794 | if (dw == WAIT_TIMEOUT)
795 | {
796 | ws_debug("extcap didn't connect to pipe within 30 seconds.")do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "wsutil/ws_pipe.c" , 796, __func__, "extcap didn't connect to pipe within 30 seconds." ); } } while (0);
797 | result = false0;
798 | break;
799 | }
800 | // If index points to our handles array
801 | else if (handle_idx >= 0 && handle_idx < num_handles)
802 | {
803 | if (handles[handle_idx] == pid)
804 | {
805 | ws_debug("extcap terminated without connecting to pipe.")do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "wsutil/ws_pipe.c" , 805, __func__, "extcap terminated without connecting to pipe." ); } } while (0);
806 | result = false0;
807 | }
808 | for (int i = 0; i < num_pipe_handles; ++i)
809 | {
810 | if (handles[handle_idx] == pipeinsts[i].ol.hEvent)
811 | {
812 | DWORD cbRet;
813 | BOOL success = GetOverlappedResult(
814 | pipeinsts[i].pipeHandle, // handle to pipe
815 | &pipeinsts[i].ol, // OVERLAPPED structure
816 | &cbRet, // bytes transferred
817 | true1); // wait
818 | if (!success)
819 | {
820 | ws_debug("Error %ld \n.", GetLastError())do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "wsutil/ws_pipe.c" , 820, __func__, "Error %ld \n.", GetLastError()); } } while ( 0);
821 | result = false0;
822 | }
823 | pipeinsts[i].pendingIO = false0;
824 | }
825 | }
826 | }
827 | else
828 | {
829 | ws_debug("WaitForMultipleObjects returned 0x%08lX. Error %ld", dw, GetLastError())do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "wsutil/ws_pipe.c" , 829, __func__, "WaitForMultipleObjects returned 0x%08lX. Error %ld" , dw, GetLastError()); } } while (0);
830 | result = false0;
831 | }
832 | }
833 |
834 | for (int i = 0; i < num_pipe_handles; ++i)
835 | {
836 | if (pipeinsts[i].pendingIO)
837 | {
838 | CancelIoEx(pipeinsts[i].pipeHandle, &pipeinsts[i].ol);
839 | WaitForSingleObject(pipeinsts[i].ol.hEvent, INFINITE);
840 | }
841 | CloseHandle(pipeinsts[i].ol.hEvent);
842 | }
843 |
844 | return result;
845 | }
846 | #endif
847 |
848 | bool_Bool
849 | ws_pipe_data_available(int pipe_fd)
850 | {
851 | #ifdef _WIN32 /* PeekNamedPipe */
852 | HANDLE hPipe = (HANDLE) _get_osfhandle(pipe_fd);
853 | DWORD bytes_avail;
854 |
855 | if (hPipe == INVALID_HANDLE_VALUE)
856 | {
857 | return false0;
858 | }
859 |
860 | if (! PeekNamedPipe(hPipe, NULL((void*)0), 0, NULL((void*)0), &bytes_avail, NULL((void*)0)))
861 | {
862 | return false0;
863 | }
864 |
865 | if (bytes_avail > 0)
866 | {
867 | return true1;
868 | }
869 | return false0;
870 | #else /* select */
871 | fd_set rfds;
872 | struct timeval timeout;
873 |
874 | FD_ZERO(&rfds)do { unsigned int __i; fd_set *__arr = (&rfds); for (__i = 0; __i < sizeof (fd_set) / sizeof (__fd_mask); ++__i) ((__arr )->__fds_bits)[__i] = 0; } while (0);
875 | FD_SET(pipe_fd, &rfds)((void) (((&rfds)->__fds_bits)[((pipe_fd) / (8 * (int) sizeof (__fd_mask)))] |= ((__fd_mask) (1UL << ((pipe_fd ) % (8 * (int) sizeof (__fd_mask)))))));
876 | timeout.tv_sec = 0;
877 | timeout.tv_usec = 0;
878 |
879 | if (select(pipe_fd + 1, &rfds, NULL((void*)0), NULL((void*)0), &timeout) > 0)
880 | {
881 | return true1;
882 | }
883 |
884 | return false0;
885 | #endif
886 | }
887 |
888 | /*
889 | * Editor modelines - https://www.wireshark.org/tools/modelines.html
890 | *
891 | * Local variables:
892 | * c-basic-offset: 4
893 | * tab-width: 8
894 | * indent-tabs-mode: nil
895 | * End:
896 | *
897 | * vi: set shiftwidth=4 tabstop=8 expandtab:
898 | * :indentSize=4:tabSize=8:noTabs=true:
899 | */