Skip to content

Commit 7c214ea

Browse files
committed
gh-148653: Fix SIGSEGV in marshal.loads for self-referencing tuples
1 parent 2faceee commit 7c214ea

File tree

3 files changed

+26
-1
lines changed

3 files changed

+26
-1
lines changed

Lib/test/test_marshal.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -731,5 +731,25 @@ def test_read_object_from_file(self):
731731
os_helper.unlink(os_helper.TESTFN)
732732

733733

734+
class SelfRefTupleTest(unittest.TestCase):
735+
"""Regression test for gh-148653: TYPE_TUPLE with FLAG_REF back-reference.
736+
737+
R_REF registered the tuple in p->refs before its slots were populated.
738+
A TYPE_REF back-reference to the partial tuple could reach a hashing
739+
site (PySet_Add) with NULL slots, crashing with SIGSEGV.
740+
741+
The fix uses the two-phase r_ref_reserve/r_ref_insert pattern so the
742+
Py_None placeholder is detected by the TYPE_REF handler, raising
743+
ValueError instead.
744+
"""
745+
746+
def test_self_ref_tuple(self):
747+
# TYPE_TUPLE|FLAG_REF n=2; NONE; TYPE_SET n=1; TYPE_REF(0)
748+
payload = (b'\xa8\x02\x00\x00\x00N'
749+
b'<\x01\x00\x00\x00r\x00\x00\x00\x00')
750+
with self.assertRaises(ValueError):
751+
marshal.loads(payload)
752+
753+
734754
if __name__ == "__main__":
735755
unittest.main()
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix SIGSEGV in :func:`marshal.loads` for self-referencing tuples. Such
2+
payloads will now raise :exc:`ValueError` instead of crashing.

Python/marshal.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1385,7 +1385,9 @@ r_object(RFILE *p)
13851385
}
13861386
_read_tuple:
13871387
v = PyTuple_New(n);
1388-
R_REF(v);
1388+
idx = r_ref_reserve(flag, p);
1389+
if (idx < 0)
1390+
Py_CLEAR(v);
13891391
if (v == NULL)
13901392
break;
13911393

@@ -1400,6 +1402,7 @@ r_object(RFILE *p)
14001402
}
14011403
PyTuple_SET_ITEM(v, i, v2);
14021404
}
1405+
v = r_ref_insert(v, idx, flag, p);
14031406
retval = v;
14041407
break;
14051408

0 commit comments

Comments
 (0)