string: Implement strerror in terms of strerror_l

If the thread is terminated then __libc_thread_freeres will free the
storage via __glibc_tls_internal_free.

It is only within the calling thread that this matters.  It makes
strerror MT-safe.

Checked on x86-64-linux-gnu, i686-linux-gnu, powerpc64le-linux-gnu,
and s390x-linux-gnu.

Tested-by: Carlos O'Donell <carlos@redhat.com>
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
This commit is contained in:
Adhemerval Zanella 2020-05-14 17:44:15 -03:00
parent 9deec7c8ba
commit 28aff04781
5 changed files with 24 additions and 26 deletions

5
NEWS
View File

@ -79,6 +79,11 @@ Deprecated and removed features, and other changes affecting compatibility:
compatibility symbols to support old binaries. All programs should use
strerror or strerror_r instead.
* Both strerror and strerror_l now share the same internal buffer in the
calling thread, meaning that the returned string pointer may be invalided
or contents might be overwritten on subsequent calls in the same thread or
if the thread is terminated. It makes strerror MT-safe.
Changes to build and runtime requirements:
* powerpc64le requires GCC 7.4 or newer. This is required for supporting

View File

@ -4,6 +4,7 @@
/* Some of these are defined as macros in the real string.h, so we must
prototype them before including it. */
#include <sys/types.h>
#include <locale.h>
extern void *__memccpy (void *__dest, const void *__src,
int __c, size_t __n);
@ -50,6 +51,8 @@ extern int __ffs (int __i) __attribute__ ((const));
extern char *__strerror_r (int __errnum, char *__buf, size_t __buflen);
extern char *__strerror_l (int __errnum, locale_t __loc);
/* Called as part of the thread shutdown sequence. */
void __strerror_thread_freeres (void) attribute_hidden;
@ -113,6 +116,7 @@ libc_hidden_proto (memmem)
extern __typeof (memmem) __memmem;
libc_hidden_proto (__memmem)
libc_hidden_proto (__ffs)
libc_hidden_proto (__strerror_l)
#if IS_IN (libc)
/* Avoid hidden reference to IFUNC symbol __explicit_bzero_chk. */

View File

@ -15,29 +15,11 @@
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#include <libintl.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
/* Return a string describing the errno code in ERRNUM.
The storage is good only until the next call to strerror.
Writing to the storage causes undefined behavior. */
libc_freeres_ptr (static char *buf);
#include <locale/localeinfo.h>
char *
strerror (int errnum)
{
char *ret = __strerror_r (errnum, NULL, 0);
int saved_errno;
if (__glibc_likely (ret != NULL))
return ret;
saved_errno = errno;
if (buf == NULL)
buf = malloc (1024);
__set_errno (saved_errno);
if (buf == NULL)
return _("Unknown error");
return __strerror_r (errnum, buf, 1024);
return __strerror_l (errnum, __libc_tsd_get (locale_t, LOCALE));
}

View File

@ -20,8 +20,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/param.h>
#include <libc-symbols.h>
#include <errno.h>
static __thread char *last_value;
@ -38,8 +37,9 @@ translate (const char *str, locale_t loc)
/* Return a string describing the errno code in ERRNUM. */
char *
strerror_l (int errnum, locale_t loc)
__strerror_l (int errnum, locale_t loc)
{
int saved_errno = errno;
char *err = (char *) __get_errlist (errnum);
if (__glibc_unlikely (err == NULL))
{
@ -48,11 +48,16 @@ strerror_l (int errnum, locale_t loc)
translate ("Unknown error ", loc), errnum) == -1)
last_value = NULL;
return last_value;
err = last_value;
}
else
err = (char *) translate (err, loc);
return (char *) translate (err, loc);
__set_errno (saved_errno);
return err;
}
weak_alias (__strerror_l, strerror_l)
libc_hidden_def (__strerror_l)
void
__strerror_thread_freeres (void)

View File

@ -42,7 +42,7 @@ translate (const char *str, locale_t loc)
/* Return a string describing the errno code in ERRNUM. */
char *
strerror_l (int errnum, locale_t loc)
__strerror_l (int errnum, locale_t loc)
{
int system;
int sub;
@ -86,6 +86,8 @@ strerror_l (int errnum, locale_t loc)
return (char *) translate (es->subsystem[sub].codes[code], loc);
}
weak_alias (__strerror_l, strerror_l)
libc_hidden_def (__strerror_l)
/* This is called when a thread is exiting to free the last_value string. */
void