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