From 836ad73fced3291f46338eb2e279c74fb9804f38 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 5 Mar 2026 14:49:21 +0100 Subject: [PATCH 1/2] gh-141510: Avoid critical section on frozendict copy --- Objects/dictobject.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 842d9be73b8792..0f35a0adff2d0b 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -4322,7 +4322,10 @@ copy_lock_held(PyObject *o, int as_frozendict) PyObject *copy; PyDictObject *mp; - ASSERT_DICT_LOCKED(o); + // frozendict is immutable and so doesn't need critical section + if (!PyFrozenDict_Check(o)) { + ASSERT_DICT_LOCKED(o); + } mp = (PyDictObject *)o; if (mp->ma_used == 0) { @@ -4445,9 +4448,14 @@ anydict_copy(PyObject *o) assert(PyAnyDict_Check(o)); PyObject *res; - Py_BEGIN_CRITICAL_SECTION(o); - res = copy_lock_held(o, PyFrozenDict_Check(o)); - Py_END_CRITICAL_SECTION(); + if (PyFrozenDict_Check(o)) { + res = copy_lock_held(o, 1); + } + else { + Py_BEGIN_CRITICAL_SECTION(o); + res = copy_lock_held(o, 0); + Py_END_CRITICAL_SECTION(); + } return res; } @@ -4459,9 +4467,14 @@ _PyDict_CopyAsDict(PyObject *o) assert(PyAnyDict_Check(o)); PyObject *res; - Py_BEGIN_CRITICAL_SECTION(o); - res = copy_lock_held(o, 0); - Py_END_CRITICAL_SECTION(); + if (PyFrozenDict_Check(o)) { + res = copy_lock_held(o, 0); + } + else { + Py_BEGIN_CRITICAL_SECTION(o); + res = copy_lock_held(o, 0); + Py_END_CRITICAL_SECTION(); + } return res; } From 02fe87faf21ee72a133c75f5d7c744adfe85c960 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 13 Mar 2026 19:43:59 +0100 Subject: [PATCH 2/2] Fix assertion in clone_combined_dict_keys() --- Objects/dictobject.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 0f35a0adff2d0b..08e40bf84c42fa 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -968,7 +968,9 @@ clone_combined_dict_keys(PyDictObject *orig) assert(orig->ma_keys != Py_EMPTY_KEYS); assert(orig->ma_keys->dk_refcnt == 1); - ASSERT_DICT_LOCKED(orig); + if (!PyFrozenDict_Check(orig)) { + ASSERT_DICT_LOCKED(orig); + } size_t keys_size = _PyDict_KeysSize(orig->ma_keys); PyDictKeysObject *keys = PyMem_Malloc(keys_size);