about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Src/compat.c63
-rw-r--r--Src/exec.c2
-rw-r--r--Src/system.h10
-rw-r--r--Src/utils.c38
4 files changed, 70 insertions, 43 deletions
diff --git a/Src/compat.c b/Src/compat.c
index ec3a8bc39..5400f627f 100644
--- a/Src/compat.c
+++ b/Src/compat.c
@@ -187,40 +187,45 @@ zpathmax(char *dir)
 #endif /* 0 */
 
 #ifdef HAVE_SYSCONF
-/* This is replaced by a macro from system.h if not HAVE_SYSCONF.    *
- * 0 is returned by sysconf if _SC_OPEN_MAX is unavailable;          *
- * -1 is returned on error                                           *
- *                                                                   *
- * Neither of these should happen, but resort to OPEN_MAX rather     *
- * than return 0 or -1 just in case.                                 */
+/*
+ * This is replaced by a macro from system.h if not HAVE_SYSCONF.
+ * 0 is returned by sysconf if _SC_OPEN_MAX is unavailable;
+ * -1 is returned on error
+ *
+ * Neither of these should happen, but resort to OPEN_MAX rather
+ * than return 0 or -1 just in case.
+ *
+ * We'll limit the open maximum to ZSH_INITIAL_OPEN_MAX to
+ * avoid probing ridiculous numbers of file descriptors.
+ */
 
 /**/
 mod_export long
 zopenmax(void)
 {
-    static long openmax = 0;
-
-    if (openmax < 1) {
-	if ((openmax = sysconf(_SC_OPEN_MAX)) < 1) {
-	    openmax = OPEN_MAX;
-	} else if (openmax > OPEN_MAX) {
-	    /* On some systems, "limit descriptors unlimited" or the  *
-	     * equivalent will set openmax to a huge number.  Unless  *
-	     * there actually is a file descriptor > OPEN_MAX already *
-	     * open, nothing in zsh requires the true maximum, and in *
-	     * fact it causes inefficiency elsewhere if we report it. *
-	     * So, report the maximum of OPEN_MAX or the largest open *
-	     * descriptor (is there a better way to find that?).      */
-	    long i, j = OPEN_MAX;
-	    for (i = j; i < openmax; i += (errno != EINTR)) {
-		errno = 0;
-		if (fcntl(i, F_GETFL, 0) < 0 &&
-		    (errno == EBADF || errno == EINTR))
-		    continue;
-		j = i;
-	    }
-	    openmax = j;
+    long openmax;
+
+    if ((openmax = sysconf(_SC_OPEN_MAX)) < 1) {
+	openmax = OPEN_MAX;
+    } else if (openmax > OPEN_MAX) {
+	/* On some systems, "limit descriptors unlimited" or the  *
+	 * equivalent will set openmax to a huge number.  Unless  *
+	 * there actually is a file descriptor > OPEN_MAX already *
+	 * open, nothing in zsh requires the true maximum, and in *
+	 * fact it causes inefficiency elsewhere if we report it. *
+	 * So, report the maximum of OPEN_MAX or the largest open *
+	 * descriptor (is there a better way to find that?).      */
+	long i, j = OPEN_MAX;
+	if (openmax > ZSH_INITIAL_OPEN_MAX)
+	    openmax = ZSH_INITIAL_OPEN_MAX;
+	for (i = j; i < openmax; i += (errno != EINTR)) {
+	    errno = 0;
+	    if (fcntl(i, F_GETFL, 0) < 0 &&
+		(errno == EBADF || errno == EINTR))
+		continue;
+	    j = i;
 	}
+	openmax = j;
     }
 
     return (max_zsh_fd > openmax) ? max_zsh_fd : openmax;
@@ -771,7 +776,7 @@ mk_wcwidth(wchar_t ucs)
 
   /* if we arrive here, ucs is not a combining or C0/C1 control character */
 
-  return 1 + 
+  return 1 +
     (ucs >= 0x1100 &&
      (ucs <= 0x115f ||                    /* Hangul Jamo init. consonants */
       ucs == 0x2329 || ucs == 0x232a ||
diff --git a/Src/exec.c b/Src/exec.c
index 02887e1aa..7ba80d986 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -1928,7 +1928,7 @@ closeallelse(struct multio *mn)
     int i, j;
     long openmax;
 
-    openmax = zopenmax();
+    openmax = fdtable_size;
 
     for (i = 0; i < openmax; i++)
 	if (mn->pipe != i) {
diff --git a/Src/system.h b/Src/system.h
index 2707d20c9..1c737087f 100644
--- a/Src/system.h
+++ b/Src/system.h
@@ -304,16 +304,22 @@ struct timezone {
 # endif
 #endif
 
+/*
+ * The number of file descriptors we'll allocate initially.
+ * We will reallocate later if necessary.
+ */
+#define ZSH_INITIAL_OPEN_MAX 64
 #ifndef OPEN_MAX
 # ifdef NOFILE
 #  define OPEN_MAX NOFILE
 # else
    /* so we will just pick something */
-#  define OPEN_MAX 64
+#  define OPEN_MAX ZSH_INITIAL_OPEN_MAX
 # endif
 #endif
 #ifndef HAVE_SYSCONF
-# define zopenmax() ((long) OPEN_MAX)
+# define zopenmax() ((long) (OPEN_MAX > ZSH_INITIAL_OPEN_MAX ? \
+			     ZSH_INITIAL_OPEN_MAX : OPEN_MAX))
 #endif
 
 #ifdef HAVE_FCNTL_H
diff --git a/Src/utils.c b/Src/utils.c
index 221d10d5d..0168c8287 100644
--- a/Src/utils.c
+++ b/Src/utils.c
@@ -1621,6 +1621,27 @@ adjustwinsize(int from)
     }
 }
 
+/*
+ * Ensure the fdtable is large enough for fd, and that the
+ * maximum fd is set appropriately.
+ */
+static void
+check_fd_table(int fd)
+{
+    if (fd <= max_zsh_fd)
+	return;
+
+    if (fd >= fdtable_size) {
+	int old_size = fdtable_size;
+	while (fd >= fdtable_size)
+	    fdtable = zrealloc(fdtable,
+			       (fdtable_size *= 2)*sizeof(*fdtable));
+	memset(fdtable + old_size, 0,
+	       (fdtable_size - old_size) * sizeof(*fdtable));
+    }
+    max_zsh_fd = fd;
+}
+
 /* Move a fd to a place >= 10 and mark the new fd in fdtable.  If the fd *
  * is already >= 10, it is not moved.  If it is invalid, -1 is returned. */
 
@@ -1644,12 +1665,7 @@ movefd(int fd)
 	fd = fe;
     }
     if(fd != -1) {
-	if (fd > max_zsh_fd) {
-	    while (fd >= fdtable_size)
-		fdtable = zrealloc(fdtable,
-				   (fdtable_size *= 2)*sizeof(*fdtable));
-	    max_zsh_fd = fd;
-	}
+	check_fd_table(fd);
 	fdtable[fd] = FDT_INTERNAL;
     }
     return fd;
@@ -1669,12 +1685,12 @@ redup(int x, int y)
     if(x < 0)
 	zclose(y);
     else if (x != y) {
-	while (y >= fdtable_size)
-	    fdtable = zrealloc(fdtable, (fdtable_size *= 2)*sizeof(*fdtable));
-	if (dup2(x, y) == -1)
+	if (dup2(x, y) == -1) {
 	    ret = -1;
-	if ((fdtable[y] = fdtable[x]) && y > max_zsh_fd)
-	    max_zsh_fd = y;
+	} else {
+	    check_fd_table(y);
+	    fdtable[y] = fdtable[x];
+	}
 	zclose(x);
     }