process: fix uv_spawn edge-case

It can happen that the `parent` end of the `signal_pipe` is given a
STDIO file descriptor, so closing it using `uv__close` fails.

This problem is happening when running the `spawn_closed_process_io`
test in `SmartOS`. The reason being that when creating a socketpair in
`uv__process_init_stdio`, the `Illumos` implementation uses 3 sockets:
one is used as a listener, and the other 2 represent both ends of the
pipe. The listener socket is closed once the pipe is created. In the
test, the listener socket is assigned to the `0` fd, as it is the
first free fd in the system. So the fd `0` remained free after the call
to `socketpair`. Afterwards, when creating the `signal_pipe`, the fd `0`
is being assigned again, so closing it with `uv__close` made the test
fail. This issue is not happening in the other unixes because
`socketpair` doesn't use 3 fd's, but only 2.

To solve the issue, a new `uv__close__nocheckstdio()` function has been
added and used.

PR-URL: https://github.com/libuv/libuv/pull/796
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Saúl Ibarra Corretgé <saghul@gmail.com>
This commit is contained in:
Santiago Gimeno 2016-03-29 18:55:14 +02:00 committed by Ben Noordhuis
parent 217f81b6a1
commit 1c0281e3e2
3 changed files with 9 additions and 3 deletions

View File

@ -498,12 +498,11 @@ skip:
}
int uv__close(int fd) {
int uv__close_nocheckstdio(int fd) {
int saved_errno;
int rc;
assert(fd > -1); /* Catch uninitialized io_watcher.fd bugs. */
assert(fd > STDERR_FILENO); /* Catch stdio close bugs. */
saved_errno = errno;
rc = close(fd);
@ -518,6 +517,12 @@ int uv__close(int fd) {
}
int uv__close(int fd) {
assert(fd > STDERR_FILENO); /* Catch stdio close bugs. */
return uv__close_nocheckstdio(fd);
}
#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \
defined(_AIX) || defined(__DragonFly__)

View File

@ -177,6 +177,7 @@ struct uv__stream_queued_fds_s {
/* core */
int uv__nonblock(int fd, int set);
int uv__close(int fd);
int uv__close_nocheckstdio(int fd);
int uv__cloexec(int fd, int set);
int uv__socket(int domain, int type, int protocol);
int uv__dup(int fd);

View File

@ -498,7 +498,7 @@ int uv_spawn(uv_loop_t* loop,
} else
abort();
uv__close(signal_pipe[0]);
uv__close_nocheckstdio(signal_pipe[0]);
for (i = 0; i < options->stdio_count; i++) {
err = uv__process_open_stream(options->stdio + i, pipes[i], i == 0);