From patchwork Mon Jan 2 11:18:45 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Weimer X-Patchwork-Id: 62541 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id D331C3858D32 for ; Mon, 2 Jan 2023 11:19:12 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org D331C3858D32 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1672658352; bh=ZxM9TiJFuBKoWh7Se+mkXecAsXklt4dh808VaVXoY/s=; h=To:Subject:Date:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=IVBO7o/vmcTOBWzLMuQ9WAyEtaXqUvfavOSS0zFbQpiNDIUTeZc/bvEnfWgOVdis/ yn+u9w203aOzi2zB/JG2lOBnF6bCA1uTvWNH5kVA0NIWfDwee6BWNskdtjX94E0VEM Fd2amC/KgtxK1+RxF6v3B66YasSC8/9Ec2dlREQI= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTPS id E28103858C83 for ; Mon, 2 Jan 2023 11:18:49 +0000 (GMT) Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-608-n_5oshaPP4uOFHB4_giGOg-1; Mon, 02 Jan 2023 06:18:48 -0500 X-MC-Unique: n_5oshaPP4uOFHB4_giGOg-1 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 2021B85A588 for ; Mon, 2 Jan 2023 11:18:48 +0000 (UTC) Received: from oldenburg.str.redhat.com (unknown [10.2.16.30]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 574931121315 for ; Mon, 2 Jan 2023 11:18:47 +0000 (UTC) To: libc-alpha@sourceware.org Subject: [PATCH] time: Set daylight to 1 for matching DST/offset change (bug 29951) Date: Mon, 02 Jan 2023 12:18:45 +0100 Message-ID: <871qodqj56.fsf@oldenburg.str.redhat.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/28.1 (gnu/linux) MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.1 on 10.11.54.3 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-10.6 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Florian Weimer via Libc-alpha From: Florian Weimer Reply-To: Florian Weimer Errors-To: libc-alpha-bounces+patchwork=sourceware.org@sourceware.org Sender: "Libc-alpha" The daylight variable is supposed to be set to 1 if DST is ever in use for the current time zone. But __tzfile_read used to do this: __daylight = rule_stdoff != rule_dstoff; This check can fail to set __daylight to 1 if the DST and non-DST offsets happen to be the same. Tested on i686-linux-gnu and x86_64-linux-gnu. --- time/tzfile.c | 46 ++++++++++++++++++-------------- timezone/Makefile | 4 ++- timezone/testdata/XT6 | Bin 0 -> 625 bytes timezone/tst-bz29951.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 99 insertions(+), 21 deletions(-) new file mode 100644 index 0000000000..357ebf3da7 base-commit: a09183aed7bb8ace211e042b2e6e982bcc004957 diff --git a/time/tzfile.c b/time/tzfile.c index 394b098856..443e40419f 100644 --- a/time/tzfile.c +++ b/time/tzfile.c @@ -61,6 +61,10 @@ static size_t num_leaps; static struct leap *leaps; static char *tzspec; +/* Used to restore the daylight variable during time conversion, as if + tzset had been called. */ +static int daylight_saved; + #include #include @@ -440,34 +444,36 @@ __tzfile_read (const char *file, size_t extra, char **extrap) if (num_transitions == 0) /* Use the first rule (which should also be the only one). */ - rule_stdoff = rule_dstoff = types[0].offset; + { + rule_stdoff = rule_dstoff = types[0].offset; + daylight_saved = 0; + } else { - int stdoff_set = 0, dstoff_set = 0; - rule_stdoff = rule_dstoff = 0; + daylight_saved = 0; + rule_stdoff = 0; + + /* Search for the last rule with a standard time offset. This + will be used for the global timezone variable. */ i = num_transitions - 1; do - { - if (!stdoff_set && !types[type_idxs[i]].isdst) - { - stdoff_set = 1; - rule_stdoff = types[type_idxs[i]].offset; - } - else if (!dstoff_set && types[type_idxs[i]].isdst) - { - dstoff_set = 1; - rule_dstoff = types[type_idxs[i]].offset; - } - if (stdoff_set && dstoff_set) + if (!types[type_idxs[i]].isdst) + { + rule_stdoff = types[type_idxs[i]].offset; break; - } + } + else + daylight_saved = 1; while (i-- > 0); - if (!dstoff_set) - rule_dstoff = rule_stdoff; + /* Keep searching to seet if there is a DST rule. This + information will be used to set the global daylight + variable. */ + while (i-- > 0 && !daylight_saved) + daylight_saved = types[type_idxs[i]].isdst; } - __daylight = rule_stdoff != rule_dstoff; + __daylight = daylight_saved; __timezone = -rule_stdoff; done: @@ -731,7 +737,7 @@ __tzfile_compute (__time64_t timer, int use_localtime, } struct ttinfo *info = &types[i]; - __daylight = rule_stdoff != rule_dstoff; + __daylight = daylight_saved; __timezone = -rule_stdoff; if (__tzname[0] == NULL) diff --git a/timezone/Makefile b/timezone/Makefile index a789c22d26..5002de39ad 100644 --- a/timezone/Makefile +++ b/timezone/Makefile @@ -23,7 +23,7 @@ subdir := timezone include ../Makeconfig others := zdump zic -tests := test-tz tst-timezone tst-tzset tst-bz28707 +tests := test-tz tst-timezone tst-tzset tst-bz28707 tst-bz29951 generated-dirs += testdata @@ -86,11 +86,13 @@ $(objpfx)tst-timezone.out: $(addprefix $(testdata)/, \ Europe/London) $(objpfx)tst-tzset.out: $(addprefix $(testdata)/XT, 1 2 3 4) $(objpfx)tst-bz28707.out: $(testdata)/XT5 +$(objpfx)tst-bz29951.out: $(testdata)/XT6 test-tz-ENV = TZDIR=$(testdata) tst-timezone-ENV = TZDIR=$(testdata) tst-tzset-ENV = TZDIR=$(testdata) tst-bz28707-ENV = TZDIR=$(testdata) +tst-bz29951-ENV = TZDIR=$(testdata) # Note this must come second in the deps list for $(built-program-cmd) to work. zic-deps = $(objpfx)zic $(leapseconds) yearistype diff --git a/timezone/testdata/XT6 b/timezone/testdata/XT6 new file mode 100644 index 0000000000000000000000000000000000000000..07b393bb7db14cef1e906ebe63cfbbe8cddc79d5 GIT binary patch literal 625 zcmb`@&nrYh0KoCtT?f{Wo{Q(l;<399B=szg#O_6Gtap+!4%F^xj&jiEPvGPrIXXyc z%Rvq-3N{@?jVZM*EQs%vx@B49?`FM-@HCOyP9P_uv%;tl)i^Sd8iFF@8 zl9lyqtMa(2t3%_edRW%a*-O7=ds5o9@5=rd(5+AXe%tM`Y%d@C9p?`+R@(48_if#^ zQ?I(WUZkU@RnN+%?#*4PcsimJsj#0+j>*1>Q{T0e5n`? z1y|&!-*2qu3%3vrOPnO;gv@@MEK$d^Xq=h##8hU1#S. */ + +#include +#include +#include +#include + +/* Set the specified time zone with error checking. */ +static void +set_timezone (const char *name) +{ + TEST_VERIFY (setenv ("TZ", name, 1) == 0); + errno = 0; + tzset (); + TEST_COMPARE (errno, 0); +} + +static int +do_test (void) +{ + /* Test zone based on tz-2022g version of Africa/Tripoli. The last + DST transition coincided with a change in the standard time + offset, effectively making it a no-op. + + Africa/Tripoli Thu Oct 24 23:59:59 2013 UT + = Fri Oct 25 01:59:59 2013 CEST isdst=1 gmtoff=7200 + Africa/Tripoli Fri Oct 25 00:00:00 2013 UT + = Fri Oct 25 02:00:00 2013 EET isdst=0 gmtoff=7200 + */ + set_timezone ("XT6"); + TEST_COMPARE (daylight, 1); + TEST_COMPARE (timezone, -7200); + + /* Check that localtime re-initializes the two variables. */ + daylight = timezone = 17; + time_t t = 844034401; + struct tm *tm = localtime (&t); + TEST_COMPARE (daylight, 1); + TEST_COMPARE (timezone, -7200); + TEST_COMPARE (tm->tm_year, 96); + TEST_COMPARE (tm->tm_mon, 8); + TEST_COMPARE (tm->tm_mday, 29); + TEST_COMPARE (tm->tm_hour, 23); + TEST_COMPARE (tm->tm_min, 0); + TEST_COMPARE (tm->tm_sec, 1); + TEST_COMPARE (tm->tm_gmtoff, 3600); + TEST_COMPARE (tm->tm_isdst, 0); + TEST_COMPARE (daylight, 1); + TEST_COMPARE (timezone, -7200); + + return 0; +} + +#include