+2011-05-19 Eric Blake <eblake@redhat.com>
+
+ 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 <eggert@cs.ucla.edu>
intprop-tests: port to older and more-pedantic compilers
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
+@code{strerror(0)}, although POSIX requires this to leave @code{errno}
+unchanged and report success, on some platforms:
+FreeBSD 8.2
+@item
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
+@code{errno}.)
@end itemize
Portability problems not fixed by Gnulib:
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
+@item
This function always fails when the third argument is less than 80 on some
platforms:
HP-UX 11.31.
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
{
-# 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,
[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
-# 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,
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(
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],
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
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
{
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;
}
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));