strerror_r-posix: work around cygwin 1.7.9
authorEric Blake <eblake@redhat.com>
Mon, 6 Jun 2011 23:59:01 +0000 (17:59 -0600)
committerEric Blake <eblake@redhat.com>
Tue, 7 Jun 2011 22:48:54 +0000 (16:48 -0600)
Cygwin __xpg_strerror_r clobbers strerror, until cygwin 1.7.10; in
this case, we must replace strerror, but there was nothing in
strerror.m4 finding fault with cygwin's native strerror.  Solve
this by splitting strerror_r.m4 into two parts, one for probing
for the strerror_r bug, and one for replacing strerror_r based
on the presence of bugs unrelated to signature issues; that way,
the 'strerror' module in isolation will not replace strerror, but
if strerror_r is in use for any other reason, then the two use
separate buffers.

Note that cygwin's strerror is thread-safe while the gnulib
replacement is not; but this is no worse than any other
platform where strerror is not thread-safe; in a single-threaded
program, the difference is not observable, and in a multi-threaded
program, you really shouldn't be using strerror in the first place.

Also note that this ends up replacing glibc 2.13 strerror as it
deems __xpg_strerror_r broken on that platform, which isn't
technically necessary for strerror, but doesn't hurt too much.
Meanwhile, glibc 2.14 fixed __xpg_strerror_r, and strerror is not
replaced in that scenario.

* m4/strerror_r.m4 (gl_FUNC_STRERROR_R): Split...
(gl_FUNC_STRERROR_R_WORKS): ...into new macro, to detect Cygwin
bug without replacing strerror_r.
* m4/strerror.m4 (gl_FUNC_STRERROR): Replace strerror if
strerror_r is buggy, but without requiring strerror_r compilation.
* doc/posix-functions/strerror_r.texi (strerror_r): Fix docs.

Signed-off-by: Eric Blake <eblake@redhat.com>
ChangeLog
doc/posix-functions/strerror_r.texi
m4/strerror.m4
m4/strerror_r.m4

index 870ec7333e200b8f6bd57c9147ab503c5518042d..af211551b5f865885e54ba7bd689ea7c595168e8 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,13 @@
 2011-06-07  Eric Blake  <eblake@redhat.com>
 
+       strerror_r-posix: work around cygwin 1.7.9
+       * m4/strerror_r.m4 (gl_FUNC_STRERROR_R): Split...
+       (gl_FUNC_STRERROR_R_WORKS): ...into new macro, to detect Cygwin
+       bug without replacing strerror_r.
+       * m4/strerror.m4 (gl_FUNC_STRERROR): Replace strerror if
+       strerror_r is buggy, but without requiring strerror_r compilation.
+       * doc/posix-functions/strerror_r.texi (strerror_r): Fix docs.
+
        test-perror: relax test to ignore cygwin bug
        * tests/test-perror2.c (main): Relax test on requiring detection
        of stream errors, and use unbuffered stream.
index e0f19c01ef8bb65ff2b5c66e2fe45c5a43761df1..4169ca9abfdea8196d4b82bedfd4fb345d5fe235 100644 (file)
@@ -64,8 +64,4 @@ glibc 2.13, FreeBSD 8.2, Solaris 10.
 
 Portability problems not fixed by Gnulib:
 @itemize
-@item
-Calling this function can clobber the buffer used by @code{strerror}
-on some platforms:
-Cygwin 1.7.9.
 @end itemize
