* localtime.c (tzloadbody): Do not reject a TZif file merely because its leap second table contains adjacent entries with equal corrections, or contains a first entry with a correction value other than +1 or -1. * NEWS: Mention this. --- NEWS | 5 +++++ localtime.c | 13 ++++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/NEWS b/NEWS index 0de05f3..d8676e6 100644 --- a/NEWS +++ b/NEWS @@ -39,6 +39,11 @@ Unreleased, experimental changes seconds error than with an hour error, so zic -L no longer truncates output in this way. + The TZif reader now allows the leap second table to begin with a + correction other than -1 or +1, and to contain adjacent + transitions with equal corrections. This supports possible + future extensions to the TZif format. + Fix bug that caused 'localtime' etc. to crash when TZ was set to a all-year DST string like "EST5EDT4,0/0,J365/25" that does not conform to POSIX but does conform to Internet RFC 8536. diff --git a/localtime.c b/localtime.c index 6627ff2..a086d4d 100644 --- a/localtime.c +++ b/localtime.c @@ -445,7 +445,7 @@ tzloadbody(char const *name, struct state *sp, bool doextend, int_fast32_t ttisstdcnt = detzcode(up->tzhead.tzh_ttisstdcnt); int_fast32_t ttisutcnt = detzcode(up->tzhead.tzh_ttisutcnt); int_fast64_t prevtr = 0; - int_fast32_t prevcorr = 0; + int_fast32_t prevcorr; int_fast32_t leapcnt = detzcode(up->tzhead.tzh_leapcnt); int_fast32_t timecnt = detzcode(up->tzhead.tzh_timecnt); int_fast32_t typecnt = detzcode(up->tzhead.tzh_typecnt); @@ -542,9 +542,16 @@ tzloadbody(char const *name, struct state *sp, bool doextend, and UTC months are at least 28 days long (minus 1 second for a negative leap second). Each leap second's correction must differ from the previous one's by 1 - second. */ + second or less, except that the first correction can be + any value; these requirements are more generous than + RFC 8536, to allow future RFC extensions. */ if (tr - prevtr < 28 * SECSPERDAY - 1 - || (corr != prevcorr - 1 && corr != prevcorr + 1)) + || ((timecnt == 0 || sp->ats[0] < tr) + && ! (i == 0 + || (prevcorr < corr + ? corr == prevcorr + 1 + : (corr == prevcorr + || corr == prevcorr - 1))))) return EINVAL; sp->lsis[leapcnt].ls_trans = prevtr = tr; sp->lsis[leapcnt].ls_corr = prevcorr = corr; -- 2.27.0