On Wed, May 17, 2023 at 10:40:05AM -0700, Paul Eggert wrote: > On 2023-05-17 04:04, Adhemerval Zanella Netto wrote: > > do you think it would be feasible to assume > > _POSIX_TZNAME_MAX or 48 (for Factory zone) to avoid the malloc call on > > strftime_l? > > ALthough it's technically feasible, it'd be some work. Among other things, > whatever limit we chose would have to become visible via <limits.h> and > sysconf and etc., and we'd need to document that there is now a limit. > Better, I think, would be to continue to follow the GNU coding standards and > not impose an arbitrary limit on time zone abbreviation length, even for the > highly unusual case where code is calling wcsftime or wcsftime_l. > > How about avoiding the malloc in the following way? I installed the attached > patch into Gnulib lib/nstrftime.c, which has forked from glibc but with some > work could be merged back in, and this should also fix the glibc bugs with > buffer sizes exceeding INT_MAX. > > If you don't want all the hassle of merging, you can cherry-pick this patch. > I haven't tested the patch, though, as Gnulib does not use this code.
I've pushed your suggested patch after testing on x86_64 and i686. [1] Thanks, Joe [1] https://sourceware.org/pipermail/libc-alpha/2023-May/148384.html > From 197eec6075bbaf2b97137115a09a6bbce43b4dd4 Mon Sep 17 00:00:00 2001 > From: Paul Eggert <egg...@cs.ucla.edu> > Date: Wed, 17 May 2023 10:27:40 -0700 > Subject: [PATCH] nstrftime: suggest to glibc how to avoid alloca > > * lib/nstrftime.c (widen) [COMPILE_WIDE]: Remove. > (__strftime_internal) [COMPILE_WIDE): Instead of converting the > multibyte time zone abbreviation into a potentially unbounded > alloca buffer, convert it directly into the output buffer. > Although this code is not used in Gnulib, this can help the glibc > developers avoid the problem on the glibc side. > --- > ChangeLog | 10 ++++++++++ > lib/nstrftime.c | 39 +++++++++++++++++++++++++-------------- > 2 files changed, 35 insertions(+), 14 deletions(-) > > diff --git a/ChangeLog b/ChangeLog > index ecbc25ef06..36b3c65b81 100644 > --- a/ChangeLog > +++ b/ChangeLog > @@ -1,3 +1,13 @@ > +2023-05-17 Paul Eggert <egg...@cs.ucla.edu> > + > + nstrftime: suggest to glibc how to avoid alloca > + * lib/nstrftime.c (widen) [COMPILE_WIDE]: Remove. > + (__strftime_internal) [COMPILE_WIDE): Instead of converting the > + multibyte time zone abbreviation into a potentially unbounded > + alloca buffer, convert it directly into the output buffer. > + Although this code is not used in Gnulib, this can help the glibc > + developers avoid the problem on the glibc side. > + > 2023-05-15 Bruno Haible <br...@clisp.org> > > doc: New chapter "Strings and Characters". > diff --git a/lib/nstrftime.c b/lib/nstrftime.c > index 68bb560910..35a9307e1a 100644 > --- a/lib/nstrftime.c > +++ b/lib/nstrftime.c > @@ -226,15 +226,6 @@ extern char *tzname[]; > # 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 = (wchar_t *) alloca ((l + 1) * sizeof (wchar_t)); > \ > - (void) __mbsrtowcs_l (ws, &__s, l, &__st, loc); > \ > - } > #endif > > > @@ -1374,11 +1365,31 @@ __strftime_internal (STREAM_OR_CHAR_T *s, > STRFTIME_ARG (size_t maxsize) > #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); > -- > 2.39.2 >