You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Segfault from zoneinfo with custom DateTime class #125318
If I run whoopsie, I get one of the following outcomes:
It prints 02:00:00
It prints 01:00:00
It prints 00:53:28
It segfaults
<project dir>/venv313/bin/python -X dev <project dir>/segfault.py
Fatal Python error: Segmentation fault
Current thread 0x00007fd62be47b80 (most recent call first):
File "<project dir>/segfault.py", line 27 in whoopsie
File "<project dir>/segfault.py", line 34 in <module>
I've tried running the test in a loop and it seems to always spit out the same result within a single run. So I assume some global state, memory layout, or or such is involved.
CPython versions tested on:
3.9, 3.13
Operating systems tested on:
Linux
Output from running 'python -VV' on the command line:
Python 3.13.0 (main, Oct 10 2024, 13:32:18) [GCC 11.4.0]
Oh wait, I figured out why I couldn't reproduce this before. The given reproducer does not call whoopsie(), so the script compiles and finishes just fine--silly me! Confirmed on all bugfix versions, thank you for the report!
As the contract for tzinfo base class is not very clear and by the docstring in pure Python zoneinfo here, I would assume these methods should only accept datetime types. However, there isn't pretty much typecheck in both C zoneinfo and pure Python one.
@robsdedude The PR is a draft and only means to be some attempt (could be bad in theory and it is). Honestly I didn't find it interesting and correct to set fold = 0 and derive hacky ymd from toordinal(), which is only a part of the datetime "contract".
If possible, we should:
either add type checks in all zoneinfo implementations to restrict the contract
or remove all type checks, and align the C module with pure Python zoneinfo behaviors
Since the missing typecheck causes out-of-bounds read now, I think the best bet here is to add type checks first.
@ZeroIntensity What would you think? Or shall we cc and discuss with datetime code owners instead?
I'm not clear on what is causing the segfault here, but I think regardless of the contract of Zoneinfo, this needs to be fixed. It should not be possible to crash the interpreter using pure Python code.
Or am I missing something, and my response is already the assumption? Is the question about whether this should raise an exception vs. doing something else?
IMO, duck-typing C code is a PITA, and we shouldn't encourage it. But, I don't know what the convention is for datetime--if we're supporting duck-typing already, then it makes sense to do it here as well.
Ah, sorry, I was on the phone and didn't really follow the context here. Thanks for the extra information.
I think for this particular issue, we need to backport a fix (possibly even to versions receiving security-only-updates), so at least for the backports, we can't do anything even remotely breaking except in cases that were already broken. If enforcing that ZoneInfo accept only datetime subclasses would break use cases that were working before and not causing segfaults, we have to maintain that.
For 3.13+, we can take a more principled stance. I'm kinda ambivalent about it. I am generally in favor of duck typing, but it is hard to detect that something actually matches the protocol — especially since we can't really declare easily that the semantic meaning of a method on a duck-typed "datetime" matches the semantics we are expecting. For example Pendulum is even a subclass of datetime, but they change the semantics of addition and subtraction, so we may be making invalid assumptions about how those work.
That said, at the end of the day, bugs introduced by "false friend" classes are basically bugs for those classes, and that's really more an argument for not creating duck-typed datetime-like classes than it is for not supporting them.
Assuming we do go with a mechanism that supports duck-typing, we will almost certainly want to do something similar to what we're doing with subclass constructors, where we have a "fast path" for datetime subclasses, and then a slow path that goes through the Python interface for anything else.
For the backport only, I would say to just try to detect the situation where a segfault is going to happen and raise an exception.
#125824 Here is the backport patch. I don't think the segfault could be precisely predicted. In favor of soundness / completeness, a type check is necessary, but would break existing usecases. The patch I made now allows only 1 step of out-of-bounds read (i.e. out-of-bounds value fold must be either 0 or 1).
I looked into this and it seems like we can pretty easily do this in a fully backwards-compatible way by dispatching to Python attribute lookups when the dt object is not a datetime.datetime, so I implemented that in #139132. I don't know if we want to consider this a valid thing to do, but at least now it won't segfault.
This is something similar to #137754. There are two implementations of both datetime and zoneinfo in the stdlib: pure Python and C. But they only work with the corresponding implementation -- Python with Python, C with C. If we are going to support independent third-party implementations, we still have a lot of work to do. For example, ZoneInfo.fromutc() raises TypeError if the argument is not the instance of the right datetime.
Activity
ZeroIntensity commentedon Oct 13, 2024
Oh wait, I figured out why I couldn't reproduce this before. The given reproducer does not call
whoopsie(), so the script compiles and finishes just fine--silly me! Confirmed on all bugfix versions, thank you for the report!y5c4l3 commentedon Oct 21, 2024
As the contract for
tzinfobase class is not very clear and by the docstring in pure Python zoneinfo here, I would assume these methods should only acceptdatetimetypes. However, there isn't pretty much typecheck in both C zoneinfo and pure Python one.cpython/Lib/_pydatetime.py
Lines 1290 to 1317 in 0cd2140
They only check the types at
fromutc(dt).cpython/Modules/_zoneinfo.c
Lines 615 to 618 in 0cd2140
cpython/Lib/zoneinfo/_zoneinfo.py
Lines 114 to 118 in 0cd2140
It turns out that the pure Python one could be leveraged safely by duck types:
cpython/Lib/zoneinfo/_zoneinfo.py
Lines 158 to 177 in 0cd2140
y5c4l3 commentedon Oct 21, 2024
@robsdedude The PR is a draft and only means to be some attempt (could be bad in theory and it is). Honestly I didn't find it interesting and correct to set
fold = 0and derive hacky ymd fromtoordinal(), which is only a part of thedatetime"contract".If possible, we should:
Since the missing typecheck causes out-of-bounds read now, I think the best bet here is to add type checks first.
@ZeroIntensity What would you think? Or shall we cc and discuss with
datetimecode owners instead?ZeroIntensity commentedon Oct 21, 2024
@pganssle As a datetime expert, what do you think?
pganssle commentedon Oct 21, 2024
I'm not clear on what is causing the segfault here, but I think regardless of the contract of
Zoneinfo, this needs to be fixed. It should not be possible to crash the interpreter using pure Python code.Or am I missing something, and my response is already the assumption? Is the question about whether this should raise an exception vs. doing something else?
ZeroIntensity commentedon Oct 21, 2024
Yeah, from my understanding it's about whether or not to try to ducktype a datetime class or just thrown a exception if it doesn't inherit.
y5c4l3 commentedon Oct 21, 2024
FYI
PyDateTime_DATE_GET_FOLDon a nonPyDateTimedtcpython/Modules/_zoneinfo.c
Lines 2180 to 2199 in 5989eb7
ZeroIntensity commentedon Oct 21, 2024
IMO, duck-typing C code is a PITA, and we shouldn't encourage it. But, I don't know what the convention is for datetime--if we're supporting duck-typing already, then it makes sense to do it here as well.
pganssle commentedon Oct 21, 2024
Ah, sorry, I was on the phone and didn't really follow the context here. Thanks for the extra information.
I think for this particular issue, we need to backport a fix (possibly even to versions receiving security-only-updates), so at least for the backports, we can't do anything even remotely breaking except in cases that were already broken. If enforcing that
ZoneInfoaccept onlydatetimesubclasses would break use cases that were working before and not causing segfaults, we have to maintain that.For 3.13+, we can take a more principled stance. I'm kinda ambivalent about it. I am generally in favor of duck typing, but it is hard to detect that something actually matches the protocol — especially since we can't really declare easily that the semantic meaning of a method on a duck-typed "datetime" matches the semantics we are expecting. For example
Pendulumis even a subclass ofdatetime, but they change the semantics of addition and subtraction, so we may be making invalid assumptions about how those work.That said, at the end of the day, bugs introduced by "false friend" classes are basically bugs for those classes, and that's really more an argument for not creating duck-typed datetime-like classes than it is for not supporting them.
Assuming we do go with a mechanism that supports duck-typing, we will almost certainly want to do something similar to what we're doing with subclass constructors, where we have a "fast path" for datetime subclasses, and then a slow path that goes through the Python interface for anything else.
For the backport only, I would say to just try to detect the situation where a segfault is going to happen and raise an exception.
y5c4l3 commentedon Oct 22, 2024
#125824 Here is the backport patch. I don't think the segfault could be precisely predicted. In favor of soundness / completeness, a type check is necessary, but would break existing usecases. The patch I made now allows only 1 step of out-of-bounds read (i.e. out-of-bounds value
foldmust be either 0 or 1).I've written a test that makes the out-of-bounds read more reproducible, but address sanitizer catches the UAF in my test:
https://github.com/python/cpython/actions/runs/11452302563/job/31862970634
Would you think it's reasonable to skip the test when address sanitizer is enabled?
pganssle commentedon Sep 18, 2025
I looked into this and it seems like we can pretty easily do this in a fully backwards-compatible way by dispatching to Python attribute lookups when the
dtobject is not adatetime.datetime, so I implemented that in #139132. I don't know if we want to consider this a valid thing to do, but at least now it won't segfault.serhiy-storchaka commentedon Sep 19, 2025
This is something similar to #137754. There are two implementations of both
datetimeandzoneinfoin the stdlib: pure Python and C. But they only work with the corresponding implementation -- Python with Python, C with C. If we are going to support independent third-party implementations, we still have a lot of work to do. For example,ZoneInfo.fromutc()raises TypeError if the argument is not the instance of the rightdatetime.robsdedude commentedon Oct 20, 2026
This is a duplicate of or at least related to #111306
pythongh-125318: Fix validation of zoneinfo false friends
docs: Unreleased summary and deploy order for the source-truth wave
fixup! pythongh-125318: Fix validation of zoneinfo false friends