From: David Spickett Date: Thu, 21 Apr 2022 14:09:56 +0000 (+0000) Subject: [libcxx] Reject month 0 in get_date/__get_month X-Git-Tag: upstream/15.0.7~8461 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=ab07d06e7b864029620927790dfb23b6a5900e13;p=platform%2Fupstream%2Fllvm.git [libcxx] Reject month 0 in get_date/__get_month [libcxx] Reject month 0 in get_date/__get_month This fixes #47663. Months in dates should be >= 1 and <= 12. We parse up to two digits then minus one, because we want to store this as "months since January" (0-11). However we didn't check that the result of that was not -1. For example if you had (MM/DD/YYYY) 00/21/2022. Added tests for: * Failing if month is 0 * Failing if month is 13 * Allowing a leading zero in month e.g. "01" Note that libc++ and libstdc++ return different values on parsing failure, and MSVC STL returns end of stream instead. Handle the first two by checking for defines, MSVC STL expects these tests to fail for other reasons already: https://github.com/microsoft/STL/blob/main/tests/libcxx/expected_results.txt#L372 so not handling that case here. Reviewed By: #libc, Mordante Differential Revision: https://reviews.llvm.org/D124175 --- diff --git a/libcxx/include/locale b/libcxx/include/locale index 8ff7567..879f4d9 100644 --- a/libcxx/include/locale +++ b/libcxx/include/locale @@ -1925,7 +1925,7 @@ time_get<_CharT, _InputIterator>::__get_month(int& __m, const ctype& __ct) const { int __t = __get_up_to_n_digits(__b, __e, __err, __ct, 2) - 1; - if (!(__err & ios_base::failbit) && __t <= 11) + if (!(__err & ios_base::failbit) && 0 <= __t && __t <= 11) __m = __t; else __err |= ios_base::failbit; diff --git a/libcxx/test/std/localization/locale.categories/category.time/locale.time.get.byname/get_date.pass.cpp b/libcxx/test/std/localization/locale.categories/category.time/locale.time.get.byname/get_date.pass.cpp index 79bcf1b..a3ae925 100644 --- a/libcxx/test/std/localization/locale.categories/category.time/locale.time.get.byname/get_date.pass.cpp +++ b/libcxx/test/std/localization/locale.categories/category.time/locale.time.get.byname/get_date.pass.cpp @@ -104,5 +104,57 @@ int main(int, char**) assert(t.tm_year == 109); assert(err == std::ios_base::eofbit); } + // Months must be > 0 and <= 12. + { + const my_facet f(LOCALE_en_US_UTF_8, 1); + const char in[] = "00/21/2022"; + err = std::ios_base::goodbit; + t = std::tm(); + I i = f.get_date(I(in), I(in+sizeof(in)/sizeof(in[0])-1), ios, err, &t); +#if _LIBCPP_VERSION + // libc++ points to the '/' after the month. + assert(base(i) == in+2); +#else + // libstdc++ points to the second character. + assert(base(i) == in+1); +#endif + // tm is not modified. + assert(t.tm_mon == 0); + assert(t.tm_mday == 0); + assert(t.tm_year == 0); + assert(err == std::ios_base::failbit); + } + { + const my_facet f(LOCALE_en_US_UTF_8, 1); + const char in[] = "13/21/2022"; + err = std::ios_base::goodbit; + t = std::tm(); + I i = f.get_date(I(in), I(in+sizeof(in)/sizeof(in[0])-1), ios, err, &t); +#if _LIBCPP_VERSION + // libc++ points to the '/' after the month. + assert(base(i) == in+2); +#else + // libstdc++ points to the second character. + assert(base(i) == in+1); +#endif + assert(base(i) == in+2); + assert(t.tm_mon == 0); + assert(t.tm_mday == 0); + assert(t.tm_year == 0); + assert(err == std::ios_base::failbit); + } + // Leading zero is allowed. + { + const my_facet f(LOCALE_en_US_UTF_8, 1); + const char in[] = "03/21/2022"; + err = std::ios_base::goodbit; + t = std::tm(); + I i = f.get_date(I(in), I(in+sizeof(in)/sizeof(in[0])-1), ios, err, &t); + assert(base(i) == in+sizeof(in)/sizeof(in[0])-1); + assert(t.tm_mon == 2); + assert(t.tm_mday == 21); + assert(t.tm_year == 122); + assert(err == std::ios_base::eofbit); + } return 0; }