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

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-08-24-100314-3660-1 -x c /builds/wireshark/wireshark/wsutil/ws_pipe.c
1/* ws_pipe.c
2 *
3 * Routines for handling pipes.
4 *
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <[email protected]>
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
45struct 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. */
54static int
55filename_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
80static void
81close_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
120static ULONG pipe_serial_number;
121
122/* Alternative for CreatePipe() where read handle is opened with FILE_FLAG_OVERLAPPED */
123static bool_Bool
124ws_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 */
166static char **
167convert_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 */
192static char *
193convert_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
260bool_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
545void 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
552GPid 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
710typedef struct
711{
712 HANDLE pipeHandle;
713 OVERLAPPED ol;
714 BOOL pendingIO;
715} PIPEINTS;
716
717bool_Bool
718ws_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
848bool_Bool
849ws_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 */