https://github.com/python/cpython/commit/f33a5e891a03df416dde7afa7e3bfb2ac800f5a4
commit: f33a5e891a03df416dde7afa7e3bfb2ac800f5a4
branch: 3.13
author: Sam Gross <[email protected]>
committer: colesbury <[email protected]>
date: 2025-06-16T17:30:52Z
summary:
[3.13] gh-132617: Fix `dict.update()` mutation check (gh-134815) (gh-135582)
Use `ma_used` instead of `ma_keys->dk_nentries` for modification check
so that we only check if the dictionary is modified, not if new keys are
added to a different dictionary that shared the same keys object.
(cherry picked from commit d8994b0a77cc9821772d05db00a6ab23382fa17d)
files:
A Misc/NEWS.d/next/Core and
Builtins/2025-05-27-20-29-00.gh-issue-132617.EmUfQQ.rst
M Lib/test/test_dict.py
M Objects/dictobject.c
diff --git a/Lib/test/test_dict.py b/Lib/test/test_dict.py
index 4729132c5a5f84..4c095464cbbc54 100644
--- a/Lib/test/test_dict.py
+++ b/Lib/test/test_dict.py
@@ -265,6 +265,39 @@ def __next__(self):
self.assertRaises(ValueError, {}.update, [(1, 2, 3)])
+ def test_update_shared_keys(self):
+ class MyClass: pass
+
+ # Subclass str to enable us to create an object during the
+ # dict.update() call.
+ class MyStr(str):
+ def __hash__(self):
+ return super().__hash__()
+
+ def __eq__(self, other):
+ # Create an object that shares the same PyDictKeysObject as
+ # obj.__dict__.
+ obj2 = MyClass()
+ obj2.a = "a"
+ obj2.b = "b"
+ obj2.c = "c"
+ return super().__eq__(other)
+
+ obj = MyClass()
+ obj.a = "a"
+ obj.b = "b"
+
+ x = {}
+ x[MyStr("a")] = MyStr("a")
+
+ # gh-132617: this previously raised "dict mutated during update" error
+ x.update(obj.__dict__)
+
+ self.assertEqual(x, {
+ MyStr("a"): "a",
+ "b": "b",
+ })
+
def test_fromkeys(self):
self.assertEqual(dict.fromkeys('abc'), {'a':None, 'b':None, 'c':None})
d = {}
diff --git a/Misc/NEWS.d/next/Core and
Builtins/2025-05-27-20-29-00.gh-issue-132617.EmUfQQ.rst b/Misc/NEWS.d/next/Core
and Builtins/2025-05-27-20-29-00.gh-issue-132617.EmUfQQ.rst
new file mode 100644
index 00000000000000..53aef541e64c23
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and
Builtins/2025-05-27-20-29-00.gh-issue-132617.EmUfQQ.rst
@@ -0,0 +1,3 @@
+Fix :meth:`dict.update` modification check that could incorrectly raise a
+"dict mutated during update" error when a different dictionary was modified
+that happens to share the same underlying keys object.
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index d135ea5f3db81b..baac54911f0371 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -3782,7 +3782,7 @@ dict_dict_merge(PyInterpreterState *interp, PyDictObject
*mp, PyDictObject *othe
}
}
- Py_ssize_t orig_size = other->ma_keys->dk_nentries;
+ Py_ssize_t orig_size = other->ma_used;
Py_ssize_t pos = 0;
Py_hash_t hash;
PyObject *key, *value;
@@ -3816,7 +3816,7 @@ dict_dict_merge(PyInterpreterState *interp, PyDictObject
*mp, PyDictObject *othe
if (err != 0)
return -1;
- if (orig_size != other->ma_keys->dk_nentries) {
+ if (orig_size != other->ma_used) {
PyErr_SetString(PyExc_RuntimeError,
"dict mutated during update");
return -1;
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]