This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
[PATCH] __fxprintf: Avoid uninitialized conversion state [BZ #23525]
- From: fweimer at redhat dot com (Florian Weimer)
- To: libc-alpha at sourceware dot org
- Date: Tue, 14 Aug 2018 16:21:00 +0200
- Subject: [PATCH] __fxprintf: Avoid uninitialized conversion state [BZ #23525]
Move the conversion code into __mbstowcs_alloc (in preparation for
fixing bug 23519). Use a fixed-size stack buffer instead of alloca
because it results in more compact code.
2018-08-14 Florian Weimer <fweimer@redhat.com>
[BZ #23519]
[BZ #23525]
* include/stdlib.h (__mbstowcs, __mbstowcs_alloc): Declare.
* stdlib/Makefile (routines): Add mbstowcs_alloc.
* stdlib/mbstowcs.c (__mbstowcs): Rename from mbstowcs. Add weak
alias.
* stdlib/mbstowcs_alloc.c: New file.
* stdio-common/fxprintf.c (locked_vfxprintf): Use
__mbstowcs_alloc.
diff --git a/include/stdlib.h b/include/stdlib.h
index 114e12d255..a61b5683a5 100644
--- a/include/stdlib.h
+++ b/include/stdlib.h
@@ -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);
diff --git a/stdio-common/fxprintf.c b/stdio-common/fxprintf.c
index 8d02b71f91..b2cc270e71 100644
--- a/stdio-common/fxprintf.c
+++ b/stdio-common/fxprintf.c
@@ -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;
}
diff --git a/stdlib/Makefile b/stdlib/Makefile
index 01194bbf7c..5f61f02d3a 100644
--- a/stdlib/Makefile
+++ b/stdlib/Makefile
@@ -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 \
diff --git a/stdlib/mbstowcs.c b/stdlib/mbstowcs.c
index d8b91a73de..1d97aa02ef 100644
--- a/stdlib/mbstowcs.c
+++ b/stdlib/mbstowcs.c
@@ -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)
diff --git a/stdlib/mbstowcs_alloc.c b/stdlib/mbstowcs_alloc.c
new file mode 100644
index 0000000000..c6cb634303
--- /dev/null
+++ b/stdlib/mbstowcs_alloc.c
@@ -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);
+}