public inbox for libstdc++-cvs@sourceware.org help / color / mirror / Atom feed
From: Jonathan Wakely <redi@gcc.gnu.org> 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 Date: Fri, 1 Sep 2023 10:55:10 +0000 (GMT) [thread overview] Message-ID: <20230901105510.1AB3A3857C4F@sourceware.org> (raw) https://gcc.gnu.org/g:e5af77adefc981cbc253cc4c589e1fc06cf07f43 commit r14-3610-ge5af77adefc981cbc253cc4c589e1fc06cf07f43 Author: Jonathan Wakely <jwakely@redhat.com> 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)
reply other threads:[~2023-09-01 10:55 UTC|newest] Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20230901105510.1AB3A3857C4F@sourceware.org \ --to=redi@gcc.gnu.org \ --cc=gcc-cvs@gcc.gnu.org \ --cc=libstdc++-cvs@gcc.gnu.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).