+2025-10-30 Bruno Haible <bruno@clisp.org>
+
+ fprintftime: Avoid size_t overflow for very large outputs.
+ Reported by Jeff Epler <jepler@unpythonic.net> in
+ <https://lists.gnu.org/archive/html/bug-gnulib/2025-10/msg00126.html>.
+ * lib/fprintftime.h: Include <sys/types.h>.
+ (fprintftime): Change return type to off64_t.
+ * lib/strftime.c (byte_count_t): New macro.
+ (my_strftime, __strftime_internal): Change return type to off64_t.
+ * modules/fprintftime (Depends-on): Add sys_types-h.
+ * NEWS: Mention the change.
+
2025-10-29 Bruno Haible <bruno@clisp.org>
Fix support for Mac OS X/PowerPC.
along with this program. If not, see <https://www.gnu.org/licenses/>. */
#include <stdio.h>
+#include <sys/types.h>
#include <time.h>
#ifdef __cplusplus
Output to stream FP the result of formatting (according to the
nstrftime format string, FMT) the time data, *TM, and the ZONE
- and NANOSECONDS values. */
-size_t fprintftime (FILE *fp, char const *fmt, struct tm const *tm,
- timezone_t zone, int nanoseconds);
+ and NANOSECONDS values.
+
+ Return the number of bytes written to the stream (always >= 0). */
+off64_t fprintftime (FILE *fp, char const *fmt, struct tm const *tm,
+ timezone_t zone, int nanoseconds);
#ifdef __cplusplus
# define mktime(tp) __mktime64 (tp)
#endif
+/* For functions that fill an in-memory string, the number of bytes fits in a
+ size_t. For functions that write to a stream, the number of bytes fits in
+ an off64_t (a type that is always at least 64 bits large). */
#if FPRINTFTIME
# define STREAM_OR_CHAR_T FILE
# define STRFTIME_ARG(x) /* empty */
+# define byte_count_t off64_t
#else
# define STREAM_OR_CHAR_T CHAR_T
# define STRFTIME_ARG(x) x,
+# define byte_count_t size_t
#endif
#if FPRINTFTIME
# define ns 0
#endif
-static size_t __strftime_internal (STREAM_OR_CHAR_T *, STRFTIME_ARG (size_t)
- const CHAR_T *, const struct tm *,
- CAL_ARGS (const struct calendar *,
- struct calendar_date *)
- bool, enum pad_style, int, bool *
- extra_args_spec LOCALE_PARAM);
+static byte_count_t __strftime_internal (STREAM_OR_CHAR_T *,
+ STRFTIME_ARG (size_t)
+ const CHAR_T *, const struct tm *,
+ CAL_ARGS (const struct calendar *,
+ struct calendar_date *)
+ bool, enum pad_style, int, bool *
+ extra_args_spec LOCALE_PARAM);
#if !defined _LIBC \
&& (!(HAVE_ONLY_C_LOCALE || (USE_C_LOCALE && !HAVE_STRFTIME_L)) \
characters written. If S is NULL, nothing will be written
anywhere, so to determine how many characters would be
written, use NULL for S and (size_t) -1 for MAXSIZE. */
-size_t
+byte_count_t
my_strftime (STREAM_OR_CHAR_T *s, STRFTIME_ARG (size_t maxsize)
const CHAR_T *format,
const struct tm *tp extra_args_spec LOCALE_PARAM)
UPCASE indicates that the result should be converted to upper case.
YR_SPEC and WIDTH specify the padding and width for the year.
*TZSET_CALLED indicates whether tzset has been called here. */
-static size_t
+static byte_count_t
__strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG (size_t maxsize)
const CHAR_T *format,
const struct tm *tp,
# define ampm (L_("AMPM") + 2 * (tp->tm_hour > 11))
# define ap_len 2
#endif
- size_t i = 0;
+ byte_count_t i = 0;
STREAM_OR_CHAR_T *p = s;
const CHAR_T *f;
#if DO_MULTIBYTE && !defined COMPILE_WIDE