diff options
author | Florian Weimer <fweimer@redhat.com> | 2018-05-11 16:30:30 +0200 |
---|---|---|
committer | Florian Weimer <fweimer@redhat.com> | 2018-05-11 16:30:30 +0200 |
commit | fc79706a3233b02909b1a75b1e43e40915eb5a04 (patch) | |
tree | ec929508205466117b6e68787aa38752c85a021f | |
parent | 89aacb513eb77549a29df2638913a0f8178cf3f5 (diff) | |
download | glibc-fc79706a3233b02909b1a75b1e43e40915eb5a04.tar.gz |
time: Use 64-bit time values for time zone parsing
-rw-r--r-- | ChangeLog | 13 | ||||
-rw-r--r-- | include/time.h | 6 | ||||
-rw-r--r-- | time/tzfile.c | 118 |
3 files changed, 56 insertions, 81 deletions
@@ -1,5 +1,18 @@ 2018-05-11 Florian Weimer <fweimer@redhat.com> + Use 64-bit epoch values in the time zone file parser. + * include/time.h (internal_time_t): Define. + (__tzfile_compute): Use it. + * time/tzfile.c (struct leap): Use internal_time_t for epoch + member. + (transitions): Switch to internal_time_t. + (__tzfile_read): Likewise. Remove code dealing with 4-byte time_t + types. + (__tzfile_compute): Use internal_time_t for timer argument. Check + for truncation before calling __offtime. + +2018-05-11 Florian Weimer <fweimer@redhat.com> + [BZ #23166] * include/rpc/clnt.h (rpc_createerr): Declare hidden alias. * include/rpc/svc.h (svc_pollfd, svc_max_pollfd, svc_fdset): diff --git a/include/time.h b/include/time.h index aab26d7768..23d2580528 100644 --- a/include/time.h +++ b/include/time.h @@ -26,6 +26,10 @@ extern __typeof (clock_getcpuclockid) __clock_getcpuclockid; /* Now define the internal interfaces. */ struct tm; +/* time_t variant for representing time zone data, independent of + time_t. */ +typedef __int64_t internal_time_t; + /* Defined in mktime.c. */ extern const unsigned short int __mon_yday[2][13] attribute_hidden; @@ -39,7 +43,7 @@ extern int __use_tzfile attribute_hidden; extern void __tzfile_read (const char *file, size_t extra, char **extrap) attribute_hidden; -extern void __tzfile_compute (time_t timer, int use_localtime, +extern void __tzfile_compute (internal_time_t timer, int use_localtime, long int *leap_correct, int *leap_hit, struct tm *tp) attribute_hidden; extern void __tzfile_default (const char *std, const char *dst, diff --git a/time/tzfile.c b/time/tzfile.c index 3e39723148..2a385b92bc 100644 --- a/time/tzfile.c +++ b/time/tzfile.c @@ -44,12 +44,12 @@ struct ttinfo struct leap { - time_t transition; /* Time the transition takes effect. */ + internal_time_t transition; /* Time the transition takes effect. */ long int change; /* Seconds of correction to apply. */ }; static size_t num_transitions; -libc_freeres_ptr (static time_t *transitions); +libc_freeres_ptr (static internal_time_t *transitions); static unsigned char *type_idxs; static size_t num_types; static struct ttinfo *types; @@ -113,8 +113,8 @@ __tzfile_read (const char *file, size_t extra, char **extrap) size_t tzspec_len; char *new = NULL; - if (sizeof (time_t) != 4 && sizeof (time_t) != 8) - abort (); + _Static_assert (sizeof (internal_time_t) == 8, + "internal_time_t must be eight bytes"); __use_tzfile = 0; @@ -200,9 +200,7 @@ __tzfile_read (const char *file, size_t extra, char **extrap) if (__glibc_unlikely (num_isstd > num_types || num_isgmt > num_types)) goto lose; - /* For platforms with 64-bit time_t we use the new format if available. */ - if (sizeof (time_t) == 8 && trans_width == 4 - && tzhead.tzh_version[0] != '\0') + if (trans_width == 4 && tzhead.tzh_version[0] != '\0') { /* We use the 8-byte format. */ trans_width = 8; @@ -222,9 +220,9 @@ __tzfile_read (const char *file, size_t extra, char **extrap) if (__builtin_expect (num_transitions > ((SIZE_MAX - (__alignof__ (struct ttinfo) - 1)) - / (sizeof (time_t) + 1)), 0)) + / (sizeof (internal_time_t) + 1)), 0)) goto lose; - total_size = num_transitions * (sizeof (time_t) + 1); + total_size = num_transitions * (sizeof (internal_time_t) + 1); total_size = ((total_size + __alignof__ (struct ttinfo) - 1) & ~(__alignof__ (struct ttinfo) - 1)); types_idx = total_size; @@ -246,7 +244,7 @@ __tzfile_read (const char *file, size_t extra, char **extrap) goto lose; total_size += num_leaps * sizeof (struct leap); tzspec_len = 0; - if (sizeof (time_t) == 8 && trans_width == 8) + if (trans_width == 8) { off_t rem = st.st_size - __ftello (f); if (__builtin_expect (rem < 0 @@ -276,23 +274,23 @@ __tzfile_read (const char *file, size_t extra, char **extrap) /* Allocate enough memory including the extra block requested by the caller. */ - transitions = (time_t *) malloc (total_size + tzspec_len + extra); + transitions = malloc (total_size + tzspec_len + extra); if (transitions == NULL) goto lose; type_idxs = (unsigned char *) transitions + (num_transitions - * sizeof (time_t)); + * sizeof (internal_time_t)); types = (struct ttinfo *) ((char *) transitions + types_idx); zone_names = (char *) types + num_types * sizeof (struct ttinfo); leaps = (struct leap *) ((char *) transitions + leaps_idx); - if (sizeof (time_t) == 8 && trans_width == 8) + if (trans_width == 8) tzspec = (char *) leaps + num_leaps * sizeof (struct leap) + extra; else tzspec = NULL; if (extra > 0) *extrap = (char *) &leaps[num_leaps]; - if (sizeof (time_t) == 4 || __builtin_expect (trans_width == 8, 1)) + if (__builtin_expect (trans_width == 8, 1)) { if (__builtin_expect (__fread_unlocked (transitions, trans_width + 1, num_transitions, f) @@ -315,19 +313,17 @@ __tzfile_read (const char *file, size_t extra, char **extrap) if (__glibc_unlikely (type_idxs[i] >= num_types)) goto lose; - if ((BYTE_ORDER != BIG_ENDIAN && (sizeof (time_t) == 4 || trans_width == 4)) - || (BYTE_ORDER == BIG_ENDIAN && sizeof (time_t) == 8 - && trans_width == 4)) + if (trans_width == 4) { /* Decode the transition times, stored as 4-byte integers in - network (big-endian) byte order. We work from the end of - the array so as not to clobber the next element to be - processed when sizeof (time_t) > 4. */ + network (big-endian) byte order. We work from the end of the + array so as not to clobber the next element to be + processed. */ i = num_transitions; while (i-- > 0) transitions[i] = decode ((char *) transitions + i * 4); } - else if (BYTE_ORDER != BIG_ENDIAN && sizeof (time_t) == 8) + else if (BYTE_ORDER != BIG_ENDIAN) { /* Decode the transition times, stored as 8-byte integers in network (big-endian) byte order. */ @@ -364,10 +360,10 @@ __tzfile_read (const char *file, size_t extra, char **extrap) if (__builtin_expect (__fread_unlocked (x, 1, trans_width, f) != trans_width, 0)) goto lose; - if (sizeof (time_t) == 4 || trans_width == 4) - leaps[i].transition = (time_t) decode (x); + if (trans_width == 4) + leaps[i].transition = decode (x); else - leaps[i].transition = (time_t) decode64 (x); + leaps[i].transition = decode64 (x); if (__glibc_unlikely (__fread_unlocked (x, 1, 4, f) != 4)) goto lose; @@ -395,7 +391,7 @@ __tzfile_read (const char *file, size_t extra, char **extrap) types[i++].isgmt = 0; /* Read the POSIX TZ-style information if possible. */ - if (sizeof (time_t) == 8 && tzspec != NULL) + if (tzspec != NULL) { /* Skip over the newline first. */ if (__getc_unlocked (f) != '\n' @@ -405,52 +401,6 @@ __tzfile_read (const char *file, size_t extra, char **extrap) else tzspec[tzspec_len - 1] = '\0'; } - else if (sizeof (time_t) == 4 && tzhead.tzh_version[0] != '\0') - { - /* Get the TZ string. */ - if (__builtin_expect (__fread_unlocked ((void *) &tzhead, - sizeof (tzhead), 1, f) != 1, 0) - || (memcmp (tzhead.tzh_magic, TZ_MAGIC, sizeof (tzhead.tzh_magic)) - != 0)) - goto lose; - - size_t num_transitions2 = (size_t) decode (tzhead.tzh_timecnt); - size_t num_types2 = (size_t) decode (tzhead.tzh_typecnt); - size_t chars2 = (size_t) decode (tzhead.tzh_charcnt); - size_t num_leaps2 = (size_t) decode (tzhead.tzh_leapcnt); - size_t num_isstd2 = (size_t) decode (tzhead.tzh_ttisstdcnt); - size_t num_isgmt2 = (size_t) decode (tzhead.tzh_ttisgmtcnt); - - /* Position the stream before the second header. */ - size_t to_skip = (num_transitions2 * (8 + 1) - + num_types2 * 6 - + chars2 - + num_leaps2 * 12 - + num_isstd2 - + num_isgmt2); - off_t off; - if (fseek (f, to_skip, SEEK_CUR) != 0 - || (off = __ftello (f)) < 0 - || st.st_size < off + 2) - goto lose; - - tzspec_len = st.st_size - off - 1; - if (tzspec_len == 0) - goto lose; - char *tzstr = malloc (tzspec_len); - if (tzstr == NULL) - goto lose; - if (__getc_unlocked (f) != '\n' - || (__fread_unlocked (tzstr, 1, tzspec_len - 1, f) - != tzspec_len - 1)) - { - free (tzstr); - goto lose; - } - tzstr[tzspec_len - 1] = '\0'; - tzspec = __tzstring (tzstr); - free (tzstr); - } /* Don't use an empty TZ string. */ if (tzspec != NULL && tzspec[0] == '\0') @@ -630,7 +580,7 @@ __tzfile_default (const char *std, const char *dst, } void -__tzfile_compute (time_t timer, int use_localtime, +__tzfile_compute (internal_time_t timer, int use_localtime, long int *leap_correct, int *leap_hit, struct tm *tp) { @@ -685,10 +635,16 @@ __tzfile_compute (time_t timer, int use_localtime, /* Convert to broken down structure. If this fails do not use the string. */ - if (__glibc_unlikely (! __offtime (&timer, 0, tp))) - goto use_last; - - /* Use the rules from the TZ string to compute the change. */ + { + time_t truncated = timer; + if (__glibc_unlikely (truncated != timer + || ! __offtime (&truncated, 0, tp))) + goto use_last; + } + + /* Use the rules from the TZ string to compute the change. + timer fits into time_t due to the truncation check + above. */ __tz_compute (timer, tp, 1); /* If tzspec comes from posixrules loaded by __tzfile_default, @@ -709,10 +665,12 @@ __tzfile_compute (time_t timer, int use_localtime, then pick the type of the transition before it. */ size_t lo = 0; size_t hi = num_transitions - 1; - /* Assume that DST is changing twice a year and guess initial - search spot from it. - Half of a gregorian year has on average 365.2425 * 86400 / 2 - = 15778476 seconds. */ + /* Assume that DST is changing twice a year and guess + initial search spot from it. Half of a gregorian year + has on average 365.2425 * 86400 / 2 = 15778476 seconds. + The value i can be truncated if size_t is smaller than + internal_time_t, but this is harmless because it is just + a guess. */ i = (transitions[num_transitions - 1] - timer) / 15778476; if (i < num_transitions) { |