gh-126883: Add check that timezone fields are in range for datetime.fromisoformat (#127242)

It was previously possible to specify things like `+00:90:00` which would be equivalent to `+01:30:00`, but is not a valid ISO8601 string.

---------

Co-authored-by: Erlend E. Aasland <erlend.aasland@protonmail.com>
Co-authored-by: Paul Ganssle <1377457+pganssle@users.noreply.github.com>
This commit is contained in:
Semyon Moroz 2025-05-19 18:07:11 +00:00 committed by GitHub
parent 8d490b3687
commit 71c42b778d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 63 additions and 9 deletions

View file

@ -1088,6 +1088,7 @@ parse_isoformat_time(const char *dtstr, size_t dtlen, int *hour, int *minute,
// -3: Failed to parse time component
// -4: Failed to parse time separator
// -5: Malformed timezone string
// -6: Timezone fields are not in range
const char *p = dtstr;
const char *p_end = dtstr + dtlen;
@ -1134,6 +1135,11 @@ parse_isoformat_time(const char *dtstr, size_t dtlen, int *hour, int *minute,
rv = parse_hh_mm_ss_ff(tzinfo_pos, p_end, &tzhour, &tzminute, &tzsecond,
tzmicrosecond);
// Check if timezone fields are in range
if (check_time_args(tzhour, tzminute, tzsecond, *tzmicrosecond, 0) < 0) {
return -6;
}
*tzoffset = tzsign * ((tzhour * 3600) + (tzminute * 60) + tzsecond);
*tzmicrosecond *= tzsign;
@ -5039,6 +5045,9 @@ time_fromisoformat(PyObject *cls, PyObject *tstr) {
&tzoffset, &tzimicrosecond);
if (rv < 0) {
if (rv == -6) {
goto error;
}
goto invalid_string_error;
}
@ -5075,6 +5084,9 @@ invalid_iso_midnight:
invalid_string_error:
PyErr_Format(PyExc_ValueError, "Invalid isoformat string: %R", tstr);
return NULL;
error:
return NULL;
}
@ -5927,6 +5939,9 @@ datetime_fromisoformat(PyObject *cls, PyObject *dtstr)
len -= (p - dt_ptr);
rv = parse_isoformat_time(p, len, &hour, &minute, &second,
&microsecond, &tzoffset, &tzusec);
if (rv == -6) {
goto error;
}
}
if (rv < 0) {
goto invalid_string_error;