From patchwork Tue May 8 13:16:41 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Weimer X-Patchwork-Id: 910180 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=sourceware.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=libc-alpha-return-92201-incoming=patchwork.ozlabs.org@sourceware.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; secure) header.d=sourceware.org header.i=@sourceware.org header.b="aokniRFj"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 40gKlF4Yrhz9s1w for ; Tue, 8 May 2018 23:16:57 +1000 (AEST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:to:cc:from:subject:message-id:date :mime-version:content-type; q=dns; s=default; b=I80Hcenlx4YuG9r4 87WE8wUyIrGSVnQtW+ZvKFmVvTkFRyGtDW4gpri4XisrTMS03JFnto9A5/KMtkKq mzlPC0TC0eT9WA1kdhIHGcNFrso7uPFKzpSy6aWROiG2ZKg8NqX8hz4A9RfpPOCf MqigNNnAb8Rx7NLDBtKNU0nIiEE= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:to:cc:from:subject:message-id:date :mime-version:content-type; s=default; bh=I3Ng40VVVOH9n/yuSCr7KV i+Rj0=; b=aokniRFjlY2vD3nMewphgOkEF8X1fEXO/h6zoc4aEmuYF3BiagFLaF BIOWsWvg6TV1oxN+jqOsE+OWCx2avg/NEmjqP6z6OurTXGn1/8gPNLtCl/JV2Qwl jasR1LpHTuNXGyzRL0hlGBO1M2VL1+c8FNW0GtbNvVFuH2kjBBvJE= Received: (qmail 125242 invoked by alias); 8 May 2018 13:16:51 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 125231 invoked by uid 89); 8 May 2018 13:16:51 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-24.6 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, SPF_HELO_PASS autolearn=ham version=3.3.2 spammy=correction, Switch, 5817, HCc:D*fr X-HELO: mx1.redhat.com To: GNU C Library Cc: Albert ARIBAUD From: Florian Weimer Subject: [PATCH] Use 64-bit time_t for time zone file parsing Message-ID: <264af3e6-84ae-d1a4-c204-c00786b61dd9@redhat.com> Date: Tue, 8 May 2018 15:16:41 +0200 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.7.0 MIME-Version: 1.0 This patch is intended as a precursor for time64_t support. Some further conversions of internal interfaces will be required. It also enables future cleanups in the parser itself. It does not change much, but I believe it is a small step in the right direction. Thanks, Florian Subject: [PATCH] time: Use 64-bit time values for time zone parsing To: libc-alpha@sourceware.org 2018-05-08 Florian Weimer 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. 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..d317db951e 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,18 @@ __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 ((BYTE_ORDER != BIG_ENDIAN && trans_width == 4) + || (BYTE_ORDER == BIG_ENDIAN && 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 +361,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 +392,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 +402,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 +581,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 +636,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; + { + 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. */ + /* 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,