bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] strerror_r: avoid clobbering strerror on cygwin


From: Eric Blake
Subject: [PATCH] strerror_r: avoid clobbering strerror on cygwin
Date: Sat, 21 May 2011 10:15:44 -0600

Avoid cygwin strerror_r, since it clobbers strerror buffer through
cygwin 1.7.9.  __xpg_strerror_r is okay, but if a program is
compiled on cygwin 1.7.8 or earlier, it is not available.

* lib/strerror_r.c (strerror_r): Don't use cygwin's strerror_r;
fall back instead to sys_errlist.
* modules/strerror (configure.ac): Add witness.
* tests/test-strerror_r.c (main): Enhance test.
* doc/posix-functions/strerror_r.texi (strerror_r): Document it.
* tests/test-perror2.c (main): Free memory before exit.

Signed-off-by: Eric Blake <address@hidden>
---
 ChangeLog                           |   10 +++++++
 doc/posix-functions/strerror_r.texi |    3 ++
 lib/strerror_r.c                    |   47 +++++++---------------------------
 modules/strerror                    |    1 +
 tests/test-perror2.c                |    5 +++
 tests/test-strerror_r.c             |   48 +++++++++++++++++++++++++++++++++++
 6 files changed, 77 insertions(+), 37 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 56ec3b6..c46dc3a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2011-05-21  Eric Blake  <address@hidden>
+
+       strerror_r: avoid clobbering strerror on cygwin
+       * lib/strerror_r.c (strerror_r): Don't use cygwin's strerror_r;
+       fall back instead to sys_errlist.
+       * modules/strerror (configure.ac): Add witness.
+       * tests/test-strerror_r.c (main): Enhance test.
+       * doc/posix-functions/strerror_r.texi (strerror_r): Document it.
+       * tests/test-perror2.c (main): Free memory before exit.
+
 2011-05-21  Bruno Haible  <address@hidden>

        mkdtemp: Use gnulib naming conventions.
diff --git a/doc/posix-functions/strerror_r.texi 
b/doc/posix-functions/strerror_r.texi
index 35cee29..21e4181 100644
--- a/doc/posix-functions/strerror_r.texi
+++ b/doc/posix-functions/strerror_r.texi
@@ -22,6 +22,9 @@ strerror_r
 char *s = strerror_r (err, buf, buflen);
 @end smallexample
 @item
+This function clobbers the @code{strerror} buffer on some platforms:
+Cygwin 1.7.9.
address@hidden
 This function is sometimes not declared in @code{<string.h>} on some platforms:
 glibc 2.8, OSF/1 5.1.
 @item
diff --git a/lib/strerror_r.c b/lib/strerror_r.c
index 2144fc6..65d230a 100644
--- a/lib/strerror_r.c
+++ b/lib/strerror_r.c
@@ -38,7 +38,7 @@

 # define USE_XPG_STRERROR_R 1

-#elif HAVE_DECL_STRERROR_R && !(__GLIBC__ >= 2 || defined __UCLIBC__)
+#elif HAVE_DECL_STRERROR_R && !(__GLIBC__ >= 2 || defined __UCLIBC__ || 
defined __CYGWIN__)

 /* The system's strerror_r function is OK, except that its third argument
    is 'int', not 'size_t', or its return type is wrong.  */
@@ -47,14 +47,16 @@

 # define USE_SYSTEM_STRERROR_R 1

-#else /* (__GLIBC__ >= 2 || defined __UCLIBC__ ? !HAVE___XPG_STRERROR_R : 
!HAVE_DECL_STRERROR_R) */
+#else /* (__GLIBC__ >= 2 || defined __UCLIBC__ || defined __CYGWIN__ ? 
!HAVE___XPG_STRERROR_R : !HAVE_DECL_STRERROR_R) */

-/* Use the system's strerror().  */
+/* Use the system's strerror().  Exclude glibc and cygwin because the
+   system strerror_r has the wrong return type, and cygwin 1.7.9
+   strerror_r clobbers strerror.  */
 # undef strerror

 # define USE_SYSTEM_STRERROR 1

-# if defined __NetBSD__ || defined __hpux || ((defined _WIN32 || defined 
__WIN32__) && !defined __CYGWIN__) || defined __sgi || (defined __sun && 
!defined _LP64)
+# if defined __NetBSD__ || defined __hpux || ((defined _WIN32 || defined 
__WIN32__) && !defined __CYGWIN__) || defined __sgi || (defined __sun && 
!defined _LP64) || defined __CYGWIN__

 /* No locking needed.  */

@@ -75,7 +77,7 @@ extern char *sys_errlist[];
 extern int sys_nerr;
 #  endif

-/* Get sys_nerr, sys_errlist on native Windows.  */
+/* Get sys_nerr, sys_errlist on native Windows and Cygwin.  */
 #  include <stdlib.h>

 # else
@@ -467,36 +469,6 @@ strerror_r (int errnum, char *buf, size_t buflen)
       else
         ret = strerror_r (errnum, buf, buflen);
     }
