From 4018d9e0e5fcaf2a7ee10309a49adc9364f67561 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Mon, 6 Jun 2011 17:59:01 -0600 Subject: [PATCH] strerror_r-posix: work around cygwin 1.7.9 Cygwin __xpg_strerror_r clobbers strerror, until cygwin 1.7.10; in this case, we must replace strerror, but there was nothing in strerror.m4 finding fault with cygwin's native strerror. Solve this by splitting strerror_r.m4 into two parts, one for probing for the strerror_r bug, and one for replacing strerror_r based on the presence of bugs unrelated to signature issues; that way, the 'strerror' module in isolation will not replace strerror, but if strerror_r is in use for any other reason, then the two use separate buffers. Note that cygwin's strerror is thread-safe while the gnulib replacement is not; but this is no worse than any other platform where strerror is not thread-safe; in a single-threaded program, the difference is not observable, and in a multi-threaded program, you really shouldn't be using strerror in the first place. Also note that this ends up replacing glibc 2.13 strerror as it deems __xpg_strerror_r broken on that platform, which isn't technically necessary for strerror, but doesn't hurt too much. Meanwhile, glibc 2.14 fixed __xpg_strerror_r, and strerror is not replaced in that scenario. * m4/strerror_r.m4 (gl_FUNC_STRERROR_R): Split... (gl_FUNC_STRERROR_R_WORKS): ...into new macro, to detect Cygwin bug without replacing strerror_r. * m4/strerror.m4 (gl_FUNC_STRERROR): Replace strerror if strerror_r is buggy, but without requiring strerror_r compilation. * doc/posix-functions/strerror_r.texi (strerror_r): Fix docs. Signed-off-by: Eric Blake --- ChangeLog | 8 +++ doc/posix-functions/strerror_r.texi | 4 -- m4/strerror.m4 | 9 ++- m4/strerror_r.m4 | 90 ++++++++++++++++++++++------- 4 files changed, 86 insertions(+), 25 deletions(-) diff --git a/ChangeLog b/ChangeLog index 870ec7333e..af211551b5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,13 @@ 2011-06-07 Eric Blake + strerror_r-posix: work around cygwin 1.7.9 + * m4/strerror_r.m4 (gl_FUNC_STRERROR_R): Split... + (gl_FUNC_STRERROR_R_WORKS): ...into new macro, to detect Cygwin + bug without replacing strerror_r. + * m4/strerror.m4 (gl_FUNC_STRERROR): Replace strerror if + strerror_r is buggy, but without requiring strerror_r compilation. + * doc/posix-functions/strerror_r.texi (strerror_r): Fix docs. + test-perror: relax test to ignore cygwin bug * tests/test-perror2.c (main): Relax test on requiring detection of stream errors, and use unbuffered stream. diff --git a/doc/posix-functions/strerror_r.texi b/doc/posix-functions/strerror_r.texi index e0f19c01ef..4169ca9abf 100644 --- a/doc/posix-functions/strerror_r.texi +++ b/doc/posix-functions/strerror_r.texi @@ -64,8 +64,4 @@ glibc 2.13, FreeBSD 8.2, Solaris 10. Portability problems not fixed by Gnulib: @itemize -@item -Calling this function can clobber the buffer used by @code{strerror} -on some platforms: -Cygwin 1.7.9. @end itemize diff --git a/m4/strerror.m4 b/m4/strerror.m4 index 25edd91367..de4ba9674b 100644 --- a/m4/strerror.m4 +++ b/m4/strerror.m4 @@ -1,4 +1,4 @@ -# strerror.m4 serial 12 +# strerror.m4 serial 13 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, @@ -8,6 +8,9 @@ AC_DEFUN([gl_FUNC_STRERROR], [ AC_REQUIRE([gl_HEADER_STRING_H_DEFAULTS]) AC_REQUIRE([gl_HEADER_ERRNO_H]) + m4_ifdef([gl_FUNC_STRERROR_R_WORKS], [ + AC_REQUIRE([gl_FUNC_STRERROR_R_WORKS]) + ]) if test -z "$ERRNO_H"; then AC_CACHE_CHECK([for working strerror function], [gl_cv_func_working_strerror], @@ -32,6 +35,10 @@ AC_DEFUN([gl_FUNC_STRERROR], dnl integers. Replace it. REPLACE_STRERROR=1 fi + dnl If the system's strerror_r clobbers strerror, we must replace strerror. + case $gl_cv_func_strerror_r_works in + *no) REPLACE_STRERROR=1 ;; + esac else dnl The system's strerror() cannot know about the new errno values we add dnl to . Replace it. diff --git a/m4/strerror_r.m4 b/m4/strerror_r.m4 index 1c0af3691d..c1d1a8eb05 100644 --- a/m4/strerror_r.m4 +++ b/m4/strerror_r.m4 @@ -1,4 +1,4 @@ -# strerror_r.m4 serial 9 +# strerror_r.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, @@ -6,9 +6,7 @@ dnl with or without modifications, as long as this notice is preserved. AC_DEFUN([gl_FUNC_STRERROR_R], [ - AC_REQUIRE([gl_HEADER_STRING_H_DEFAULTS]) - AC_REQUIRE([gl_HEADER_ERRNO_H]) - AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles + AC_REQUIRE([gl_FUNC_STRERROR_R_WORKS]) dnl Persuade Solaris to declare strerror_r(). AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS]) @@ -20,7 +18,40 @@ AC_DEFUN([gl_FUNC_STRERROR_R], HAVE_DECL_STRERROR_R=0 fi - AC_CHECK_FUNCS([strerror_r]) + if test $ac_cv_func_strerror_r = yes; then + if test -z "$ERRNO_H"; then + if test $gl_cv_func_strerror_r_posix_signature = yes; then + case "$gl_cv_func_strerror_r_works" in + dnl The system's strerror_r has bugs. Replace it. + *no) REPLACE_STRERROR_R=1 ;; + esac + else + dnl The system's strerror() has a wrong signature. Replace it. + REPLACE_STRERROR_R=1 + fi + else + dnl The system's strerror_r() cannot know about the new errno values we + dnl add to . Replace it. + REPLACE_STRERROR_R=1 + fi + fi +]) + +# Prerequisites of lib/strerror_r.c. +AC_DEFUN([gl_PREREQ_STRERROR_R], [ + AC_CHECK_FUNCS_ONCE([catgets]) + : +]) + +# Detect if strerror_r works, but without affecting whether a replacement +# strerror_r will be used. +AC_DEFUN([gl_FUNC_STRERROR_R_WORKS], +[ + AC_REQUIRE([gl_HEADER_STRING_H_DEFAULTS]) + AC_REQUIRE([gl_HEADER_ERRNO_H]) + AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles + + AC_CHECK_FUNCS_ONCE([strerror_r]) if test $ac_cv_func_strerror_r = yes; then if test -z "$ERRNO_H"; then dnl The POSIX prototype is: int strerror_r (int, char *, size_t); @@ -85,25 +116,44 @@ changequote(,)dnl changequote([,])dnl ]) ]) - case "$gl_cv_func_strerror_r_works" in - *no) REPLACE_STRERROR_R=1 ;; - esac else - dnl The system's strerror() has a wrong signature. Replace it. - REPLACE_STRERROR_R=1 + dnl The system's strerror() has a wrong signature. dnl glibc >= 2.3.4 and cygwin 1.7.9 have a function __xpg_strerror_r. AC_CHECK_FUNCS([__xpg_strerror_r]) + dnl glibc < 2.14 does not populate buf on failure + dnl cygwin < 1.7.10 clobbers strerror + if test $ac_cv_func___xpg_strerror_r = yes; then + AC_CACHE_CHECK([whether strerror_r works], + [gl_cv_func_strerror_r_works], + [AC_RUN_IFELSE( + [AC_LANG_PROGRAM( + [[#include + #include + extern int __xpg_strerror_r(int, char *, size_t); + ]], + [[int result = 0; + char buf[256] = "^"; + char copy[256]; + char *str = strerror (-1); + strcpy (copy, str); + if (__xpg_strerror_r (-2, buf, 1) == 0) + result |= 1; + if (*buf) + result |= 2; + __xpg_strerror_r (-2, buf, 256); + if (strcmp (str, copy)) + result |= 4; + return result; + ]])], + [gl_cv_func_strerror_r_works=yes], + [gl_cv_func_strerror_r_works=no], + [dnl guess no on all platforms that have __xpg_strerror_r, + dnl at least until fixed glibc and cygwin are more common + gl_cv_func_strerror_r_works="guessing no" + ]) + ]) + fi fi - else - dnl The system's strerror_r() cannot know about the new errno values we - dnl add to . Replace it. - REPLACE_STRERROR_R=1 fi fi ]) - -# Prerequisites of lib/strerror_r.c. -AC_DEFUN([gl_PREREQ_STRERROR_R], [ - AC_CHECK_FUNCS_ONCE([catgets]) - : -]) -- 2.30.2