Skip to content

Commit 50552fa

Browse files
committed
Merge remote-tracking branch 'upstream/main' into fix-mimetypes-case-sensitive-add-type
2 parents 2ed828a + 0a179e7 commit 50552fa

24 files changed

Lines changed: 551 additions & 68 deletions

Doc/tools/extensions/profiling_trace.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,10 +154,15 @@ def inject_trace(app, exception):
154154
)
155155

156156

157+
def add_assets(app, pagename, templatename, context, doctree):
158+
if pagename == 'library/profiling.sampling':
159+
app.add_js_file('profiling-sampling-visualization.js')
160+
app.add_css_file('profiling-sampling-visualization.css')
161+
162+
157163
def setup(app):
158164
app.connect('build-finished', inject_trace)
159-
app.add_js_file('profiling-sampling-visualization.js')
160-
app.add_css_file('profiling-sampling-visualization.css')
165+
app.connect('html-page-context', add_assets)
161166

162167
return {
163168
'version': '1.0',

Lib/test/datetimetester.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7509,6 +7509,36 @@ def func():
75097509
self.assertEqual(out, b"a" * 8)
75107510
self.assertEqual(err, b"")
75117511

7512+
@support.cpython_only
7513+
@support.subTests(("setup", "call"), [
7514+
("obj = _datetime.timedelta", "obj(seconds=2)"),
7515+
("obj = _datetime.timedelta(seconds=2)", "obj.total_seconds()"),
7516+
("obj = _datetime.date(2026, 6, 7)", "obj.isocalendar()"),
7517+
])
7518+
def test_static_datetime_types_outlive_collected_module(self, setup, call):
7519+
# gh-151039: This code used to crash
7520+
script = f"""if True:
7521+
import sys, gc
7522+
import _datetime
7523+
7524+
{setup} # static C type, survives the module
7525+
del sys.modules['_datetime']
7526+
del _datetime
7527+
sys.modules['_datetime'] = None # block re-import
7528+
gc.collect() # module object is collected
7529+
7530+
try:
7531+
{call} # used to be a segmentation fault
7532+
except ImportError:
7533+
pass
7534+
else:
7535+
raise AssertionError("ImportError not raised")
7536+
"""
7537+
rc, out, err = script_helper.assert_python_ok("-c", script)
7538+
self.assertEqual(rc, 0)
7539+
self.assertEqual(out, b'')
7540+
self.assertEqual(err, b'')
7541+
75127542

75137543
def load_tests(loader, standard_tests, pattern):
75147544
standard_tests.addTest(ZoneInfoCompleteTest())

Lib/test/test_capi/test_weakref.py

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
import weakref
2+
import unittest
3+
from test.support import import_helper
4+
5+
_testcapi = import_helper.import_module('_testcapi')
6+
_testlimitedcapi = import_helper.import_module('_testlimitedcapi')
7+
NULL = None
8+
9+
class Object:
10+
pass
11+
12+
class Ref(weakref.ReferenceType):
13+
pass
14+
15+
16+
class CAPIWeakrefTest(unittest.TestCase):
17+
def test_pyweakref_check(self):
18+
# Test PyWeakref_Check()
19+
check = _testlimitedcapi.pyweakref_check
20+
obj = Object()
21+
self.assertEqual(check(obj), 0)
22+
self.assertEqual(check(weakref.ref(obj)), 1)
23+
self.assertEqual(check(Ref(obj)), 1)
24+
self.assertEqual(check(weakref.proxy(obj)), 1)
25+
26+
# CRASHES check(NULL)
27+
28+
def test_pyweakref_checkref(self):
29+
# Test PyWeakref_CheckRef()
30+
checkref = _testlimitedcapi.pyweakref_checkref
31+
obj = Object()
32+
self.assertEqual(checkref(obj), 0)
33+
self.assertEqual(checkref(weakref.ref(obj)), 1)
34+
self.assertEqual(checkref(Ref(obj)), 1)
35+
self.assertEqual(checkref(weakref.proxy(obj)), 0)
36+
37+
# CRASHES checkref(NULL)
38+
39+
def test_pyweakref_checkrefexact(self):
40+
# Test PyWeakref_CheckRefExact()
41+
checkrefexact = _testlimitedcapi.pyweakref_checkrefexact
42+
obj = Object()
43+
self.assertEqual(checkrefexact(obj), 0)
44+
self.assertEqual(checkrefexact(weakref.ref(obj)), 1)
45+
self.assertEqual(checkrefexact(Ref(obj)), 0)
46+
self.assertEqual(checkrefexact(weakref.proxy(obj)), 0)
47+
48+
# CRASHES checkrefexact(NULL)
49+
50+
def test_pyweakref_checkproxy(self):
51+
# Test PyWeakref_CheckProxy()
52+
checkproxy = _testlimitedcapi.pyweakref_checkproxy
53+
obj = Object()
54+
self.assertEqual(checkproxy(obj), 0)
55+
self.assertEqual(checkproxy(weakref.ref(obj)), 0)
56+
self.assertEqual(checkproxy(Ref(obj)), 0)
57+
self.assertEqual(checkproxy(weakref.proxy(obj)), 1)
58+
59+
# CRASHES checkproxy(NULL)
60+
61+
def test_pyweakref_getref(self):
62+
# Test PyWeakref_GetRef()
63+
getref = _testcapi.pyweakref_getref
64+
obj = Object()
65+
wr = weakref.ref(obj)
66+
wp = weakref.proxy(obj)
67+
self.assertEqual(getref(wr), (1, obj))
68+
self.assertEqual(getref(wp), (1, obj))
69+
del obj
70+
self.assertEqual(getref(wr), 0)
71+
self.assertEqual(getref(wp), 0)
72+
73+
self.assertRaises(TypeError, getref, 42)
74+
self.assertRaises(SystemError, getref, NULL)
75+
76+
def test_pyweakref_isdead(self):
77+
# Test PyWeakref_IsDead()
78+
isdead = _testcapi.pyweakref_isdead
79+
obj = Object()
80+
wr = weakref.ref(obj)
81+
wp = weakref.proxy(obj)
82+
self.assertEqual(isdead(wr), 0)
83+
self.assertEqual(isdead(wp), 0)
84+
del obj
85+
self.assertEqual(isdead(wr), 1)
86+
self.assertEqual(isdead(wp), 1)
87+
88+
self.assertRaises(TypeError, isdead, 42)
89+
self.assertRaises(SystemError, isdead, NULL)
90+
91+
def test_pyweakref_newref(self):
92+
# Test PyWeakref_NewRef()
93+
newref = _testlimitedcapi.pyweakref_newref
94+
obj = Object()
95+
wr = newref(obj)
96+
self.assertIs(type(wr), weakref.ReferenceType)
97+
# PyWeakref_NewRef() handles None callback as NULL callback
98+
wr = newref(obj, None)
99+
self.assertIs(type(wr), weakref.ReferenceType)
100+
log = []
101+
wr = newref(obj, log.append)
102+
self.assertIs(type(wr), weakref.ReferenceType)
103+
self.assertEqual(log, [])
104+
del obj
105+
self.assertEqual(log, [wr])
106+
107+
self.assertRaises(TypeError, newref, [])
108+
# CRASHES newref(NULL)
109+
110+
def test_pyweakref_newproxy(self):
111+
# Test PyWeakref_NewProxy()
112+
newproxy = _testlimitedcapi.pyweakref_newproxy
113+
obj = Object()
114+
wp = newproxy(obj)
115+
self.assertIs(type(wp), weakref.ProxyType)
116+
# PyWeakref_NewProxy() handles None callback as NULL callback
117+
wp = newproxy(obj, None)
118+
self.assertIs(type(wp), weakref.ProxyType)
119+
log = []
120+
wp = newproxy(obj, log.append)
121+
self.assertIs(type(wp), weakref.ProxyType)
122+
self.assertEqual(log, [])
123+
del obj
124+
self.assertEqual(log, [wp])
125+
126+
def func():
127+
pass
128+
wp = newproxy(func)
129+
self.assertIs(type(wp), weakref.CallableProxyType)
130+
131+
self.assertRaises(TypeError, newproxy, [])
132+
# CRASHES newproxy(NULL)
133+
134+
135+
if __name__ == "__main__":
136+
unittest.main()

Lib/test/test_io/test_textio.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1560,6 +1560,56 @@ def closed(self):
15601560
wrapper = self.TextIOWrapper(raw)
15611561
wrapper.close() # should not crash
15621562

1563+
def test_reentrant_detach_during_flush(self):
1564+
# gh-143008: Reentrant detach() during flush should not crash.
1565+
1566+
class DetachOnce(self.BufferedRandom):
1567+
wrapper = None
1568+
1569+
def detach_once(self):
1570+
original = self.wrapper
1571+
self.wrapper = None
1572+
if original is not None:
1573+
original.detach()
1574+
original.flush()
1575+
1576+
class DetachOnFlush(DetachOnce):
1577+
def flush(self):
1578+
self.detach_once()
1579+
1580+
class DetachOnWrite(DetachOnce):
1581+
def write(self, b):
1582+
self.detach_once()
1583+
return len(b)
1584+
1585+
# Separate reference for after detach_once.
1586+
wrapper = None
1587+
1588+
def make_text(buffer):
1589+
nonlocal wrapper
1590+
buffer.wrapper = self.TextIOWrapper(buffer, encoding='utf-8')
1591+
wrapper = buffer.wrapper
1592+
1593+
# Many calls could result in the same null self->buffer crash.
1594+
tests = [
1595+
('truncate', lambda: wrapper.truncate(0)),
1596+
('close', lambda: wrapper.close()),
1597+
('detach', lambda: wrapper.detach()),
1598+
('seek', lambda: wrapper.seek(0)),
1599+
('tell', lambda: wrapper.tell()),
1600+
('reconfigure', lambda: wrapper.reconfigure(line_buffering=True)),
1601+
]
1602+
for name, method in tests:
1603+
with self.subTest(name):
1604+
make_text(DetachOnFlush(self.MockRawIO()))
1605+
self.assertRaisesRegex(ValueError, "detached", method)
1606+
1607+
# Should not crash.
1608+
with self.subTest('read via writeflush'):
1609+
make_text(DetachOnWrite(self.MockRawIO()))
1610+
wrapper.write('x')
1611+
self.assertRaisesRegex(ValueError, "detached", wrapper.read)
1612+
15631613

15641614
class PyTextIOWrapperTest(TextIOWrapperTest, PyTestCase):
15651615
shutdown_error = "LookupError: unknown encoding: ascii"
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix a crash, when there's no memory left on a device,
2+
which happened in code compilation.
3+
Now it raises a proper :exc:`MemoryError`.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix crash in :class:`io.TextIOWrapper` when reentrant
2+
:meth:`io.TextIOBase.detach` is called reentrantly from the underlying buffer.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix race conditions when re-initializing a :class:`io.TextIOWrapper` object.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix a crash when static :mod:`datetime` types outlive the ``_datetime`` module.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add more tests for ``PyWeakref_*`` C API.

Modules/Setup.stdlib.in

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,8 +173,8 @@
173173
@MODULE__XXTESTFUZZ_TRUE@_xxtestfuzz _xxtestfuzz/_xxtestfuzz.c _xxtestfuzz/fuzzer.c
174174
@MODULE__TESTBUFFER_TRUE@_testbuffer _testbuffer.c
175175
@MODULE__TESTINTERNALCAPI_TRUE@_testinternalcapi _testinternalcapi.c _testinternalcapi/test_lock.c _testinternalcapi/pytime.c _testinternalcapi/set.c _testinternalcapi/test_critical_sections.c _testinternalcapi/complex.c _testinternalcapi/interpreter.c _testinternalcapi/tuple.c
176-
@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/heaptype.c _testcapi/abstract.c _testcapi/unicode.c _testcapi/dict.c _testcapi/set.c _testcapi/list.c _testcapi/tuple.c _testcapi/getargs.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/complex.c _testcapi/numbers.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/buffer.c _testcapi/pyatomic.c _testcapi/run.c _testcapi/file.c _testcapi/codec.c _testcapi/immortal.c _testcapi/gc.c _testcapi/hash.c _testcapi/time.c _testcapi/bytes.c _testcapi/object.c _testcapi/modsupport.c _testcapi/monitoring.c _testcapi/config.c _testcapi/import.c _testcapi/frame.c _testcapi/type.c _testcapi/function.c _testcapi/module.c
177-
@MODULE__TESTLIMITEDCAPI_TRUE@_testlimitedcapi _testlimitedcapi.c _testlimitedcapi/abstract.c _testlimitedcapi/bytearray.c _testlimitedcapi/bytes.c _testlimitedcapi/codec.c _testlimitedcapi/complex.c _testlimitedcapi/dict.c _testlimitedcapi/eval.c _testlimitedcapi/float.c _testlimitedcapi/heaptype_relative.c _testlimitedcapi/import.c _testlimitedcapi/list.c _testlimitedcapi/long.c _testlimitedcapi/object.c _testlimitedcapi/pyos.c _testlimitedcapi/set.c _testlimitedcapi/slots.c _testlimitedcapi/sys.c _testlimitedcapi/threadstate.c _testlimitedcapi/tuple.c _testlimitedcapi/unicode.c _testlimitedcapi/vectorcall_limited.c _testlimitedcapi/version.c _testlimitedcapi/file.c
176+
@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/heaptype.c _testcapi/abstract.c _testcapi/unicode.c _testcapi/dict.c _testcapi/set.c _testcapi/list.c _testcapi/tuple.c _testcapi/getargs.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/complex.c _testcapi/numbers.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/buffer.c _testcapi/pyatomic.c _testcapi/run.c _testcapi/file.c _testcapi/codec.c _testcapi/immortal.c _testcapi/gc.c _testcapi/hash.c _testcapi/time.c _testcapi/bytes.c _testcapi/object.c _testcapi/modsupport.c _testcapi/monitoring.c _testcapi/config.c _testcapi/import.c _testcapi/frame.c _testcapi/type.c _testcapi/function.c _testcapi/module.c _testcapi/weakref.c
177+
@MODULE__TESTLIMITEDCAPI_TRUE@_testlimitedcapi _testlimitedcapi.c _testlimitedcapi/abstract.c _testlimitedcapi/bytearray.c _testlimitedcapi/bytes.c _testlimitedcapi/codec.c _testlimitedcapi/complex.c _testlimitedcapi/dict.c _testlimitedcapi/eval.c _testlimitedcapi/float.c _testlimitedcapi/heaptype_relative.c _testlimitedcapi/import.c _testlimitedcapi/list.c _testlimitedcapi/long.c _testlimitedcapi/object.c _testlimitedcapi/pyos.c _testlimitedcapi/set.c _testlimitedcapi/slots.c _testlimitedcapi/sys.c _testlimitedcapi/threadstate.c _testlimitedcapi/tuple.c _testlimitedcapi/unicode.c _testlimitedcapi/vectorcall_limited.c _testlimitedcapi/version.c _testlimitedcapi/file.c _testlimitedcapi/weakref.c
178178
@MODULE__TESTCLINIC_TRUE@_testclinic _testclinic.c
179179
@MODULE__TESTCLINIC_LIMITED_TRUE@_testclinic_limited _testclinic_limited.c
180180

0 commit comments

Comments
 (0)