diff --git a/Lib/test/datetimetester.py b/Lib/test/datetimetester.py index 55e061950ff..404894ac36b 100644 --- a/Lib/test/datetimetester.py +++ b/Lib/test/datetimetester.py @@ -1908,6 +1908,10 @@ class TestDate(HarmlessMixedComparison, unittest.TestCase): '2009-02-29', # Invalid leap day '2019-W53-1', # No week 53 in 2019 '2020-W54-1', # No week 54 + '0000-W25-1', # Invalid year + '10000-W25-1', # Invalid year + '2020-W25-0', # Invalid day-of-week + '2020-W25-8', # Invalid day-of-week '2009\ud80002\ud80028', # Separators are surrogate codepoints ] diff --git a/Misc/ACKS b/Misc/ACKS index 371e9376582..29a70b121fa 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -492,6 +492,7 @@ David Edelsohn John Edmonds Benjamin Edwards Grant Edwards +Vlad Efanov Zvi Effron John Ehresman Tal Einat diff --git a/Misc/NEWS.d/next/C API/2024-04-08-09-44-29.gh-issue-117534.54ZE_n.rst b/Misc/NEWS.d/next/C API/2024-04-08-09-44-29.gh-issue-117534.54ZE_n.rst new file mode 100644 index 00000000000..4b7dda610fc --- /dev/null +++ b/Misc/NEWS.d/next/C API/2024-04-08-09-44-29.gh-issue-117534.54ZE_n.rst @@ -0,0 +1,2 @@ +Improve validation logic in the C implementation of :meth:`datetime.fromisoformat` +to better handle invalid years. Patch by Vlad Efanov. diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index c8dbc750b0e..8552e42d8be 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -392,6 +392,10 @@ iso_week1_monday(int year) static int iso_to_ymd(const int iso_year, const int iso_week, const int iso_day, int *year, int *month, int *day) { + // Year is bounded to 0 < year < 10000 because 9999-12-31 is (9999, 52, 5) + if (iso_year < MINYEAR || iso_year > MAXYEAR) { + return -4; + } if (iso_week <= 0 || iso_week >= 53) { int out_of_range = 1; if (iso_week == 53) { @@ -738,7 +742,7 @@ parse_isoformat_date(const char *dtstr, const size_t len, int *year, int *month, * -2: Inconsistent date separator usage * -3: Failed to parse ISO week. * -4: Failed to parse ISO day. - * -5, -6: Failure in iso_to_ymd + * -5, -6, -7: Failure in iso_to_ymd */ const char *p = dtstr; p = parse_digits(p, year, 4); @@ -3097,15 +3101,13 @@ date_fromisocalendar(PyObject *cls, PyObject *args, PyObject *kw) return NULL; } - // Year is bounded to 0 < year < 10000 because 9999-12-31 is (9999, 52, 5) - if (year < MINYEAR || year > MAXYEAR) { - PyErr_Format(PyExc_ValueError, "Year is out of range: %d", year); - return NULL; - } - int month; int rv = iso_to_ymd(year, week, day, &year, &month, &day); + if (rv == -4) { + PyErr_Format(PyExc_ValueError, "Year is out of range: %d", year); + return NULL; + } if (rv == -2) { PyErr_Format(PyExc_ValueError, "Invalid week: %d", week);