From patchwork Tue Aug 14 14:21:00 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Weimer X-Patchwork-Id: 28894 Received: (qmail 70375 invoked by alias); 14 Aug 2018 14:21:06 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 70233 invoked by uid 89); 14 Aug 2018 14:21:05 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-26.9 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, SPF_HELO_PASS autolearn=ham version=3.3.2 spammy=3015 X-HELO: mx1.redhat.com Date: Tue, 14 Aug 2018 16:21:00 +0200 To: libc-alpha@sourceware.org Subject: [PATCH] __fxprintf: Avoid uninitialized conversion state [BZ #23525] User-Agent: Heirloom mailx 12.5 7/5/10 MIME-Version: 1.0 Message-Id: <20180814142101.024B4405971F1@oldenburg.str.redhat.com> From: fweimer@redhat.com (Florian Weimer) 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 [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 . */ +#include #include #include #include @@ -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 + . */ + +#include +#include +#include +#include + +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); +}