mirror of
https://github.com/python/cpython.git
synced 2026-06-04 16:50:51 +00:00
gh-148450: abc.register needs to update type_version when tp_flags is changed (#148623)
This commit is contained in:
parent
82191c6d2c
commit
e7eaed5614
3 changed files with 37 additions and 0 deletions
|
|
@ -1,4 +1,5 @@
|
|||
""" Tests for the internal type cache in CPython. """
|
||||
import collections.abc
|
||||
import dis
|
||||
import unittest
|
||||
import warnings
|
||||
|
|
@ -114,6 +115,25 @@ class HolderSub(Holder):
|
|||
Holder.set_value()
|
||||
HolderSub.value
|
||||
|
||||
def test_abc_register_invalidates_subclass_versions(self):
|
||||
class Parent:
|
||||
pass
|
||||
|
||||
class Child(Parent):
|
||||
pass
|
||||
|
||||
type_assign_version(Parent)
|
||||
type_assign_version(Child)
|
||||
parent_version = type_get_version(Parent)
|
||||
child_version = type_get_version(Child)
|
||||
if parent_version == 0 or child_version == 0:
|
||||
self.skipTest("Could not assign valid type versions")
|
||||
|
||||
collections.abc.Mapping.register(Parent)
|
||||
|
||||
self.assertEqual(type_get_version(Parent), 0)
|
||||
self.assertEqual(type_get_version(Child), 0)
|
||||
|
||||
@support.cpython_only
|
||||
class TypeCacheWithSpecializationTests(unittest.TestCase):
|
||||
def tearDown(self):
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
Fix ``abc.register()`` so it invalidates type version tags for registered classes.
|
||||
|
|
@ -6490,9 +6490,25 @@ set_flags_recursive(PyTypeObject *self, unsigned long mask, unsigned long flags)
|
|||
void
|
||||
_PyType_SetFlagsRecursive(PyTypeObject *self, unsigned long mask, unsigned long flags)
|
||||
{
|
||||
BEGIN_TYPE_LOCK();
|
||||
/* Ideally, changing flags and invalidating the old version tag would
|
||||
happen in one step. But type_modified_unlocked() is re-entrant and
|
||||
cannot run with the world stopped, so we must invalidate first.
|
||||
Immutable/static-builtin types are skipped because
|
||||
set_flags_recursive() does not modify them. */
|
||||
if (!PyType_HasFeature(self, Py_TPFLAGS_IMMUTABLETYPE) &&
|
||||
(self->tp_flags & mask) != flags)
|
||||
{
|
||||
type_modified_unlocked(self);
|
||||
}
|
||||
/* Keep TYPE_LOCK held while waiting for stop-the-world so no thread
|
||||
can reassign a version tag before the flag update. */
|
||||
type_lock_prevent_release();
|
||||
types_stop_world();
|
||||
set_flags_recursive(self, mask, flags);
|
||||
types_start_world();
|
||||
type_lock_allow_release();
|
||||
END_TYPE_LOCK();
|
||||
}
|
||||
|
||||
/* This is similar to PyObject_GenericGetAttr(),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue