gh-132713: Fix repr(list) race condition (#132801)
Hold a strong reference to the item while calling repr(item).
This commit is contained in:
parent
722c501dba
commit
a4ea80d523
@ -118,6 +118,19 @@ class ListTest(list_tests.CommonTest):
|
|||||||
with self.assertRaises((MemoryError, OverflowError)):
|
with self.assertRaises((MemoryError, OverflowError)):
|
||||||
lst *= size
|
lst *= size
|
||||||
|
|
||||||
|
def test_repr_mutate(self):
|
||||||
|
class Obj:
|
||||||
|
@staticmethod
|
||||||
|
def __repr__():
|
||||||
|
try:
|
||||||
|
mylist.pop()
|
||||||
|
except IndexError:
|
||||||
|
pass
|
||||||
|
return 'obj'
|
||||||
|
|
||||||
|
mylist = [Obj() for _ in range(5)]
|
||||||
|
self.assertEqual(repr(mylist), '[obj, obj, obj]')
|
||||||
|
|
||||||
def test_repr_large(self):
|
def test_repr_large(self):
|
||||||
# Check the repr of large list objects
|
# Check the repr of large list objects
|
||||||
def check(n):
|
def check(n):
|
||||||
|
@ -0,0 +1,2 @@
|
|||||||
|
Fix ``repr(list)`` race condition: hold a strong reference to the item while
|
||||||
|
calling ``repr(item)``. Patch by Victor Stinner.
|
@ -583,6 +583,7 @@ list_repr_impl(PyListObject *v)
|
|||||||
/* "[" + "1" + ", 2" * (len - 1) + "]" */
|
/* "[" + "1" + ", 2" * (len - 1) + "]" */
|
||||||
Py_ssize_t prealloc = 1 + 1 + (2 + 1) * (Py_SIZE(v) - 1) + 1;
|
Py_ssize_t prealloc = 1 + 1 + (2 + 1) * (Py_SIZE(v) - 1) + 1;
|
||||||
PyUnicodeWriter *writer = PyUnicodeWriter_Create(prealloc);
|
PyUnicodeWriter *writer = PyUnicodeWriter_Create(prealloc);
|
||||||
|
PyObject *item = NULL;
|
||||||
if (writer == NULL) {
|
if (writer == NULL) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
@ -594,6 +595,13 @@ list_repr_impl(PyListObject *v)
|
|||||||
/* Do repr() on each element. Note that this may mutate the list,
|
/* Do repr() on each element. Note that this may mutate the list,
|
||||||
so must refetch the list size on each iteration. */
|
so must refetch the list size on each iteration. */
|
||||||
for (Py_ssize_t i = 0; i < Py_SIZE(v); ++i) {
|
for (Py_ssize_t i = 0; i < Py_SIZE(v); ++i) {
|
||||||
|
item = list_get_item_ref(v, i);
|
||||||
|
if (item == NULL) {
|
||||||
|
// List truncated while iterating on it
|
||||||
|
PyErr_Clear();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
if (PyUnicodeWriter_WriteChar(writer, ',') < 0) {
|
if (PyUnicodeWriter_WriteChar(writer, ',') < 0) {
|
||||||
goto error;
|
goto error;
|
||||||
@ -603,9 +611,10 @@ list_repr_impl(PyListObject *v)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PyUnicodeWriter_WriteRepr(writer, v->ob_item[i]) < 0) {
|
if (PyUnicodeWriter_WriteRepr(writer, item) < 0) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
Py_CLEAR(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PyUnicodeWriter_WriteChar(writer, ']') < 0) {
|
if (PyUnicodeWriter_WriteChar(writer, ']') < 0) {
|
||||||
@ -616,6 +625,7 @@ list_repr_impl(PyListObject *v)
|
|||||||
return PyUnicodeWriter_Finish(writer);
|
return PyUnicodeWriter_Finish(writer);
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
Py_XDECREF(item);
|
||||||
PyUnicodeWriter_Discard(writer);
|
PyUnicodeWriter_Discard(writer);
|
||||||
Py_ReprLeave((PyObject *)v);
|
Py_ReprLeave((PyObject *)v);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user