@@ -35,6 +35,14 @@ extern __typeof (qsort_r) __qsort_r;
libc_hidden_proto (__qsort_r)
libc_hidden_proto (lrand48_r)
libc_hidden_proto (wctomb)
+__typeof (mbstowcs) __mbstowcs attribute_hidden;
+
+/* Convert the multi-byte string S to a wide string. Use
+ SCRATCH_COUNT wide characters at SCRATCH as storage if possible.
+ The caller must free *TO_FREE upon successful return. */
+wchar_t *__mbstowcs_alloc (const char *s, wchar_t *scratch,
+ size_t scratch_count, void **to_free)
+ attribute_hidden __nonnull ((1, 2, 4));
extern long int __random (void) attribute_hidden;
extern void __srandom (unsigned int __seed);
@@ -16,6 +16,7 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
+#include <array_length.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
@@ -29,35 +30,15 @@ locked_vfxprintf (FILE *fp, const char *fmt, va_list ap)
if (_IO_fwide (fp, 0) <= 0)
return _IO_vfprintf (fp, fmt, ap);
- /* We must convert the narrow format string to a wide one.
- Each byte can produce at most one wide character. */
- wchar_t *wfmt;
- mbstate_t mbstate;
- int res;
- int used_malloc = 0;
- size_t len = strlen (fmt) + 1;
-
- if (__glibc_unlikely (len > SIZE_MAX / sizeof (wchar_t)))
- {
- __set_errno (EOVERFLOW);
- return -1;
- }
- if (__libc_use_alloca (len * sizeof (wchar_t)))
- wfmt = alloca (len * sizeof (wchar_t));
- else if ((wfmt = malloc (len * sizeof (wchar_t))) == NULL)
+ /* We must convert the narrow format string to a wide one. */
+ wchar_t buffer[80];
+ void *to_free;
+ wchar_t *wfmt = __mbstowcs_alloc (fmt, buffer, array_length (buffer),
+ &to_free);
+ if (wfmt == NULL)
return -1;
- else
- used_malloc = 1;
-
- memset (&mbstate, 0, sizeof mbstate);
- res = __mbsrtowcs (wfmt, &fmt, len, &mbstate);
-
- if (res != -1)
- res = _IO_vfwprintf (fp, wfmt, ap);
-
- if (used_malloc)
- free (wfmt);
-
+ int res = _IO_vfwprintf (fp, wfmt, ap);
+ free (to_free);
return res;
}
@@ -40,7 +40,7 @@ routines := \
quick_exit at_quick_exit cxa_at_quick_exit cxa_thread_atexit_impl \
abs labs llabs \
div ldiv lldiv \
- mblen mbstowcs mbtowc wcstombs wctomb \
+ mblen mbstowcs mbstowcs_alloc mbtowc wcstombs wctomb \
random random_r rand rand_r \
drand48 erand48 lrand48 nrand48 mrand48 jrand48 \
srand48 seed48 lcong48 \
@@ -24,7 +24,7 @@
PWCS, writing no more than N. Return the number written,
or (size_t) -1 if an invalid multibyte character is encountered. */
size_t
-mbstowcs (wchar_t *pwcs, const char *s, size_t n)
+__mbstowcs (wchar_t *pwcs, const char *s, size_t n)
{
mbstate_t state;
@@ -32,3 +32,5 @@ mbstowcs (wchar_t *pwcs, const char *s, size_t n)
/* Return how many we wrote (or maybe an error). */
return __mbsrtowcs (pwcs, &s, n, &state);
}
+
+weak_alias (__mbstowcs, mbstowcs)
new file mode 100644
@@ -0,0 +1,64 @@
+/* mbstowcs with scratch buffer and fallback heap allocation.
+ Copyright (C) 2018 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+
+static wchar_t *
+mbstowcs_heap (const char *s, void **to_free)
+{
+ /* We assume that each byte produces at most one wide character. */
+ size_t len = strlen (s) + 1;
+ wchar_t *buffer = __libc_reallocarray (NULL, len, sizeof (*buffer));
+ size_t res = __mbstowcs (buffer, s, len);
+ if (res == (size_t) -1)
+ {
+ free (buffer);
+ return NULL;
+ }
+ else if (res >= len)
+ {
+ /* The assumption that the length would not grow was not
+ true. */
+ __set_errno (EILSEQ);
+ free (buffer);
+ return NULL;
+ }
+ *to_free = buffer;
+ return buffer;
+}
+
+wchar_t *
+__mbstowcs_alloc (const char *s, wchar_t *scratch, size_t scratch_count,
+ void **to_free)
+{
+ *to_free = NULL;
+ size_t res = __mbstowcs (scratch, s, scratch_count);
+ if (res == (size_t) -1)
+ return NULL;
+
+ /* Check if the conversion fit into the scratch buffer. The number
+ of converted characters does not included the null
+ terminator. */
+ if (res < scratch_count)
+ return scratch;
+ else
+ return mbstowcs_heap (s, to_free);
+}