bug-gnulib
[Top][All Lists]
Advanced

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

[PATCH] strerror: enforce POSIX ruling on strerror(0)


From: Eric Blake
Subject: [PATCH] strerror: enforce POSIX ruling on strerror(0)
Date: Thu, 19 May 2011 09:34:26 -0600

http://austingroupbugs.net/view.php?id=382 requires that strerror(0)
succeed, but FreeBSD reports "Unknown error: 0" and fails with EINVAL.

* m4/strerror.m4 (gl_FUNC_STRERROR_SEPARATE): Expose BSD bug.
* m4/strerror_r.m4 (gl_FUNC_STRERROR_R): Likewise.
* lib/strerror_r.c (rpl_strerror_r): Work around it.
* doc/posix-functions/strerror.texi (strerror): Document it.
* doc/posix-functions/strerror_r.texi (strerror_r): Likewise.
* tests/test-strerror.c (main): Strengthen test.
* tests/test-strerror_r.c (main): Likewise.

Signed-off-by: Eric Blake <address@hidden>
---
 ChangeLog                           |   11 +++++++++++
 doc/posix-functions/strerror.texi   |   11 +++++++++--
 doc/posix-functions/strerror_r.texi |    4 ++++
 lib/strerror_r.c                    |   16 ++++++++++++++++
 m4/strerror.m4                      |   21 ++++++++++-----------
 m4/strerror_r.m4                    |   14 +++++++++++---
 tests/test-strerror.c               |   20 +++++++++++++++++++-
 tests/test-strerror_r.c             |   16 ++++++++++------
 8 files changed, 90 insertions(+), 23 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index b21dc1b..8c1200c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2011-05-19  Eric Blake  <address@hidden>
+
+       strerror: enforce POSIX ruling on strerror(0)
+       * m4/strerror.m4 (gl_FUNC_STRERROR_SEPARATE): Expose BSD bug.
+       * m4/strerror_r.m4 (gl_FUNC_STRERROR_R): Likewise.
+       * lib/strerror_r.c (rpl_strerror_r): Work around it.
+       * doc/posix-functions/strerror.texi (strerror): Document it.
+       * doc/posix-functions/strerror_r.texi (strerror_r): Likewise.
+       * tests/test-strerror.c (main): Strengthen test.
+       * tests/test-strerror_r.c (main): Likewise.
+
 2011-05-19  Paul Eggert  <address@hidden>

        intprop-tests: port to older and more-pedantic compilers
diff --git a/doc/posix-functions/strerror.texi 
b/doc/posix-functions/strerror.texi
index 68a98da..6f9519a 100644
--- a/doc/posix-functions/strerror.texi
+++ b/doc/posix-functions/strerror.texi
@@ -13,11 +13,18 @@ strerror
 but not defined by the system, on some platforms:
 OpenBSD 4.0, OSF/1 5.1, NonStop Kernel, Cygwin 1.5.x, mingw.
 @item
+This function reports failure (by setting @code{errno}) for
address@hidden(0)}, although POSIX requires this to leave @code{errno}
+unchanged and report success, on some platforms:
+FreeBSD 8.2
address@hidden
 This function fails to return a string for out-of-range integers on
 some platforms:
 HP-UX 11, IRIX 6.5, Solaris 8.
-(This is not a POSIX violation, but can still cause bugs because most programs
-call @code{strerror} without setting and testing @code{errno}.)
+(Some return NULL which is a POSIX violation, others return the empty
+string which is valid but not as useful); this can still cause bugs
+because most programs call @code{strerror} without setting and testing
address@hidden)
 @end itemize

 Portability problems not fixed by Gnulib:
diff --git a/doc/posix-functions/strerror_r.texi 
b/doc/posix-functions/strerror_r.texi
index bf43164..9d6639e 100644
--- a/doc/posix-functions/strerror_r.texi
+++ b/doc/posix-functions/strerror_r.texi
@@ -37,6 +37,10 @@ strerror_r
 but not defined by the system, on some platforms:
 OpenBSD 4.0, OSF/1 5.1, NonStop Kernel, Cygwin 1.5.x.
 @item
+This function reports failure for @code{strerror_r(0, buf, len)},
+although POSIX requires this to succeed, on some platforms:
+FreeBSD 8.2
address@hidden
 This function always fails when the third argument is less than 80 on some
 platforms:
 HP-UX 11.31.
diff --git a/lib/strerror_r.c b/lib/strerror_r.c
index 3bba26c..fc0603c 100644
--- a/lib/strerror_r.c
+++ b/lib/strerror_r.c
@@ -436,6 +436,22 @@ strerror_r (int errnum, char *buf, size_t buflen)
     if (ret < 0)
       ret = errno;

+    /* FreeBSD rejects 0; see http://austingroupbugs.net/view.php?id=382.  */
+    if (errnum == 0 && ret == EINVAL)
+      {
+        if (buflen <= strlen ("Success"))
+          {
+            ret = ERANGE;
+            if (buflen)
+              buf[0] = 0;
+          }
+        else
+          {
+            ret = 0;
+            strcpy (buf, "Success");
+          }
+      }
+
 #elif USE_XPG_STRERROR_R

     {
diff --git a/m4/strerror.m4 b/m4/strerror.m4
index 73d1d54..d891031 100644
--- a/m4/strerror.m4
+++ b/m4/strerror.m4
@@ -1,4 +1,4 @@
-# strerror.m4 serial 9
+# strerror.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,
@@ -25,19 +25,18 @@ AC_DEFUN([gl_FUNC_STRERROR_SEPARATE],
      [AC_RUN_IFELSE(
         [AC_LANG_PROGRAM(
            [[#include <string.h>
+             #include <errno.h>
            ]],
-           [[return !*strerror (-2);]])],
+           [[int result = 0;
+             if (!*strerror (-2)) result |= 1;
+             errno = 0;
+             if (!*strerror (0)) result |= 2;
+             if (errno) result |= 4;
+             return result;]])],
         [gl_cv_func_working_strerror=yes],
         [gl_cv_func_working_strerror=no],
-        [dnl Assume crossbuild works if it compiles.
-         AC_COMPILE_IFELSE(
-           [AC_LANG_PROGRAM(
-              [[#include <string.h>
-              ]],
-              [[return !*strerror (-2);]])],
-           [gl_cv_func_working_strerror=yes],
-           [gl_cv_func_working_strerror=no])
-      ])
+        [dnl Be pessimistic on cross-compiles for now.
+         gl_cv_func_working_strerror=no])
     ])
     if test $gl_cv_func_working_strerror = no; then
       dnl The system's strerror() fails to return a string for out-of-range
diff --git a/m4/strerror_r.m4 b/m4/strerror_r.m4
index 1883458..ca3904c 100644
--- a/m4/strerror_r.m4
+++ b/m4/strerror_r.m4
@@ -1,4 +1,4 @@
-# strerror_r.m4 serial 3
+# strerror_r.m4 serial 4
 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,
@@ -41,6 +41,7 @@ AC_DEFUN([gl_FUNC_STRERROR_R],
         dnl AIX 6.1 strerror_r fails by returning -1, not an error number.
         dnl HP-UX 11.31 strerror_r always fails when the buffer length argument
         dnl is less than 80.
+        dnl FreeBSD 8.s strerror_r claims failure on 0
         AC_CACHE_CHECK([whether strerror_r works],
           [gl_cv_func_strerror_r_works],
           [AC_RUN_IFELSE(
@@ -53,8 +54,13 @@ AC_DEFUN([gl_FUNC_STRERROR_R],
                   char buf[79];
                   if (strerror_r (EACCES, buf, 0) < 0)
                     result |= 1;
-                  if (strerror_r (EACCES, buf, sizeof (buf)) != 0)
+                  errno = 0;
+                  if (strerror_r (EACCES, buf, sizeof buf) != 0)
                     result |= 2;
+                  if (strerror_r (0, buf, sizeof buf) != 0)
+                    result |= 4;
+                  if (errno)
+                    result |= 8;
                   return result;
                 ]])],
              [gl_cv_func_strerror_r_works=yes],
@@ -66,6 +72,8 @@ changequote(,)dnl
                 aix*)  gl_cv_func_strerror_r_works="guessing no";;
                        # Guess no on HP-UX.
                 hpux*) gl_cv_func_strerror_r_works="guessing no";;
