]> git.ipfire.org Git - thirdparty/gnulib.git/commitdiff
nstrftime: fix very-unlikely integer overflow issues
authorPaul Eggert <eggert@cs.ucla.edu>
Sat, 1 Nov 2025 20:38:13 +0000 (14:38 -0600)
committerPaul Eggert <eggert@cs.ucla.edu>
Sat, 1 Nov 2025 20:39:14 +0000 (14:39 -0600)
* 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
lib/strftime.c

index 19960aa0fd9ed15d5953b5a5d6a8026b3adc55f6..b2f223fc6aab16c5ac4f8fb94884bf3d64b66962 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,13 @@
 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>
 
index 35ec5e4fc475c7d348ff6184483cb42c24460a63..5ed3cf5900ae1ab47d1421b146d23a5775e8f1a4 100644 (file)
@@ -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));