Content-Length: 427016 | pFad | http://github.com/python/cpython/commit/#start-of-content

68726D0E gh-91153: prevent a crash in `bytearray.__setitem__(ind, ...)` when `… · python/cpython@5e1e21d · GitHub
Skip to content

Commit 5e1e21d

Browse files
bast0006picnixz
andauthored
gh-91153: prevent a crash in bytearray.__setitem__(ind, ...) when ind.__index__ has side-effects (#132379)
Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
1 parent 25335d2 commit 5e1e21d

File tree

3 files changed

+42
-2
lines changed

3 files changed

+42
-2
lines changed

Lib/test/test_bytes.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1899,6 +1899,8 @@ def test_repeat_after_setslice(self):
18991899
self.assertEqual(b3, b'xcxcxc')
19001900

19011901
def test_mutating_index(self):
1902+
# bytearray slice assignment can call into python code
1903+
# that reallocates the internal buffer
19021904
# See gh-91153
19031905

19041906
class Boom:
@@ -1916,6 +1918,39 @@ def __index__(self):
19161918
with self.assertRaises(IndexError):
19171919
self._testlimitedcapi.sequence_setitem(b, 0, Boom())
19181920

1921+
def test_mutating_index_inbounds(self):
1922+
# gh-91153 continued
1923+
# Ensure buffer is not broken even if length is correct
1924+
1925+
class MutatesOnIndex:
1926+
def __init__(self):
1927+
self.ba = bytearray(0x180)
1928+
1929+
def __index__(self):
1930+
self.ba.clear()
1931+
self.new_ba = bytearray(0x180) # to catch out-of-bounds writes
1932+
self.ba.extend([0] * 0x180) # to check bounds checks
1933+
return 0
1934+
1935+
with self.subTest("skip_bounds_safety"):
1936+
instance = MutatesOnIndex()
1937+
instance.ba[instance] = ord("?")
1938+
self.assertEqual(instance.ba[0], ord("?"), "Assigned bytearray not altered")
1939+
self.assertEqual(instance.new_ba, bytearray(0x180), "Wrong object altered")
1940+
1941+
with self.subTest("skip_bounds_safety_capi"):
1942+
instance = MutatesOnIndex()
1943+
instance.ba[instance] = ord("?")
1944+
self._testlimitedcapi.sequence_setitem(instance.ba, instance, ord("?"))
1945+
self.assertEqual(instance.ba[0], ord("?"), "Assigned bytearray not altered")
1946+
self.assertEqual(instance.new_ba, bytearray(0x180), "Wrong object altered")
1947+
1948+
with self.subTest("skip_bounds_safety_slice"):
1949+
instance = MutatesOnIndex()
1950+
instance.ba[instance:1] = [ord("?")]
1951+
self.assertEqual(instance.ba[0], ord("?"), "Assigned bytearray not altered")
1952+
self.assertEqual(instance.new_ba, bytearray(0x180), "Wrong object altered")
1953+
19191954

19201955
class AssortedBytesTest(unittest.TestCase):
19211956
#
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix a crash when a :class:`bytearray` is concurrently mutated during item assignment.

Objects/bytearrayobject.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -709,7 +709,9 @@ bytearray_ass_subscript_lock_held(PyObject *op, PyObject *index, PyObject *value
709709
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(op);
710710
PyByteArrayObject *self = _PyByteArray_CAST(op);
711711
Py_ssize_t start, stop, step, slicelen;
712-
char *buf = PyByteArray_AS_STRING(self);
712+
// Do not store a reference to the internal buffer since
713+
// index.__index__() or _getbytevalue() may alter 'self'.
714+
// See https://github.com/python/cpython/issues/91153.
713715

714716
if (_PyIndex_Check(index)) {
715717
Py_ssize_t i = PyNumber_AsSsize_t(index, PyExc_IndexError);
@@ -744,7 +746,7 @@ bytearray_ass_subscript_lock_held(PyObject *op, PyObject *index, PyObject *value
744746
}
745747
else {
746748
assert(0 <= ival && ival < 256);
747-
buf[i] = (char)ival;
749+
PyByteArray_AS_STRING(self)[i] = (char)ival;
748750
return 0;
749751
}
750752
}
@@ -805,6 +807,7 @@ bytearray_ass_subscript_lock_held(PyObject *op, PyObject *index, PyObject *value
805807
/* Delete slice */
806808
size_t cur;
807809
Py_ssize_t i;
810+
char *buf = PyByteArray_AS_STRING(self);
808811

809812
if (!_canresize(self))
810813
return -1;
@@ -845,6 +848,7 @@ bytearray_ass_subscript_lock_held(PyObject *op, PyObject *index, PyObject *value
845848
/* Assign slice */
846849
Py_ssize_t i;
847850
size_t cur;
851+
char *buf = PyByteArray_AS_STRING(self);
848852

849853
if (needed != slicelen) {
850854
PyErr_Format(PyExc_ValueError,

0 commit comments

Comments
 (0)








ApplySandwichStrip

pFad - (p)hone/(F)rame/(a)nonymizer/(d)eclutterfier!      Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

Fetched URL: http://github.com/python/cpython/commit/#start-of-content

Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy