strerror_r: fix OpenBSD behavior on out-of-range
authorEric Blake <eblake@redhat.com>
Tue, 21 Jun 2011 16:00:55 +0000 (10:00 -0600)
committerEric Blake <eblake@redhat.com>
Tue, 21 Jun 2011 17:06:12 +0000 (11:06 -0600)
On OpenBSD, strerror_r(1000,buf,19) gives "Unknown error: " rather
than "Unknown error: 100" while failing with ERANGE.  Admittedly,
this behavior is nice, since a truncated integer is misleading,
but all other platforms use maximal strings on ERANGE and we are
already replacing strerror_r for other reasons, so it is easier
to work around this behavior than to adjust the testsuite (how
do you quickly decide if the only reason that the ERANGE string
was shorter than maximal was because the implementation avoided
truncating an integer?).

This patch intentionally avoids dragging in the strnlen module.

* lib/strerror_r.c (strerror_r): Always use maximal string.
* doc/posix-functions/strerror_r.texi (strerror_r): Document it.

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

index 70c1903d45d68a4a8c51e103670dd3ae42a74e27..07f38198f4620a0c16ea90ae37b527e53c21db5c 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,9 @@
 2011-06-21  Eric Blake  <eblake@redhat.com>
 
+       strerror_r: fix OpenBSD behavior on out-of-range
+       * lib/strerror_r.c (strerror_r): Always use maximal string.
+       * doc/posix-functions/strerror_r.texi (strerror_r): Document it.
+
        strerror_r: fix OpenBSD behavior on 0
        * lib/strerror-override.c (strerror_override): Also override 0
        when needed.
index 5aaa1c64128b13a01ce65075830abb63bd0242d1..08b59ec0b094b9e46eb7e230d1b374792ea3cefe 100644 (file)
@@ -64,6 +64,11 @@ When the value is not in range or the buffer is too small, this
 function fails to leave a NUL-terminated string in the buffer on some
 platforms:
 glibc 2.13, FreeBSD 8.2, Solaris 10.
+@item
+When the value is out of range but the buffer is too small, this
+function does not always return the longest possible string on some
+platforms:
+OpenBSD 4.7.
 @end itemize
 
 Portability problems not fixed by Gnulib:
index 0da9ba25e083868765f06d7843d975097af5ff76..2b3f1f267e2a671019b5e2709aa9d5c42aa47991 100644 (file)
@@ -175,17 +175,11 @@ strerror_r (int errnum, char *buf, size_t buflen)
         ret = strerror_r (errnum, buf, buflen);
     }
 # else
-    /* Solaris 10 does not populate buf on ERANGE.  */
     ret = strerror_r (errnum, buf, buflen);
-    if (ret == ERANGE && !*buf)
-      {
-        char stackbuf[STACKBUF_LEN];
 
-        if (strerror_r (errnum, stackbuf, sizeof stackbuf) == ERANGE)
-          /* STACKBUF_LEN should have been large enough.  */
-          abort ();
-        safe_copy (buf, buflen, stackbuf);
-      }
+    /* Some old implementations may return (-1, EINVAL) instead of EINVAL.  */
+    if (ret < 0)
+      ret = errno;
 # endif
 
 # ifdef _AIX
@@ -203,11 +197,23 @@ strerror_r (int errnum, char *buf, size_t buflen)
         if (buflen <= len)
           ret = ERANGE;
       }
-# endif
+# else
+    /* Solaris 10 does not populate buf on ERANGE.  OpenBSD 4.7
+       truncates early on ERANGE rather than return a partial integer.
+       We prefer the maximal string.  We set buf[0] earlier, and we
+       know of no implementation that modifies buf to be an
+       unterminated string, so this strlen should be portable in
+       practice (rather than pulling in a safer strnlen).  */
+    if (ret == ERANGE && strlen (buf) < buflen - 1)
+      {
+        char stackbuf[STACKBUF_LEN];
 
-    /* Some old implementations may return (-1, EINVAL) instead of EINVAL.  */
-    if (ret < 0)
-      ret = errno;
+        /* STACKBUF_LEN should have been large enough.  */
+        if (strerror_r (errnum, stackbuf, sizeof stackbuf) == ERANGE)
+          abort ();
+        safe_copy (buf, buflen, stackbuf);
+      }
+# endif
 
 #else /* USE_SYSTEM_STRERROR */