From d9559536909c5c8f819321cabc05f12652c7f9fd Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Wed, 8 Sep 2021 19:18:37 -0700 Subject: strerror_r-posix: port even better to Android MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * lib/strerror_r.c: Use STRERROR_R_CHAR_P to decide whether the system strerror_r returns char *, and HAVE_DECL_STRERROR_R to decide whether it either does that or returns an integer. In the former case, use the system strerror_r even on platforms like Android API level 23 that don’t have __xpg_strerror_r; also check for strerror_r failure just in case. * m4/error.m4 (gl_PREREQ_ERROR): * m4/strerror_r.m4 (gl_PREREQ_STRERROR_R): Use system extensions on Android, to avoid mishandling strerror_r on API level 23 and later. * modules/error, modules/strerror_r-posix (configure.ac): Surround gl_PREREQ_ERROR with AS_IF instead of plain if, so that AC_REQUIREs are propagated out. --- ChangeLog | 15 +++++++++++++++ lib/strerror_r.c | 35 +++++++++++++++++------------------ m4/error.m4 | 6 +++++- m4/strerror_r.m4 | 3 ++- modules/error | 4 ++-- modules/strerror_r-posix | 4 ++-- 6 files changed, 43 insertions(+), 24 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1db7e333bc..7c56ed2a2f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,20 @@ 2021-09-08 Paul Eggert + strerror_r-posix: port even better to Android + * lib/strerror_r.c: Use STRERROR_R_CHAR_P to decide whether the + system strerror_r returns char *, and HAVE_DECL_STRERROR_R to + decide whether it either does that or returns an integer. In the + former case, use the system strerror_r even on platforms like + Android API level 23 that don’t have __xpg_strerror_r; also + check for strerror_r failure just in case. + * m4/error.m4 (gl_PREREQ_ERROR): + * m4/strerror_r.m4 (gl_PREREQ_STRERROR_R): + Use system extensions on Android, to avoid mishandling strerror_r + on API level 23 and later. + * modules/error, modules/strerror_r-posix (configure.ac): + Surround gl_PREREQ_ERROR with AS_IF instead of plain if, so that + AC_REQUIREs are propagated out. + strerror_r-posix: port better to Android * m4/strerror_r.m4 (gl_FUNC_STRERROR_R): Move requirement of gl_USE_SYSTEM_EXTENSIONS from here ... diff --git a/lib/strerror_r.c b/lib/strerror_r.c index f0244520b1..90043c2237 100644 --- a/lib/strerror_r.c +++ b/lib/strerror_r.c @@ -34,33 +34,26 @@ #include "strerror-override.h" -#if (__GLIBC__ >= 2 || defined __UCLIBC__ || defined __CYGWIN__) && HAVE___XPG_STRERROR_R /* glibc >= 2.3.4, cygwin >= 1.7.9 */ +#if STRERROR_R_CHAR_P -# define USE_XPG_STRERROR_R 1 -extern -#ifdef __cplusplus -"C" -#endif -int __xpg_strerror_r (int errnum, char *buf, size_t buflen); +# if HAVE___XPG_STRERROR_R +_GL_EXTERN_C int __xpg_strerror_r (int errnum, char *buf, size_t buflen); +# endif -#elif HAVE_DECL_STRERROR_R && !(__GLIBC__ >= 2 || defined __UCLIBC__ || defined __CYGWIN__) +#elif HAVE_DECL_STRERROR_R -/* The system's strerror_r function is OK, except that its third argument +/* The system's strerror_r function's API is OK, except that its third argument is 'int', not 'size_t', or its return type is wrong. */ # include -# define USE_SYSTEM_STRERROR_R 1 - -#else /* (__GLIBC__ >= 2 || defined __UCLIBC__ || defined __CYGWIN__ ? !HAVE___XPG_STRERROR_R : !HAVE_DECL_STRERROR_R) */ +#else /* Use the system's strerror(). Exclude glibc and cygwin because the system strerror_r has the wrong return type, and cygwin 1.7.9 strerror_r clobbers strerror. */ # undef strerror -# define USE_SYSTEM_STRERROR 1 - # if defined __NetBSD__ || defined __hpux || (defined _WIN32 && !defined __CYGWIN__) || defined __sgi || (defined __sun && !defined _LP64) || defined __CYGWIN__ /* No locking needed. */ @@ -166,22 +159,28 @@ strerror_r (int errnum, char *buf, size_t buflen) int ret; int saved_errno = errno; -#if USE_XPG_STRERROR_R +#if STRERROR_R_CHAR_P { + ret = 0; + +# if HAVE___XPG_STRERROR_R ret = __xpg_strerror_r (errnum, buf, buflen); if (ret < 0) ret = errno; +# endif + if (!*buf) { /* glibc 2.13 would not touch buf on err, so we have to fall back to GNU strerror_r which always returns a thread-safe untruncated string to (partially) copy into our buf. */ - safe_copy (buf, buflen, strerror_r (errnum, buf, buflen)); + char *errstring = strerror_r (errnum, buf, buflen); + ret = errstring ? safe_copy (buf, buflen, errstring) : errno; } } -#elif USE_SYSTEM_STRERROR_R +#elif HAVE_DECL_STRERROR_R if (buflen > INT_MAX) buflen = INT_MAX; @@ -245,7 +244,7 @@ strerror_r (int errnum, char *buf, size_t buflen) } # endif -#else /* USE_SYSTEM_STRERROR */ +#else /* strerror_r is not declared. */ /* Try to do what strerror (errnum) does, but without clobbering the buffer used by strerror(). */ diff --git a/m4/error.m4 b/m4/error.m4 index 77f67f78b0..8e3cf95d94 100644 --- a/m4/error.m4 +++ b/m4/error.m4 @@ -1,4 +1,4 @@ -#serial 14 +#serial 15 # Copyright (C) 1996-1998, 2001-2004, 2009-2021 Free Software Foundation, Inc. # @@ -22,6 +22,10 @@ AC_DEFUN([gl_ERROR], # Prerequisites of lib/error.c. AC_DEFUN([gl_PREREQ_ERROR], [ + dnl Use system extensions on Android, so that AC_FUNC_STRERROR_R + dnl discovers the GNU API for strerror_r on Android API level 23 and later. + AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS]) + AC_REQUIRE([AC_FUNC_STRERROR_R]) : ]) diff --git a/m4/strerror_r.m4 b/m4/strerror_r.m4 index 29b309221f..bc40ec294b 100644 --- a/m4/strerror_r.m4 +++ b/m4/strerror_r.m4 @@ -1,4 +1,4 @@ -# strerror_r.m4 serial 22 +# strerror_r.m4 serial 23 dnl Copyright (C) 2002, 2007-2021 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -37,6 +37,7 @@ AC_DEFUN([gl_FUNC_STRERROR_R], # Prerequisites of lib/strerror_r.c. AC_DEFUN([gl_PREREQ_STRERROR_R], [ + AC_REQUIRE([AC_FUNC_STRERROR_R]) dnl glibc >= 2.3.4 and cygwin 1.7.9 have a function __xpg_strerror_r. AC_CHECK_FUNCS_ONCE([__xpg_strerror_r]) AC_CHECK_FUNCS_ONCE([catgets]) diff --git a/modules/error b/modules/error index 2945c48454..08370da770 100644 --- a/modules/error +++ b/modules/error @@ -15,10 +15,10 @@ msvc-nothrow [test $ac_cv_lib_error_at_line = no] configure.ac: gl_ERROR -if test $ac_cv_lib_error_at_line = no; then +AS_IF([test "$ac_cv_lib_error_at_line" = no], [ AC_LIBOBJ([error]) gl_PREREQ_ERROR -fi +]) m4_ifdef([AM_XGETTEXT_OPTION], [AM_][XGETTEXT_OPTION([--flag=error:3:c-format]) AM_][XGETTEXT_OPTION([--flag=error_at_line:5:c-format])]) diff --git a/modules/strerror_r-posix b/modules/strerror_r-posix index f91bc0e7cc..25f049365a 100644 --- a/modules/strerror_r-posix +++ b/modules/strerror_r-posix @@ -14,10 +14,10 @@ strerror-override [test $HAVE_DECL_STRERROR_R = 0 || test $REPLACE_STRERROR_R = configure.ac: gl_FUNC_STRERROR_R -if test $HAVE_DECL_STRERROR_R = 0 || test $REPLACE_STRERROR_R = 1; then +AS_IF([test $HAVE_DECL_STRERROR_R = 0 || test $REPLACE_STRERROR_R = 1], [ AC_LIBOBJ([strerror_r]) gl_PREREQ_STRERROR_R -fi +]) gl_STRING_MODULE_INDICATOR([strerror_r]) dnl For the modules argp, error. gl_MODULE_INDICATOR([strerror_r-posix]) -- cgit v1.2.1