Skip to content

Commit fa795c2

Browse files
[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 5a63d35) Co-authored-by: Gregory P. Smith <68491+gpshead@users.noreply.github.com>
1 parent e8d685f commit fa795c2

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
@@ -2404,6 +2404,16 @@ def test_reinit_with_view(self):
24042404
self.assertRaises(BufferError, a.__init__, "x", "ascii")
24052405
self.assertEqual(a, b"")
24062406

2407+
def test_reinit_error(self):
2408+
# A failed __init__() must not leave uninitialized bytes in the
2409+
# object: it must be empty afterwards.
2410+
for source in ([256] * 100, (-1,) * 100, [0] * 50 + [1000],
2411+
(1, 2, 1 << 100)):
2412+
with self.subTest(source=source):
2413+
a = bytearray(b"abc")
2414+
self.assertRaises(ValueError, a.__init__, source)
2415+
self.assertEqual(a, b"")
2416+
24072417

24082418
class AssortedBytesTest(unittest.TestCase):
24092419
#
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
@@ -1086,7 +1086,11 @@ bytearray___init___impl(PyByteArrayObject *self, PyObject *arg,
10861086
if (PyByteArray_Resize((PyObject *)self, size) < 0) goto fail;
10871087
if (PyBuffer_ToContiguous(PyByteArray_AS_STRING(self),
10881088
&view, size, 'C') < 0)
1089+
{
1090+
/* Don't expose the uninitialized bytes: reset to empty */
1091+
(void)PyByteArray_Resize((PyObject *)self, 0);
10891092
goto fail;
1093+
}
10901094
PyBuffer_Release(&view);
10911095
return 0;
10921096
fail:
@@ -1114,6 +1118,8 @@ bytearray___init___impl(PyByteArrayObject *self, PyObject *arg,
11141118
}
11151119
int rc = _getbytevalue(items[i], &value);
11161120
if (!rc) {
1121+
/* Don't expose the uninitialized bytes: reset to empty */
1122+
(void)PyByteArray_Resize((PyObject *)self, 0);
11171123
return -1;
11181124
}
11191125
s[i] = value;

0 commit comments

Comments
 (0)