https://github.com/python/cpython/commit/b6c11feb677f88f8367e80892b1c1979e16b68ee
commit: b6c11feb677f88f8367e80892b1c1979e16b68ee
branch: main
author: tonghuaroot (童话) <[email protected]>
committer: serhiy-storchaka <[email protected]>
date: 2026-08-17T10:36:48+03:00
summary:
gh-155315: Fix marshal round-trip of shared frozendict references (GH-155316)
The TYPE_FROZENDICT reader reserved a reference slot but never filled it with
r_ref_insert, unlike TYPE_FROZENSET, so a frozendict referenced more than once
failed to load with ValueError.
files:
A
Misc/NEWS.d/next/Core_and_Builtins/2026-08-07-14-45-02.gh-issue-155315.Mk9Fd2.rst
M Lib/test/test_marshal.py
M Python/marshal.c
diff --git a/Lib/test/test_marshal.py b/Lib/test/test_marshal.py
index 9c4d91c456dc5d9..0e71d65f22b4f0d 100644
--- a/Lib/test/test_marshal.py
+++ b/Lib/test/test_marshal.py
@@ -386,6 +386,16 @@ def test_reference_loop_frozendict(self):
for v in range(marshal.version + 1):
self.assertRaises(ValueError, marshal.dumps, a, v)
+ def test_shared_reference_frozendict(self):
+ # A frozendict referenced more than once must round-trip with the
+ # shared identity preserved, like frozenset.
+ fd = frozendict({'a': 1, 'b': 2})
+ out = marshal.loads(marshal.dumps([fd, fd]))
+ self.assertEqual(out[0], fd)
+ self.assertIs(out[0], out[1])
+ nested = marshal.loads(marshal.dumps(frozendict({'x': fd, 'y': fd})))
+ self.assertIs(nested['x'], nested['y'])
+
def test_loads_reference_loop_list(self):
data = b'\xdb\x01\x00\x00\x00r\x00\x00\x00\x00' # [<R>]
a = marshal.loads(data)
diff --git
a/Misc/NEWS.d/next/Core_and_Builtins/2026-08-07-14-45-02.gh-issue-155315.Mk9Fd2.rst
b/Misc/NEWS.d/next/Core_and_Builtins/2026-08-07-14-45-02.gh-issue-155315.Mk9Fd2.rst
new file mode 100644
index 000000000000000..a62059c0fa26160
--- /dev/null
+++
b/Misc/NEWS.d/next/Core_and_Builtins/2026-08-07-14-45-02.gh-issue-155315.Mk9Fd2.rst
@@ -0,0 +1,3 @@
+Fix :mod:`marshal` so that a ``frozendict`` referenced more than once in the
+serialized data round-trips correctly, instead of failing to load with
+:exc:`ValueError`. Patch by tonghuaroot.
diff --git a/Python/marshal.c b/Python/marshal.c
index 603697e9081c59a..b11f2dca57a226c 100644
--- a/Python/marshal.c
+++ b/Python/marshal.c
@@ -1505,6 +1505,7 @@ r_object(RFILE *p)
}
if (type == TYPE_FROZENDICT && v != NULL) {
Py_SETREF(v, PyFrozenDict_New(v));
+ v = r_ref_insert(v, idx, flag, p);
}
retval = v;
break;
_______________________________________________
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]