• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 /* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to
6  * deal in the Software without restriction, including without limitation the
7  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8  * sell copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20  * IN THE SOFTWARE.
21  */
22 
23 #include "uv.h"
24 #include "task.h"
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 
31 #ifdef _WIN32
32 # include <shellapi.h>
33 # include <wchar.h>
34   typedef BOOL (WINAPI *sCompareObjectHandles)(_In_ HANDLE, _In_ HANDLE);
35 #else
36 # include <unistd.h>
37 # include <sys/wait.h>
38 #endif
39 
40 
41 static int close_cb_called;
42 static int exit_cb_called;
43 static uv_process_t process;
44 static uv_timer_t timer;
45 static uv_process_options_t options;
46 static char exepath[1024];
47 static size_t exepath_size = 1024;
48 static char* args[5];
49 static int no_term_signal;
50 static int timer_counter;
51 static uv_tcp_t tcp_server;
52 
53 #define OUTPUT_SIZE 1024
54 static char output[OUTPUT_SIZE];
55 static int output_used;
56 
57 
close_cb(uv_handle_t * handle)58 static void close_cb(uv_handle_t* handle) {
59   printf("close_cb\n");
60   close_cb_called++;
61 }
62 
exit_cb(uv_process_t * process,int64_t exit_status,int term_signal)63 static void exit_cb(uv_process_t* process,
64                     int64_t exit_status,
65                     int term_signal) {
66   printf("exit_cb\n");
67   exit_cb_called++;
68   ASSERT(exit_status == 1);
69   ASSERT(term_signal == 0);
70   uv_close((uv_handle_t*) process, close_cb);
71 }
72 
73 
fail_cb(uv_process_t * process,int64_t exit_status,int term_signal)74 static void fail_cb(uv_process_t* process,
75                     int64_t exit_status,
76                     int term_signal) {
77     return;
78 }
79 
80 
kill_cb(uv_process_t * process,int64_t exit_status,int term_signal)81 static void kill_cb(uv_process_t* process,
82                     int64_t exit_status,
83                     int term_signal) {
84   int err;
85 
86   printf("exit_cb\n");
87   exit_cb_called++;
88 #ifdef _WIN32
89   ASSERT(exit_status == 1);
90 #else
91   ASSERT(exit_status == 0);
92 #endif
93 #if defined(__APPLE__) || defined(__MVS__)
94   /*
95    * At least starting with Darwin Kernel Version 16.4.0, sending a SIGTERM to a
96    * process that is still starting up kills it with SIGKILL instead of SIGTERM.
97    * See: https://github.com/libuv/libuv/issues/1226
98    */
99   ASSERT(no_term_signal || term_signal == SIGTERM || term_signal == SIGKILL);
100 #else
101   ASSERT(no_term_signal || term_signal == SIGTERM);
102 #endif
103   uv_close((uv_handle_t*) process, close_cb);
104 
105   /*
106    * Sending signum == 0 should check if the
107    * child process is still alive, not kill it.
108    * This process should be dead.
109    */
110   err = uv_kill(process->pid, 0);
111   ASSERT(err == UV_ESRCH);
112 }
113 
detach_failure_cb(uv_process_t * process,int64_t exit_status,int term_signal)114 static void detach_failure_cb(uv_process_t* process,
115                               int64_t exit_status,
116                               int term_signal) {
117   printf("detach_cb\n");
118   exit_cb_called++;
119 }
120 
on_alloc(uv_handle_t * handle,size_t suggested_size,uv_buf_t * buf)121 static void on_alloc(uv_handle_t* handle,
122                      size_t suggested_size,
123                      uv_buf_t* buf) {
124   buf->base = output + output_used;
125   buf->len = OUTPUT_SIZE - output_used;
126 }
127 
128 
on_read(uv_stream_t * tcp,ssize_t nread,const uv_buf_t * buf)129 static void on_read(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) {
130   if (nread > 0) {
131     output_used += nread;
132   } else if (nread < 0) {
133     ASSERT(nread == UV_EOF);
134     uv_close((uv_handle_t*) tcp, close_cb);
135   }
136 }
137 
138 
on_read_once(uv_stream_t * tcp,ssize_t nread,const uv_buf_t * buf)139 static void on_read_once(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) {
140   uv_read_stop(tcp);
141   on_read(tcp, nread, buf);
142 }
143 
144 
write_cb(uv_write_t * req,int status)145 static void write_cb(uv_write_t* req, int status) {
146   ASSERT(status == 0);
147   uv_close((uv_handle_t*) req->handle, close_cb);
148 }
149 
150 
write_null_cb(uv_write_t * req,int status)151 static void write_null_cb(uv_write_t* req, int status) {
152   ASSERT(status == 0);
153 }
154 
155 
init_process_options(char * test,uv_exit_cb exit_cb)156 static void init_process_options(char* test, uv_exit_cb exit_cb) {
157   /* Note spawn_helper1 defined in test/run-tests.c */
158   int r = uv_exepath(exepath, &exepath_size);
159   ASSERT(r == 0);
160   exepath[exepath_size] = '\0';
161   args[0] = exepath;
162   args[1] = test;
163   args[2] = NULL;
164   args[3] = NULL;
165   args[4] = NULL;
166   options.file = exepath;
167   options.args = args;
168   options.exit_cb = exit_cb;
169   options.flags = 0;
170 }
171 
172 
timer_cb(uv_timer_t * handle)173 static void timer_cb(uv_timer_t* handle) {
174   uv_process_kill(&process, SIGTERM);
175   uv_close((uv_handle_t*) handle, close_cb);
176 }
177 
178 
timer_counter_cb(uv_timer_t * handle)179 static void timer_counter_cb(uv_timer_t* handle) {
180   ++timer_counter;
181 }
182 
183 
TEST_IMPL(spawn_fails)184 TEST_IMPL(spawn_fails) {
185   int r;
186 
187   init_process_options("", fail_cb);
188   options.file = options.args[0] = "program-that-had-better-not-exist";
189 
190   r = uv_spawn(uv_default_loop(), &process, &options);
191   ASSERT(r == UV_ENOENT || r == UV_EACCES);
192   ASSERT(0 == uv_is_active((uv_handle_t*) &process));
193   uv_close((uv_handle_t*) &process, NULL);
194   ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
195 
196   MAKE_VALGRIND_HAPPY();
197   return 0;
198 }
199 
200 
201 #ifndef _WIN32
TEST_IMPL(spawn_fails_check_for_waitpid_cleanup)202 TEST_IMPL(spawn_fails_check_for_waitpid_cleanup) {
203   int r;
204   int status;
205   int err;
206 
207   init_process_options("", fail_cb);
208   options.file = options.args[0] = "program-that-had-better-not-exist";
209 
210   r = uv_spawn(uv_default_loop(), &process, &options);
211   ASSERT(r == UV_ENOENT || r == UV_EACCES);
212   ASSERT(0 == uv_is_active((uv_handle_t*) &process));
213   ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
214 
215   /* verify the child is successfully cleaned up within libuv */
216   do
217     err = waitpid(process.pid, &status, 0);
218   while (err == -1 && errno == EINTR);
219 
220   ASSERT(err == -1);
221   ASSERT(errno == ECHILD);
222 
223   uv_close((uv_handle_t*) &process, NULL);
224   ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
225 
226   MAKE_VALGRIND_HAPPY();
227   return 0;
228 }
229 #endif
230 
231 
TEST_IMPL(spawn_empty_env)232 TEST_IMPL(spawn_empty_env) {
233   char* env[1];
234 
235   /* The autotools dynamic library build requires the presence of
236    * DYLD_LIBARY_PATH (macOS) or LD_LIBRARY_PATH/LIBPATH (other Unices)
237    * in the environment, but of course that doesn't work with
238    * the empty environment that we're testing here.
239    */
240   if (NULL != getenv("DYLD_LIBRARY_PATH") ||
241       NULL != getenv("LD_LIBRARY_PATH") ||
242       NULL != getenv("LIBPATH")) {
243     RETURN_SKIP("doesn't work with DYLD_LIBRARY_PATH/LD_LIBRARY_PATH/LIBPATH");
244   }
245 
246   init_process_options("spawn_helper1", exit_cb);
247   options.env = env;
248   env[0] = NULL;
249 
250   ASSERT(0 == uv_spawn(uv_default_loop(), &process, &options));
251   ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
252 
253   ASSERT(exit_cb_called == 1);
254   ASSERT(close_cb_called == 1);
255 
256   MAKE_VALGRIND_HAPPY();
257   return 0;
258 }
259 
260 
TEST_IMPL(spawn_exit_code)261 TEST_IMPL(spawn_exit_code) {
262   int r;
263 
264   init_process_options("spawn_helper1", exit_cb);
265 
266   r = uv_spawn(uv_default_loop(), &process, &options);
267   ASSERT(r == 0);
268 
269   r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
270   ASSERT(r == 0);
271 
272   ASSERT(exit_cb_called == 1);
273   ASSERT(close_cb_called == 1);
274 
275   MAKE_VALGRIND_HAPPY();
276   return 0;
277 }
278 
279 
TEST_IMPL(spawn_stdout)280 TEST_IMPL(spawn_stdout) {
281   int r;
282   uv_pipe_t out;
283   uv_stdio_container_t stdio[2];
284 
285   init_process_options("spawn_helper2", exit_cb);
286 
287   uv_pipe_init(uv_default_loop(), &out, 0);
288   options.stdio = stdio;
289   options.stdio[0].flags = UV_IGNORE;
290   options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
291   options.stdio[1].data.stream = (uv_stream_t*) &out;
292   options.stdio_count = 2;
293 
294   r = uv_spawn(uv_default_loop(), &process, &options);
295   ASSERT(r == 0);
296 
297   r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read);
298   ASSERT(r == 0);
299 
300   r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
301   ASSERT(r == 0);
302 
303   ASSERT(exit_cb_called == 1);
304   ASSERT(close_cb_called == 2); /* Once for process once for the pipe. */
305   printf("output is: %s", output);
306   ASSERT(strcmp("hello world\n", output) == 0);
307 
308   MAKE_VALGRIND_HAPPY();
309   return 0;
310 }
311 
312 
TEST_IMPL(spawn_stdout_to_file)313 TEST_IMPL(spawn_stdout_to_file) {
314   int r;
315   uv_file file;
316   uv_fs_t fs_req;
317   uv_stdio_container_t stdio[2];
318   uv_buf_t buf;
319 
320   /* Setup. */
321   unlink("stdout_file");
322 
323   init_process_options("spawn_helper2", exit_cb);
324 
325   r = uv_fs_open(NULL, &fs_req, "stdout_file", O_CREAT | O_RDWR,
326       S_IRUSR | S_IWUSR, NULL);
327   ASSERT(r != -1);
328   uv_fs_req_cleanup(&fs_req);
329 
330   file = r;
331 
332   options.stdio = stdio;
333   options.stdio[0].flags = UV_IGNORE;
334   options.stdio[1].flags = UV_INHERIT_FD;
335   options.stdio[1].data.fd = file;
336   options.stdio_count = 2;
337 
338   r = uv_spawn(uv_default_loop(), &process, &options);
339   ASSERT(r == 0);
340 
341   r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
342   ASSERT(r == 0);
343 
344   ASSERT(exit_cb_called == 1);
345   ASSERT(close_cb_called == 1);
346 
347   buf = uv_buf_init(output, sizeof(output));
348   r = uv_fs_read(NULL, &fs_req, file, &buf, 1, 0, NULL);
349   ASSERT(r == 12);
350   uv_fs_req_cleanup(&fs_req);
351 
352   r = uv_fs_close(NULL, &fs_req, file, NULL);
353   ASSERT(r == 0);
354   uv_fs_req_cleanup(&fs_req);
355 
356   printf("output is: %s", output);
357   ASSERT(strcmp("hello world\n", output) == 0);
358 
359   /* Cleanup. */
360   unlink("stdout_file");
361 
362   MAKE_VALGRIND_HAPPY();
363   return 0;
364 }
365 
366 
TEST_IMPL(spawn_stdout_and_stderr_to_file)367 TEST_IMPL(spawn_stdout_and_stderr_to_file) {
368   int r;
369   uv_file file;
370   uv_fs_t fs_req;
371   uv_stdio_container_t stdio[3];
372   uv_buf_t buf;
373 
374   /* Setup. */
375   unlink("stdout_file");
376 
377   init_process_options("spawn_helper6", exit_cb);
378 
379   r = uv_fs_open(NULL, &fs_req, "stdout_file", O_CREAT | O_RDWR,
380       S_IRUSR | S_IWUSR, NULL);
381   ASSERT(r != -1);
382   uv_fs_req_cleanup(&fs_req);
383 
384   file = r;
385 
386   options.stdio = stdio;
387   options.stdio[0].flags = UV_IGNORE;
388   options.stdio[1].flags = UV_INHERIT_FD;
389   options.stdio[1].data.fd = file;
390   options.stdio[2].flags = UV_INHERIT_FD;
391   options.stdio[2].data.fd = file;
392   options.stdio_count = 3;
393 
394   r = uv_spawn(uv_default_loop(), &process, &options);
395   ASSERT(r == 0);
396 
397   r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
398   ASSERT(r == 0);
399 
400   ASSERT(exit_cb_called == 1);
401   ASSERT(close_cb_called == 1);
402 
403   buf = uv_buf_init(output, sizeof(output));
404   r = uv_fs_read(NULL, &fs_req, file, &buf, 1, 0, NULL);
405   ASSERT(r == 27);
406   uv_fs_req_cleanup(&fs_req);
407 
408   r = uv_fs_close(NULL, &fs_req, file, NULL);
409   ASSERT(r == 0);
410   uv_fs_req_cleanup(&fs_req);
411 
412   printf("output is: %s", output);
413   ASSERT(strcmp("hello world\nhello errworld\n", output) == 0);
414 
415   /* Cleanup. */
416   unlink("stdout_file");
417 
418   MAKE_VALGRIND_HAPPY();
419   return 0;
420 }
421 
422 
TEST_IMPL(spawn_stdout_and_stderr_to_file2)423 TEST_IMPL(spawn_stdout_and_stderr_to_file2) {
424 #ifndef _WIN32
425   int r;
426   uv_file file;
427   uv_fs_t fs_req;
428   uv_stdio_container_t stdio[3];
429   uv_buf_t buf;
430 
431   /* Setup. */
432   unlink("stdout_file");
433 
434   init_process_options("spawn_helper6", exit_cb);
435 
436   /* Replace stderr with our file */
437   r = uv_fs_open(NULL,
438                  &fs_req,
439                  "stdout_file",
440                  O_CREAT | O_RDWR,
441                  S_IRUSR | S_IWUSR,
442                  NULL);
443   ASSERT(r != -1);
444   uv_fs_req_cleanup(&fs_req);
445   file = dup2(r, STDERR_FILENO);
446   ASSERT(file != -1);
447 
448   options.stdio = stdio;
449   options.stdio[0].flags = UV_IGNORE;
450   options.stdio[1].flags = UV_INHERIT_FD;
451   options.stdio[1].data.fd = file;
452   options.stdio[2].flags = UV_INHERIT_FD;
453   options.stdio[2].data.fd = file;
454   options.stdio_count = 3;
455 
456   r = uv_spawn(uv_default_loop(), &process, &options);
457   ASSERT(r == 0);
458 
459   r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
460   ASSERT(r == 0);
461 
462   ASSERT(exit_cb_called == 1);
463   ASSERT(close_cb_called == 1);
464 
465   buf = uv_buf_init(output, sizeof(output));
466   r = uv_fs_read(NULL, &fs_req, file, &buf, 1, 0, NULL);
467   ASSERT(r == 27);
468   uv_fs_req_cleanup(&fs_req);
469 
470   r = uv_fs_close(NULL, &fs_req, file, NULL);
471   ASSERT(r == 0);
472   uv_fs_req_cleanup(&fs_req);
473 
474   printf("output is: %s", output);
475   ASSERT(strcmp("hello world\nhello errworld\n", output) == 0);
476 
477   /* Cleanup. */
478   unlink("stdout_file");
479 
480   MAKE_VALGRIND_HAPPY();
481   return 0;
482 #else
483   RETURN_SKIP("Unix only test");
484 #endif
485 }
486 
487 
TEST_IMPL(spawn_stdout_and_stderr_to_file_swap)488 TEST_IMPL(spawn_stdout_and_stderr_to_file_swap) {
489 #ifndef _WIN32
490   int r;
491   uv_file stdout_file;
492   uv_file stderr_file;
493   uv_fs_t fs_req;
494   uv_stdio_container_t stdio[3];
495   uv_buf_t buf;
496 
497   /* Setup. */
498   unlink("stdout_file");
499   unlink("stderr_file");
500 
501   init_process_options("spawn_helper6", exit_cb);
502 
503   /* open 'stdout_file' and replace STDOUT_FILENO with it */
504   r = uv_fs_open(NULL,
505                  &fs_req,
506                  "stdout_file",
507                  O_CREAT | O_RDWR,
508                  S_IRUSR | S_IWUSR,
509                  NULL);
510   ASSERT(r != -1);
511   uv_fs_req_cleanup(&fs_req);
512   stdout_file = dup2(r, STDOUT_FILENO);
513   ASSERT(stdout_file != -1);
514 
515   /* open 'stderr_file' and replace STDERR_FILENO with it */
516   r = uv_fs_open(NULL, &fs_req, "stderr_file", O_CREAT | O_RDWR,
517       S_IRUSR | S_IWUSR, NULL);
518   ASSERT(r != -1);
519   uv_fs_req_cleanup(&fs_req);
520   stderr_file = dup2(r, STDERR_FILENO);
521   ASSERT(stderr_file != -1);
522 
523   /* now we're going to swap them: the child process' stdout will be our
524    * stderr_file and vice versa */
525   options.stdio = stdio;
526   options.stdio[0].flags = UV_IGNORE;
527   options.stdio[1].flags = UV_INHERIT_FD;
528   options.stdio[1].data.fd = stderr_file;
529   options.stdio[2].flags = UV_INHERIT_FD;
530   options.stdio[2].data.fd = stdout_file;
531   options.stdio_count = 3;
532 
533   r = uv_spawn(uv_default_loop(), &process, &options);
534   ASSERT(r == 0);
535 
536   r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
537   ASSERT(r == 0);
538 
539   ASSERT(exit_cb_called == 1);
540   ASSERT(close_cb_called == 1);
541 
542   buf = uv_buf_init(output, sizeof(output));
543 
544   /* check the content of stdout_file */
545   r = uv_fs_read(NULL, &fs_req, stdout_file, &buf, 1, 0, NULL);
546   ASSERT(r >= 15);
547   uv_fs_req_cleanup(&fs_req);
548 
549   r = uv_fs_close(NULL, &fs_req, stdout_file, NULL);
550   ASSERT(r == 0);
551   uv_fs_req_cleanup(&fs_req);
552 
553   printf("output is: %s", output);
554   ASSERT(strncmp("hello errworld\n", output, 15) == 0);
555 
556   /* check the content of stderr_file */
557   r = uv_fs_read(NULL, &fs_req, stderr_file, &buf, 1, 0, NULL);
558   ASSERT(r >= 12);
559   uv_fs_req_cleanup(&fs_req);
560 
561   r = uv_fs_close(NULL, &fs_req, stderr_file, NULL);
562   ASSERT(r == 0);
563   uv_fs_req_cleanup(&fs_req);
564 
565   printf("output is: %s", output);
566   ASSERT(strncmp("hello world\n", output, 12) == 0);
567 
568   /* Cleanup. */
569   unlink("stdout_file");
570   unlink("stderr_file");
571 
572   MAKE_VALGRIND_HAPPY();
573   return 0;
574 #else
575   RETURN_SKIP("Unix only test");
576 #endif
577 }
578 
579 
TEST_IMPL(spawn_stdin)580 TEST_IMPL(spawn_stdin) {
581   int r;
582   uv_pipe_t out;
583   uv_pipe_t in;
584   uv_write_t write_req;
585   uv_buf_t buf;
586   uv_stdio_container_t stdio[2];
587   char buffer[] = "hello-from-spawn_stdin";
588 
589   init_process_options("spawn_helper3", exit_cb);
590 
591   uv_pipe_init(uv_default_loop(), &out, 0);
592   uv_pipe_init(uv_default_loop(), &in, 0);
593   options.stdio = stdio;
594   options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE;
595   options.stdio[0].data.stream = (uv_stream_t*) &in;
596   options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
597   options.stdio[1].data.stream = (uv_stream_t*) &out;
598   options.stdio_count = 2;
599 
600   r = uv_spawn(uv_default_loop(), &process, &options);
601   ASSERT(r == 0);
602 
603   buf.base = buffer;
604   buf.len = sizeof(buffer);
605   r = uv_write(&write_req, (uv_stream_t*) &in, &buf, 1, write_cb);
606   ASSERT(r == 0);
607 
608   r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read);
609   ASSERT(r == 0);
610 
611   r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
612   ASSERT(r == 0);
613 
614   ASSERT(exit_cb_called == 1);
615   ASSERT(close_cb_called == 3); /* Once for process twice for the pipe. */
616   ASSERT(strcmp(buffer, output) == 0);
617 
618   MAKE_VALGRIND_HAPPY();
619   return 0;
620 }
621 
622 
TEST_IMPL(spawn_stdio_greater_than_3)623 TEST_IMPL(spawn_stdio_greater_than_3) {
624   int r;
625   uv_pipe_t pipe;
626   uv_stdio_container_t stdio[4];
627 
628   init_process_options("spawn_helper5", exit_cb);
629 
630   uv_pipe_init(uv_default_loop(), &pipe, 0);
631   options.stdio = stdio;
632   options.stdio[0].flags = UV_IGNORE;
633   options.stdio[1].flags = UV_IGNORE;
634   options.stdio[2].flags = UV_IGNORE;
635   options.stdio[3].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
636   options.stdio[3].data.stream = (uv_stream_t*) &pipe;
637   options.stdio_count = 4;
638 
639   r = uv_spawn(uv_default_loop(), &process, &options);
640   ASSERT(r == 0);
641 
642   r = uv_read_start((uv_stream_t*) &pipe, on_alloc, on_read);
643   ASSERT(r == 0);
644 
645   r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
646   ASSERT(r == 0);
647 
648   ASSERT(exit_cb_called == 1);
649   ASSERT(close_cb_called == 2); /* Once for process once for the pipe. */
650   printf("output from stdio[3] is: %s", output);
651   ASSERT(strcmp("fourth stdio!\n", output) == 0);
652 
653   MAKE_VALGRIND_HAPPY();
654   return 0;
655 }
656 
657 
spawn_tcp_server_helper(void)658 int spawn_tcp_server_helper(void) {
659   uv_tcp_t tcp;
660   uv_os_sock_t handle;
661   int r;
662 
663   r = uv_tcp_init(uv_default_loop(), &tcp);
664   ASSERT(r == 0);
665 
666 #ifdef _WIN32
667   handle = _get_osfhandle(3);
668 #else
669   handle = 3;
670 #endif
671   r = uv_tcp_open(&tcp, handle);
672   ASSERT(r == 0);
673 
674   /* Make sure that we can listen on a socket that was
675    * passed down from the parent process
676    */
677   r = uv_listen((uv_stream_t*) &tcp, SOMAXCONN, NULL);
678   ASSERT(r == 0);
679 
680   return 1;
681 }
682 
683 
TEST_IMPL(spawn_tcp_server)684 TEST_IMPL(spawn_tcp_server) {
685   uv_stdio_container_t stdio[4];
686   struct sockaddr_in addr;
687   int fd;
688   int r;
689 #ifdef _WIN32
690   uv_os_fd_t handle;
691 #endif
692 
693   init_process_options("spawn_tcp_server_helper", exit_cb);
694 
695   ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
696 
697   fd = -1;
698   r = uv_tcp_init_ex(uv_default_loop(), &tcp_server, AF_INET);
699   ASSERT(r == 0);
700   r = uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr, 0);
701   ASSERT(r == 0);
702 #ifdef _WIN32
703   r = uv_fileno((uv_handle_t*) &tcp_server, &handle);
704   fd = _open_osfhandle((intptr_t) handle, 0);
705 #else
706   r = uv_fileno((uv_handle_t*) &tcp_server, &fd);
707  #endif
708   ASSERT(r == 0);
709   ASSERT(fd > 0);
710 
711   options.stdio = stdio;
712   options.stdio[0].flags = UV_INHERIT_FD;
713   options.stdio[0].data.fd = 0;
714   options.stdio[1].flags = UV_INHERIT_FD;
715   options.stdio[1].data.fd = 1;
716   options.stdio[2].flags = UV_INHERIT_FD;
717   options.stdio[2].data.fd = 2;
718   options.stdio[3].flags = UV_INHERIT_FD;
719   options.stdio[3].data.fd = fd;
720   options.stdio_count = 4;
721 
722   r = uv_spawn(uv_default_loop(), &process, &options);
723   ASSERT(r == 0);
724 
725   r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
726   ASSERT(r == 0);
727 
728   ASSERT(exit_cb_called == 1);
729   ASSERT(close_cb_called == 1);
730 
731   MAKE_VALGRIND_HAPPY();
732   return 0;
733 }
734 
735 
TEST_IMPL(spawn_ignored_stdio)736 TEST_IMPL(spawn_ignored_stdio) {
737   int r;
738 
739   init_process_options("spawn_helper6", exit_cb);
740 
741   options.stdio = NULL;
742   options.stdio_count = 0;
743 
744   r = uv_spawn(uv_default_loop(), &process, &options);
745   ASSERT(r == 0);
746 
747   r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
748   ASSERT(r == 0);
749 
750   ASSERT(exit_cb_called == 1);
751   ASSERT(close_cb_called == 1);
752 
753   MAKE_VALGRIND_HAPPY();
754   return 0;
755 }
756 
757 
TEST_IMPL(spawn_and_kill)758 TEST_IMPL(spawn_and_kill) {
759   int r;
760 
761   init_process_options("spawn_helper4", kill_cb);
762 
763   r = uv_spawn(uv_default_loop(), &process, &options);
764   ASSERT(r == 0);
765 
766   r = uv_timer_init(uv_default_loop(), &timer);
767   ASSERT(r == 0);
768 
769   r = uv_timer_start(&timer, timer_cb, 500, 0);
770   ASSERT(r == 0);
771 
772   r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
773   ASSERT(r == 0);
774 
775   ASSERT(exit_cb_called == 1);
776   ASSERT(close_cb_called == 2); /* Once for process and once for timer. */
777 
778   MAKE_VALGRIND_HAPPY();
779   return 0;
780 }
781 
782 
TEST_IMPL(spawn_preserve_env)783 TEST_IMPL(spawn_preserve_env) {
784   int r;
785   uv_pipe_t out;
786   uv_stdio_container_t stdio[2];
787 
788   init_process_options("spawn_helper7", exit_cb);
789 
790   uv_pipe_init(uv_default_loop(), &out, 0);
791   options.stdio = stdio;
792   options.stdio[0].flags = UV_IGNORE;
793   options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
794   options.stdio[1].data.stream = (uv_stream_t*) &out;
795   options.stdio_count = 2;
796 
797   r = putenv("ENV_TEST=testval");
798   ASSERT(r == 0);
799 
800   /* Explicitly set options.env to NULL to test for env clobbering. */
801   options.env = NULL;
802 
803   r = uv_spawn(uv_default_loop(), &process, &options);
804   ASSERT(r == 0);
805 
806   r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read);
807   ASSERT(r == 0);
808 
809   r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
810   ASSERT(r == 0);
811 
812   ASSERT(exit_cb_called == 1);
813   ASSERT(close_cb_called == 2);
814 
815   printf("output is: %s", output);
816   ASSERT(strcmp("testval", output) == 0);
817 
818   MAKE_VALGRIND_HAPPY();
819   return 0;
820 }
821 
822 
TEST_IMPL(spawn_detached)823 TEST_IMPL(spawn_detached) {
824   int r;
825 
826   init_process_options("spawn_helper4", detach_failure_cb);
827 
828   options.flags |= UV_PROCESS_DETACHED;
829 
830   r = uv_spawn(uv_default_loop(), &process, &options);
831   ASSERT(r == 0);
832 
833   uv_unref((uv_handle_t*) &process);
834 
835   r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
836   ASSERT(r == 0);
837 
838   ASSERT(exit_cb_called == 0);
839 
840   ASSERT(process.pid == uv_process_get_pid(&process));
841 
842   r = uv_kill(process.pid, 0);
843   ASSERT(r == 0);
844 
845   r = uv_kill(process.pid, SIGTERM);
846   ASSERT(r == 0);
847 
848   MAKE_VALGRIND_HAPPY();
849   return 0;
850 }
851 
TEST_IMPL(spawn_and_kill_with_std)852 TEST_IMPL(spawn_and_kill_with_std) {
853   int r;
854   uv_pipe_t in, out, err;
855   uv_write_t write;
856   char message[] = "Nancy's joining me because the message this evening is "
857                    "not my message but ours.";
858   uv_buf_t buf;
859   uv_stdio_container_t stdio[3];
860 
861   init_process_options("spawn_helper4", kill_cb);
862 
863   r = uv_pipe_init(uv_default_loop(), &in, 0);
864   ASSERT(r == 0);
865 
866   r = uv_pipe_init(uv_default_loop(), &out, 0);
867   ASSERT(r == 0);
868 
869   r = uv_pipe_init(uv_default_loop(), &err, 0);
870   ASSERT(r == 0);
871 
872   options.stdio = stdio;
873   options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE;
874   options.stdio[0].data.stream = (uv_stream_t*) &in;
875   options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
876   options.stdio[1].data.stream = (uv_stream_t*) &out;
877   options.stdio[2].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
878   options.stdio[2].data.stream = (uv_stream_t*) &err;
879   options.stdio_count = 3;
880 
881   r = uv_spawn(uv_default_loop(), &process, &options);
882   ASSERT(r == 0);
883 
884   buf = uv_buf_init(message, sizeof message);
885   r = uv_write(&write, (uv_stream_t*) &in, &buf, 1, write_cb);
886   ASSERT(r == 0);
887 
888   r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read);
889   ASSERT(r == 0);
890 
891   r = uv_read_start((uv_stream_t*) &err, on_alloc, on_read);
892   ASSERT(r == 0);
893 
894   r = uv_timer_init(uv_default_loop(), &timer);
895   ASSERT(r == 0);
896 
897   r = uv_timer_start(&timer, timer_cb, 500, 0);
898   ASSERT(r == 0);
899 
900   r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
901   ASSERT(r == 0);
902 
903   ASSERT(exit_cb_called == 1);
904   ASSERT(close_cb_called == 5); /* process x 1, timer x 1, stdio x 3. */
905 
906   MAKE_VALGRIND_HAPPY();
907   return 0;
908 }
909 
910 
TEST_IMPL(spawn_and_ping)911 TEST_IMPL(spawn_and_ping) {
912   uv_write_t write_req;
913   uv_pipe_t in, out;
914   uv_buf_t buf;
915   uv_stdio_container_t stdio[2];
916   int r;
917 
918   init_process_options("spawn_helper3", exit_cb);
919   buf = uv_buf_init("TEST", 4);
920 
921   uv_pipe_init(uv_default_loop(), &out, 0);
922   uv_pipe_init(uv_default_loop(), &in, 0);
923   options.stdio = stdio;
924   options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE;
925   options.stdio[0].data.stream = (uv_stream_t*) &in;
926   options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
927   options.stdio[1].data.stream = (uv_stream_t*) &out;
928   options.stdio_count = 2;
929 
930   r = uv_spawn(uv_default_loop(), &process, &options);
931   ASSERT(r == 0);
932 
933   /* Sending signum == 0 should check if the
934    * child process is still alive, not kill it.
935    */
936   r = uv_process_kill(&process, 0);
937   ASSERT(r == 0);
938 
939   r = uv_write(&write_req, (uv_stream_t*) &in, &buf, 1, write_cb);
940   ASSERT(r == 0);
941 
942   r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read);
943   ASSERT(r == 0);
944 
945   ASSERT(exit_cb_called == 0);
946 
947   r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
948   ASSERT(r == 0);
949 
950   ASSERT(exit_cb_called == 1);
951   ASSERT(strcmp(output, "TEST") == 0);
952 
953   MAKE_VALGRIND_HAPPY();
954   return 0;
955 }
956 
957 
TEST_IMPL(spawn_same_stdout_stderr)958 TEST_IMPL(spawn_same_stdout_stderr) {
959   uv_write_t write_req;
960   uv_pipe_t in, out;
961   uv_buf_t buf;
962   uv_stdio_container_t stdio[3];
963   int r;
964 
965   init_process_options("spawn_helper3", exit_cb);
966   buf = uv_buf_init("TEST", 4);
967 
968   uv_pipe_init(uv_default_loop(), &out, 0);
969   uv_pipe_init(uv_default_loop(), &in, 0);
970   options.stdio = stdio;
971   options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE;
972   options.stdio[0].data.stream = (uv_stream_t*) &in;
973   options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
974   options.stdio[1].data.stream = (uv_stream_t*) &out;
975   options.stdio_count = 2;
976 
977   r = uv_spawn(uv_default_loop(), &process, &options);
978   ASSERT(r == 0);
979 
980   /* Sending signum == 0 should check if the
981    * child process is still alive, not kill it.
982    */
983   r = uv_process_kill(&process, 0);
984   ASSERT(r == 0);
985 
986   r = uv_write(&write_req, (uv_stream_t*) &in, &buf, 1, write_cb);
987   ASSERT(r == 0);
988 
989   r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read);
990   ASSERT(r == 0);
991 
992   ASSERT(exit_cb_called == 0);
993 
994   r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
995   ASSERT(r == 0);
996 
997   ASSERT(exit_cb_called == 1);
998   ASSERT(strcmp(output, "TEST") == 0);
999 
1000   MAKE_VALGRIND_HAPPY();
1001   return 0;
1002 }
1003 
1004 
TEST_IMPL(spawn_closed_process_io)1005 TEST_IMPL(spawn_closed_process_io) {
1006   uv_pipe_t in;
1007   uv_write_t write_req;
1008   uv_buf_t buf;
1009   uv_stdio_container_t stdio[2];
1010   static char buffer[] = "hello-from-spawn_stdin\n";
1011 
1012   init_process_options("spawn_helper3", exit_cb);
1013 
1014   uv_pipe_init(uv_default_loop(), &in, 0);
1015   options.stdio = stdio;
1016   options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE;
1017   options.stdio[0].data.stream = (uv_stream_t*) &in;
1018   options.stdio_count = 1;
1019 
1020   close(0); /* Close process stdin. */
1021 
1022   ASSERT(0 == uv_spawn(uv_default_loop(), &process, &options));
1023 
1024   buf = uv_buf_init(buffer, sizeof(buffer));
1025   ASSERT(0 == uv_write(&write_req, (uv_stream_t*) &in, &buf, 1, write_cb));
1026 
1027   ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
1028 
1029   ASSERT(exit_cb_called == 1);
1030   ASSERT(close_cb_called == 2); /* process, child stdin */
1031 
1032   MAKE_VALGRIND_HAPPY();
1033   return 0;
1034 }
1035 
1036 
TEST_IMPL(kill)1037 TEST_IMPL(kill) {
1038   int r;
1039 
1040 #ifdef _WIN32
1041   no_term_signal = 1;
1042 #endif
1043 
1044   init_process_options("spawn_helper4", kill_cb);
1045 
1046   /* Verify that uv_spawn() resets the signal disposition. */
1047 #ifndef _WIN32
1048   {
1049     sigset_t set;
1050     sigemptyset(&set);
1051     sigaddset(&set, SIGTERM);
1052     ASSERT(0 == pthread_sigmask(SIG_BLOCK, &set, NULL));
1053   }
1054   ASSERT(SIG_ERR != signal(SIGTERM, SIG_IGN));
1055 #endif
1056 
1057   r = uv_spawn(uv_default_loop(), &process, &options);
1058   ASSERT(r == 0);
1059 
1060 #ifndef _WIN32
1061   {
1062     sigset_t set;
1063     sigemptyset(&set);
1064     sigaddset(&set, SIGTERM);
1065     ASSERT(0 == pthread_sigmask(SIG_UNBLOCK, &set, NULL));
1066   }
1067   ASSERT(SIG_ERR != signal(SIGTERM, SIG_DFL));
1068 #endif
1069 
1070   /* Sending signum == 0 should check if the
1071    * child process is still alive, not kill it.
1072    */
1073   r = uv_kill(process.pid, 0);
1074   ASSERT(r == 0);
1075 
1076   /* Kill the process. */
1077   r = uv_kill(process.pid, SIGTERM);
1078   ASSERT(r == 0);
1079 
1080   r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
1081   ASSERT(r == 0);
1082 
1083   ASSERT(exit_cb_called == 1);
1084   ASSERT(close_cb_called == 1);
1085 
1086   MAKE_VALGRIND_HAPPY();
1087   return 0;
1088 }
1089 
1090 
1091 #ifdef _WIN32
TEST_IMPL(spawn_detect_pipe_name_collisions_on_windows)1092 TEST_IMPL(spawn_detect_pipe_name_collisions_on_windows) {
1093   int r;
1094   uv_pipe_t out;
1095   char name[64];
1096   HANDLE pipe_handle;
1097   uv_stdio_container_t stdio[2];
1098 
1099   init_process_options("spawn_helper2", exit_cb);
1100 
1101   uv_pipe_init(uv_default_loop(), &out, 0);
1102   options.stdio = stdio;
1103   options.stdio[0].flags = UV_IGNORE;
1104   options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
1105   options.stdio[1].data.stream = (uv_stream_t*) &out;
1106   options.stdio_count = 2;
1107 
1108   /* Create a pipe that'll cause a collision. */
1109   snprintf(name,
1110            sizeof(name),
1111            "\\\\.\\pipe\\uv\\%p-%d",
1112            &out,
1113            GetCurrentProcessId());
1114   pipe_handle = CreateNamedPipeA(name,
1115                                 PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
1116                                 PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
1117                                 10,
1118                                 65536,
1119                                 65536,
1120                                 0,
1121                                 NULL);
1122   ASSERT(pipe_handle != INVALID_HANDLE_VALUE);
1123 
1124   r = uv_spawn(uv_default_loop(), &process, &options);
1125   ASSERT(r == 0);
1126 
1127   r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read);
1128   ASSERT(r == 0);
1129 
1130   r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
1131   ASSERT(r == 0);
1132 
1133   ASSERT(exit_cb_called == 1);
1134   ASSERT(close_cb_called == 2); /* Once for process once for the pipe. */
1135   printf("output is: %s", output);
1136   ASSERT(strcmp("hello world\n", output) == 0);
1137 
1138   MAKE_VALGRIND_HAPPY();
1139   return 0;
1140 }
1141 
1142 
1143 #if !defined(USING_UV_SHARED)
1144 int make_program_args(char** args, int verbatim_arguments, WCHAR** dst_ptr);
1145 WCHAR* quote_cmd_arg(const WCHAR *source, WCHAR *target);
1146 
TEST_IMPL(argument_escaping)1147 TEST_IMPL(argument_escaping) {
1148   const WCHAR* test_str[] = {
1149     L"",
1150     L"HelloWorld",
1151     L"Hello World",
1152     L"Hello\"World",
1153     L"Hello World\\",
1154     L"Hello\\\"World",
1155     L"Hello\\World",
1156     L"Hello\\\\World",
1157     L"Hello World\\",
1158     L"c:\\path\\to\\node.exe --eval \"require('c:\\\\path\\\\to\\\\test.js')\""
1159   };
1160   const int count = sizeof(test_str) / sizeof(*test_str);
1161   WCHAR** test_output;
1162   WCHAR* command_line;
1163   WCHAR** cracked;
1164   size_t total_size = 0;
1165   int i;
1166   int num_args;
1167   int result;
1168 
1169   char* verbatim[] = {
1170     "cmd.exe",
1171     "/c",
1172     "c:\\path\\to\\node.exe --eval \"require('c:\\\\path\\\\to\\\\test.js')\"",
1173     NULL
1174   };
1175   WCHAR* verbatim_output;
1176   WCHAR* non_verbatim_output;
1177 
1178   test_output = calloc(count, sizeof(WCHAR*));
1179   ASSERT_NOT_NULL(test_output);
1180   for (i = 0; i < count; ++i) {
1181     test_output[i] = calloc(2 * (wcslen(test_str[i]) + 2), sizeof(WCHAR));
1182     quote_cmd_arg(test_str[i], test_output[i]);
1183     wprintf(L"input : %s\n", test_str[i]);
1184     wprintf(L"output: %s\n", test_output[i]);
1185     total_size += wcslen(test_output[i]) + 1;
1186   }
1187   command_line = calloc(total_size + 1, sizeof(WCHAR));
1188   ASSERT_NOT_NULL(command_line);
1189   for (i = 0; i < count; ++i) {
1190     wcscat(command_line, test_output[i]);
1191     wcscat(command_line, L" ");
1192   }
1193   command_line[total_size - 1] = L'\0';
1194 
1195   wprintf(L"command_line: %s\n", command_line);
1196 
1197   cracked = CommandLineToArgvW(command_line, &num_args);
1198   for (i = 0; i < num_args; ++i) {
1199     wprintf(L"%d: %s\t%s\n", i, test_str[i], cracked[i]);
1200     ASSERT(wcscmp(test_str[i], cracked[i]) == 0);
1201   }
1202 
1203   LocalFree(cracked);
1204   for (i = 0; i < count; ++i) {
1205     free(test_output[i]);
1206   }
1207   free(test_output);
1208 
1209   result = make_program_args(verbatim, 1, &verbatim_output);
1210   ASSERT(result == 0);
1211   result = make_program_args(verbatim, 0, &non_verbatim_output);
1212   ASSERT(result == 0);
1213 
1214   wprintf(L"    verbatim_output: %s\n", verbatim_output);
1215   wprintf(L"non_verbatim_output: %s\n", non_verbatim_output);
1216 
1217   ASSERT(wcscmp(verbatim_output,
1218                 L"cmd.exe /c c:\\path\\to\\node.exe --eval "
1219                 L"\"require('c:\\\\path\\\\to\\\\test.js')\"") == 0);
1220   ASSERT(wcscmp(non_verbatim_output,
1221                 L"cmd.exe /c \"c:\\path\\to\\node.exe --eval "
1222                 L"\\\"require('c:\\\\path\\\\to\\\\test.js')\\\"\"") == 0);
1223 
1224   free(verbatim_output);
1225   free(non_verbatim_output);
1226 
1227   return 0;
1228 }
1229 
1230 int make_program_env(char** env_block, WCHAR** dst_ptr);
1231 
TEST_IMPL(environment_creation)1232 TEST_IMPL(environment_creation) {
1233   size_t i;
1234   char* environment[] = {
1235     "FOO=BAR",
1236     "SYSTEM=ROOT", /* substring of a supplied var name */
1237     "SYSTEMROOTED=OMG", /* supplied var name is a substring */
1238     "TEMP=C:\\Temp",
1239     "INVALID",
1240     "BAZ=QUX",
1241     "B_Z=QUX",
1242     "B\xe2\x82\xacZ=QUX",
1243     "B\xf0\x90\x80\x82Z=QUX",
1244     "B\xef\xbd\xa1Z=QUX",
1245     "B\xf0\xa3\x91\x96Z=QUX",
1246     "BAZ", /* repeat, invalid variable */
1247     NULL
1248   };
1249   WCHAR* wenvironment[] = {
1250     L"BAZ=QUX",
1251     L"B_Z=QUX",
1252     L"B\x20acZ=QUX",
1253     L"B\xd800\xdc02Z=QUX",
1254     L"B\xd84d\xdc56Z=QUX",
1255     L"B\xff61Z=QUX",
1256     L"FOO=BAR",
1257     L"SYSTEM=ROOT", /* substring of a supplied var name */
1258     L"SYSTEMROOTED=OMG", /* supplied var name is a substring */
1259     L"TEMP=C:\\Temp",
1260   };
1261   WCHAR* from_env[] = {
1262     /* list should be kept in sync with list
1263      * in process.c, minus variables in wenvironment */
1264     L"HOMEDRIVE",
1265     L"HOMEPATH",
1266     L"LOGONSERVER",
1267     L"PATH",
1268     L"USERDOMAIN",
1269     L"USERNAME",
1270     L"USERPROFILE",
1271     L"SYSTEMDRIVE",
1272     L"SYSTEMROOT",
1273     L"WINDIR",
1274     /* test for behavior in the absence of a
1275      * required-environment variable: */
1276     L"ZTHIS_ENV_VARIABLE_DOES_NOT_EXIST",
1277   };
1278   int found_in_loc_env[ARRAY_SIZE(wenvironment)] = {0};
1279   int found_in_usr_env[ARRAY_SIZE(from_env)] = {0};
1280   WCHAR *expected[ARRAY_SIZE(from_env)];
1281   int result;
1282   WCHAR* str;
1283   WCHAR* prev;
1284   WCHAR* env;
1285 
1286   for (i = 0; i < ARRAY_SIZE(from_env); i++) {
1287       /* copy expected additions to environment locally */
1288       size_t len = GetEnvironmentVariableW(from_env[i], NULL, 0);
1289       if (len == 0) {
1290         found_in_usr_env[i] = 1;
1291         str = malloc(1 * sizeof(WCHAR));
1292         *str = 0;
1293         expected[i] = str;
1294       } else {
1295         size_t name_len = wcslen(from_env[i]);
1296         str = malloc((name_len+1+len) * sizeof(WCHAR));
1297         wmemcpy(str, from_env[i], name_len);
1298         expected[i] = str;
1299         str += name_len;
1300         *str++ = L'=';
1301         GetEnvironmentVariableW(from_env[i], str, len);
1302      }
1303   }
1304 
1305   result = make_program_env(environment, &env);
1306   ASSERT(result == 0);
1307 
1308   for (str = env, prev = NULL; *str; prev = str, str += wcslen(str) + 1) {
1309     int found = 0;
1310 #if 0
1311     _cputws(str);
1312     putchar('\n');
1313 #endif
1314     for (i = 0; i < ARRAY_SIZE(wenvironment) && !found; i++) {
1315       if (!wcscmp(str, wenvironment[i])) {
1316         ASSERT(!found_in_loc_env[i]);
1317         found_in_loc_env[i] = 1;
1318         found = 1;
1319       }
1320     }
1321     for (i = 0; i < ARRAY_SIZE(expected) && !found; i++) {
1322       if (!wcscmp(str, expected[i])) {
1323         ASSERT(!found_in_usr_env[i]);
1324         found_in_usr_env[i] = 1;
1325         found = 1;
1326       }
1327     }
1328     if (prev) { /* verify sort order */
1329 #if !defined(__MINGW32__) || defined(__MINGW64_VERSION_MAJOR)
1330       ASSERT(CompareStringOrdinal(prev, -1, str, -1, TRUE) == 1);
1331 #endif
1332     }
1333     ASSERT(found); /* verify that we expected this variable */
1334   }
1335 
1336   /* verify that we found all expected variables */
1337   for (i = 0; i < ARRAY_SIZE(wenvironment); i++) {
1338     ASSERT(found_in_loc_env[i]);
1339   }
1340   for (i = 0; i < ARRAY_SIZE(expected); i++) {
1341     ASSERT(found_in_usr_env[i]);
1342   }
1343 
1344   return 0;
1345 }
1346 #endif
1347 
1348 /* Regression test for issue #909 */
TEST_IMPL(spawn_with_an_odd_path)1349 TEST_IMPL(spawn_with_an_odd_path) {
1350   int r;
1351 
1352   char newpath[2048];
1353   char *path = getenv("PATH");
1354   ASSERT_NOT_NULL(path);
1355   snprintf(newpath, 2048, ";.;%s", path);
1356   SetEnvironmentVariable("PATH", newpath);
1357 
1358   init_process_options("", exit_cb);
1359   options.file = options.args[0] = "program-that-had-better-not-exist";
1360   r = uv_spawn(uv_default_loop(), &process, &options);
1361   ASSERT(r == UV_ENOENT || r == UV_EACCES);
1362   ASSERT(0 == uv_is_active((uv_handle_t*) &process));
1363   uv_close((uv_handle_t*) &process, NULL);
1364   ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
1365 
1366   MAKE_VALGRIND_HAPPY();
1367   return 0;
1368 }
1369 #endif
1370 
1371 
1372 #ifndef _WIN32
TEST_IMPL(spawn_setuid_fails)1373 TEST_IMPL(spawn_setuid_fails) {
1374   int r;
1375   init_process_options("spawn_helper1", fail_cb);
1376 
1377   options.flags |= UV_PROCESS_SETUID;
1378   /* On IBMi PASE, there is no root user. User may grant
1379    * root-like privileges, including setting uid to 0.
1380    */
1381 #if defined(__PASE__)
1382   options.uid = -1;
1383 #else
1384   options.uid = 0;
1385 #endif
1386 
1387   /* These flags should be ignored on Unices. */
1388   options.flags |= UV_PROCESS_WINDOWS_HIDE;
1389   options.flags |= UV_PROCESS_WINDOWS_HIDE_CONSOLE;
1390   options.flags |= UV_PROCESS_WINDOWS_HIDE_GUI;
1391   options.flags |= UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS;
1392 
1393   r = uv_spawn(uv_default_loop(), &process, &options);
1394 #if defined(__CYGWIN__)
1395   ASSERT(r == UV_EINVAL);
1396 #endif
1397 
1398   r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
1399   ASSERT(r == 0);
1400 
1401   ASSERT(close_cb_called == 0);
1402 
1403   MAKE_VALGRIND_HAPPY();
1404   return 0;
1405 }
1406 
1407 
TEST_IMPL(spawn_setgid_fails)1408 TEST_IMPL(spawn_setgid_fails) {
1409   int r;
1410   init_process_options("spawn_helper1", fail_cb);
1411 
1412   options.flags |= UV_PROCESS_SETGID;
1413   /* On IBMi PASE, there is no root user. User may grant
1414    * root-like privileges, including setting gid to 0.
1415    */
1416 #if defined(__MVS__) || defined(__PASE__)
1417   options.gid = -1;
1418 #else
1419   options.gid = 0;
1420 #endif
1421 
1422   r = uv_spawn(uv_default_loop(), &process, &options);
1423 #if defined(__CYGWIN__) || defined(__MVS__)
1424   ASSERT(r == UV_EINVAL);
1425 #endif
1426 
1427   r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
1428   ASSERT(r == 0);
1429 
1430   ASSERT(close_cb_called == 0);
1431 
1432   MAKE_VALGRIND_HAPPY();
1433   return 0;
1434 }
1435 #endif
1436 
1437 
1438 #ifdef _WIN32
1439 
exit_cb_unexpected(uv_process_t * process,int64_t exit_status,int term_signal)1440 static void exit_cb_unexpected(uv_process_t* process,
1441                                int64_t exit_status,
1442                                int term_signal) {
1443   ASSERT(0 && "should not have been called");
1444 }
1445 
1446 
TEST_IMPL(spawn_setuid_fails)1447 TEST_IMPL(spawn_setuid_fails) {
1448   int r;
1449 
1450   init_process_options("spawn_helper1", exit_cb_unexpected);
1451 
1452   options.flags |= UV_PROCESS_SETUID;
1453   options.uid = (uv_uid_t) -42424242;
1454 
1455   r = uv_spawn(uv_default_loop(), &process, &options);
1456   ASSERT(r == UV_ENOTSUP);
1457 
1458   r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
1459   ASSERT(r == 0);
1460 
1461   ASSERT(close_cb_called == 0);
1462 
1463   MAKE_VALGRIND_HAPPY();
1464   return 0;
1465 }
1466 
1467 
TEST_IMPL(spawn_setgid_fails)1468 TEST_IMPL(spawn_setgid_fails) {
1469   int r;
1470 
1471   init_process_options("spawn_helper1", exit_cb_unexpected);
1472 
1473   options.flags |= UV_PROCESS_SETGID;
1474   options.gid = (uv_gid_t) -42424242;
1475 
1476   r = uv_spawn(uv_default_loop(), &process, &options);
1477   ASSERT(r == UV_ENOTSUP);
1478 
1479   r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
1480   ASSERT(r == 0);
1481 
1482   ASSERT(close_cb_called == 0);
1483 
1484   MAKE_VALGRIND_HAPPY();
1485   return 0;
1486 }
1487 #endif
1488 
1489 
TEST_IMPL(spawn_auto_unref)1490 TEST_IMPL(spawn_auto_unref) {
1491   init_process_options("spawn_helper1", NULL);
1492   ASSERT(0 == uv_spawn(uv_default_loop(), &process, &options));
1493   ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
1494   ASSERT(0 == uv_is_closing((uv_handle_t*) &process));
1495   uv_close((uv_handle_t*) &process, NULL);
1496   ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
1497   ASSERT(1 == uv_is_closing((uv_handle_t*) &process));
1498   MAKE_VALGRIND_HAPPY();
1499   return 0;
1500 }
1501 
1502 
TEST_IMPL(spawn_fs_open)1503 TEST_IMPL(spawn_fs_open) {
1504   int r;
1505   uv_os_fd_t fd;
1506   uv_os_fd_t dup_fd;
1507   uv_fs_t fs_req;
1508   uv_pipe_t in;
1509   uv_write_t write_req;
1510   uv_write_t write_req2;
1511   uv_buf_t buf;
1512   uv_stdio_container_t stdio[1];
1513 #ifdef _WIN32
1514   const char dev_null[] = "NUL";
1515   HMODULE kernelbase_module;
1516   sCompareObjectHandles pCompareObjectHandles; /* function introduced in Windows 10 */
1517 #else
1518   const char dev_null[] = "/dev/null";
1519 #endif
1520 
1521   r = uv_fs_open(NULL, &fs_req, dev_null, O_RDWR, 0, NULL);
1522   ASSERT(r != -1);
1523   fd = uv_get_osfhandle((uv_file) fs_req.result);
1524   uv_fs_req_cleanup(&fs_req);
1525 
1526   init_process_options("spawn_helper8", exit_cb);
1527 
1528   ASSERT(0 == uv_pipe_init(uv_default_loop(), &in, 0));
1529 
1530   options.stdio = stdio;
1531   options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE;
1532   options.stdio[0].data.stream = (uv_stream_t*) &in;
1533   options.stdio_count = 1;
1534 
1535   /* make an inheritable copy */
1536 #ifdef _WIN32
1537   ASSERT(0 != DuplicateHandle(GetCurrentProcess(), fd, GetCurrentProcess(), &dup_fd,
1538                               0, /* inherit */ TRUE, DUPLICATE_SAME_ACCESS));
1539   kernelbase_module = GetModuleHandleA("kernelbase.dll");
1540   pCompareObjectHandles = (sCompareObjectHandles)
1541       GetProcAddress(kernelbase_module, "CompareObjectHandles");
1542   ASSERT(pCompareObjectHandles == NULL || pCompareObjectHandles(fd, dup_fd));
1543 #else
1544   dup_fd = dup(fd);
1545 #endif
1546 
1547   ASSERT(0 == uv_spawn(uv_default_loop(), &process, &options));
1548 
1549   buf = uv_buf_init((char*) &fd, sizeof(fd));
1550   ASSERT(0 == uv_write(&write_req, (uv_stream_t*) &in, &buf, 1, write_null_cb));
1551 
1552   buf = uv_buf_init((char*) &dup_fd, sizeof(fd));
1553   ASSERT(0 == uv_write(&write_req2, (uv_stream_t*) &in, &buf, 1, write_cb));
1554 
1555   ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
1556   ASSERT(0 == uv_fs_close(NULL, &fs_req, r, NULL));
1557 
1558   ASSERT(exit_cb_called == 1);
1559   ASSERT(close_cb_called == 2);  /* One for `in`, one for process */
1560 
1561   MAKE_VALGRIND_HAPPY();
1562   return 0;
1563 }
1564 
1565 
TEST_IMPL(closed_fd_events)1566 TEST_IMPL(closed_fd_events) {
1567   uv_stdio_container_t stdio[3];
1568   uv_pipe_t pipe_handle;
1569   uv_fs_t req;
1570   uv_buf_t bufs[1];
1571   uv_file fd[2];
1572   bufs[0] = uv_buf_init("", 1);
1573 
1574   /* create a pipe and share it with a child process */
1575   ASSERT(0 == uv_pipe(fd, 0, 0));
1576   ASSERT(fd[0] > 2);
1577   ASSERT(fd[1] > 2);
1578 
1579   /* spawn_helper4 blocks indefinitely. */
1580   init_process_options("spawn_helper4", exit_cb);
1581   options.stdio_count = 3;
1582   options.stdio = stdio;
1583   options.stdio[0].flags = UV_INHERIT_FD;
1584   options.stdio[0].data.fd = fd[0];
1585   options.stdio[1].flags = UV_IGNORE;
1586   options.stdio[2].flags = UV_IGNORE;
1587 
1588   ASSERT(0 == uv_spawn(uv_default_loop(), &process, &options));
1589   uv_unref((uv_handle_t*) &process);
1590 
1591   /* read from the pipe with uv */
1592   ASSERT(0 == uv_pipe_init(uv_default_loop(), &pipe_handle, 0));
1593   ASSERT(0 == uv_pipe_open(&pipe_handle, fd[0]));
1594   /* uv_pipe_open() takes ownership of the file descriptor. */
1595   fd[0] = -1;
1596 
1597   ASSERT(0 == uv_read_start((uv_stream_t*) &pipe_handle, on_alloc, on_read_once));
1598 
1599   ASSERT(1 == uv_fs_write(NULL, &req, fd[1], bufs, 1, -1, NULL));
1600   ASSERT(req.result == 1);
1601   uv_fs_req_cleanup(&req);
1602 
1603 #ifdef _WIN32
1604   ASSERT(1 == uv_run(uv_default_loop(), UV_RUN_ONCE));
1605 #endif
1606   ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE));
1607 
1608   /* should have received just one byte */
1609   ASSERT(output_used == 1);
1610 
1611   /* close the pipe and see if we still get events */
1612   uv_close((uv_handle_t*) &pipe_handle, close_cb);
1613 
1614   ASSERT(1 == uv_fs_write(NULL, &req, fd[1], bufs, 1, -1, NULL));
1615   ASSERT(req.result == 1);
1616   uv_fs_req_cleanup(&req);
1617 
1618   ASSERT(0 == uv_timer_init(uv_default_loop(), &timer));
1619   ASSERT(0 == uv_timer_start(&timer, timer_counter_cb, 10, 0));
1620 
1621   /* see if any spurious events interrupt the timer */
1622   if (1 == uv_run(uv_default_loop(), UV_RUN_ONCE))
1623     /* have to run again to really trigger the timer */
1624     ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE));
1625 
1626   ASSERT(timer_counter == 1);
1627 
1628   /* cleanup */
1629   ASSERT(0 == uv_process_kill(&process, SIGTERM));
1630 #ifdef _WIN32
1631   ASSERT(0 == _close(fd[1]));
1632 #else
1633   ASSERT(0 == close(fd[1]));
1634 #endif
1635 
1636   MAKE_VALGRIND_HAPPY();
1637   return 0;
1638 }
1639 
1640 
TEST_IMPL(spawn_reads_child_path)1641 TEST_IMPL(spawn_reads_child_path) {
1642   int r;
1643   int len;
1644   char file[64];
1645   char path[1024];
1646   char* env[3];
1647 
1648   /* Need to carry over the dynamic linker path when the test runner is
1649    * linked against libuv.so, see https://github.com/libuv/libuv/issues/85.
1650    */
1651 #if defined(__APPLE__)
1652   static const char dyld_path_var[] = "DYLD_LIBRARY_PATH";
1653 #elif defined(__MVS__) || defined(__PASE__)
1654   static const char dyld_path_var[] = "LIBPATH";
1655 #else
1656   static const char dyld_path_var[] = "LD_LIBRARY_PATH";
1657 #endif
1658 
1659   /* Set up the process, but make sure that the file to run is relative and
1660    * requires a lookup into PATH. */
1661   init_process_options("spawn_helper1", exit_cb);
1662 
1663   /* Set up the PATH env variable */
1664   for (len = strlen(exepath);
1665        exepath[len - 1] != '/' && exepath[len - 1] != '\\';
1666        len--);
1667   strcpy(file, exepath + len);
1668   exepath[len] = 0;
1669   strcpy(path, "PATH=");
1670   strcpy(path + 5, exepath);
1671 #if defined(__CYGWIN__) || defined(__MSYS__)
1672   /* Carry over the dynamic linker path in case the test runner
1673      is linked against cyguv-1.dll or msys-uv-1.dll, see above.  */
1674   {
1675     char* syspath = getenv("PATH");
1676     if (syspath != NULL) {
1677       strcat(path, ":");
1678       strcat(path, syspath);
1679     }
1680   }
1681 #endif
1682 
1683   env[0] = path;
1684   env[1] = getenv(dyld_path_var);
1685   env[2] = NULL;
1686 
1687   if (env[1] != NULL) {
1688     static char buf[1024 + sizeof(dyld_path_var)];
1689     snprintf(buf, sizeof(buf), "%s=%s", dyld_path_var, env[1]);
1690     env[1] = buf;
1691   }
1692 
1693   options.file = file;
1694   options.args[0] = file;
1695   options.env = env;
1696 
1697   r = uv_spawn(uv_default_loop(), &process, &options);
1698   ASSERT(r == 0);
1699 
1700   r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
1701   ASSERT(r == 0);
1702 
1703   ASSERT(exit_cb_called == 1);
1704   ASSERT(close_cb_called == 1);
1705 
1706   MAKE_VALGRIND_HAPPY();
1707   return 0;
1708 }
1709 
TEST_IMPL(spawn_inherit_streams)1710 TEST_IMPL(spawn_inherit_streams) {
1711   uv_process_t child_req;
1712   uv_stdio_container_t child_stdio[2];
1713   int fds_stdin[2];
1714   int fds_stdout[2];
1715   uv_pipe_t pipe_stdin_child;
1716   uv_pipe_t pipe_stdout_child;
1717   uv_pipe_t pipe_stdin_parent;
1718   uv_pipe_t pipe_stdout_parent;
1719   unsigned char ubuf[OUTPUT_SIZE - 1];
1720   uv_buf_t buf;
1721   unsigned int i;
1722   int r;
1723   int bidir;
1724   uv_write_t write_req;
1725   uv_loop_t* loop;
1726 
1727   init_process_options("spawn_helper9", exit_cb);
1728 
1729   loop = uv_default_loop();
1730   ASSERT(uv_pipe_init(loop, &pipe_stdin_child, 0) == 0);
1731   ASSERT(uv_pipe_init(loop, &pipe_stdout_child, 0) == 0);
1732   ASSERT(uv_pipe_init(loop, &pipe_stdin_parent, 0) == 0);
1733   ASSERT(uv_pipe_init(loop, &pipe_stdout_parent, 0) == 0);
1734 
1735   ASSERT(uv_pipe(fds_stdin, 0, 0) == 0);
1736   ASSERT(uv_pipe(fds_stdout, 0, 0) == 0);
1737 
1738   ASSERT(uv_pipe_open(&pipe_stdin_child, fds_stdin[0]) == 0);
1739   ASSERT(uv_pipe_open(&pipe_stdout_child, fds_stdout[1]) == 0);
1740   ASSERT(uv_pipe_open(&pipe_stdin_parent, fds_stdin[1]) == 0);
1741   ASSERT(uv_pipe_open(&pipe_stdout_parent, fds_stdout[0]) == 0);
1742   ASSERT(uv_is_readable((uv_stream_t*) &pipe_stdin_child));
1743   ASSERT(uv_is_writable((uv_stream_t*) &pipe_stdout_child));
1744   ASSERT(uv_is_writable((uv_stream_t*) &pipe_stdin_parent));
1745   ASSERT(uv_is_readable((uv_stream_t*) &pipe_stdout_parent));
1746   /* Some systems (SVR4) open a bidirectional pipe, most don't. */
1747   bidir = uv_is_writable((uv_stream_t*) &pipe_stdin_child);
1748   ASSERT(uv_is_readable((uv_stream_t*) &pipe_stdout_child) == bidir);
1749   ASSERT(uv_is_readable((uv_stream_t*) &pipe_stdin_parent) == bidir);
1750   ASSERT(uv_is_writable((uv_stream_t*) &pipe_stdout_parent) == bidir);
1751 
1752   child_stdio[0].flags = UV_INHERIT_STREAM;
1753   child_stdio[0].data.stream = (uv_stream_t *) &pipe_stdin_child;
1754 
1755   child_stdio[1].flags = UV_INHERIT_STREAM;
1756   child_stdio[1].data.stream = (uv_stream_t *) &pipe_stdout_child;
1757 
1758   options.stdio = child_stdio;
1759   options.stdio_count = 2;
1760 
1761   ASSERT(uv_spawn(loop, &child_req, &options) == 0);
1762 
1763   uv_close((uv_handle_t*) &pipe_stdin_child, NULL);
1764   uv_close((uv_handle_t*) &pipe_stdout_child, NULL);
1765 
1766   buf = uv_buf_init((char*) ubuf, sizeof ubuf);
1767   for (i = 0; i < sizeof ubuf; ++i)
1768     ubuf[i] = i & 255u;
1769   memset(output, 0, sizeof ubuf);
1770 
1771   r = uv_write(&write_req,
1772                (uv_stream_t*) &pipe_stdin_parent,
1773                &buf,
1774                1,
1775                write_cb);
1776   ASSERT(r == 0);
1777 
1778   r = uv_read_start((uv_stream_t*) &pipe_stdout_parent, on_alloc, on_read);
1779   ASSERT(r == 0);
1780 
1781   r = uv_run(loop, UV_RUN_DEFAULT);
1782   ASSERT(r == 0);
1783 
1784   ASSERT(exit_cb_called == 1);
1785   ASSERT(close_cb_called == 3);
1786 
1787   r = memcmp(ubuf, output, sizeof ubuf);
1788   ASSERT(r == 0);
1789 
1790   MAKE_VALGRIND_HAPPY();
1791   return 0;
1792 }
1793 
TEST_IMPL(spawn_quoted_path)1794 TEST_IMPL(spawn_quoted_path) {
1795 #ifndef _WIN32
1796   RETURN_SKIP("Test for Windows");
1797 #else
1798   char* quoted_path_env[2];
1799   args[0] = "not_existing";
1800   args[1] = NULL;
1801   options.file = args[0];
1802   options.args = args;
1803   options.exit_cb = exit_cb;
1804   options.flags = 0;
1805   /* We test if search_path works correctly with semicolons in quoted path. We
1806    * will use an invalid drive, so we are sure no executable is spawned. */
1807   quoted_path_env[0] = "PATH=\"xyz:\\test;\";xyz:\\other";
1808   quoted_path_env[1] = NULL;
1809   options.env = quoted_path_env;
1810 
1811   /* We test if libuv will not segfault. */
1812   uv_spawn(uv_default_loop(), &process, &options);
1813 
1814   MAKE_VALGRIND_HAPPY();
1815   return 0;
1816 #endif
1817 }
1818 
TEST_IMPL(spawn_exercise_sigchld_issue)1819 TEST_IMPL(spawn_exercise_sigchld_issue) {
1820   int r;
1821   int i;
1822   uv_process_options_t dummy_options = {0};
1823   uv_process_t dummy_processes[100];
1824   char* args[2];
1825 
1826   init_process_options("spawn_helper1", exit_cb);
1827 
1828   r = uv_spawn(uv_default_loop(), &process, &options);
1829   ASSERT_EQ(r, 0);
1830 
1831   // This test exercises a bug in the darwin kernel that causes SIGCHLD not to
1832   // be delivered sometimes. Calling posix_spawn many times increases the
1833   // likelihood of encountering this issue, so spin a few times to make this
1834   // test more reliable.
1835   dummy_options.file = args[0] = "program-that-had-better-not-exist";
1836   args[1] = NULL;
1837   dummy_options.args = args;
1838   dummy_options.exit_cb = fail_cb;
1839   dummy_options.flags = 0;
1840   for (i = 0; i < 100; i++) {
1841     r = uv_spawn(uv_default_loop(), &dummy_processes[i], &dummy_options);
1842     if (r != UV_ENOENT)
1843       ASSERT_EQ(r, UV_EACCES);
1844     uv_close((uv_handle_t*) &dummy_processes[i], close_cb);
1845   }
1846 
1847   r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
1848   ASSERT_EQ(r, 0);
1849 
1850   ASSERT_EQ(exit_cb_called, 1);
1851   ASSERT_EQ(close_cb_called, 101);
1852 
1853   MAKE_VALGRIND_HAPPY();
1854   return 0;
1855 }
1856 
1857 /* Helper for child process of spawn_inherit_streams */
1858 #ifndef _WIN32
spawn_stdin_stdout(void)1859 void spawn_stdin_stdout(void) {
1860   char buf[1024];
1861   char* pbuf;
1862   for (;;) {
1863     ssize_t r, w, c;
1864     do {
1865       r = read(0, buf, sizeof buf);
1866     } while (r == -1 && errno == EINTR);
1867     if (r == 0) {
1868       return;
1869     }
1870     ASSERT(r > 0);
1871     c = r;
1872     pbuf = buf;
1873     while (c) {
1874       do {
1875         w = write(1, pbuf, (size_t)c);
1876       } while (w == -1 && errno == EINTR);
1877       ASSERT(w >= 0);
1878       pbuf = pbuf + w;
1879       c = c - w;
1880     }
1881   }
1882 }
1883 #else
spawn_stdin_stdout(void)1884 void spawn_stdin_stdout(void) {
1885   char buf[1024];
1886   char* pbuf;
1887   HANDLE h_stdin = GetStdHandle(STD_INPUT_HANDLE);
1888   HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
1889   ASSERT(h_stdin != INVALID_HANDLE_VALUE);
1890   ASSERT(h_stdout != INVALID_HANDLE_VALUE);
1891   for (;;) {
1892     DWORD n_read;
1893     DWORD n_written;
1894     DWORD to_write;
1895     if (!ReadFile(h_stdin, buf, sizeof buf, &n_read, NULL)) {
1896       ASSERT(GetLastError() == ERROR_BROKEN_PIPE);
1897       return;
1898     }
1899     to_write = n_read;
1900     pbuf = buf;
1901     while (to_write) {
1902       ASSERT(WriteFile(h_stdout, pbuf, to_write, &n_written, NULL));
1903       to_write -= n_written;
1904       pbuf += n_written;
1905     }
1906   }
1907 }
1908 #endif /* !_WIN32 */
1909