changeset 37189:82ff83d5d4a7

dup2, dup3: work around another cygwin crasher Cygwin 1.7.25 can crash due to an off-by-one bug on an attempt to duplicate a file into the current RLIMIT_NOFILE soft limit, when that limit is smaller than the hard limit. The intent in the cygwin code was to allow the dup and auto-increase the soft limit, which is itself questionable (and which we work around in the gnulib getdtablesize module); but avoiding the crash is worth doing even if the soft limit semantics are wrong. http://cygwin.com/ml/cygwin/2013-09/msg00397.html http://cygwin.com/ml/cygwin-developers/2013-q3/msg00010.html * m4/dup2.m4 (gl_FUNC_DUP2): Expose the bug. * m4/dup3.m4 (gl_FUNC_DUP3): Likewise. * tests/test-dup2.c (main): Likewise. * lib/dup2.c (rpl_dup2): Use setdtablesize to avoid it. * lib/dup3.c (dup3): Likewise. * doc/posix-functions/dup2.texi (dup2): Document it. * doc/glibc-functions/dup3.texi (dup3): Likewise. Signed-off-by: Eric Blake <eblake@redhat.com>
author Eric Blake <eblake@redhat.com>
date Thu, 26 Sep 2013 07:07:07 -0600
parents ae8079a89eec
children 375bd75c4123
files ChangeLog doc/glibc-functions/dup3.texi doc/posix-functions/dup2.texi lib/dup2.c lib/dup3.c m4/dup2.m4 m4/dup3.m4 tests/test-dup2.c tests/test-dup3.c
diffstat 9 files changed, 50 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Thu Sep 26 11:26:29 2013 -0600
+++ b/ChangeLog	Thu Sep 26 07:07:07 2013 -0600
@@ -1,5 +1,14 @@
 2013-09-26  Eric Blake  <eblake@redhat.com>
 
+	dup2, dup3: work around another cygwin crasher
+	* m4/dup2.m4 (gl_FUNC_DUP2): Expose the bug.
+	* m4/dup3.m4 (gl_FUNC_DUP3): Likewise.
+	* tests/test-dup2.c (main): Likewise.
+	* lib/dup2.c (rpl_dup2): Use setdtablesize to avoid it.
+	* lib/dup3.c (dup3): Likewise.
+	* doc/posix-functions/dup2.texi (dup2): Document it.
+	* doc/glibc-functions/dup3.texi (dup3): Likewise.
+
 	getdtablesize: work around cygwin issue
 	* m4/getdtablesize.m4 (gl_FUNC_GETDTABLESIZE): Detect problem.
 	* modules/getdtablesize (configure.ac): Build replacement.
--- a/doc/glibc-functions/dup3.texi	Thu Sep 26 11:26:29 2013 -0600
+++ b/doc/glibc-functions/dup3.texi	Thu Sep 26 07:07:07 2013 -0600
@@ -10,6 +10,10 @@
 This function is missing on many non-glibc platforms:
 Mac OS X 10.5, FreeBSD 6.0, NetBSD 5.0, OpenBSD 3.8, Minix 3.1.8, AIX 5.1, HP-UX 11,
 IRIX 6.5, OSF/1 5.1, Solaris 11 2011-11, Cygwin 1.7.1, mingw, MSVC 9, Interix 3.5, BeOS.
+
+@item
+This function can crash on some platforms:
+Cygwin 1.7.25.
 @end itemize
 
 Portability problems not fixed by Gnulib:
--- a/doc/posix-functions/dup2.texi	Thu Sep 26 11:26:29 2013 -0600
+++ b/doc/posix-functions/dup2.texi	Thu Sep 26 07:07:07 2013 -0600
@@ -21,6 +21,10 @@
 Cygwin 1.7.17, MSVC 9.
 
 @item
+This function crashes when invoked with valid arguments on some platforms:
+Cygwin 1.7.25.
+
+@item
 This function resets the @code{FD_CLOEXEC} flag when duplicating an fd
 to itself on some platforms:
 Haiku.
--- a/lib/dup2.c	Thu Sep 26 11:26:29 2013 -0600
+++ b/lib/dup2.c	Thu Sep 26 07:07:07 2013 -0600
@@ -96,7 +96,11 @@
   /* On Linux kernels 2.6.26-2.6.29, dup2 (fd, fd) returns -EBADF.
      On Cygwin 1.5.x, dup2 (1, 1) returns 0.
      On Cygwin 1.7.17, dup2 (1, -1) dumps core.
+     On Cygwin 1.7.25, dup2 (1, 256) can dump core.
      On Haiku, dup2 (fd, fd) mistakenly clears FD_CLOEXEC.  */
