Skip to content

Commit 8cf3fec

Browse files
authored
[3.14] gh-160179: Leave bytearray empty when __init__() fails midway (GH-160180) (#160204)
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 5a63d35)
1 parent 23dc7c9 commit 8cf3fec

3 files changed

Lines changed: 19 additions & 0 deletions

File tree

‎Lib/test/test_bytes.py‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2151,6 +2151,16 @@ def __len__(self):
21512151

21522152
self.assertRaises(BufferError, ba.hex, S(b':'))
21532153

2154+
def test_reinit_error(self):
2155+
# A failed __init__() must not leave uninitialized bytes in the
2156+
# object: it must be empty afterwards.
2157+
for source in ([256] * 100, (-1,) * 100, [0] * 50 + [1000],
2158+
(1, 2, 1 << 100)):
2159+
with self.subTest(source=source):
2160+
a = bytearray(b"abc")
2161+
self.assertRaises(ValueError, a.__init__, source)
2162+
self.assertEqual(a, b"")
2163+
21542164

21552165
class AssortedBytesTest(unittest.TestCase):
21562166
#
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix :meth:`!bytearray.__init__` leaving uninitialized memory in the object
2+
when it fails on a :class:`list` or :class:`tuple` containing an integer not
3+
in ``range(256)``. The object is now empty after the failed call.

‎Objects/bytearrayobject.c‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1000,7 +1000,11 @@ bytearray___init___impl(PyByteArrayObject *self, PyObject *arg,
10001000
if (PyByteArray_Resize((PyObject *)self, size) < 0) goto fail;
10011001
if (PyBuffer_ToContiguous(PyByteArray_AS_STRING(self),
10021002
&view, size, 'C') < 0)
1003+
{
1004+
/* Don't expose the uninitialized bytes: reset to empty */
1005+
(void)PyByteArray_Resize((PyObject *)self, 0);
10031006
goto fail;
1007+
}
10041008
PyBuffer_Release(&view);
10051009
return 0;
10061010
fail:
@@ -1028,6 +1032,8 @@ bytearray___init___impl(PyByteArrayObject *self, PyObject *arg,
10281032
}
10291033
int rc = _getbytevalue(items[i], &value);
10301034
if (!rc) {
1035+
/* Don't expose the uninitialized bytes: reset to empty */
1036+
(void)PyByteArray_Resize((PyObject *)self, 0);
10311037
return -1;
10321038
}
10331039
s[i] = value;

0 commit comments

Comments
 (0)