From 6f2e9b6938c421ff05d57a73f0bbe0dabed0456d Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Mon, 6 Jun 2022 11:20:08 -0700 Subject: [PROPOSED] Stricter mktime -1 heuristic in strftime This responds to comments by Almaz Mingaleev in: https://mm.icann.org/pipermail/tz/2022-June/031469.html * strftime.c (signum): New static function. (_fmt): Use a stricter heuristic when checking mktime when it returns -1. --- strftime.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/strftime.c b/strftime.c index 5273155..504639e 100644 --- a/strftime.c +++ b/strftime.c @@ -126,6 +126,13 @@ strftime_l(char *s, size_t maxsize, char const *format, struct tm const *t, } #endif +/* Return -1, 0, 1 if n is negative, zero, positive. */ +static int +signum(int n) +{ + return (n > 0) - (n < 0); +} + size_t strftime(char *s, size_t maxsize, const char *format, const struct tm *t) { @@ -323,17 +330,31 @@ label: tm.tm_yday = -1; mkt = mktime(&tm); if (mkt == (time_t) -1) { - /* Fail unless this -1 represents - a valid time. */ + /* Fail unless the -1 almost surely + represents a valid time. Do not + rely on errno, since it can change + even if mktime succeeds. A + non-TZDB failing mktime might + set TM to junk values, so reject + mktime's result unless it matches + localtime_r so closely that it's + unlikely to be junk. */ struct tm tm_1; if (!localtime_r(&mkt, &tm_1)) return NULL; if (!(tm.tm_year == tm_1.tm_year && tm.tm_yday == tm_1.tm_yday + && tm.tm_mon == tm_1.tm_mon + && tm.tm_mday == tm_1.tm_mday + && tm.tm_wday == tm_1.tm_wday && tm.tm_hour == tm_1.tm_hour && tm.tm_min == tm_1.tm_min - && tm.tm_sec == tm_1.tm_sec)) + && tm.tm_sec == tm_1.tm_sec + && (signum(tm.tm_isdst) + == signum(tm_1.tm_isdst)))) return NULL; + /* Guarantee that tm is not junk. */ + tm = tm_1; } if (TYPE_SIGNED(time_t)) { intmax_t n = mkt; -- 2.36.1