2025-11-01 Paul Eggert <eggert@cs.ucla.edu>
+ 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>
# 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
#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; \
f; \
advance (p, _n); \
} \
- i += _incr; \
} while (0)
#define add1(c) width_add1 (width, c)
#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
{
if (ckd_mul (&width, width, 10)
|| ckd_add (&width, width, *f - L_('0')))
- width = SBYTE_COUNT_MAX;
+ return FAILURE;
++f;
}
while (ISDIGIT (*f));