[tz] [PROPOSED 2/4] Fix localtime bug with unusual TZif data
Paul Eggert
eggert at cs.ucla.edu
Sun Oct 15 20:10:50 UTC 2023
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
More information about the tz
mailing list