Bug report
Bug description:
Modules/_zoneinfo.c:get_local_timestamp() incorrectly treats the valid integer value -1 returned by PyLong_AsLong() as an error for the hour, minute, and second fields.
PyLong_AsLong() returns -1 both on conversion failure and for the legitimate Python integer -1. The C API requires checking PyErr_Occurred() to distinguish these cases.
The function already does this correctly for toordinal():
ord = PyLong_AsLong(num); if (ord == -1 && PyErr_Occurred()) { return -1; }
However, the checks for hour, minute, and second only test == -1:
hour = PyLong_AsLong(num); if (hour == -1) { return -1; } minute = PyLong_AsLong(num); if (minute == -1) { return -1; } second = PyLong_AsLong(num); if (second == -1) { return -1; }
As a result, valid values of -1 are incorrectly treated as conversion failures, causing the function to return an error without an exception being set.
Reproducer
from datetime import datetime from zoneinfo import ZoneInfo class BadDateTime(datetime): @property def hour(self): return -1 dt = BadDateTime(2024, 1, 1, tzinfo=ZoneInfo("UTC")) dt.utcoffset()
Current behavior:
SystemError: <method 'utcoffset' of 'zoneinfo.ZoneInfo' objects> returned NULL without setting an exception
The same issue also affects:
ZoneInfo.dst()ZoneInfo.tzname()ZoneInfo.fromutc()
The issue reproduces on the current main branch on Linux.
CPython versions tested on:
CPython main branch
Operating systems tested on:
Linux
Linked PRs
- gh-154892: Fix PyLong_AsLong() error checks in _zoneinfo #154901
- [3.15] gh-154892: Fix
PyLong_AsLong()error checks in_zoneinfo(GH-154901) #155056 - [3.14] gh-154892: Fix
PyLong_AsLong()error checks in_zoneinfo(GH-154901) #155057 - [3.13] gh-154892: Fix
PyLong_AsLong()error checks in_zoneinfo(GH-154901) #155058