summaryrefslogtreecommitdiff
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);
}