mirror of
git://sourceware.org/git/glibc.git
synced 2025-03-06 20:58:33 +01:00
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:
parent
9deec7c8ba
commit
28aff04781
5 changed files with 24 additions and 26 deletions
5
NEWS
5
NEWS
|
@ -79,6 +79,11 @@ Deprecated and removed features, and other changes affecting compatibility:
|
||||||
compatibility symbols to support old binaries. All programs should use
|
compatibility symbols to support old binaries. All programs should use
|
||||||
strerror or strerror_r instead.
|
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:
|
Changes to build and runtime requirements:
|
||||||
|
|
||||||
* powerpc64le requires GCC 7.4 or newer. This is required for supporting
|
* powerpc64le requires GCC 7.4 or newer. This is required for supporting
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
/* Some of these are defined as macros in the real string.h, so we must
|
/* Some of these are defined as macros in the real string.h, so we must
|
||||||
prototype them before including it. */
|
prototype them before including it. */
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <locale.h>
|
||||||
|
|
||||||
extern void *__memccpy (void *__dest, const void *__src,
|
extern void *__memccpy (void *__dest, const void *__src,
|
||||||
int __c, size_t __n);
|
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_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. */
|
/* Called as part of the thread shutdown sequence. */
|
||||||
void __strerror_thread_freeres (void) attribute_hidden;
|
void __strerror_thread_freeres (void) attribute_hidden;
|
||||||
|
|
||||||
|
@ -113,6 +116,7 @@ libc_hidden_proto (memmem)
|
||||||
extern __typeof (memmem) __memmem;
|
extern __typeof (memmem) __memmem;
|
||||||
libc_hidden_proto (__memmem)
|
libc_hidden_proto (__memmem)
|
||||||
libc_hidden_proto (__ffs)
|
libc_hidden_proto (__ffs)
|
||||||
|
libc_hidden_proto (__strerror_l)
|
||||||
|
|
||||||
#if IS_IN (libc)
|
#if IS_IN (libc)
|
||||||
/* Avoid hidden reference to IFUNC symbol __explicit_bzero_chk. */
|
/* Avoid hidden reference to IFUNC symbol __explicit_bzero_chk. */
|
||||||
|
|
|
@ -15,29 +15,11 @@
|
||||||
License along with the GNU C Library; if not, see
|
License along with the GNU C Library; if not, see
|
||||||
<https://www.gnu.org/licenses/>. */
|
<https://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
#include <libintl.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <locale/localeinfo.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);
|
|
||||||
|
|
||||||
char *
|
char *
|
||||||
strerror (int errnum)
|
strerror (int errnum)
|
||||||
{
|
{
|
||||||
char *ret = __strerror_r (errnum, NULL, 0);
|
return __strerror_l (errnum, __libc_tsd_get (locale_t, LOCALE));
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,8 +20,7 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/param.h>
|
#include <errno.h>
|
||||||
#include <libc-symbols.h>
|
|
||||||
|
|
||||||
static __thread char *last_value;
|
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. */
|
/* Return a string describing the errno code in ERRNUM. */
|
||||||
char *
|
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);
|
char *err = (char *) __get_errlist (errnum);
|
||||||
if (__glibc_unlikely (err == NULL))
|
if (__glibc_unlikely (err == NULL))
|
||||||
{
|
{
|
||||||
|
@ -48,11 +48,16 @@ strerror_l (int errnum, locale_t loc)
|
||||||
translate ("Unknown error ", loc), errnum) == -1)
|
translate ("Unknown error ", loc), errnum) == -1)
|
||||||
last_value = NULL;
|
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
|
void
|
||||||
__strerror_thread_freeres (void)
|
__strerror_thread_freeres (void)
|
||||||
|
|
|
@ -42,7 +42,7 @@ translate (const char *str, locale_t loc)
|
||||||
|
|
||||||
/* Return a string describing the errno code in ERRNUM. */
|
/* Return a string describing the errno code in ERRNUM. */
|
||||||
char *
|
char *
|
||||||
strerror_l (int errnum, locale_t loc)
|
__strerror_l (int errnum, locale_t loc)
|
||||||
{
|
{
|
||||||
int system;
|
int system;
|
||||||
int sub;
|
int sub;
|
||||||
|
@ -86,6 +86,8 @@ strerror_l (int errnum, locale_t loc)
|
||||||
|
|
||||||
return (char *) translate (es->subsystem[sub].codes[code], 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. */
|
/* This is called when a thread is exiting to free the last_value string. */
|
||||||
void
|
void
|
||||||
|
|
Loading…
Add table
Reference in a new issue