summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoss Burton <ross@burtonini.com>2020-10-26 18:01:06 +0000
committerRichard Purdie <richard.purdie@linuxfoundation.org>2020-10-26 22:08:36 +0000
commit5689a70b23df001d5502bf756f115a84b29b0159 (patch)
tree2fa50593ff53a97857ce7e569005a2f02cb454c2
parentad818f8b23ad9317a7e7d5daa6958ff9054e93f6 (diff)
downloadpoky-5689a70b23df001d5502bf756f115a84b29b0159.tar.gz
glib-2.0: fix parsing of slim encoded tzdata
As of tzcode 2020b the timezone data is encoded using the 'slim' format instead of the previous 'fat'. This exposes a number of bugs in GLib, so backport the fixes to improve the parser. [ YOCTO #14106 ] (From OE-Core rev: 09aec7ea87ffc28d1b22d904b20dc23ea55225c9) Signed-off-by: Ross Burton <ross.burton@arm.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
-rw-r--r--meta/recipes-core/glib-2.0/glib-2.0/tzdata-update.patch458
-rw-r--r--meta/recipes-core/glib-2.0/glib-2.0_2.64.5.bb1
2 files changed, 459 insertions, 0 deletions
diff --git a/meta/recipes-core/glib-2.0/glib-2.0/tzdata-update.patch b/meta/recipes-core/glib-2.0/glib-2.0/tzdata-update.patch
new file mode 100644
index 0000000000..0af036f8bd
--- /dev/null
+++ b/meta/recipes-core/glib-2.0/glib-2.0/tzdata-update.patch
@@ -0,0 +1,458 @@
1Backport a number of patches from upstream to fix reading of the new 'slim'
2encoding for tzdata files.
3
4Upstream-Status: Backport
5Signed-off-by: Ross Burton <ross.burton@arm.com>
6
7commit 18cbd5e5a4812e9bd0b06a058322d2b44ed2ad92
8Author: Paul Eggert <eggert@cs.ucla.edu>
9Date: Thu Jul 16 12:41:49 2020 -0700
10
11 Clarify memset in set_tz_name
12
13 * glib/gtimezone.c (set_tz_name): Use size, not NAME_SIZE,
14 to clear the buffer. Suggested by Philip Withnall in:
15 https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1533#note_867859
16
17commit 1ab3f927d6d09a8cf3349a3545f5351446f43d47
18Author: Paul Eggert <eggert@cs.ucla.edu>
19Date: Thu Jul 16 12:41:49 2020 -0700
20
21 gtimezone: support footers in TZif files
22
23 Since tzcode95f (1995), TZif files have had a trailing
24 TZ string, used for timestamps after the last transition.
25 This string is specified in Internet RFC 8536 section 3.3.
26 init_zone_from_iana_info has ignored this string, causing it
27 to mishandle timestamps past the year 2038. With zic's new -b
28 slim flag, init_zone_from_iana_info would even mishandle current
29 timestamps. Fix this by parsing the trailing TZ string and adding
30 its transitions.
31
32 Closes #2129
33
34commit e8b763e35235a2c6b4bdd48a5099c00f72741059
35Author: Paul Eggert <eggert@cs.ucla.edu>
36Date: Thu Jul 16 12:41:49 2020 -0700
37
38 gtimezone: add support for RFC 8536 time zone transitions
39
40 Time zone transition times can range from -167:59:59 through
41 +167:59:59, according to Internet RFC 8536 section 3.3.1;
42 this is an extension to POSIX. It is needed for proper
43 support of TZif version 3 files.
44
45commit 1c65dd48b8ebd31af8bc9b2263f83c0c411f7519
46Author: Paul Eggert <eggert@cs.ucla.edu>
47Date: Thu Jul 16 12:41:49 2020 -0700
48
49 gtimezone: allow hh to be 24, as per POSIX
50
51 POSIX allows hh to be 24; see
52 https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html#tag_08_03
53
54commit 368b65cb4cb17e29a4f55654149f554a14f48bc6
55Author: Paul Eggert <eggert@cs.ucla.edu>
56Date: Thu Jul 16 12:41:49 2020 -0700
57
58 gtimezone: support POSIX 1003.1-2001 quoted TZ abbreviations
59
60 TZ strings like '<-03>3' were introduced in POSIX 1003.1-2001 and
61 are currently specified in:
62 https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html#tag_08_03
63
64commit fd528aaab6bb077c6d217e62f2228ec9fe3ed760
65Author: Paul Eggert <eggert@cs.ucla.edu>
66Date: Thu Jul 16 12:41:49 2020 -0700
67
68 gtimezone: get 64-bit data from version-3 TZif files
69
70 Version 3 was introduced in tzdb 2013e (2013).
71 See Internet RFC 8536 section 3.1 under "ver(sion)".
72
73diff --git a/glib/gtimezone.c b/glib/gtimezone.c
74index 5a835dea9..f9eee1967 100644
75--- a/glib/gtimezone.c
76+++ b/glib/gtimezone.c
77@@ -142,9 +142,7 @@ typedef struct
78 gint mday;
79 gint wday;
80 gint week;
81- gint hour;
82- gint min;
83- gint sec;
84+ gint32 offset; /* hour*3600 + min*60 + sec; can be negative. */
85 } TimeZoneDate;
86
87 /* POSIX Timezone abbreviations are typically 3 or 4 characters, but
88@@ -205,6 +203,10 @@ static GTimeZone *tz_local = NULL;
89 there's no point in getting carried
90 away. */
91
92+#ifdef G_OS_UNIX
93+static GTimeZone *parse_footertz (const gchar *, size_t);
94+#endif
95+
96 /**
97 * g_time_zone_unref:
98 * @tz: a #GTimeZone
99@@ -286,13 +288,20 @@ g_time_zone_ref (GTimeZone *tz)
100 /* fake zoneinfo creation (for RFC3339/ISO 8601 timezones) {{{1 */
101 /*
102 * parses strings of the form h or hh[[:]mm[[[:]ss]]] where:
103- * - h[h] is 0 to 23
104+ * - h[h] is 0 to 24
105 * - mm is 00 to 59
106 * - ss is 00 to 59
107+ * If RFC8536, TIME_ is a transition time sans sign,
108+ * so colons are required before mm and ss, and hh can be up to 167.
109+ * See Internet RFC 8536 section 3.3.1:
110+ * https://tools.ietf.org/html/rfc8536#section-3.3.1
111+ * and POSIX Base Definitions 8.3 TZ rule time:
112+ * https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html#tag_08_03
113 */
114 static gboolean
115 parse_time (const gchar *time_,
116- gint32 *offset)
117+ gint32 *offset,
118+ gboolean rfc8536)
119 {
120 if (*time_ < '0' || '9' < *time_)
121 return FALSE;
122@@ -310,7 +319,20 @@ parse_time (const gchar *time_,
123 *offset *= 10;
124 *offset += 60 * 60 * (*time_++ - '0');
125
126- if (*offset > 23 * 60 * 60)
127+ if (rfc8536)
128+ {
129+ /* Internet RFC 8536 section 3.3.1 and POSIX 8.3 TZ together say
130+ that a transition time must be of the form [+-]hh[:mm[:ss]] where
131+ the hours part can range from -167 to 167. */
132+ if ('0' <= *time_ && *time_ <= '9')
133+ {
134+ *offset *= 10;
135+ *offset += 60 * 60 * (*time_++ - '0');
136+ }
137+ if (*offset > 167 * 60 * 60)
138+ return FALSE;
139+ }
140+ else if (*offset > 24 * 60 * 60)
141 return FALSE;
142
143 if (*time_ == '\0')
144@@ -319,6 +341,8 @@ parse_time (const gchar *time_,
145
146 if (*time_ == ':')
147 time_++;
148+ else if (rfc8536)
149+ return FALSE;
150
151 if (*time_ < '0' || '5' < *time_)
152 return FALSE;
153@@ -335,6 +359,8 @@ parse_time (const gchar *time_,
154
155 if (*time_ == ':')
156 time_++;
157+ else if (rfc8536)
158+ return FALSE;
159
160 if (*time_ < '0' || '5' < *time_)
161 return FALSE;
162@@ -351,28 +377,32 @@ parse_time (const gchar *time_,
163
164 static gboolean
165 parse_constant_offset (const gchar *name,
166- gint32 *offset)
167+ gint32 *offset,
168+ gboolean rfc8536)
169 {
170- if (g_strcmp0 (name, "UTC") == 0)
171+ /* Internet RFC 8536 section 3.3.1 and POSIX 8.3 TZ together say
172+ that a transition time must be numeric. */
173+ if (!rfc8536 && g_strcmp0 (name, "UTC") == 0)
174 {
175 *offset = 0;
176 return TRUE;
177 }
178
179 if (*name >= '0' && '9' >= *name)
180- return parse_time (name, offset);
181+ return parse_time (name, offset, rfc8536);
182
183 switch (*name++)
184 {
185 case 'Z':
186 *offset = 0;
187- return !*name;
188+ /* Internet RFC 8536 section 3.3.1 requires a numeric zone. */
189+ return !rfc8536 && !*name;
190
191 case '+':
192- return parse_time (name, offset);
193+ return parse_time (name, offset, rfc8536);
194
195 case '-':
196- if (parse_time (name, offset))
197+ if (parse_time (name, offset, rfc8536))
198 {
199 *offset = -*offset;
200 return TRUE;
201@@ -391,7 +421,7 @@ zone_for_constant_offset (GTimeZone *gtz, const gchar *name)
202 gint32 offset;
203 TransitionInfo info;
204
205- if (name == NULL || !parse_constant_offset (name, &offset))
206+ if (name == NULL || !parse_constant_offset (name, &offset, FALSE))
207 return;
208
209 info.gmt_offset = offset;
210@@ -529,12 +559,17 @@ init_zone_from_iana_info (GTimeZone *gtz,
211 guint8 *tz_transitions, *tz_type_index, *tz_ttinfo;
212 guint8 *tz_abbrs;
213 gsize timesize = sizeof (gint32);
214- const struct tzhead *header = g_bytes_get_data (zoneinfo, &size);
215+ gconstpointer header_data = g_bytes_get_data (zoneinfo, &size);
216+ const gchar *data = header_data;
217+ const struct tzhead *header = header_data;
218+ GTimeZone *footertz = NULL;
219+ guint extra_time_count = 0, extra_type_count = 0;
220+ gint64 last_explicit_transition_time;
221
222 g_return_if_fail (size >= sizeof (struct tzhead) &&
223 memcmp (header, "TZif", 4) == 0);
224
225- if (header->tzh_version == '2')
226+ if (header->tzh_version >= '2')
227 {
228 /* Skip ahead to the newer 64-bit data if it's available. */
229 header = (const struct tzhead *)
230@@ -550,6 +585,30 @@ init_zone_from_iana_info (GTimeZone *gtz,
231 time_count = guint32_from_be(header->tzh_timecnt);
232 type_count = guint32_from_be(header->tzh_typecnt);
233
234+ if (header->tzh_version >= '2')
235+ {
236+ const gchar *footer = (((const gchar *) (header + 1))
237+ + guint32_from_be(header->tzh_ttisgmtcnt)
238+ + guint32_from_be(header->tzh_ttisstdcnt)
239+ + 12 * guint32_from_be(header->tzh_leapcnt)
240+ + 9 * time_count
241+ + 6 * type_count
242+ + guint32_from_be(header->tzh_charcnt));
243+ const gchar *footerlast;
244+ size_t footerlen;
245+ g_return_if_fail (footer <= data + size - 2 && footer[0] == '\n');
246+ footerlast = memchr (footer + 1, '\n', data + size - (footer + 1));
247+ g_return_if_fail (footerlast);
248+ footerlen = footerlast + 1 - footer;
249+ if (footerlen != 2)
250+ {
251+ footertz = parse_footertz (footer, footerlen);
252+ g_return_if_fail (footertz);
253+ extra_type_count = footertz->t_info->len;
254+ extra_time_count = footertz->transitions->len;
255+ }
256+ }
257+
258 tz_transitions = ((guint8 *) (header) + sizeof (*header));
259 tz_type_index = tz_transitions + timesize * time_count;
260 tz_ttinfo = tz_type_index + time_count;
261@@ -557,9 +616,9 @@ init_zone_from_iana_info (GTimeZone *gtz,
262
263 gtz->name = g_steal_pointer (&identifier);
264 gtz->t_info = g_array_sized_new (FALSE, TRUE, sizeof (TransitionInfo),
265- type_count);
266+ type_count + extra_type_count);
267 gtz->transitions = g_array_sized_new (FALSE, TRUE, sizeof (Transition),
268- time_count);
269+ time_count + extra_time_count);
270
271 for (index = 0; index < type_count; index++)
272 {
273@@ -574,15 +633,50 @@ init_zone_from_iana_info (GTimeZone *gtz,
274 for (index = 0; index < time_count; index++)
275 {
276 Transition trans;
277- if (header->tzh_version == '2')
278+ if (header->tzh_version >= '2')
279 trans.time = gint64_from_be (((gint64_be*)tz_transitions)[index]);
280 else
281 trans.time = gint32_from_be (((gint32_be*)tz_transitions)[index]);
282+ last_explicit_transition_time = trans.time;
283 trans.info_index = tz_type_index[index];
284 g_assert (trans.info_index >= 0);
285 g_assert ((guint) trans.info_index < gtz->t_info->len);
286 g_array_append_val (gtz->transitions, trans);
287 }
288+
289+ if (footertz)
290+ {
291+ /* Append footer time types. Don't bother to coalesce
292+ duplicates with existing time types. */
293+ for (index = 0; index < extra_type_count; index++)
294+ {
295+ TransitionInfo t_info;
296+ TransitionInfo *footer_t_info
297+ = &g_array_index (footertz->t_info, TransitionInfo, index);
298+ t_info.gmt_offset = footer_t_info->gmt_offset;
299+ t_info.is_dst = footer_t_info->is_dst;
300+ t_info.abbrev = g_steal_pointer (&footer_t_info->abbrev);
301+ g_array_append_val (gtz->t_info, t_info);
302+ }
303+
304+ /* Append footer transitions that follow the last explicit
305+ transition. */
306+ for (index = 0; index < extra_time_count; index++)
307+ {
308+ Transition *footer_transition
309+ = &g_array_index (footertz->transitions, Transition, index);
310+ if (time_count <= 0
311+ || last_explicit_transition_time < footer_transition->time)
312+ {
313+ Transition trans;
314+ trans.time = footer_transition->time;
315+ trans.info_index = type_count + footer_transition->info_index;
316+ g_array_append_val (gtz->transitions, trans);
317+ }
318+ }
319+
320+ g_time_zone_unref (footertz);
321+ }
322 }
323
324 #elif defined (G_OS_WIN32)
325@@ -590,9 +684,8 @@ init_zone_from_iana_info (GTimeZone *gtz,
326 static void
327 copy_windows_systemtime (SYSTEMTIME *s_time, TimeZoneDate *tzdate)
328 {
329- tzdate->sec = s_time->wSecond;
330- tzdate->min = s_time->wMinute;
331- tzdate->hour = s_time->wHour;
332+ tzdate->offset
333+ = s_time->wHour * 3600 + s_time->wMinute * 60 + s_time->wSecond;
334 tzdate->mon = s_time->wMonth;
335 tzdate->year = s_time->wYear;
336 tzdate->wday = s_time->wDayOfWeek ? s_time->wDayOfWeek : 7;
337@@ -979,7 +1072,7 @@ boundary_for_year (TimeZoneDate *boundary,
338 g_date_clear (&date, 1);
339 g_date_set_dmy (&date, buffer.mday, buffer.mon, buffer.year);
340 return ((g_date_get_julian (&date) - unix_epoch_start) * seconds_per_day +
341- buffer.hour * 3600 + buffer.min * 60 + buffer.sec - offset);
342+ buffer.offset - offset);
343 }
344
345 static void
346@@ -1156,7 +1249,7 @@ init_zone_from_rules (GTimeZone *gtz,
347 * - N is 0 to 365
348 *
349 * time is either h or hh[[:]mm[[[:]ss]]]
350- * - h[h] is 0 to 23
351+ * - h[h] is 0 to 24
352 * - mm is 00 to 59
353 * - ss is 00 to 59
354 */
355@@ -1289,25 +1382,10 @@ parse_tz_boundary (const gchar *identifier,
356 /* Time */
357
358 if (*pos == '/')
359- {
360- gint32 offset;
361-
362- if (!parse_time (++pos, &offset))
363- return FALSE;
364-
365- boundary->hour = offset / 3600;
366- boundary->min = (offset / 60) % 60;
367- boundary->sec = offset % 3600;
368-
369- return TRUE;
370- }
371-
372+ return parse_constant_offset (pos + 1, &boundary->offset, TRUE);
373 else
374 {
375- boundary->hour = 2;
376- boundary->min = 0;
377- boundary->sec = 0;
378-
379+ boundary->offset = 2 * 60 * 60;
380 return *pos == '\0';
381 }
382 }
383@@ -1341,7 +1419,7 @@ parse_offset (gchar **pos, gint32 *target)
384 ++(*pos);
385
386 buffer = g_strndup (target_pos, *pos - target_pos);
387- ret = parse_constant_offset (buffer, target);
388+ ret = parse_constant_offset (buffer, target, FALSE);
389 g_free (buffer);
390
391 return ret;
392@@ -1366,21 +1444,32 @@ parse_identifier_boundary (gchar **pos, TimeZoneDate *target)
393 static gboolean
394 set_tz_name (gchar **pos, gchar *buffer, guint size)
395 {
396+ gboolean quoted = **pos == '<';
397 gchar *name_pos = *pos;
398 guint len;
399
400- /* Name is ASCII alpha (Is this necessarily true?) */
401- while (g_ascii_isalpha (**pos))
402- ++(*pos);
403+ if (quoted)
404+ {
405+ name_pos++;
406+ do
407+ ++(*pos);
408+ while (g_ascii_isalnum (**pos) || **pos == '-' || **pos == '+');
409+ if (**pos != '>')
410+ return FALSE;
411+ }
412+ else
413+ while (g_ascii_isalpha (**pos))
414+ ++(*pos);
415
416- /* Name should be three or more alphabetic characters */
417+ /* Name should be three or more characters */
418 if (*pos - name_pos < 3)
419 return FALSE;
420
421- memset (buffer, 0, NAME_SIZE);
422+ memset (buffer, 0, size);
423 /* name_pos isn't 0-terminated, so we have to limit the length expressly */
424 len = *pos - name_pos > size - 1 ? size - 1 : *pos - name_pos;
425 strncpy (buffer, name_pos, len);
426+ *pos += quoted;
427 return TRUE;
428 }
429
430@@ -1483,6 +1572,28 @@ rules_from_identifier (const gchar *identifier,
431 return create_ruleset_from_rule (rules, &tzr);
432 }
433
434+#ifdef G_OS_UNIX
435+static GTimeZone *
436+parse_footertz (const gchar *footer, size_t footerlen)
437+{
438+ gchar *tzstring = g_strndup (footer + 1, footerlen - 2);
439+ GTimeZone *footertz = NULL;
440+ gchar *ident;
441+ TimeZoneRule *rules;
442+ guint rules_num = rules_from_identifier (tzstring, &ident, &rules);
443+ g_free (ident);
444+ g_free (tzstring);
445+ if (rules_num > 1)
446+ {
447+ footertz = g_slice_new0 (GTimeZone);
448+ init_zone_from_rules (footertz, rules, rules_num, NULL);
449+ footertz->ref_count++;
450+ }
451+ g_free (rules);
452+ return footertz;
453+}
454+#endif
455+
456 /* Construction {{{1 */
457 /**
458 * g_time_zone_new:
diff --git a/meta/recipes-core/glib-2.0/glib-2.0_2.64.5.bb b/meta/recipes-core/glib-2.0/glib-2.0_2.64.5.bb
index a1233e6926..a30c5215be 100644
--- a/meta/recipes-core/glib-2.0/glib-2.0_2.64.5.bb
+++ b/meta/recipes-core/glib-2.0/glib-2.0_2.64.5.bb
@@ -16,6 +16,7 @@ SRC_URI = "${GNOME_MIRROR}/glib/${SHRT_VER}/glib-${PV}.tar.xz \
16 file://0001-Do-not-write-bindir-into-pkg-config-files.patch \ 16 file://0001-Do-not-write-bindir-into-pkg-config-files.patch \
17 file://0001-meson-Run-atomics-test-on-clang-as-well.patch \ 17 file://0001-meson-Run-atomics-test-on-clang-as-well.patch \
18 file://0001-gio-tests-resources.c-comment-out-a-build-host-only-.patch \ 18 file://0001-gio-tests-resources.c-comment-out-a-build-host-only-.patch \
19 file://tzdata-update.patch \
19 " 20 "
20 21
21SRC_URI_append_class-native = " file://relocate-modules.patch" 22SRC_URI_append_class-native = " file://relocate-modules.patch"