@@ -49,6 +49,7 @@ extern void __bzero (void *__s, size_t __n) __THROW __nonnull ((1));
extern int __ffs (int __i) __attribute__ ((const));
extern char *__strerror_r (int __errnum, char *__buf, size_t __buflen);
+extern char *__strerror_lookup (int errnum) attribute_hidden;
/* Called as part of the thread shutdown sequence. */
void __strsignal_thread_freeres (void) attribute_hidden;
@@ -1147,7 +1147,7 @@ name of the program that encountered the error.
@deftypefun {char *} strerror (int @var{errnum})
@standards{ISO, string.h}
-@safety{@prelim{}@mtunsafe{@mtasurace{:strerror}}@asunsafe{@ascuheap{} @ascuintl{}}@acunsafe{@acsmem{}}}
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
@c Calls strerror_r with a static buffer allocated with malloc on the
@c first use.
The @code{strerror} function maps the error code (@pxref{Checking for
@@ -15,60 +15,64 @@
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
-#include <libintl.h>
-#include <stdbool.h>
#include <stdio.h>
-#include <stdlib.h>
#include <string.h>
+#include <stdlib.h>
+#include <array_length.h>
#include <sys/param.h>
-#include <_itoa.h>
+#include <tls_internal-struct.h>
+
+#define UNK_ERR_STR "Unknown error "
+_Static_assert (sizeof (UNK_ERR_STR) <= strerror_str_len,
+ UNK_ERR_STR " > strerror_str_len");
-/* It is critical here that we always use the `dcgettext' function for
- the message translation. Since <libintl.h> only defines the macro
- `dgettext' to use `dcgettext' for optimizing programs this is not
- always guaranteed. */
-#ifndef dgettext
-# include <locale.h> /* We need LC_MESSAGES. */
-# define dgettext(domainname, msgid) dcgettext (domainname, msgid, LC_MESSAGES)
-#endif
+char *
+__strerror_lookup (int errnum)
+{
+ if (__glibc_unlikely (errnum < 0 || errnum >= _sys_nerr_internal))
+ return NULL;
+ return (char *) _sys_errlist_internal[errnum];
+}
/* Return a string describing the errno code in ERRNUM. */
char *
__strerror_r (int errnum, char *buf, size_t buflen)
{
- if (__glibc_unlikely (errnum < 0 || errnum >= _sys_nerr_internal
- || _sys_errlist_internal[errnum] == NULL))
- {
- /* Buffer we use to print the number in. For a maximum size for
- `int' of 8 bytes we never need more than 20 digits. */
- char numbuf[21];
- const char *unk = _("Unknown error ");
- size_t unklen = strlen (unk);
- char *p, *q;
- bool negative = errnum < 0;
+ char *r = __strerror_lookup (errnum);
+ if (r != NULL)
+ return r;
- numbuf[20] = '\0';
- p = _itoa_word (abs (errnum), &numbuf[20], 10, 0);
+ const size_t unklen = array_length (UNK_ERR_STR) - 1;
+ char *q = __mempcpy (buf, UNK_ERR_STR, MIN (buflen, unklen));
+ if (unklen < buflen)
+ {
+ char numstr[INT_STRLEN_BOUND (int) + 1];
+ size_t numstrlen = 1;
- /* Now construct the result while taking care for the destination
- buffer size. */
- q = __mempcpy (buf, unk, MIN (unklen, buflen));
- if (negative && unklen < buflen)
+ char *p = numstr;
+ long int errn = errnum;
+ if (errnum < 0)
{
- *q++ = '-';
- ++unklen;
+ *p++ = '-';
+ errn = labs (errnum);
+ numstrlen++;
}
- if (unklen < buflen)
- memcpy (q, p, MIN ((size_t) (&numbuf[21] - p), buflen - unklen));
+ for (long int d = errn; p++, (d /= 10) != 0; )
+ continue;
+ *p = '\0';
+ for (long int d = errn;
+ *--p = '0' + d % 10, (d /= 10) != 0;
+ numstrlen++)
+ continue;
- /* Terminate the string in any case. */
- if (buflen > 0)
- buf[buflen - 1] = '\0';
-
- return buf;
+ memcpy (q, numstr, MIN (MIN (numstrlen, INT_STRLEN_BOUND (int)) + 1,
+ buflen - unklen));
}
- return (char *) _(_sys_errlist_internal[errnum]);
+ if (buflen > 0)
+ buf[buflen - 1] = '\0';
+
+ return buf;
}
weak_alias (__strerror_r, strerror_r)
libc_hidden_def (__strerror_r)
@@ -15,29 +15,17 @@
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 <tls_internal.h>
char *
strerror (int errnum)
{
- char *ret = __strerror_r (errnum, NULL, 0);
- int saved_errno;
-
- if (__glibc_likely (ret != NULL))
+ char *ret = __strerror_lookup (errnum);
+ if (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);
+
+ char *buffer = __glibc_tls_internal ()->strerror_buf;
+ __strerror_r (errnum, buffer, TLS_INTERNAL_STRERROR_LEN);
+ return buffer;
}
@@ -22,12 +22,17 @@
#include <intprops.h>
enum { strsignal_str_len = 20 };
+enum { strerror_str_len = 37 };
struct tls_internal_t
{
/* Used on strsignal.c. */
char strsignal_buf[strsignal_str_len + INT_STRLEN_BOUND (int) + 1];
char *strsignal_l_buf;
+ char strerror_buf[strerror_str_len + INT_STRLEN_BOUND (int) + 1];
};
+#define TLS_INTERNAL_STRERROR_LEN \
+ sizeof ((struct tls_internal_t){0}.strerror_buf)
+
#endif
@@ -15,22 +15,45 @@
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 <mach/error.h>
#include <errorlib.h>
#include <sys/param.h>
#include <_itoa.h>
+#include <tls_internal-struct.h>
-/* It is critical here that we always use the `dcgettext' function for
- the message translation. Since <libintl.h> only defines the macro
- `dgettext' to use `dcgettext' for optimizing programs this is not
- always guaranteed. */
-#ifndef dgettext
-# include <locale.h> /* We need LC_MESSAGES. */
-# define dgettext(domainname, msgid) dcgettext (domainname, msgid, LC_MESSAGES)
-#endif
+#define UNK_SYSTEM_ERR_STR "Error in unknown error system: "
+_Static_assert (sizeof (UNK_SYSTEM_ERR_STR) <= strerror_str_len,
+ UNK_SYSTEM_ERR_STR " > strerror_str_len");
+#define UNK_SUBSYSTEM_ERR_STR "Unknown error "
+_Static_assert (sizeof (UNK_SUBSYSTEM_ERR_STR) <= strerror_str_len,
+ UNK_SUBSYSTEM_ERR_STR " > strerror_str_len");
+
+extern void __mach_error_map_compat (int *);
+
+char *
+__strerror_lookup (int errnum)
+{
+ __mach_error_map_compat (&errnum);
+
+ int system = err_get_system (errnum);
+ int sub = err_get_sub (errnum);
+ int code = err_get_code (errnum);
+
+ if (system > err_max_system || ! __mach_error_systems[system].bad_sub)
+ return NULL;
+
+ const struct error_system *es = &__mach_error_systems[system];
+
+ if (sub >= es->max_sub)
+ return (char *) es->bad_sub;
+
+ if (code >= es->subsystem[sub].max_code)
+ return NULL;
+
+ return (char *) es->subsystem[sub].codes[code];
+}
/* Return a string describing the errno code in ERRNUM. */
char *
@@ -40,7 +63,6 @@ __strerror_r (int errnum, char *buf, size_t buflen)
int sub;
int code;
const struct error_system *es;
- extern void __mach_error_map_compat (int *);
__mach_error_map_compat (&errnum);
@@ -53,7 +75,7 @@ __strerror_r (int errnum, char *buf, size_t buflen)
/* Buffer we use to print the number in. For a maximum size for
`int' of 8 bytes we never need more than 20 digits. */
char numbuf[21];
- const char *unk = _("Error in unknown error system: ");
+ const char *unk = UNK_SYSTEM_ERR_STR;
const size_t unklen = strlen (unk);
char *p, *q;
@@ -83,7 +105,7 @@ __strerror_r (int errnum, char *buf, size_t buflen)
/* Buffer we use to print the number in. For a maximum size for
`int' of 8 bytes we never need more than 20 digits. */
char numbuf[21];
- const char *unk = _("Unknown error ");
+ const char *unk = UNK_SUBSYSTEM_ERR_STR;
const size_t unklen = strlen (unk);
char *p, *q;
size_t len = strlen (es->subsystem[sub].subsys_name);
@@ -114,7 +136,7 @@ __strerror_r (int errnum, char *buf, size_t buflen)
return buf;
}
- return (char *) _(es->subsystem[sub].codes[code]);
+ return (char *) es->subsystem[sub].codes[code];
}
libc_hidden_def (__strerror_r)
weak_alias (__strerror_r, strerror_r)