summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2014-03-11 22:25:15 -0700
committerKaz Kylheku <kaz@kylheku.com>2014-03-11 22:25:15 -0700
commit5382f4a6aa4a38c5f2f229f79bee55dfcb3843fc (patch)
tree7ae07decfd27a60929b2168bcd42382a84101ef1
parentd5915cf610b71691a95f5af3fe09848adb3f0d3d (diff)
downloadtxr-5382f4a6aa4a38c5f2f229f79bee55dfcb3843fc.tar.gz
txr-5382f4a6aa4a38c5f2f229f79bee55dfcb3843fc.tar.bz2
txr-5382f4a6aa4a38c5f2f229f79bee55dfcb3843fc.zip
* 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.
-rw-r--r--ChangeLog13
-rwxr-xr-xconfigure24
-rw-r--r--stream.c12
3 files changed, 48 insertions, 1 deletions
diff --git a/ChangeLog b/ChangeLog
index ad9e6096..20b772da 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,18 @@
2014-03-11 Kaz Kylheku <kaz@kylheku.com>
+ * 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 <kaz@kylheku.com>
+
* stream.c (open_process): In the event of fdopen failure,
kill the child process less abruptly by hitting it with SIGINT and
SIGTERM, rather than with SIGKILL. Also, collect the child
diff --git a/configure b/configure
index ddc8ee0b..c897c7e2 100755
--- a/configure
+++ b/configure
@@ -1330,6 +1330,30 @@ else
fi
#
+# fcntl
+#
+
+printf "Checking for POSIX fcntl ... "
+
+cat > conftest.c <<!
+#include "config.h"
+#include <fcntl.h>
+
+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 <unistd.h>
#endif
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
#include <float.h>
#if HAVE_SYS_WAIT
#include <sys/wait.h>
@@ -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);