From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2181) id 1AB3A3857C4F; Fri, 1 Sep 2023 10:55:10 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 1AB3A3857C4F DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1693565710; bh=nMNPlUer+8Z5KgRPZhquaiIcGeVvrGPczoo10P/Hc5U=; h=From:To:Subject:Date:From; b=lAgbwzWKZhBeM12u6JfIfpg4un8mR+QAaiNHf3ji+OGulzIE/9FOlNwhB1A4FP6hL rlfLOhcZ1eLuTp9wJUIbhLOUJsa4Rru2/aqQLxUPk5GpOuF50APSFQN1sa3SqFG0Pl 2NSrtKp0h2KeIMfvUGeOmGPTOxRC2vnAf987xGi8= MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="utf-8" From: Jonathan Wakely To: gcc-cvs@gcc.gnu.org, libstdc++-cvs@gcc.gnu.org Subject: [gcc r14-3610] libstdc++: Fix how chrono::parse handles errors for time-of-day values X-Act-Checkin: gcc X-Git-Author: Jonathan Wakely X-Git-Refname: refs/heads/master X-Git-Oldrev: 207c507499d23f0176cbfdfe96d3cd50dec39584 X-Git-Newrev: e5af77adefc981cbc253cc4c589e1fc06cf07f43 Message-Id: <20230901105510.1AB3A3857C4F@sourceware.org> Date: Fri, 1 Sep 2023 10:55:10 +0000 (GMT) List-Id: https://gcc.gnu.org/g:e5af77adefc981cbc253cc4c589e1fc06cf07f43 commit r14-3610-ge5af77adefc981cbc253cc4c589e1fc06cf07f43 Author: Jonathan Wakely Date: Thu Aug 31 15:48:15 2023 +0100 libstdc++: Fix how chrono::parse handles errors for time-of-day values 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". Diff: --- 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 f359571b4dba..7352df095ff4 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) - { - __h = __bad_h; - __min = __bad_min; - __s = __bad_sec; - break; - } - if (!__read_chr(':')) + if (__val == -1 || __val > 23) [[unlikely]] { - __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 46eb7f28c85e..86222d595967 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)