https://github.com/python/cpython/commit/fa795c294f414c06e05e7f9df77ef70338c7b56f commit: fa795c294f414c06e05e7f9df77ef70338c7b56f branch: 3.15 author: Miss Islington (bot) <[email protected]> committer: gpshead <[email protected]> date: 2026-10-22T05:53:01Z summary:
[3.15] gh-160179: Leave bytearray empty when __init__() fails midway (GH-160180) (#160202) gh-160179: Leave bytearray empty when __init__() fails midway (GH-160180) 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. (cherry picked from commit 5a63d3568197ac470561e95cbc744c1bc679f80d) Co-authored-by: Gregory P. Smith <[email protected]> files: A Misc/NEWS.d/next/Core_and_Builtins/2026-10-22-00-30-02.gh-issue-160179.dQ2e7m.rst M Lib/test/test_bytes.py M Objects/bytearrayobject.c diff --git a/Lib/test/test_bytes.py b/Lib/test/test_bytes.py index 4b4857295663dc..d402654c887a43 100644 --- a/Lib/test/test_bytes.py +++ b/Lib/test/test_bytes.py @@ -2404,6 +2404,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 579d5cbadd0b39..0fa1ca0334245f 100644 --- a/Objects/bytearrayobject.c +++ b/Objects/bytearrayobject.c @@ -1086,7 +1086,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: @@ -1114,6 +1118,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; _______________________________________________ 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]
