self.assertEqual(b3, b'xcxcxc')
def test_mutating_index(self):
+ # bytearray slice assignment can call into python code
+ # that reallocates the internal buffer
# See gh-91153
class Boom:
with self.assertRaises(IndexError):
self._testlimitedcapi.sequence_setitem(b, 0, Boom())
+ def test_mutating_index_inbounds(self):
+ # gh-91153 continued
+ # Ensure buffer is not broken even if length is correct
+
+ class MutatesOnIndex:
+ def __init__(self):
+ self.ba = bytearray(0x180)
+
+ def __index__(self):
+ self.ba.clear()
+ self.new_ba = bytearray(0x180) # to catch out-of-bounds writes
+ self.ba.extend([0] * 0x180) # to check bounds checks
+ return 0
+
+ with self.subTest("skip_bounds_safety"):
+ instance = MutatesOnIndex()
+ instance.ba[instance] = ord("?")
+ self.assertEqual(instance.ba[0], ord("?"), "Assigned bytearray not altered")
+ self.assertEqual(instance.new_ba, bytearray(0x180), "Wrong object altered")
+
+ with self.subTest("skip_bounds_safety_capi"):
+ instance = MutatesOnIndex()
+ instance.ba[instance] = ord("?")
+ self._testlimitedcapi.sequence_setitem(instance.ba, instance, ord("?"))
+ self.assertEqual(instance.ba[0], ord("?"), "Assigned bytearray not altered")
+ self.assertEqual(instance.new_ba, bytearray(0x180), "Wrong object altered")
+
+ with self.subTest("skip_bounds_safety_slice"):
+ instance = MutatesOnIndex()
+ instance.ba[instance:1] = [ord("?")]
+ self.assertEqual(instance.ba[0], ord("?"), "Assigned bytearray not altered")
+ self.assertEqual(instance.new_ba, bytearray(0x180), "Wrong object altered")
+
class AssortedBytesTest(unittest.TestCase):
#
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(op);
PyByteArrayObject *self = _PyByteArray_CAST(op);
Py_ssize_t start, stop, step, slicelen;
- char *buf = PyByteArray_AS_STRING(self);
+ // Do not store a reference to the internal buffer since
+ // index.__index__() or _getbytevalue() may alter 'self'.
+ // See https://github.com/python/cpython/issues/91153.
if (_PyIndex_Check(index)) {
Py_ssize_t i = PyNumber_AsSsize_t(index, PyExc_IndexError);
}
else {
assert(0 <= ival && ival < 256);
- buf[i] = (char)ival;
+ PyByteArray_AS_STRING(self)[i] = (char)ival;
return 0;
}
}
/* Delete slice */
size_t cur;
Py_ssize_t i;
+ char *buf = PyByteArray_AS_STRING(self);
if (!_canresize(self))
return -1;
/* Assign slice */
Py_ssize_t i;
size_t cur;
+ char *buf = PyByteArray_AS_STRING(self);
if (needed != slicelen) {
PyErr_Format(PyExc_ValueError,