* lib/strftime.c (SBYTE_COUNT_MAX): Remove. (incr_overflow): New macro. (width_add): Use it. (__strftime_internal): Omit no-longer-needed local. Fail If the width overflows rather than substituting SBYTE_COUNT_MAX, as the latter approach is unreliable. --- ChangeLog | 8 ++++++++ lib/strftime.c | 20 ++++++++++++-------- 2 files changed, 20 insertions(+), 8 deletions(-)
diff --git a/ChangeLog b/ChangeLog index 19960aa0fd..b2f223fc6a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,13 @@ 2025-11-01 Paul Eggert <[email protected]> + nstrftime: fix very-unlikely integer overflow issues + * lib/strftime.c (SBYTE_COUNT_MAX): Remove. + (incr_overflow): New macro. + (width_add): Use it. + (__strftime_internal): Omit no-longer-needed local. + Fail If the width overflows rather than substituting + SBYTE_COUNT_MAX, as the latter approach is unreliable. + nstrftime: don’t assume <time.h> defines ptrdiff_t * lib/strftime.h: Include <stddef.h> diff --git a/lib/strftime.c b/lib/strftime.c index 35ec5e4fc4..5ed3cf5900 100644 --- a/lib/strftime.c +++ b/lib/strftime.c @@ -207,13 +207,11 @@ enum pad_style # define STRFTIME_ARG(x) /* empty */ typedef off64_t byte_count_t; typedef off64_t sbyte_count_t; -# define SBYTE_COUNT_MAX 0x7fffffffffffffff #else # define STREAM_OR_CHAR_T CHAR_T # define STRFTIME_ARG(x) x, typedef size_t byte_count_t; typedef ptrdiff_t sbyte_count_t; -# define SBYTE_COUNT_MAX PTRDIFF_MAX #endif /* The functions strftime[_l], wcsftime[_l] defined by glibc have a return type @@ -260,13 +258,23 @@ typedef sbyte_count_t retval_t; #endif #define add(n, f) width_add (width, n, f) + +/* Add INCR, returning true if I would become too large. + INCR should not have side effects. */ +#if FPRINTFTIME +# define incr_overflow(incr) ckd_add (&i, i, incr) +#else +/* Use <= not <, to leave room for trailing NUL. */ +# define incr_overflow(incr) (maxsize - i <= (incr) || (i += (incr), false)) +#endif + #define width_add(width, n, f) \ do \ { \ byte_count_t _n = n; \ byte_count_t _w = pad == NO_PAD || width < 0 ? 0 : width; \ byte_count_t _incr = _n < _w ? _w : _n; \ - if (_incr >= maxsize - i) \ + if (incr_overflow (_incr)) \ { \ errno = ERANGE; \ return FAILURE; \ @@ -284,7 +292,6 @@ typedef sbyte_count_t retval_t; f; \ advance (p, _n); \ } \ - i += _incr; \ } while (0) #define add1(c) width_add1 (width, c) @@ -1180,9 +1187,6 @@ __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG (size_t maxsize) #if defined _LIBC && defined USE_IN_EXTENDED_LOCALE_MODEL struct __locale_data *const current = loc->__locales[LC_TIME]; #endif -#if FPRINTFTIME - byte_count_t maxsize = SBYTE_COUNT_MAX; -#endif #if FAILURE == 0 int saved_errno = errno; #endif @@ -1402,7 +1406,7 @@ __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG (size_t maxsize) { if (ckd_mul (&width, width, 10) || ckd_add (&width, width, *f - L_('0'))) - width = SBYTE_COUNT_MAX; + return FAILURE; ++f; } while (ISDIGIT (*f)); -- 2.51.0
