From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTPS id 5077B3856DE6 for ; Fri, 1 Sep 2023 10:55:29 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 5077B3856DE6 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1693565729; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=y5yUru6bFgE13KdE1+WSnZjaoKY97CETKwoAdfKusP4=; b=ZhPlL5QG9B19sUVUWkx7/YTExDtXs0WWd3UMANcV1bvVAAdrsucJVqXjuYR5ORI0uIeuBk kZV+PW7OdPQHjptxEiRsv+QC3yXn1g65whBNCgYt0qd0v9nLnYsh19pZjOZQH5YM6+6bxy QRv8GTmV1kKa/vR+/vAPQ5rUSaJOd88= 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-613-9X9plWawODKPVPwVkFvsGQ-1; Fri, 01 Sep 2023 06:55:27 -0400 X-MC-Unique: 9X9plWawODKPVPwVkFvsGQ-1 Received: from smtp.corp.redhat.com (int-mx09.intmail.prod.int.rdu2.redhat.com [10.11.54.9]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 4C3AE800193; Fri, 1 Sep 2023 10:55:27 +0000 (UTC) Received: from localhost (unknown [10.42.28.181]) by smtp.corp.redhat.com (Postfix) with ESMTP id 11A2F493110; Fri, 1 Sep 2023 10:55:26 +0000 (UTC) From: Jonathan Wakely To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Subject: [committed] libstdc++: Fix how chrono::parse handles errors for time-of-day values Date: Fri, 1 Sep 2023 11:55:20 +0100 Message-ID: <20230901105526.226787-1-jwakely@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.1 on 10.11.54.9 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Type: text/plain Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-11.0 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,GIT_PATCH_0,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H4,RCVD_IN_MSPIKE_WL,SPF_HELO_NONE,SPF_NONE,TXREP,URIBL_BLACK autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: Tested x86_64-linux. Pushed to trunk. -- >8 -- We fail to diagnose an error and extract an incorrect time for cases like "25:59" >> parse("%H:%M", mins). The bad "25" hour value gets ignored (on the basis that we might not care about it if trying to extract something like a weekday or a month name), but then when we get to the end of the function we think we have a valid time from "59" and so the result is 00:59. The problem is that the '__bad_h' value is used for "no hour value read yet" as well as "bad hour value read". If we just set __h = __bad_h and continue, we can't tell later that we read an invalid hour. The fix is to set failbit early when we're trying to extract a time-of-day (e.g. duration or time_point) and we encounter an invalid hour, minute, or second value. We can still delay other error checking to the end. libstdc++-v3/ChangeLog: * include/bits/chrono_io.h (_Parser::operator()): Set failbit early if invalid values are read when _M_need & _TimeOfDay is non-zero. * testsuite/std/time/parse.cc: Check that "25:59" cannot be parsed for "%H:%M". --- libstdc++-v3/include/bits/chrono_io.h | 53 +++++++++++++----------- libstdc++-v3/testsuite/std/time/parse.cc | 7 ++++ 2 files changed, 36 insertions(+), 24 deletions(-) diff --git a/libstdc++-v3/include/bits/chrono_io.h b/libstdc++-v3/include/bits/chrono_io.h index f359571b4db..7352df095ff 100644 --- a/libstdc++-v3/include/bits/chrono_io.h +++ b/libstdc++-v3/include/bits/chrono_io.h @@ -3327,7 +3327,16 @@ namespace __detail __h = __bad_h; } else if (__c == 'H' && __val >= 0 && __val <= 23) - __h = hours(__val); + { + __h = hours(__val); + __h12 = __bad_h; + } + else + { + if (_M_need & _ChronoParts::_TimeOfDay) + __err |= ios_base::failbit; + break; + } } __parts |= _ChronoParts::_TimeOfDay; break; @@ -3392,9 +3401,8 @@ namespace __detail __min = minutes(__val); else { - __h = __bad_h; - __min = __bad_min; - __s = __bad_sec; + if (_M_need & _ChronoParts::_TimeOfDay) + __err |= ios_base::failbit; break; } } @@ -3481,33 +3489,31 @@ namespace __detail else { auto __val = __read_unsigned(2); - if (__val == -1 || __val > 23) + if (__val == -1 || __val > 23) [[unlikely]] { - __h = __bad_h; - __min = __bad_min; - __s = __bad_sec; - break; - } - if (!__read_chr(':')) - { - __err |= ios_base::failbit; + if (_M_need & _ChronoParts::_TimeOfDay) + __err |= ios_base::failbit; break; } + if (!__read_chr(':')) [[unlikely]] + break; __h = hours(__val); __val = __read_unsigned(2); - if (__val == -1 || __val > 60) + if (__val == -1 || __val > 60) [[unlikely]] { - __h = __bad_h; - __min = __bad_min; - __s = __bad_sec; + if (_M_need & _ChronoParts::_TimeOfDay) + __err |= ios_base::failbit; break; } __min = minutes(__val); - __parts |= _ChronoParts::_TimeOfDay; - - if (__c != 'T' || !__read_chr(':')) + if (__c == 'R') + { + __parts |= _ChronoParts::_TimeOfDay; + break; + } + else if (!__read_chr(':')) [[unlikely]] break; } [[fallthrough]]; @@ -3527,13 +3533,12 @@ namespace __detail ratio<1>>) { auto __val = __read_unsigned(__num ? __num : 2); - if (0 <= __val && __val <= 59) + if (0 <= __val && __val <= 59) [[likely]] __s = seconds(__val); else { - __h = __bad_h; - __min = __bad_min; - __s = __bad_sec; + if (_M_need & _ChronoParts::_TimeOfDay) + __err |= ios_base::failbit; break; } } diff --git a/libstdc++-v3/testsuite/std/time/parse.cc b/libstdc++-v3/testsuite/std/time/parse.cc index 46eb7f28c85..86222d59596 100644 --- a/libstdc++-v3/testsuite/std/time/parse.cc +++ b/libstdc++-v3/testsuite/std/time/parse.cc @@ -252,6 +252,13 @@ test_errors() VERIFY( is.eof() && ! is.fail() ); VERIFY( y == 2010y ); + min = -1min; + is.clear(); + is.str("25:59"); + is >> parse("%H:%M", min); // 25h is out of range and needed + VERIFY( is.fail() ); + VERIFY( min == -1min ); + is.clear(); is.str("328 00"); is >> parse("%3C %y", y); // 328 is out of range for %C (PR libstdc++/111162) -- 2.41.0