From 797442728f96822be26d395143c576f6bf61227e Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Sun, 13 Sep 2026 07:04:11 +0200 Subject: [PATCH 1/3] gh-128509: Use bytes singleton in marshal Replace soft deprecated PyBytes_FromStringAndSize(NULL, n) with PyBytes_FromStringAndSize(str, n) so marshal can get bytes singleton. --- Lib/test/test_marshal.py | 7 +++++++ Python/marshal.c | 8 ++------ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_marshal.py b/Lib/test/test_marshal.py index c595e8cf14f1e15..07d488b5f704d23 100644 --- a/Lib/test/test_marshal.py +++ b/Lib/test/test_marshal.py @@ -116,6 +116,13 @@ def test_bytes(self): for s in [b"", b"Andr\xe8 Previn", b"abc", b" "*10000]: self.helper(s) + @support.cpython_only + def test_bytes_singleton(self): + for sample in [b"", b"x"]: + new = marshal.loads(marshal.dumps(sample)) + self.assertIs(new, sample) + + class ExceptionTestCase(unittest.TestCase): def test_exceptions(self): new = marshal.loads(marshal.dumps(StopIteration)) diff --git a/Python/marshal.c b/Python/marshal.c index 1897d700c055bd3..420c3ee115a7377 100644 --- a/Python/marshal.c +++ b/Python/marshal.c @@ -1388,16 +1388,12 @@ r_object(RFILE *p) } break; } - v = PyBytes_FromStringAndSize((char *)NULL, n); - if (v == NULL) - break; ptr = r_string(n, p); if (ptr == NULL) { - Py_DECREF(v); break; } - memcpy(PyBytes_AS_STRING(v), ptr, n); - retval = v; + // Get a singleton for 1-byte string + retval = PyBytes_FromStringAndSize(ptr, n); // can be NULL R_REF(retval); break; } From b3fc6f5437f9312f96643bbe4c1f589e74c4ee7e Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Sun, 13 Sep 2026 07:14:40 +0200 Subject: [PATCH 2/3] Add Changelog entry --- .../next/Library/2026-09-13-07-14-35.gh-issue-128509.9F2GCE.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2026-09-13-07-14-35.gh-issue-128509.9F2GCE.rst diff --git a/Misc/NEWS.d/next/Library/2026-09-13-07-14-35.gh-issue-128509.9F2GCE.rst b/Misc/NEWS.d/next/Library/2026-09-13-07-14-35.gh-issue-128509.9F2GCE.rst new file mode 100644 index 000000000000000..7699242c8c647ea --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-09-13-07-14-35.gh-issue-128509.9F2GCE.rst @@ -0,0 +1,2 @@ +:func:`marshal.load` and :func:`marshal.loads` can now get 1-byte string +singletons. Patch by Victor Stinner. From 8f370c8fd8a57142d8624f53ff48fb4b5adcd776 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Sun, 13 Sep 2026 13:38:27 +0200 Subject: [PATCH 3/3] Test all marshal versions --- Lib/test/test_marshal.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_marshal.py b/Lib/test/test_marshal.py index 07d488b5f704d23..042cad03ce80e79 100644 --- a/Lib/test/test_marshal.py +++ b/Lib/test/test_marshal.py @@ -118,9 +118,10 @@ def test_bytes(self): @support.cpython_only def test_bytes_singleton(self): - for sample in [b"", b"x"]: - new = marshal.loads(marshal.dumps(sample)) - self.assertIs(new, sample) + for version in range(marshal.version + 1): + for sample in [b"", b"x"]: + new = marshal.loads(marshal.dumps(sample, version)) + self.assertIs(new, sample) class ExceptionTestCase(unittest.TestCase):