Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions Lib/test/test_bytes.py
Original file line number Diff line number Diff line change
Expand Up @@ -2085,6 +2085,22 @@ def g():
alloc = b.__alloc__()
self.assertGreater(alloc, len(b))

def test_init_from_iterator_with_offset(self):
# gh-158928: Inserting form an iterator in __init__ needs to take into
# account if there is a start offset.
b = bytearray()
def iterator_which_resets():
# __init__ reset ob_start. Make it an offset inside by allocating
# then doing fast prefix delete.
nonlocal b
b.resize(200)
del b[:100]
# Fill remaining already allocated space
yield from b'A' * 100
# Fill to end. Used to land out of bounds and crash.
b.__init__(iterator_which_resets())
self.assertEqual(b, bytes(100) + b'A' * 100)

def test_extend(self):
orig = b'hello'
a = bytearray(orig)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Fix a buffer overflow when initializing a :class:`bytearray` from an
iterator.
17 changes: 13 additions & 4 deletions Objects/bytearrayobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -1158,17 +1158,26 @@ bytearray___init___impl(PyByteArrayObject *self, PyObject *arg,
/* Interpret it as an int (__index__) */
rc = _getbytevalue(item, &value);
Py_DECREF(item);
if (!rc)
if (!rc) {
goto error;
}

/* Append the byte.

/* Append the byte */
if (Py_SIZE(self) + 1 < self->ob_alloc) {
gh-158928: Iterators are arbitrary code which could modify the
bytearray so this must re-calculate if there is enough space(). */
Py_ssize_t needed =
self->ob_start - self->ob_bytes + Py_SIZE(self) + 1;
if (needed < self->ob_alloc) {
Py_SET_SIZE(self, Py_SIZE(self) + 1);
bytearray_write_trailing_null_byte(self);
}
else if (PyByteArray_Resize((PyObject *)self, Py_SIZE(self)+1) < 0)
else if (PyByteArray_Resize((PyObject *)self, Py_SIZE(self)+1) < 0) {
goto error;
}
PyByteArray_AS_STRING(self)[Py_SIZE(self)-1] = value;
assert(self->ob_start - self->ob_bytes + Py_SIZE(self) <=
self->ob_alloc);
}

/* Clean up and return success */
Expand Down
Loading