+                       # Guess no on FreeBSD.
+                freebsd*)  gl_cv_func_strerror_r_works="guessing no";;
                        # Guess yes otherwise.
                 *)     gl_cv_func_strerror_r_works="guessing yes";;
               esac
@@ -78,7 +86,7 @@ changequote([,])dnl
       else
         dnl The system's strerror() has a wrong signature. Replace it.
         REPLACE_STRERROR_R=1
-        dnl glibc >= 2.3.4 has a function __xpg_strerror_r.
+        dnl glibc >= 2.3.4 and cygwin 1.7.9 have a function __xpg_strerror_r.
         AC_CHECK_FUNCS([__xpg_strerror_r])
       fi
     else
diff --git a/tests/test-strerror.c b/tests/test-strerror.c
index 66dbe82..46d339e 100644
--- a/tests/test-strerror.c
+++ b/tests/test-strerror.c
@@ -33,25 +33,43 @@ main (void)
 {
   char *str;

+  errno = 0;
   str = strerror (EACCES);
   ASSERT (str);
   ASSERT (*str);
+  ASSERT (errno == 0);

+  errno = 0;
   str = strerror (ETIMEDOUT);
   ASSERT (str);
   ASSERT (*str);
+  ASSERT (errno == 0);

+  errno = 0;
   str = strerror (EOVERFLOW);
   ASSERT (str);
   ASSERT (*str);
+  ASSERT (errno == 0);

+  /* POSIX requires strerror (0) to succeed; use of "Unknown error" or
+     "error 0" does not count as success, but "No error" works.
+     http://austingroupbugs.net/view.php?id=382  */
+  errno = 0;
   str = strerror (0);
   ASSERT (str);
   ASSERT (*str);
-
+  ASSERT (errno == 0);
+  ASSERT (strchr (str, '0') == NULL);
+  ASSERT (strstr (str, "nknown") == NULL);
+
+  /* POSIX requires strerror to produce a non-NULL result for all
+     inputs; as an extension, we also guarantee a non-empty reseult.
+     Reporting EINVAL is optional.  */
+  errno = 0;
   str = strerror (-3);
   ASSERT (str);
   ASSERT (*str);
+  ASSERT (errno == 0 || errno == EINVAL);

   return 0;
 }
diff --git a/tests/test-strerror_r.c b/tests/test-strerror_r.c
index b2fdaf9..0661bdf 100644
--- a/tests/test-strerror_r.c
+++ b/tests/test-strerror_r.c
@@ -46,13 +46,17 @@ main (void)
   ASSERT (strerror_r (EOVERFLOW, buf, sizeof (buf)) == 0);
   ASSERT (buf[0] != '\0');

-  /* Test results with out-of-range errnum and enough room.  */
-
-  buf[0] = '^';
+  /* POSIX requires strerror (0) to succeed; use of "Unknown error" or
+     "error 0" does not count as success, but "No error" works.
+     http://austingroupbugs.net/view.php?id=382  */
+  buf[0] = '\0';
   ret = strerror_r (0, buf, sizeof (buf));
-  ASSERT (ret == 0 || ret == EINVAL);
-  if (ret == 0)
-    ASSERT (buf[0] != '^');
+  ASSERT (ret == 0);
+  ASSERT (buf[0]);
+  ASSERT (strchr (buf, '0') == NULL);
+  ASSERT (strstr (buf, "nknown") == NULL);
+
+  /* Test results with out-of-range errnum and enough room.  */

   buf[0] = '^';
   ret = strerror_r (-3, buf, sizeof (buf));
-- 
1.7.4.4




reply via email to

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