From 6c0757509cf73ba6e086be9ce145815942ddf486 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Sun, 1 May 2016 01:05:21 -0700 Subject: [PATCH 7/8] 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 . + (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 . 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