To reproduce the bug, use the following file foo.zi: Rule R 2073 max - Mar Sat<=30 2:00 1:00 S Rule R 2073 max - Oct Sat<=30 2:00 0 - Zone Z 2:00 R EE%sT and run ‘zic foo.zi; zdump -i -c 2072,2073 Z’. Without the fix, this incorrectly outputs the following two lines: 2072-03-26 03 +03 EEST 1 2072-10-29 01 +02 EET even though there are no transitions in 2072. * localtime.c (tzloadbody): Compute sp->goahead from ts->goahead. Do not guess goahead and goback from the timestamps, as that was just a guess that predates having TZ strings in the TZif file, and the guess is no longer needed and sometimes guesses wrong. (typesequiv): Remove; no longer used. (tzparse): Last arg is now pointer to const. This is just for clarity; it doesn’t affect behavior. --- NEWS | 4 ++++ localtime.c | 62 ++++++++--------------------------------------------- 2 files changed, 13 insertions(+), 53 deletions(-) diff --git a/NEWS b/NEWS index 411935a5..44ed20f3 100644 --- a/NEWS +++ b/NEWS @@ -11,6 +11,10 @@ Unreleased, experimental changes Changes to code + localtime.c no longer mishandles TZif files that contain a single + transition into a DST regime. Previously, it incorrectly assumed + DST was in effect before the transition too. + zic now works again on Linux 2.6.16 and 2.6.17 (2006). (Problem reported by Rune Torgersen.) diff --git a/localtime.c b/localtime.c index 7cd43dc1..a54d3ae4 100644 --- a/localtime.c +++ b/localtime.c @@ -153,8 +153,7 @@ static int_fast32_t leapcorr(struct state const *, time_t); static bool normalize_overflow32(int_fast32_t *, int *, int); static struct tm *timesub(time_t const *, int_fast32_t, struct state const *, struct tm *); -static bool typesequiv(struct state const *, int, int); -static bool tzparse(char const *, struct state *, struct state *); +static bool tzparse(char const *, struct state *, struct state const *); #ifdef ALL_STATE static struct state * lclptr; @@ -674,14 +673,18 @@ tzloadbody(char const *name, struct state *sp, bool doextend, == sp->types[sp->timecnt - 2])) sp->timecnt--; - for (i = 0; - i < ts->timecnt && sp->timecnt < TZ_MAX_TIMES; - i++) { + sp->goahead = ts->goahead; + + for (i = 0; i < ts->timecnt; i++) { time_t t = ts->ats[i]; if (increment_overflow_time(&t, leapcorr(sp, t)) || (0 < sp->timecnt && t <= sp->ats[sp->timecnt - 1])) continue; + if (TZ_MAX_TIMES <= sp->timecnt) { + sp->goahead = false; + break; + } sp->ats[sp->timecnt] = t; sp->types[sp->timecnt] = (sp->typecnt + ts->types[i]); @@ -694,28 +697,6 @@ tzloadbody(char const *name, struct state *sp, bool doextend, } if (sp->typecnt == 0) return EINVAL; - if (sp->timecnt > 1) { - if (sp->ats[0] <= TIME_T_MAX - SECSPERREPEAT) { - time_t repeatat = sp->ats[0] + SECSPERREPEAT; - int repeattype = sp->types[0]; - for (i = 1; i < sp->timecnt; ++i) - if (sp->ats[i] == repeatat - && typesequiv(sp, sp->types[i], repeattype)) { - sp->goback = true; - break; - } - } - if (TIME_T_MIN + SECSPERREPEAT <= sp->ats[sp->timecnt - 1]) { - time_t repeatat = sp->ats[sp->timecnt - 1] - SECSPERREPEAT; - int repeattype = sp->types[sp->timecnt - 1]; - for (i = sp->timecnt - 2; i >= 0; --i) - if (sp->ats[i] == repeatat - && typesequiv(sp, sp->types[i], repeattype)) { - sp->goahead = true; - break; - } - } - } /* Infer sp->defaulttype from the data. Although this default type is always zero for data from recent tzdb releases, @@ -792,31 +773,6 @@ tzload(char const *name, struct state *sp, bool doextend) #endif } -static bool -typesequiv(const struct state *sp, int a, int b) -{ - register bool result; - - if (sp == NULL || - a < 0 || a >= sp->typecnt || - b < 0 || b >= sp->typecnt) - result = false; - else { - /* Compare the relevant members of *AP and *BP. - Ignore tt_ttisstd and tt_ttisut, as they are - irrelevant now and counting them could cause - sp->goahead to mistakenly remain false. */ - register const struct ttinfo * ap = &sp->ttis[a]; - register const struct ttinfo * bp = &sp->ttis[b]; - result = (ap->tt_utoff == bp->tt_utoff - && ap->tt_isdst == bp->tt_isdst - && (strcmp(&sp->chars[ap->tt_desigidx], - &sp->chars[bp->tt_desigidx]) - == 0)); - } - return result; -} - static const int mon_lengths[2][MONSPERYEAR] = { { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } @@ -1116,7 +1072,7 @@ transtime(const int year, register const struct rule *const rulep, */ static bool -tzparse(const char *name, struct state *sp, struct state *basep) +tzparse(const char *name, struct state *sp, struct state const *basep) { const char * stdname; const char * dstname; -- 2.41.0