From 5382f4a6aa4a38c5f2f229f79bee55dfcb3843fc Mon Sep 17 00:00:00 2001 From: Kaz Kylheku Date: Tue, 11 Mar 2014 22:25:15 -0700 Subject: * configure: new test for fcntl. * stream.c (open_process): Fixed off-by one erroneous value of nargs, causing memory leak of one string. Fixed memory leak on fork failure. Fixed a deadlock that can occur in the pipe close function when multiple pipes are in existence. This is fixed by setting the FD_CLOEXEC flag on the pipe file descriptor. Without this, one child process can hold another's pipe open, causing that other one not to terminate when we're trying to shut it down, resulting in that child blocked on a write, while we block on waitpid. --- ChangeLog | 13 +++++++++++++ configure | 24 ++++++++++++++++++++++++ stream.c | 12 +++++++++++- 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index ad9e6096..20b772da 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2014-03-11 Kaz Kylheku + + * configure: new test for fcntl. + + * stream.c (open_process): Fixed off-by one erroneous value of nargs, + causing memory leak of one string. Fixed memory leak on fork failure. + Fixed a deadlock that can occur in the pipe close function when + multiple pipes are in existence. This is fixed by setting the + FD_CLOEXEC flag on the pipe file descriptor. Without this, one child + process can hold another's pipe open, causing that other one not to + terminate when we're trying to shut it down, resulting in that child + blocked on a write, while we block on waitpid. + 2014-03-11 Kaz Kylheku * stream.c (open_process): In the event of fdopen failure, diff --git a/configure b/configure index ddc8ee0b..c897c7e2 100755 --- a/configure +++ b/configure @@ -1329,6 +1329,30 @@ else printf "no\n" fi +# +# fcntl +# + +printf "Checking for POSIX fcntl ... " + +cat > conftest.c < + +int main(int argc, char **argv) +{ + int err = fcntl(0, F_SETFD, FD_CLOEXEC); + return 0; +} +! + +if conftest ; then + printf "yes\n" + printf "#define HAVE_FCNTL_H 1\n" >> config.h +else + printf "no\n" +fi + # # Check for fields inside struct tm # diff --git a/stream.c b/stream.c index da58e38d..85c16d80 100644 --- a/stream.c +++ b/stream.c @@ -38,6 +38,9 @@ #if HAVE_UNISTD_H #include #endif +#if HAVE_FCNTL_H +#include +#endif #include #if HAVE_SYS_WAIT #include @@ -2131,7 +2134,7 @@ val open_process(val name, val mode_str, val args) int i, nargs; args = default_bool_arg(args); - nargs = c_num(length(args)); + nargs = c_num(length(args)) + 1; if (pipe(fd) == -1) { uw_throwf(file_error_s, lit("opening pipe ~a, pipe syscall failed: ~a/~s"), @@ -2151,6 +2154,9 @@ val open_process(val name, val mode_str, val args) pid = fork(); if (pid == -1) { + for (i = 0; i < nargs; i++) + free(argv[i]); + free(argv); uw_throwf(file_error_s, lit("opening pipe ~a, fork syscall failed: ~a/~s"), name, num(errno), string_utf8(strerror(errno)), nao); } @@ -2187,6 +2193,10 @@ val open_process(val name, val mode_str, val args) free(argv[i]); free(argv); +#if HAVE_FCNTL_H + fcntl(whichfd, F_SETFD, FD_CLOEXEC); +#endif + if ((f = fdopen(whichfd, utf8mode)) == 0) { int status; kill(pid, SIGINT); -- cgit v1.2.3