Skip to content
Open
17 changes: 17 additions & 0 deletions Lib/test/test_array.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,23 @@ def test_empty(self):
a += a
self.assertEqual(len(a), 0)

def test_fromlist_reentrant_index_mutation(self):

class Evil:
def __init__(self, lst):
self.lst = lst
def __index__(self):
self.lst.clear()
return "not an int"

for typecode in ('I', 'L', 'Q'):
with self.subTest(typecode=typecode):
lst = []
lst.append(Evil(lst))
a = array.array(typecode)
with self.assertRaises(TypeError):
a.fromlist(lst)


# Machine format codes.
#
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Fix a crash in :meth:`array.array.fromlist` when an element's :meth:`~object.__index__` method mutates
the input list during conversion.
21 changes: 15 additions & 6 deletions Modules/arraymodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -408,10 +408,13 @@ II_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v)
int do_decref = 0; /* if nb_int was called */

if (!PyLong_Check(v)) {
v = _PyNumber_Index(v);
if (NULL == v) {
Py_INCREF(v);
PyObject *res = _PyNumber_Index(v);
Py_DECREF(v);
if (NULL == res) {
return -1;
}
v = res;
do_decref = 1;
}
x = PyLong_AsUnsignedLong(v);
Expand Down Expand Up @@ -468,10 +471,13 @@ LL_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v)
int do_decref = 0; /* if nb_int was called */

if (!PyLong_Check(v)) {
v = _PyNumber_Index(v);
if (NULL == v) {
Py_INCREF(v);
PyObject *res = _PyNumber_Index(v);
Py_DECREF(v);
if (NULL == res) {
return -1;
}
v = res;
do_decref = 1;
}
x = PyLong_AsUnsignedLong(v);
Expand Down Expand Up @@ -521,10 +527,13 @@ QQ_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v)
int do_decref = 0; /* if nb_int was called */

if (!PyLong_Check(v)) {
v = _PyNumber_Index(v);
if (NULL == v) {
Py_INCREF(v);
PyObject *res = _PyNumber_Index(v);
Py_DECREF(v);
if (NULL == res) {
return -1;
}
v = res;
do_decref = 1;
}
x = PyLong_AsUnsignedLongLong(v);
Expand Down
Loading