From 1fde7a8b09ba4e26c1c02c91493369de6b3c3699 Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith" Date: Thu, 22 Oct 2026 00:34:19 +0000 Subject: [PATCH] gh-160179: Leave bytearray empty when __init__() fails midway The list/tuple fast path and the buffer path resized the object before filling it and did not undo the resize on error, leaving stale bytes. --- Lib/test/test_bytes.py | 10 ++++++++++ .../2026-10-22-00-30-02.gh-issue-160179.dQ2e7m.rst | 3 +++ Objects/bytearrayobject.c | 6 ++++++ 3 files changed, 19 insertions(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-10-22-00-30-02.gh-issue-160179.dQ2e7m.rst diff --git a/Lib/test/test_bytes.py b/Lib/test/test_bytes.py index 05faad4532b867..9c36fbed9eb19a 100644 --- a/Lib/test/test_bytes.py +++ b/Lib/test/test_bytes.py @@ -2499,6 +2499,16 @@ def test_reinit_with_view(self): self.assertRaises(BufferError, a.__init__, "x", "ascii") self.assertEqual(a, b"") + def test_reinit_error(self): + # A failed __init__() must not leave uninitialized bytes in the + # object: it must be empty afterwards. + for source in ([256] * 100, (-1,) * 100, [0] * 50 + [1000], + (1, 2, 1 << 100)): + with self.subTest(source=source): + a = bytearray(b"abc") + self.assertRaises(ValueError, a.__init__, source) + self.assertEqual(a, b"") + class AssortedBytesTest(unittest.TestCase): # diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-10-22-00-30-02.gh-issue-160179.dQ2e7m.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-10-22-00-30-02.gh-issue-160179.dQ2e7m.rst new file mode 100644 index 00000000000000..5377e59a60ea48 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-10-22-00-30-02.gh-issue-160179.dQ2e7m.rst @@ -0,0 +1,3 @@ +Fix :meth:`!bytearray.__init__` leaving uninitialized memory in the object +when it fails on a :class:`list` or :class:`tuple` containing an integer not +in ``range(256)``. The object is now empty after the failed call. diff --git a/Objects/bytearrayobject.c b/Objects/bytearrayobject.c index 9c0127ee4751b6..87f8da4af53ae5 100644 --- a/Objects/bytearrayobject.c +++ b/Objects/bytearrayobject.c @@ -1087,7 +1087,11 @@ bytearray___init___impl(PyByteArrayObject *self, PyObject *arg, if (PyByteArray_Resize((PyObject *)self, size) < 0) goto fail; if (PyBuffer_ToContiguous(PyByteArray_AS_STRING(self), &view, size, 'C') < 0) + { + /* Don't expose the uninitialized bytes: reset to empty */ + (void)PyByteArray_Resize((PyObject *)self, 0); goto fail; + } PyBuffer_Release(&view); return 0; fail: @@ -1115,6 +1119,8 @@ bytearray___init___impl(PyByteArrayObject *self, PyObject *arg, } int rc = _getbytevalue(items[i], &value); if (!rc) { + /* Don't expose the uninitialized bytes: reset to empty */ + (void)PyByteArray_Resize((PyObject *)self, 0); return -1; } s[i] = value;