changeset 15309:8254c6270130

strerror_r: fix OpenBSD behavior on out-of-range 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>
author Eric Blake <eblake@redhat.com>
date Tue, 21 Jun 2011 10:00:55 -0600
parents a3ba680ad389
children edde4951a1a8
files ChangeLog doc/posix-functions/strerror_r.texi lib/strerror_r.c
diffstat 3 files changed, 28 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- 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.
--- a/doc/posix-functions/strerror_r.texi
+++ b/doc/posix-functions/strerror_r.texi
@@ -64,6 +64,11 @@
 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:
--- a/lib/strerror_r.c
+++ b/lib/strerror_r.c
@@ -175,17 +175,11 @@
         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 @@
         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 */