Skip to content

Commit d154d55

Browse files
Merge branch '3.14' into backport-32823af-3.14
2 parents 5a7f669 + 86ffaf1 commit d154d55

4 files changed

Lines changed: 32 additions & 0 deletions

File tree

Lib/test/test_type_cache.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
""" Tests for the internal type cache in CPython. """
2+
import collections.abc
23
import dis
34
import unittest
45
import warnings
@@ -114,6 +115,25 @@ class HolderSub(Holder):
114115
Holder.set_value()
115116
HolderSub.value
116117

118+
def test_abc_register_invalidates_subclass_versions(self):
119+
class Parent:
120+
pass
121+
122+
class Child(Parent):
123+
pass
124+
125+
type_assign_version(Parent)
126+
type_assign_version(Child)
127+
parent_version = type_get_version(Parent)
128+
child_version = type_get_version(Child)
129+
if parent_version == 0 or child_version == 0:
130+
self.skipTest("Could not assign valid type versions")
131+
132+
collections.abc.Mapping.register(Parent)
133+
134+
self.assertEqual(type_get_version(Parent), 0)
135+
self.assertEqual(type_get_version(Child), 0)
136+
117137
@support.cpython_only
118138
class TypeCacheWithSpecializationTests(unittest.TestCase):
119139
def tearDown(self):
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix ``abc.register()`` so it invalidates type version tags for registered classes.

Modules/_io/bufferedio.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1497,7 +1497,9 @@ buffered_iternext(PyObject *op)
14971497
tp == state->PyBufferedRandom_Type)
14981498
{
14991499
/* Skip method call overhead for speed */
1500+
Py_BEGIN_CRITICAL_SECTION(self);
15001501
line = _buffered_readline(self, -1);
1502+
Py_END_CRITICAL_SECTION();
15011503
}
15021504
else {
15031505
line = PyObject_CallMethodNoArgs((PyObject *)self,

Objects/typeobject.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6066,6 +6066,15 @@ void
60666066
_PyType_SetFlagsRecursive(PyTypeObject *self, unsigned long mask, unsigned long flags)
60676067
{
60686068
BEGIN_TYPE_LOCK();
6069+
/* Ideally, changing flags and invalidating the old version tag would happen
6070+
in one step. In 3.14, invalidate first while holding TYPE_LOCK so readers
6071+
cannot assign a fresh tag from stale flags. Immutable types are skipped by
6072+
set_flags_recursive(). */
6073+
if (!PyType_HasFeature(self, Py_TPFLAGS_IMMUTABLETYPE) &&
6074+
(self->tp_flags & mask) != flags)
6075+
{
6076+
type_modified_unlocked(self);
6077+
}
60696078
set_flags_recursive(self, mask, flags);
60706079
END_TYPE_LOCK();
60716080
}

0 commit comments

Comments
 (0)