[PROPOSED PATCH 1/2] Mostly work around Qt bug 53071 by inserting dummy
Problem reported by Zhanibek Adilbekov in: http://mm.icann.org/pipermail/tz/2016-April/023605.html Also see the Qt bug report in: https://bugreports.qt.io/browse/QTBUG-53071 * NEWS: Document this. * zic.c (WORK_AROUND_QTBUG_53071): New constant. (growalloc): Don't grow past INT_MAX - 1 if the bug is present, since we add 1 at the end. (writezone) [WORK_AROUND_QTBUG_53071]: Work around most of QTBUG-53071, by inserting a dummy transition at time 2**31 - 1. --- NEWS | 7 +++++++ zic.c | 30 +++++++++++++++++++++++++++--- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/NEWS b/NEWS index e16f489..b5fb182 100644 --- a/NEWS +++ b/NEWS @@ -14,6 +14,13 @@ Unreleased, experimental changes Asia/Baku's 1992-09-27 transition from +04 (DST) to +04 (non-DST) was at 03:00, not 23:00 the previous day. (Thanks to Michael Deckers.) + Changes to code + + zic now outputs a dummy transition at time 2**31 - 1 in zones + whose POSIX-style TZ strings contain a '<'. This mostly works + around Qt bug 53071 <https://bugreports.qt.io/browse/QTBUG-53071>. + (Thanks to Zhanibek Adilbekov for reporting the Qt bug.) + Changes affecting documentation and commentary tz-link.htm says why governments should give plenty of notice for diff --git a/zic.c b/zic.c index 0ec3359..3b32f9b 100644 --- a/zic.c +++ b/zic.c @@ -143,6 +143,13 @@ static bool yearistype(int year, const char * type); /* Bound on length of what %z can expand to. */ enum { PERCENT_Z_LEN_BOUND = sizeof "+995959" - 1 }; +/* If true, work around a bug in Qt 5.6 and earlier, which mishandles + tzdata binary files whose POSIX-TZ-style strings contain '<'; see + QTBUG-53071 <https://bugreports.qt.io/browse/QTBUG-53071>. This + workaround will no longer be needed when Qt 5.6 is obsolete, say in + the year 2021. */ +enum { WORK_AROUND_QTBUG_53071 = true }; + static int charcnt; static bool errors; static bool warnings; @@ -420,7 +427,8 @@ growalloc(void *ptr, size_t itemsize, int nitems, int *nitems_alloc) if (nitems < *nitems_alloc) return ptr; else { - int amax = INT_MAX < SIZE_MAX ? INT_MAX : SIZE_MAX; + int nitems_max = INT_MAX - WORK_AROUND_QTBUG_53071; + int amax = nitems_max < SIZE_MAX ? nitems_max : SIZE_MAX; if ((amax - 1) / 3 * 2 < *nitems_alloc) memory_exhausted(_("int overflow")); *nitems_alloc = *nitems_alloc + (*nitems_alloc >> 1) + 1; @@ -1616,8 +1624,11 @@ writezone(const char *const name, const char *const string, char version) char * fullname; static const struct tzhead tzh0; static struct tzhead tzh; - zic_t *ats = emalloc(size_product(timecnt, sizeof *ats + 1)); - void *typesptr = ats + timecnt; + zic_t one = 1; + zic_t y2038_boundary = one << 31; + int nats = timecnt + WORK_AROUND_QTBUG_53071; + zic_t *ats = emalloc(size_product(nats, sizeof *ats + 1)); + void *typesptr = ats + nats; unsigned char *types = typesptr; /* @@ -1661,6 +1672,19 @@ writezone(const char *const name, const char *const string, char version) ats[i] = attypes[i].at; types[i] = attypes[i].type; } + + /* Work around QTBUG-53071 for time stamps less than y2038_boundary - 1, + by inserting a no-op transition at time y2038_boundary - 1. + This works only for timestamps before the boundary, which + should be good enough in practice as QTBUG-53071 should be + long-dead by 2038. */ + if (WORK_AROUND_QTBUG_53071 && timecnt != 0 + && ats[timecnt - 1] < y2038_boundary - 1 && strchr(string, '<')) { + ats[timecnt] = y2038_boundary - 1; + types[timecnt] = types[timecnt - 1]; + timecnt++; + } + /* ** Correct for leap seconds. */ -- 2.7.4
* zic.c (WORK_AROUND_GNOME_BUG_730332): New constant. (early_time): Rename from big_bang_time. All uses changed. --- zic.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/zic.c b/zic.c index 3b32f9b..2284d2c 100644 --- a/zic.c +++ b/zic.c @@ -857,10 +857,6 @@ static zic_t const max_time = MAXVAL (zic_t, TIME_T_BITS_IN_FILE); rounded downward to the negation of a power of two that is comfortably outside the error bounds. - zic does not output time stamps before this, partly because they - are physically suspect, and partly because GNOME mishandles them; see - GNOME bug 730332 <https://bugzilla.gnome.org/show_bug.cgi?id=730332>. - For the time of the Big Bang, see: Ade PAR, Aghanim N, Armitage-Caplan C et al. Planck 2013 results. @@ -881,7 +877,15 @@ static zic_t const max_time = MAXVAL (zic_t, TIME_T_BITS_IN_FILE); #define BIG_BANG (- (1LL << 59)) #endif -static const zic_t big_bang_time = BIG_BANG; +/* If true, work around GNOME bug 730332 + <https://bugzilla.gnome.org/show_bug.cgi?id=730332> + by refusing to output time stamps before BIG_BANG. + Such time stamps are physically suspect anyway. */ +enum { WORK_AROUND_GNOME_BUG_730332 = true }; + +static const zic_t early_time = (WORK_AROUND_GNOME_BUG_730332 + ? BIG_BANG + : MINVAL(zic_t, TIME_T_BITS_IN_FILE)); /* Return 1 if NAME is a directory, 0 if it's something else, -1 if trouble. */ static int @@ -1380,7 +1384,7 @@ inleap(char **fields, int nfields) return; } t = tadd(t, tod); - if (t < big_bang_time) { + if (t < early_time) { error(_("leap second precedes Big Bang")); return; } @@ -1645,7 +1649,7 @@ writezone(const char *const name, const char *const string, char version) toi = 0; fromi = 0; - while (fromi < timecnt && attypes[fromi].at < big_bang_time) + while (fromi < timecnt && attypes[fromi].at < early_time) ++fromi; for ( ; fromi < timecnt; ++fromi) { if (toi > 1 && ((attypes[fromi].at + @@ -2387,9 +2391,9 @@ outzone(const struct zone *zpfirst, int zonecount) */ stdoff = 0; zp = &zpfirst[i]; - usestart = i > 0 && (zp - 1)->z_untiltime > big_bang_time; + usestart = i > 0 && (zp - 1)->z_untiltime > early_time; useuntil = i < (zonecount - 1); - if (useuntil && zp->z_untiltime <= big_bang_time) + if (useuntil && zp->z_untiltime <= early_time) continue; gmtoff = zp->z_gmtoff; eat(zp->z_filename, zp->z_linenum); @@ -2404,7 +2408,7 @@ outzone(const struct zone *zpfirst, int zonecount) if (usestart) { addtt(starttime, type); usestart = false; - } else addtt(big_bang_time, type); + } else addtt(early_time, type); } else for (year = min_year; year <= max_year; ++year) { if (useuntil && year > zp->z_untilrule.r_hiyear) break; @@ -2590,8 +2594,8 @@ error(_("can't determine time zone abbreviation to use just after until time")); static void addtt(zic_t starttime, int type) { - if (starttime <= big_bang_time || - (timecnt == 1 && attypes[0].at < big_bang_time)) { + if (starttime <= early_time + || (timecnt == 1 && attypes[0].at < early_time)) { gmtoffs[0] = gmtoffs[type]; isdsts[0] = isdsts[type]; ttisstds[0] = ttisstds[type]; -- 2.7.4
participants (1)
-
Paul Eggert