+#  if HAVE_SETDTABLESIZE
+  setdtablesize (desired_fd + 1);
+#  endif
   if (desired_fd < 0)
     fd = desired_fd;
   if (fd == desired_fd)
--- a/lib/dup3.c	Thu Sep 26 11:26:29 2013 -0600
+++ b/lib/dup3.c	Thu Sep 26 07:07:07 2013 -0600
@@ -30,6 +30,10 @@
 {
 #if HAVE_DUP3
 # undef dup3
+# if HAVE_SETDTABLESIZE
+  /* Avoid a cygwin crasher. */
+  setdtablesize (newfd + 1);
+# endif
   /* Try the system call first, if it exists.  (We may be running with a glibc
      that has the function but with an older kernel that lacks it.)  */
   {
--- a/m4/dup2.m4	Thu Sep 26 11:26:29 2013 -0600
+++ b/m4/dup2.m4	Thu Sep 26 07:07:07 2013 -0600
@@ -1,4 +1,4 @@
-#serial 19
+#serial 20
 dnl Copyright (C) 2002, 2005, 2007, 2009-2013 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -39,9 +39,11 @@
             /* Many gnulib modules require POSIX conformance of EBADF.  */
             if (dup2 (2, 1000000) == -1 && errno != EBADF)
               result |= 16;
-            /* Flush out a cygwin core dump.  */
+            /* Flush out some cygwin core dumps.  */
             if (dup2 (2, -1) != -1 || errno != EBADF)
               result |= 32;
+            dup2 (2, 255);
+            dup2 (2, 256);
             return result;
            ])
         ],
@@ -65,6 +67,7 @@
       *yes) ;;
       *)
         REPLACE_DUP2=1
+        AC_CHECK_FUNCS([setdtablesize])
         ;;
     esac
   fi
--- a/m4/dup3.m4	Thu Sep 26 11:26:29 2013 -0600
+++ b/m4/dup3.m4	Thu Sep 26 07:07:07 2013 -0600
@@ -1,4 +1,4 @@
-# dup3.m4 serial 4
+# dup3.m4 serial 5
 dnl Copyright (C) 2009-2013 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -11,7 +11,7 @@
   dnl Persuade glibc <unistd.h> to declare dup3().
   AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
 
-  AC_CHECK_FUNCS_ONCE([dup3])
+  AC_CHECK_FUNCS_ONCE([dup3 setdtablesize])
   if test $ac_cv_func_dup3 != yes; then
     HAVE_DUP3=0
   fi
--- a/tests/test-dup2.c	Thu Sep 26 11:26:29 2013 -0600
+++ b/tests/test-dup2.c	Thu Sep 26 07:07:07 2013 -0600
@@ -150,6 +150,15 @@
   errno = 0;
   ASSERT (dup2 (fd, -2) == -1);
   ASSERT (errno == EBADF);
+  if (bad_fd > 256)
+    {
+      ASSERT (dup2 (fd, 255) == 255);
+      ASSERT (dup2 (fd, 256) == 256);
+      ASSERT (close (255) == 0);
+      ASSERT (close (256) == 0);
+    }
+  ASSERT (dup2 (fd, bad_fd - 1) == bad_fd - 1);
+  ASSERT (close (bad_fd - 1) == 0);
   errno = 0;
   ASSERT (dup2 (fd, bad_fd) == -1);
   ASSERT (errno == EBADF);
--- a/tests/test-dup3.c	Thu Sep 26 11:26:29 2013 -0600
+++ b/tests/test-dup3.c	Thu Sep 26 07:07:07 2013 -0600
@@ -124,6 +124,15 @@
       errno = 0;
       ASSERT (dup3 (fd, -2, o_flags) == -1);
       ASSERT (errno == EBADF);
+      if (bad_fd > 256)
+        {
+          ASSERT (dup3 (fd, 255, 0) == 255);
+          ASSERT (dup3 (fd, 256, 0) == 256);
+          ASSERT (close (255) == 0);
+          ASSERT (close (256) == 0);
+        }
+      ASSERT (dup3 (fd, bad_fd - 1, 0) == bad_fd - 1);
+      ASSERT (close (bad_fd - 1) == 0);
       errno = 0;
       ASSERT (dup3 (fd, bad_fd, o_flags) == -1);
       ASSERT (errno == EBADF);