unix: reap child on execvp() failure
Reap the forked process when execvp() fails. Fixes leaking zombie child processes. PR-URL: https://github.com/libuv/libuv/pull/274 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Saúl Ibarra Corretgé <saghul@gmail.com>
This commit is contained in:
parent
252f3624c2
commit
3616e61439
@ -367,6 +367,7 @@ int uv_spawn(uv_loop_t* loop,
|
||||
int err;
|
||||
int exec_errorno;
|
||||
int i;
|
||||
int status;
|
||||
|
||||
assert(options->file != NULL);
|
||||
assert(!(options->flags & ~(UV_PROCESS_DETACHED |
|
||||
@ -453,11 +454,17 @@ int uv_spawn(uv_loop_t* loop,
|
||||
|
||||
if (r == 0)
|
||||
; /* okay, EOF */
|
||||
else if (r == sizeof(exec_errorno))
|
||||
; /* okay, read errorno */
|
||||
else if (r == -1 && errno == EPIPE)
|
||||
; /* okay, got EPIPE */
|
||||
else
|
||||
else if (r == sizeof(exec_errorno)) {
|
||||
do
|
||||
err = waitpid(pid, &status, 0); /* okay, read errorno */
|
||||
while (err == -1 && errno == EINTR);
|
||||
assert(err == pid);
|
||||
} else if (r == -1 && errno == EPIPE) {
|
||||
do
|
||||
err = waitpid(pid, &status, 0); /* okay, got EPIPE */
|
||||
while (err == -1 && errno == EINTR);
|
||||
assert(err == pid);
|
||||
} else
|
||||
abort();
|
||||
|
||||
uv__close(signal_pipe[0]);
|
||||
|
||||
@ -196,6 +196,9 @@ TEST_DECLARE (fail_always)
|
||||
TEST_DECLARE (pass_always)
|
||||
TEST_DECLARE (socket_buffer_size)
|
||||
TEST_DECLARE (spawn_fails)
|
||||
#ifndef _WIN32
|
||||
TEST_DECLARE (spawn_fails_check_for_waitpid_cleanup)
|
||||
#endif
|
||||
TEST_DECLARE (spawn_exit_code)
|
||||
TEST_DECLARE (spawn_stdout)
|
||||
TEST_DECLARE (spawn_stdin)
|
||||
@ -553,6 +556,9 @@ TASK_LIST_START
|
||||
TEST_ENTRY (socket_buffer_size)
|
||||
|
||||
TEST_ENTRY (spawn_fails)
|
||||
#ifndef _WIN32
|
||||
TEST_ENTRY (spawn_fails_check_for_waitpid_cleanup)
|
||||
#endif
|
||||
TEST_ENTRY (spawn_exit_code)
|
||||
TEST_ENTRY (spawn_stdout)
|
||||
TEST_ENTRY (spawn_stdin)
|
||||
|
||||
@ -21,6 +21,7 @@
|
||||
|
||||
#include "uv.h"
|
||||
#include "task.h"
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@ -34,6 +35,7 @@
|
||||
# include <wchar.h>
|
||||
#else
|
||||
# include <unistd.h>
|
||||
# include <sys/wait.h>
|
||||
#endif
|
||||
|
||||
|
||||
@ -180,6 +182,37 @@ TEST_IMPL(spawn_fails) {
|
||||
}
|
||||
|
||||
|
||||
#ifndef _WIN32
|
||||
TEST_IMPL(spawn_fails_check_for_waitpid_cleanup) {
|
||||
int r;
|
||||
int status;
|
||||
int err;
|
||||
|
||||
init_process_options("", fail_cb);
|
||||
options.file = options.args[0] = "program-that-had-better-not-exist";
|
||||
|
||||
r = uv_spawn(uv_default_loop(), &process, &options);
|
||||
ASSERT(r == UV_ENOENT || r == UV_EACCES);
|
||||
ASSERT(0 == uv_is_active((uv_handle_t*) &process));
|
||||
ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
|
||||
|
||||
/* verify the child is successfully cleaned up within libuv */
|
||||
do
|
||||
err = waitpid(process.pid, &status, 0);
|
||||
while (err == -1 && errno == EINTR);
|
||||
|
||||
ASSERT(err == -1);
|
||||
ASSERT(errno == ECHILD);
|
||||
|
||||
uv_close((uv_handle_t*) &process, NULL);
|
||||
ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
TEST_IMPL(spawn_exit_code) {
|
||||
int r;
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user