From 19eb511ba4f4914c1914472132d3601069bef906 Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Wed, 9 Sep 2015 11:16:30 -0400 Subject: [PATCH] More g_strerror() fixes Add a check to configure.ac for strerror_r, since we don't currently require POSIX.1-2001 conformance in general. Add back a plain-strerror() case as a fallback, and rearrange the glibc-vs-POSIX strerror_r() branches. Update the docs to not claim that "not all platforms support the strerror() function" (we require C90), but still mention the UTF-8 and always-valid-string benefits. (And make test_strerror() check that last part.) https://bugzilla.gnome.org/show_bug.cgi?id=754788 --- configure.ac | 2 +- glib/gstrfuncs.c | 27 +++++++++++++++------------ glib/tests/strfuncs.c | 11 +++++++++++ 3 files changed, 27 insertions(+), 13 deletions(-) diff --git a/configure.ac b/configure.ac index 5cda0a763..ffca7a2ed 100644 --- a/configure.ac +++ b/configure.ac @@ -525,7 +525,7 @@ AM_CONDITIONAL(OS_WIN32_AND_DLL_COMPILATION, [test x$glib_native_win32 = xyes -a # Checks for library functions. AC_FUNC_ALLOCA AC_CHECK_FUNCS(mmap posix_memalign memalign valloc fsync pipe2 issetugid) -AC_CHECK_FUNCS(timegm gmtime_r) +AC_CHECK_FUNCS(timegm gmtime_r strerror_r) AC_CACHE_CHECK([for __libc_enable_secure], glib_cv_have_libc_enable_secure, [AC_TRY_LINK([#include diff --git a/glib/gstrfuncs.c b/glib/gstrfuncs.c index 2f0cda1dc..7d6e8ef86 100644 --- a/glib/gstrfuncs.c +++ b/glib/gstrfuncs.c @@ -1238,13 +1238,15 @@ g_ascii_strtoll (const gchar *nptr, * @errnum: the system error number. See the standard C %errno * documentation * - * Returns a string corresponding to the given error code, e.g. - * "no such process". You should use this function in preference to - * strerror(), because it returns a string in UTF-8 encoding, and since - * not all platforms support the strerror() function. + * Returns a string corresponding to the given error code, e.g. "no + * such process". Unlike strerror(), this always returns a string in + * UTF-8 encoding, and the pointer is guaranteed to remain valid for + * the lifetime of the process. * * Note that the string may be translated according to the current locale. * + * The value of %errno will not be changed by this function. + * * Returns: a UTF-8 string describing the error code. If the error code * is unknown, it returns a string like "unknown error ()". */ @@ -1258,19 +1260,20 @@ g_strerror (gint errnum) gint saved_errno = errno; GError *error = NULL; -#ifdef G_OS_WIN32 +#if defined(G_OS_WIN32) strerror_s (buf, sizeof (buf), errnum); msg = buf; - /* If we're using glibc, since we are building with _GNU_SOURCE, we - * expect to get the GNU variant of strerror_r. However, use the - * provided check from man strerror_r(3) in case we ever stop using - * _GNU_SOURCE (admittedly unlikely). - */ -#elif (defined __GLIBC__) && !((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && ! _GNU_SOURCE) +#elif defined(HAVE_STRERROR_R) + /* Match the condition in strerror_r(3) for glibc */ +# if defined(__GLIBC__) && !((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && ! _GNU_SOURCE) msg = strerror_r (errnum, buf, sizeof (buf)); -#else +# else strerror_r (errnum, buf, sizeof (buf)); msg = buf; +# endif /* HAVE_STRERROR_R */ +#else + g_strlcpy (buf, strerror (errnum), sizeof (buf)); + msg = buf; #endif if (!g_get_charset (NULL)) { diff --git a/glib/tests/strfuncs.c b/glib/tests/strfuncs.c index ad14a3c94..cbf5be7bb 100644 --- a/glib/tests/strfuncs.c +++ b/glib/tests/strfuncs.c @@ -1317,17 +1317,28 @@ test_strip_context (void) static void test_strerror (void) { + GHashTable *strs; gint i; const gchar *str; + GHashTableIter iter; setlocale (LC_ALL, "C"); + strs = g_hash_table_new (g_str_hash, g_str_equal); for (i = 1; i < 200; i++) { str = g_strerror (i); g_assert (str != NULL); g_assert (g_utf8_validate (str, -1, NULL)); + g_assert_false (g_hash_table_contains (strs, str)); + g_hash_table_add (strs, (char *)str); } + + g_hash_table_iter_init (&iter, strs); + while (g_hash_table_iter_next (&iter, (gpointer *)&str, NULL)) + g_assert (g_utf8_validate (str, -1, NULL)); + + g_hash_table_unref (strs); } static void