diff --git a/ChangeLog b/ChangeLog index e7ebfdaa..4ca4fffe 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2014.01.08, Version 0.10.22 (Stable), f526c90eeff271d9323a9107b9a64a4671fd3103 + +Changes since version 0.10.21: + +* windows: avoid assertion failure when pipe server is closed (Bert Belder) + + 2013.12.32, Version 0.11.17 (Unstable), 589c224d4c2e79fec65db01d361948f1e4976858 Changes since version 0.11.16: diff --git a/src/unix/linux-core.c b/src/unix/linux-core.c index 78b23436..5acfb0dd 100644 --- a/src/unix/linux-core.c +++ b/src/unix/linux-core.c @@ -635,9 +635,9 @@ static int read_times(unsigned int numcpus, uv_cpu_info_t* ci) { /* skip "cpu " marker */ { - unsigned int n = num; + unsigned int n; + assert(sscanf(buf, "cpu%u ", &n) == 1); for (len = sizeof("cpu0"); n /= 10; len++); - assert(sscanf(buf, "cpu%u ", &n) == 1 && n == num); } /* Line contains user, nice, system, idle, iowait, irq, softirq, steal, @@ -664,6 +664,7 @@ static int read_times(unsigned int numcpus, uv_cpu_info_t* ci) { ci[num++].cpu_times = ts; } fclose(fp); + assert(num == numcpus); return 0; } diff --git a/src/unix/openbsd.c b/src/unix/openbsd.c index 0ff9ad64..f052d80c 100644 --- a/src/unix/openbsd.c +++ b/src/unix/openbsd.c @@ -228,7 +228,7 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { uint64_t info[CPUSTATES]; char model[512]; int numcpus = 1; - static int which[] = {CTL_HW,HW_MODEL,0}; + int which[] = {CTL_HW,HW_MODEL,0}; size_t size; int i; uv_cpu_info_t* cpu_info; diff --git a/src/unix/process.c b/src/unix/process.c index 6854ac11..6f96b754 100644 --- a/src/unix/process.c +++ b/src/unix/process.c @@ -287,34 +287,41 @@ static void uv__process_child_init(const uv_process_options_t* options, close_fd = pipes[fd][0]; use_fd = pipes[fd][1]; - if (use_fd >= 0) { - if (close_fd != -1) - uv__close(close_fd); - } - else if (fd >= 3) - continue; - else { - /* redirect stdin, stdout and stderr to /dev/null even if UV_IGNORE is - * set - */ - use_fd = open("/dev/null", fd == 0 ? O_RDONLY : O_RDWR); + if (use_fd < 0) { + if (fd >= 3) + continue; + else { + /* redirect stdin, stdout and stderr to /dev/null even if UV_IGNORE is + * set + */ + use_fd = open("/dev/null", fd == 0 ? O_RDONLY : O_RDWR); + close_fd = use_fd; - if (use_fd == -1) { + if (use_fd == -1) { uv__write_int(error_fd, -errno); - perror("failed to open stdio"); - _exit(127); + perror("failed to open stdio"); + _exit(127); + } } } if (fd == use_fd) uv__cloexec(use_fd, 0); - else { + else dup2(use_fd, fd); - uv__close(use_fd); - } if (fd <= 2) uv__nonblock(fd, 0); + + if (close_fd != -1) + uv__close(close_fd); + } + + for (fd = 0; fd < stdio_count; fd++) { + use_fd = pipes[fd][1]; + + if (use_fd >= 0 && fd != use_fd) + close(use_fd); } if (options->cwd != NULL && chdir(options->cwd)) { diff --git a/test/test-list.h b/test/test-list.h index 2195e232..c3e15783 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -168,6 +168,7 @@ TEST_DECLARE (spawn_preserve_env) TEST_DECLARE (spawn_setuid_fails) TEST_DECLARE (spawn_setgid_fails) TEST_DECLARE (spawn_stdout_to_file) +TEST_DECLARE (spawn_stdout_and_stderr_to_file) TEST_DECLARE (spawn_auto_unref) TEST_DECLARE (fs_poll) TEST_DECLARE (kill) @@ -456,6 +457,7 @@ TASK_LIST_START TEST_ENTRY (spawn_setuid_fails) TEST_ENTRY (spawn_setgid_fails) TEST_ENTRY (spawn_stdout_to_file) + TEST_ENTRY (spawn_stdout_and_stderr_to_file) TEST_ENTRY (spawn_auto_unref) TEST_ENTRY (fs_poll) TEST_ENTRY (kill) diff --git a/test/test-spawn.c b/test/test-spawn.c index d11e5a8e..8dc18bed 100644 --- a/test/test-spawn.c +++ b/test/test-spawn.c @@ -266,6 +266,61 @@ TEST_IMPL(spawn_stdout_to_file) { } +TEST_IMPL(spawn_stdout_and_stderr_to_file) { + int r; + uv_file file; + uv_fs_t fs_req; + uv_stdio_container_t stdio[3]; + + /* Setup. */ + unlink("stdout_file"); + + init_process_options("spawn_helper6", exit_cb); + + r = uv_fs_open(uv_default_loop(), &fs_req, "stdout_file", O_CREAT | O_RDWR, + S_IREAD | S_IWRITE, NULL); + ASSERT(r != -1); + uv_fs_req_cleanup(&fs_req); + + file = r; + + options.stdio = stdio; + options.stdio[0].flags = UV_IGNORE; + options.stdio[1].flags = UV_INHERIT_FD; + options.stdio[1].data.fd = file; + options.stdio[2].flags = UV_INHERIT_FD; + options.stdio[2].data.fd = file; + options.stdio_count = 3; + + r = uv_spawn(uv_default_loop(), &process, options); + ASSERT(r == 0); + + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r == 0); + + ASSERT(exit_cb_called == 1); + ASSERT(close_cb_called == 1); + + r = uv_fs_read(uv_default_loop(), &fs_req, file, output, sizeof(output), + 0, NULL); + ASSERT(r == 27); + uv_fs_req_cleanup(&fs_req); + + r = uv_fs_close(uv_default_loop(), &fs_req, file, NULL); + ASSERT(r == 0); + uv_fs_req_cleanup(&fs_req); + + printf("output is: %s", output); + ASSERT(strcmp("hello world\nhello errworld\n", output) == 0); + + /* Cleanup. */ + unlink("stdout_file"); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + TEST_IMPL(spawn_stdin) { int r; uv_pipe_t out; @@ -564,6 +619,53 @@ TEST_IMPL(spawn_and_ping) { } +TEST_IMPL(spawn_same_stdout_stderr) { + uv_write_t write_req; + uv_pipe_t in, out; + uv_buf_t buf; + uv_stdio_container_t stdio[3]; + int r; + + init_process_options("spawn_helper3", exit_cb); + buf = uv_buf_init("TEST", 4); + + uv_pipe_init(uv_default_loop(), &out, 0); + uv_pipe_init(uv_default_loop(), &in, 0); + options.stdio = stdio; + options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE; + options.stdio[0].data.stream = (uv_stream_t*)∈ + options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; + options.stdio[1].data.stream = (uv_stream_t*)&out; + options.stdio_count = 2; + + r = uv_spawn(uv_default_loop(), &process, options); + ASSERT(r == 0); + + /* Sending signum == 0 should check if the + * child process is still alive, not kill it. + */ + r = uv_process_kill(&process, 0); + ASSERT(r == 0); + + r = uv_write(&write_req, (uv_stream_t*)&in, &buf, 1, write_cb); + ASSERT(r == 0); + + r = uv_read_start((uv_stream_t*)&out, on_alloc, on_read); + ASSERT(r == 0); + + ASSERT(exit_cb_called == 0); + + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r == 0); + + ASSERT(exit_cb_called == 1); + ASSERT(strcmp(output, "TEST") == 0); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + TEST_IMPL(kill) { int r;