Skip to content

Commit 636741f

Browse files
committed
chore: resolve comment issue
1 parent 7712b1d commit 636741f

File tree

2 files changed

+18
-24
lines changed

2 files changed

+18
-24
lines changed

Lib/test/test_array.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1368,20 +1368,18 @@ 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()
1371+
# Prevent crash when a writer concurrently mutates the array.
1372+
# See https://github.com/python/cpython/issues/142884.
1373+
# Keep 'BLOCKSIZE' in sync with the array.tofile() C implementation.
13731374
BLOCKSIZE = 64 * 1024
13741375
victim = array.array('B', b'\0' * (BLOCKSIZE * 2))
13751376

13761377
class Writer:
1377-
cleared = False
13781378
def write(self, data):
1379-
if not self.cleared:
1380-
self.cleared = True
1381-
victim.clear()
1379+
victim.clear()
13821380
return 0
13831381

1384-
victim.tofile(Writer())
1382+
victim.tofile(Writer()) # should not crash
13851383

13861384

13871385
class IntegerNumberTest(NumberTest):

Modules/arraymodule.c

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1591,32 +1591,28 @@ array_array_tofile_impl(arrayobject *self, PyTypeObject *cls, PyObject *f)
15911591
/* XXX Make the block size settable */
15921592
Py_ssize_t BLOCKSIZE = 64*1024;
15931593
Py_ssize_t max_items = PY_SSIZE_T_MAX / self->ob_descr->itemsize;
1594+
Py_ssize_t total_size = Py_SIZE(self);
1595+
Py_ssize_t current_nbytes = total_size * self->ob_descr->itemsize;
1596+
Py_ssize_t offset = 0;
15941597

15951598
if (Py_SIZE(self) == 0)
15961599
goto done;
15971600

15981601
array_state *state = get_array_state_by_class(cls);
15991602
assert(state != NULL);
16001603

1601-
Py_ssize_t offset = 0;
1602-
while (1) {
1603-
Py_ssize_t total_size = Py_SIZE(self);
1604-
if (self->ob_item == NULL || total_size == 0) {
1605-
break;
1606-
}
1607-
1608-
if (total_size > max_items) {
1609-
return PyErr_NoMemory();
1610-
}
1604+
if (total_size == 0) {
1605+
goto done;
1606+
}
16111607

1612-
Py_ssize_t current_nbytes = total_size * self->ob_descr->itemsize;
1613-
if (offset >= current_nbytes) {
1614-
break;
1615-
}
1608+
if (total_size > max_items) {
1609+
return PyErr_NoMemory();
1610+
}
16161611

1617-
Py_ssize_t size = current_nbytes - offset;
1618-
if (size > BLOCKSIZE) {
1619-
size = BLOCKSIZE;
1612+
while (self->ob_item != NULL && offset < current_nbytes) {
1613+
Py_ssize_t size = BLOCKSIZE;
1614+
if (offset + size > current_nbytes) {
1615+
size = current_nbytes - offset;
16201616
}
16211617

16221618
char* ptr = self->ob_item + offset;

0 commit comments

Comments
 (0)