perror: work around FreeBSD bug
authorEric Blake <eblake@redhat.com>
Fri, 20 May 2011 17:09:53 +0000 (11:09 -0600)
committerEric Blake <eblake@redhat.com>
Fri, 20 May 2011 18:01:05 +0000 (12:01 -0600)
POSIX requires that 'errno = 0; perror ("")' print the same message
as strerror(0), but this failed if we were replacing strerror to work
around the FreeBSD bug of treating 0 as a failure.

The goal here is to _not_ replace perror on glibc, even though
strerror_r has to be replaced, because the strerror_r replacement is
only for the sake of correcting the signature rather than working
around bugs in the handling of any particular errnum value.  Recall
that $gl_cv_func_strerror_r_works is only set if the POSIX signature
was detected in the first place.

* m4/perror.m4 (gl_FUNC_PERROR): Also replace perror if strerror_r
is broken.  Move AC_LIBOBJ...
* modules/perror (configure.ac): Here.
* doc/posix-functions/perror.texi (perror): Document this.
* tests/test-perror2.c (main): Enhance test.

Signed-off-by: Eric Blake <eblake@redhat.com>
ChangeLog
doc/posix-functions/perror.texi
m4/perror.m4
modules/perror
tests/test-perror2.c

index 5001637a60272b275813e3e8fa6f7d413501d735..e1f9b6773dc0c4e94cc9ed05053e91e404269f0c 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,12 @@
 2011-05-20  Eric Blake  <eblake@redhat.com>
 
+       perror: work around FreeBSD bug
+       * m4/perror.m4 (gl_FUNC_PERROR): Also replace perror if strerror_r
+       is broken.  Move AC_LIBOBJ...
+       * modules/perror (configure.ac): Here.
+       * doc/posix-functions/perror.texi (perror): Document this.
+       * tests/test-perror2.c (main): Enhance test.
+
        test-perror: check for strerror interactions
        * tests/macros.h (STREQ) Add macro.
        * modules/perror-tests (Files): Add second test.
index 29231064b3bc2952fb962778c7686e50329a95cc..cf6ac79d1c9568302a740582b82d5226926da167 100644 (file)
@@ -12,6 +12,10 @@ Portability problems fixed by Gnulib:
 This function does not support the error values that are specified by POSIX
 but not defined by the system, on some platforms:
 OpenBSD 4.0, OSF/1 5.1, Cygwin 1.5.x, mingw.
+@item
+This function treats @code{errno} of 0 like failure, although POSIX
+requires that the message declare it as a success, on some platforms:
+FreeBSD 8.2
 @end itemize
 
 Portability problems not fixed by Gnulib:
index 2a03e0809d1060bd0187583afdc4cb5c2f1e1917..d08f365e0782cd7586a30a0c4fd0bfdeba6dd1a5 100644 (file)
@@ -1,4 +1,4 @@
-# perror.m4 serial 1
+# perror.m4 serial 2
 dnl Copyright (C) 2008-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,10 +8,16 @@ AC_DEFUN([gl_FUNC_PERROR],
 [
   AC_REQUIRE([gl_STDIO_H_DEFAULTS])
   AC_REQUIRE([gl_HEADER_ERRNO_H])
+  AC_REQUIRE([gl_FUNC_STRERROR_R])
   if test -n "$ERRNO_H"; then
     dnl The system's perror() cannot know about the new errno values we add
     dnl to <errno.h>. Replace it.
     REPLACE_PERROR=1
-    AC_LIBOBJ([perror])
   fi
+  case ${gl_cv_func_strerror_r_works-unset} in
+    unset|*yes) ;;
+    *) dnl The system's perror() probably inherits the bugs in the
+       dnl system's strerror_r(). Replace it.
+      REPLACE_PERROR=1 ;;
+  esac
 ])
index af79a0d8e752231aa6cf4e9ccf29171621eacbb7..1ff9ec27e54a4d103435488187ff6d8750cf22fa 100644 (file)
@@ -16,6 +16,9 @@ strerror_r-posix [test $REPLACE_PERROR = 1]
 configure.ac:
 gl_FUNC_PERROR
 gl_STRING_MODULE_INDICATOR([perror])
+if test $REPLACE_PERROR = 1; then
+  AC_LIBOBJ([perror])
+fi
 
 Makefile.am:
 
index dfcabb4fb73c18e7cb1de602d37dd57e149d4246..fe5e33eba0a0065f19601c68dd29f81d32f7ff71 100644 (file)
@@ -88,6 +88,28 @@ main (void)
     ASSERT (STREQ (msg4, str4));
   }
 
+  /* Test that perror uses the same message as strerror.  */
+  {
+    int errs[] = { EACCES, 0, -3, };
+    int i;
+    for (i = 0; i < SIZEOF (errs); i++)
+      {
+        char buf[256];
+        char *err = strerror (errs[i]);
+
+        ASSERT (err);
+        ASSERT (strlen (err) < sizeof buf);
+        rewind (stderr);
+        ASSERT (ftruncate (fileno (stderr), 0) == 0);
+        errno = errs[i];
+        perror (NULL);
+        ASSERT (!ferror (stderr));
+        rewind (stderr);
+        ASSERT (fgets (buf, sizeof buf, stderr) == buf);
+        ASSERT (strstr (buf, err));
+      }
+  }
+
   /* Test that perror reports write failure.  */
   {
     ASSERT (freopen (BASE ".tmp", "r", stderr) == stderr);