index 25edd913676b74668f72b9218c541ab35ac2fddc..de4ba9674b5cb4ab1f7ac0fafd6cd6ba29e2c3e2 100644 (file)
@@ -1,4 +1,4 @@
-# strerror.m4 serial 12
+# strerror.m4 serial 13
 dnl Copyright (C) 2002, 2007-2011 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -8,6 +8,9 @@ AC_DEFUN([gl_FUNC_STRERROR],
 [
   AC_REQUIRE([gl_HEADER_STRING_H_DEFAULTS])
   AC_REQUIRE([gl_HEADER_ERRNO_H])
+  m4_ifdef([gl_FUNC_STRERROR_R_WORKS], [
+    AC_REQUIRE([gl_FUNC_STRERROR_R_WORKS])
+  ])
   if test -z "$ERRNO_H"; then
     AC_CACHE_CHECK([for working strerror function],
      [gl_cv_func_working_strerror],
@@ -32,6 +35,10 @@ AC_DEFUN([gl_FUNC_STRERROR],
       dnl integers. Replace it.
       REPLACE_STRERROR=1
     fi
+    dnl If the system's strerror_r clobbers strerror, we must replace strerror.
+    case $gl_cv_func_strerror_r_works in
+      *no) REPLACE_STRERROR=1 ;;
+    esac
   else
     dnl The system's strerror() cannot know about the new errno values we add
     dnl to <errno.h>. Replace it.
index 1c0af3691dc0f7b01dffcc6020835d0e7d8f6847..c1d1a8eb05fb975a492fb6d4ad6420137ba4d378 100644 (file)
@@ -1,4 +1,4 @@
-# strerror_r.m4 serial 9
+# strerror_r.m4 serial 10
 dnl Copyright (C) 2002, 2007-2011 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -6,9 +6,7 @@ dnl with or without modifications, as long as this notice is preserved.
 
 AC_DEFUN([gl_FUNC_STRERROR_R],
 [
-  AC_REQUIRE([gl_HEADER_STRING_H_DEFAULTS])
-  AC_REQUIRE([gl_HEADER_ERRNO_H])
-  AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
+  AC_REQUIRE([gl_FUNC_STRERROR_R_WORKS])
 
   dnl Persuade Solaris <string.h> to declare strerror_r().
   AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
@@ -20,7 +18,40 @@ AC_DEFUN([gl_FUNC_STRERROR_R],
     HAVE_DECL_STRERROR_R=0
   fi
 
-  AC_CHECK_FUNCS([strerror_r])
+  if test $ac_cv_func_strerror_r = yes; then
+    if test -z "$ERRNO_H"; then
+      if test $gl_cv_func_strerror_r_posix_signature = yes; then
+        case "$gl_cv_func_strerror_r_works" in
+          dnl The system's strerror_r has bugs.  Replace it.
+          *no) REPLACE_STRERROR_R=1 ;;
+        esac
+      else
+        dnl The system's strerror() has a wrong signature. Replace it.
+        REPLACE_STRERROR_R=1
+      fi
+    else
+      dnl The system's strerror_r() cannot know about the new errno values we
+      dnl add to <errno.h>. Replace it.
+      REPLACE_STRERROR_R=1
+    fi
+  fi
+])
+
+# Prerequisites of lib/strerror_r.c.
+AC_DEFUN([gl_PREREQ_STRERROR_R], [
+  AC_CHECK_FUNCS_ONCE([catgets])
+  :
+])
+
+# Detect if strerror_r works, but without affecting whether a replacement
+# strerror_r will be used.
+AC_DEFUN([gl_FUNC_STRERROR_R_WORKS],
+[
+  AC_REQUIRE([gl_HEADER_STRING_H_DEFAULTS])
+  AC_REQUIRE([gl_HEADER_ERRNO_H])
+  AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
+
+  AC_CHECK_FUNCS_ONCE([strerror_r])
   if test $ac_cv_func_strerror_r = yes; then
     if test -z "$ERRNO_H"; then
       dnl The POSIX prototype is:  int strerror_r (int, char *, size_t);
@@ -85,25 +116,44 @@ changequote(,)dnl
 changequote([,])dnl
              ])
           ])
-        case "$gl_cv_func_strerror_r_works" in
-          *no) REPLACE_STRERROR_R=1 ;;
-        esac
       else
-        dnl The system's strerror() has a wrong signature. Replace it.
-        REPLACE_STRERROR_R=1
+        dnl The system's strerror() has a wrong signature.
         dnl glibc >= 2.3.4 and cygwin 1.7.9 have a function __xpg_strerror_r.
         AC_CHECK_FUNCS([__xpg_strerror_r])
+        dnl glibc < 2.14 does not populate buf on failure
+        dnl cygwin < 1.7.10 clobbers strerror
+        if test $ac_cv_func___xpg_strerror_r = yes; then
+          AC_CACHE_CHECK([whether strerror_r works],
+            [gl_cv_func_strerror_r_works],
+            [AC_RUN_IFELSE(
+               [AC_LANG_PROGRAM(
+                  [[#include <errno.h>
+                    #include <string.h>
+                    extern int __xpg_strerror_r(int, char *, size_t);
+                  ]],
+                  [[int result = 0;
+                    char buf[256] = "^";
+                    char copy[256];
+                    char *str = strerror (-1);
+                    strcpy (copy, str);
+                    if (__xpg_strerror_r (-2, buf, 1) == 0)
+                      result |= 1;
+                    if (*buf)
+                      result |= 2;
+                    __xpg_strerror_r (-2, buf, 256);
+                    if (strcmp (str, copy))
+                      result |= 4;
+                    return result;
+                  ]])],
+               [gl_cv_func_strerror_r_works=yes],
+               [gl_cv_func_strerror_r_works=no],
+               [dnl guess no on all platforms that have __xpg_strerror_r,
+                dnl at least until fixed glibc and cygwin are more common
+                gl_cv_func_strerror_r_works="guessing no"
+               ])
+            ])
+        fi
       fi
-    else
-      dnl The system's strerror_r() cannot know about the new errno values we
-      dnl add to <errno.h>. Replace it.
-      REPLACE_STRERROR_R=1
     fi
   fi
 ])
-
-# Prerequisites of lib/strerror_r.c.
-AC_DEFUN([gl_PREREQ_STRERROR_R], [
-  AC_CHECK_FUNCS_ONCE([catgets])
-  :
-])