Skip to content

Commit 31f4513

Browse files
committed
chore: resolve comment review
1 parent 7e5244e commit 31f4513

File tree

3 files changed

+12
-12
lines changed

3 files changed

+12
-12
lines changed

Lib/test/test_array.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1368,6 +1368,8 @@ def test_frombytearray(self):
13681368
self.assertEqual(a, b)
13691369

13701370
def test_tofile_concurrent_mutation(self):
1371+
# Keep this test in sync with the implementation in
1372+
# Modules/arraymodule.c:array_array_tofile_impl()
13711373
BLOCKSIZE = 64 * 1024
13721374
victim = array.array('B', b'\0' * (BLOCKSIZE * 2))
13731375

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
Use-After-Free Vulnerability Fixed in CPython array.array.tofile().
1+
:mod:`array`: fix a crash in :mod:`array.array.tofile` when the array is concurrently modified by the writer.

Modules/arraymodule.c

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1589,29 +1589,26 @@ array_array_tofile_impl(arrayobject *self, PyTypeObject *cls, PyObject *f)
15891589
{
15901590
/* Write 64K blocks at a time */
15911591
/* XXX Make the block size settable */
1592-
const Py_ssize_t BLOCKSIZE = 64*1024;
1593-
const Py_ssize_t itemsize = self->ob_descr->itemsize;
1594-
1595-
Py_ssize_t nbytes = Py_SIZE(self) * itemsize;
1596-
Py_ssize_t nblocks = (nbytes + BLOCKSIZE - 1) / BLOCKSIZE;
1592+
Py_ssize_t BLOCKSIZE = 64*1024;
1593+
Py_ssize_t max_items = PY_SSIZE_T_MAX / self->ob_descr->itemsize;
15971594

15981595
if (Py_SIZE(self) == 0)
15991596
goto done;
16001597

16011598
array_state *state = get_array_state_by_class(cls);
16021599
assert(state != NULL);
16031600

1604-
for (Py_ssize_t i = 0; i < nblocks; i++) {
1601+
Py_ssize_t offset = 0;
1602+
while (1) {
16051603
if (self->ob_item == NULL || Py_SIZE(self) == 0) {
16061604
break;
16071605
}
16081606

1609-
if (Py_SIZE(self) > PY_SSIZE_T_MAX / itemsize) {
1607+
if (Py_SIZE(self) > max_items) {
16101608
return PyErr_NoMemory();
16111609
}
16121610

1613-
Py_ssize_t current_nbytes = Py_SIZE(self) * itemsize;
1614-
const Py_ssize_t offset = i * BLOCKSIZE;
1611+
Py_ssize_t current_nbytes = Py_SIZE(self) * self->ob_descr->itemsize;
16151612
if (offset >= current_nbytes) {
16161613
break;
16171614
}
@@ -1627,12 +1624,13 @@ array_array_tofile_impl(arrayobject *self, PyTypeObject *cls, PyObject *f)
16271624
bytes = PyBytes_FromStringAndSize(ptr, size);
16281625
if (bytes == NULL)
16291626
return NULL;
1630-
16311627
res = PyObject_CallMethodOneArg(f, state->str_write, bytes);
16321628
Py_DECREF(bytes);
16331629
if (res == NULL)
16341630
return NULL;
1635-
Py_DECREF(res);
1631+
Py_DECREF(res); /* drop write result */
1632+
1633+
offset += size;
16361634
}
16371635

16381636
done:

0 commit comments

Comments
 (0)