diff options
author | Joe Simmons-Talbott <josimmon@redhat.com> | 2023-05-23 15:41:29 -0400 |
---|---|---|
committer | Siddhesh Poyarekar <siddhesh@sourceware.org> | 2023-05-29 09:09:15 -0400 |
commit | 79b2667d1eb06c6503c22f2f323c1c574ac5917b (patch) | |
tree | 7003929d9ab695638e3685e228d67950814d448b | |
parent | ed2f9dc9420c4c61436328778a70459d0a35556a (diff) | |
download | glibc-79b2667d1eb06c6503c22f2f323c1c574ac5917b.zip glibc-79b2667d1eb06c6503c22f2f323c1c574ac5917b.tar.gz glibc-79b2667d1eb06c6503c22f2f323c1c574ac5917b.tar.bz2 |
time: strftime_l: Avoid an unbounded alloca.
Avoid possible stack overflow by removing alloca() and converting to
wide characters within the buffer.
Suggested-by: Paul Eggert <eggert@cs.ucla.edu>
-rw-r--r-- | time/strftime_l.c | 39 |
1 files changed, 25 insertions, 14 deletions
diff --git a/time/strftime_l.c b/time/strftime_l.c index 402c6c4..3901bd7 100644 --- a/time/strftime_l.c +++ b/time/strftime_l.c @@ -267,15 +267,6 @@ static const CHAR_T zeroes[16] = /* "0000000000000000" */ # undef __mbsrtowcs_l # define __mbsrtowcs_l(d, s, l, st, loc) __mbsrtowcs (d, s, l, st) # endif -# define widen(os, ws, l) \ - { \ - mbstate_t __st; \ - const char *__s = os; \ - memset (&__st, '\0', sizeof (__st)); \ - l = __mbsrtowcs_l (NULL, &__s, 0, &__st, loc); \ - ws = alloca ((l + 1) * sizeof (wchar_t)); \ - (void) __mbsrtowcs_l (ws, &__s, l, &__st, loc); \ - } #endif @@ -1342,11 +1333,31 @@ __strftime_internal (CHAR_T *s, size_t maxsize, const CHAR_T *format, #ifdef COMPILE_WIDE { /* The zone string is always given in multibyte form. We have - to transform it first. */ - wchar_t *wczone; - size_t len; - widen (zone, wczone, len); - cpy (len, wczone); + to convert it to wide character. */ + size_t w = pad == L_('-') || width < 0 ? 0 : width; + char const *z = zone; + mbstate_t st = {0}; + size_t len = __mbsrtowcs_l (p, &z, maxsize - i, &st, loc); + if (len == (size_t) -1) + return 0; + size_t incr = len < w ? w : len; + if (incr >= maxsize - i) + { + errno = ERANGE; + return 0; + } + if (p) + { + if (len < w) + { + size_t delta = w - len; + __wmemmove (p + delta, p, len); + wchar_t wc = pad == L_('0') || pad == L_('+') ? L'0' : L' '; + wmemset (p, wc, delta); + } + p += incr; + } + i += incr; } #else cpy (strlen (zone), zone); |