From 7c214ea52efbcf12261128b458db8fe025cbc61b Mon Sep 17 00:00:00 2001 From: Michael Bommarito Date: Thu, 16 Apr 2026 13:40:35 -0400 Subject: [PATCH] gh-148653: Fix SIGSEGV in marshal.loads for self-referencing tuples --- Lib/test/test_marshal.py | 20 +++++++++++++++++++ ...-04-16-12-51-32.gh-issue-148653.G0_AMQ.rst | 2 ++ Python/marshal.c | 5 ++++- 3 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-04-16-12-51-32.gh-issue-148653.G0_AMQ.rst diff --git a/Lib/test/test_marshal.py b/Lib/test/test_marshal.py index 78db4219e2997c..477203a913476c 100644 --- a/Lib/test/test_marshal.py +++ b/Lib/test/test_marshal.py @@ -731,5 +731,25 @@ def test_read_object_from_file(self): os_helper.unlink(os_helper.TESTFN) +class SelfRefTupleTest(unittest.TestCase): + """Regression test for gh-148653: TYPE_TUPLE with FLAG_REF back-reference. + + R_REF registered the tuple in p->refs before its slots were populated. + A TYPE_REF back-reference to the partial tuple could reach a hashing + site (PySet_Add) with NULL slots, crashing with SIGSEGV. + + The fix uses the two-phase r_ref_reserve/r_ref_insert pattern so the + Py_None placeholder is detected by the TYPE_REF handler, raising + ValueError instead. + """ + + def test_self_ref_tuple(self): + # TYPE_TUPLE|FLAG_REF n=2; NONE; TYPE_SET n=1; TYPE_REF(0) + payload = (b'\xa8\x02\x00\x00\x00N' + b'<\x01\x00\x00\x00r\x00\x00\x00\x00') + with self.assertRaises(ValueError): + marshal.loads(payload) + + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Library/2026-04-16-12-51-32.gh-issue-148653.G0_AMQ.rst b/Misc/NEWS.d/next/Library/2026-04-16-12-51-32.gh-issue-148653.G0_AMQ.rst new file mode 100644 index 00000000000000..d33a29705f7f6b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-04-16-12-51-32.gh-issue-148653.G0_AMQ.rst @@ -0,0 +1,2 @@ +Fix SIGSEGV in :func:`marshal.loads` for self-referencing tuples. Such +payloads will now raise :exc:`ValueError` instead of crashing. diff --git a/Python/marshal.c b/Python/marshal.c index b60a36e128cd9f..8b4ab90700ebb4 100644 --- a/Python/marshal.c +++ b/Python/marshal.c @@ -1385,7 +1385,9 @@ r_object(RFILE *p) } _read_tuple: v = PyTuple_New(n); - R_REF(v); + idx = r_ref_reserve(flag, p); + if (idx < 0) + Py_CLEAR(v); if (v == NULL) break; @@ -1400,6 +1402,7 @@ r_object(RFILE *p) } PyTuple_SET_ITEM(v, i, v2); } + v = r_ref_insert(v, idx, flag, p); retval = v; break;