`datetime` : Type Confusion in tzinfo_fromutc()
Chưa có ai nhận issue này.
- Ngôn ngữ chính
- Python
- Star
- 77.2k
- Fork
- 35.9k
- Chỉ số merge pull request
- Chỉ số pull request đang chờ
Mô tả
Crash report
What happened?
In tzinfo_fromutc(), the first call to add_datetime_timedelta() at line 4168 internally calls new_datetime_subclass_ex(), which invokes the subclass __new__() method. If the subclass __new__() returns an object that is not a datetime instance, the code proceeds to use it as a PyDateTime_DateTime * without any type check.
At line 4179, this non-datetime object is passed to add_datetime_timedelta() again with a direct (PyDateTime_DateTime *) cast:
// Line 4168 — first call, result can be any Python object
result = add_datetime_timedelta((PyDateTime_DateTime *)dt, delta, 1);
if (result == NULL)
goto Fail;
// Line 4179 — second call, result cast to PyDateTime_DateTime* without type check
Py_SETREF(result, add_datetime_timedelta((PyDateTime_DateTime *)result,
(PyDateTime_Delta *)dst, 1));
Inside add_datetime_timedelta() (line 6194–6217), the accessor macros GET_YEAR(), GET_MONTH(), GET_DAY() etc. read from fixed offsets relative to the PyDateTime_DateTime struct layout. When the object is actually a bytearray, these offsets correspond to entirely different fields (ob_alloc, ob_bytes, ob_start), resulting in garbage values.
import datetime
call_count = 0
class EvilDatetime(datetime.datetime):
def __new__(cls, *args, **kwargs):
global call_count
call_count += 1
if call_count > 1:
return bytearray(b'\x00' * 200)
return super().__new__(cls, *args, **kwargs)
class SimpleTZ(datetime.tzinfo):
def utcoffset(self, dt):
return datetime.timedelta(hours=2)
def dst(self, dt):
return datetime.timedelta(hours=1)
def tzname(self, dt):
return "Test"
tz = SimpleTZ()
call_count = 0
dt = EvilDatetime(2000, 1, 1, 12, 0, 0, tzinfo=tz)
tz.fromutc(dt) # Crash
Direct execution (ASAN build)
$ ./build-asan/python fromutc_type_confusion.py
python: ../Modules/_datetimemodule.c:770: normalize_y_m_d: Assertion `1 <= *m && *m <= 12' failed.
Exit code: 134
The interpreter aborts due to the assertion 1 <= *m && *m <= 12 in normalize_y_m_d() (line 770), because GET_MONTH() reads a zero value from the bytearray's ob_alloc field instead of the datetime's data[2] field.
Crash backtrace
(gdb) continue
Program received signal SIGABRT, Aborted.
(gdb) backtrace
#0 __pthread_kill_implementation (signo=6) at ./nptl/pthread_kill.c:44
#1 __pthread_kill_internal (signo=6) at ./nptl/pthread_kill.c:78
#2 __GI___pthread_kill (signo=6) at ./nptl/pthread_kill.c:89
#3 __GI_raise (sig=6) at ../sysdeps/posix/raise.c:26
#4 __GI_abort () at ./stdlib/abort.c:79
#5 __assert_fail_base (assertion=0x55555611ad20 "1 <= *m && *m <= 12",
file=0x555556119940 "../Modules/_datetimemodule.c", line=770,
function=0x55555611fb40 "normalize_y_m_d") at ./assert/assert.c:96
#6 __assert_fail (assertion=0x55555611ad20 "1 <= *m && *m <= 12",
file=0x555556119940 "../Modules/_datetimemodule.c", line=770,
function=0x55555611fb40 "normalize_y_m_d") at ./assert/assert.c:105
#7 normalize_y_m_d (m=0x7ffff551ec30) at ../Modules/_datetimemodule.c:770
#8 normalize_date at ../Modules/_datetimemodule.c:831
#9 normalize_datetime at ../Modules/_datetimemodule.c:846
#10 add_datetime_timedelta (date=0x5080000d4b30, delta=0x50600005dd50, factor=1)
at ../Modules/_datetimemodule.c:6208
#11 tzinfo_fromutc at ../Modules/_datetimemodule.c:4179
CPython versions tested on:
CPython main branch
Operating systems tested on:
macOS, Linux
Output from running 'python -VV' on the command line:
Python 3.15.0a6+
Linked PRs
- gh-145181
Hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Hướng nghiên cứu
Đọc Modules/_datetimemodule.c quanh tzinfo_fromutc() và add_datetime_timedelta(), sau đó chạy reproducer được cung cấp với bản build ASAN. Hoàn thành khi kết quả của subclass không phải datetime không còn đi tới thao tác truy cập các field của datetime và một regression test bao quát trường hợp crash. PR gh-145181 đã được liên kết.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Đánh giá
- Công nghệ
- c, python
- Lĩnh vực
- backend
- Loại issue
- Lỗi
- Độ khó
- 4/5
- Thời gian dự kiến
- 3-5 ngày
- Mức độ hoạt động
- Đình trệ
- Độ rõ ràng
- Đặc tả rõ ràng
- Mức phù hợp với người mới
- 25/100