-# elif defined __CYGWIN__
-    /* Cygwin <= 1.7.7 only provides the glibc interface, is thread-safe, and
-       always succeeds (although it may truncate).  In Cygwin >= 1.7.8, for
-       valid errnum values, instead of truncating, it leaves the buffer
-       untouched.  */
-    {
-      char stackbuf[256];
-
-      if (buflen < sizeof (stackbuf))
-        {
-          size_t len;
-
-          stackbuf[0] = '\0'; /* in case strerror_r does nothing */
-          strerror_r (errnum, stackbuf, sizeof (stackbuf));
-          len = strlen (stackbuf);
-          if (len < buflen)
-            {
-              memcpy (buf, stackbuf, len + 1);
-              ret = 0;
-            }
-          else
-            ret = ERANGE;
-        }
-      else
-        {
-          buf[0] = '\0'; /* in case strerror_r does nothing */
-          strerror_r (errnum, buf, buflen);
-          ret = 0;
-        }
-    }
 # else
     ret = strerror_r (errnum, buf, buflen);
 # endif
@@ -526,12 +498,13 @@ strerror_r (int errnum, char *buf, size_t buflen)
     /* Try to do what strerror (errnum) does, but without clobbering the
        buffer used by strerror().  */

-# if defined __NetBSD__ || defined __hpux || ((defined _WIN32 || defined 
__WIN32__) && !defined __CYGWIN__) /* NetBSD, HP-UX, native Win32 */
+# if defined __NetBSD__ || defined __hpux || ((defined _WIN32 || defined 
__WIN32__) && !defined __CYGWIN__) || defined __CYGWIN__ /* NetBSD, HP-UX, 
native Win32, Cygwin */

     /* NetBSD:        sys_nerr, sys_errlist are declared through _NETBSD_SOURCE
                       and <errno.h> above.
        HP-UX:         sys_nerr, sys_errlist are declared explicitly above.
-       native Win32:  sys_nerr, sys_errlist are declared in <stdlib.h>.  */
+       native Win32:  sys_nerr, sys_errlist are declared in <stdlib.h>.
+       Cygwin:        sys_nerr, sys_errlist are declared in <stdlib.h>.  */
     if (errnum >= 0 && errnum < sys_nerr)
       {
 #  if HAVE_CATGETS && (defined __NetBSD__ || defined __hpux)
diff --git a/modules/strerror b/modules/strerror
index 42a476c..0e7a254 100644
--- a/modules/strerror
+++ b/modules/strerror
@@ -15,6 +15,7 @@ strerror_r-posix [test $REPLACE_STRERROR = 1]

 configure.ac:
 gl_FUNC_STRERROR
+gl_MODULE_INDICATOR([strerror])
 gl_STRING_MODULE_INDICATOR([strerror])

 Makefile.am:
diff --git a/tests/test-perror2.c b/tests/test-perror2.c
index fe5e33e..d8e0ec5 100644
--- a/tests/test-perror2.c
+++ b/tests/test-perror2.c
@@ -86,6 +86,11 @@ main (void)
     ASSERT (msg2 == msg4 || STREQ (msg2, str2));
     ASSERT (msg3 == msg4 || STREQ (msg3, str3));
     ASSERT (STREQ (msg4, str4));
+
+    free (str1);
+    free (str2);
+    free (str3);
+    free (str4);
   }

   /* Test that perror uses the same message as strerror.  */
diff --git a/tests/test-strerror_r.c b/tests/test-strerror_r.c
index 4828767..9c4874f 100644
--- a/tests/test-strerror_r.c
+++ b/tests/test-strerror_r.c
@@ -108,5 +108,53 @@ main (void)
     ASSERT (errno == 0);
   }

+#if GNULIB_STRERROR
+  /* Test that strerror_r does not clobber strerror buffer.  On some
+     platforms, this test can only succeed if gnulib also replaces
+     strerror.  */
+  {
+    const char *msg1;
+    const char *msg2;
+    const char *msg3;
+    const char *msg4;
+    char *str1;
+    char *str2;
+    char *str3;
+    char *str4;
+
+    msg1 = strerror (ENOENT);
+    ASSERT (msg1);
+    str1 = strdup (msg1);
+    ASSERT (str1);
+
+    msg2 = strerror (ERANGE);
+    ASSERT (msg2);
+    str2 = strdup (msg2);
+    ASSERT (str2);
+
+    msg3 = strerror (-4);
+    ASSERT (msg3);
+    str3 = strdup (msg3);
+    ASSERT (str3);
+
+    msg4 = strerror (1729576);
+    ASSERT (msg4);
+    str4 = strdup (msg4);
+    ASSERT (str4);
+
+    strerror_r (EACCES, buf, sizeof buf);
+    strerror_r (-5, buf, sizeof buf);
+    ASSERT (msg1 == msg2 || msg1 == msg4 || STREQ (msg1, str1));
+    ASSERT (msg2 == msg4 || STREQ (msg2, str2));
+    ASSERT (msg3 == msg4 || STREQ (msg3, str3));
+    ASSERT (STREQ (msg4, str4));
+
+    free (str1);
+    free (str2);
+    free (str3);
+    free (str4);
+  }
+#endif
+
   return 0;
 }
-- 
1.7.4.4




reply via email to

[Prev in Thread] Current Thread [Next in Thread]