mirror of
https://github.com/python/cpython.git
synced 2025-11-01 06:01:29 +00:00
[3.13] gh-91153: prevent a crash in bytearray.__setitem__(ind, ...) when ind.__index__ has side-effects (GH-132379) (#136582)
(cherry picked from commit 5e1e21dee3)
Co-authored-by: Bast <52266665+bast0006@users.noreply.github.com>
This commit is contained in:
parent
6176101b4a
commit
360540fd47
3 changed files with 43 additions and 3 deletions
|
|
@ -1827,6 +1827,8 @@ def test_repeat_after_setslice(self):
|
||||||
self.assertEqual(b3, b'xcxcxc')
|
self.assertEqual(b3, b'xcxcxc')
|
||||||
|
|
||||||
def test_mutating_index(self):
|
def test_mutating_index(self):
|
||||||
|
# bytearray slice assignment can call into python code
|
||||||
|
# that reallocates the internal buffer
|
||||||
# See gh-91153
|
# See gh-91153
|
||||||
|
|
||||||
class Boom:
|
class Boom:
|
||||||
|
|
@ -1844,6 +1846,39 @@ def __index__(self):
|
||||||
with self.assertRaises(IndexError):
|
with self.assertRaises(IndexError):
|
||||||
self._testlimitedcapi.sequence_setitem(b, 0, Boom())
|
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):
|
class AssortedBytesTest(unittest.TestCase):
|
||||||
#
|
#
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
Fix a crash when a :class:`bytearray` is concurrently mutated during item assignment.
|
||||||
|
|
@ -591,8 +591,10 @@ static int
|
||||||
bytearray_ass_subscript(PyByteArrayObject *self, PyObject *index, PyObject *values)
|
bytearray_ass_subscript(PyByteArrayObject *self, PyObject *index, PyObject *values)
|
||||||
{
|
{
|
||||||
Py_ssize_t start, stop, step, slicelen, needed;
|
Py_ssize_t start, stop, step, slicelen, needed;
|
||||||
char *buf, *bytes;
|
char *bytes;
|
||||||
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)) {
|
if (_PyIndex_Check(index)) {
|
||||||
Py_ssize_t i = PyNumber_AsSsize_t(index, PyExc_IndexError);
|
Py_ssize_t i = PyNumber_AsSsize_t(index, PyExc_IndexError);
|
||||||
|
|
@ -627,7 +629,7 @@ bytearray_ass_subscript(PyByteArrayObject *self, PyObject *index, PyObject *valu
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
assert(0 <= ival && ival < 256);
|
assert(0 <= ival && ival < 256);
|
||||||
buf[i] = (char)ival;
|
PyByteArray_AS_STRING(self)[i] = (char)ival;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -682,6 +684,7 @@ bytearray_ass_subscript(PyByteArrayObject *self, PyObject *index, PyObject *valu
|
||||||
/* Delete slice */
|
/* Delete slice */
|
||||||
size_t cur;
|
size_t cur;
|
||||||
Py_ssize_t i;
|
Py_ssize_t i;
|
||||||
|
char *buf = PyByteArray_AS_STRING(self);
|
||||||
|
|
||||||
if (!_canresize(self))
|
if (!_canresize(self))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
@ -722,6 +725,7 @@ bytearray_ass_subscript(PyByteArrayObject *self, PyObject *index, PyObject *valu
|
||||||
/* Assign slice */
|
/* Assign slice */
|
||||||
Py_ssize_t i;
|
Py_ssize_t i;
|
||||||
size_t cur;
|
size_t cur;
|
||||||
|
char *buf = PyByteArray_AS_STRING(self);
|
||||||
|
|
||||||
if (needed != slicelen) {
|
if (needed != slicelen) {
|
||||||
PyErr_Format(PyExc_ValueError,
|
PyErr_Format(PyExc_ValueError,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue