bpo-32137: The repr of deeply nested dict now raises a RecursionError (#4570)
instead of crashing due to a stack overflow. This perhaps will fix similar problems in other extension types.
This commit is contained in:
parent
eea3cc1ef0
commit
1fb72d2ad2
|
@ -53,10 +53,11 @@ class CommonTest(seq_tests.CommonTest):
|
|||
self.assertEqual(str(a2), "[0, 1, 2, [...], 3]")
|
||||
self.assertEqual(repr(a2), "[0, 1, 2, [...], 3]")
|
||||
|
||||
l0 = []
|
||||
def test_repr_deep(self):
|
||||
a = self.type2test([])
|
||||
for i in range(sys.getrecursionlimit() + 100):
|
||||
l0 = [l0]
|
||||
self.assertRaises(RecursionError, repr, l0)
|
||||
a = self.type2test([a])
|
||||
self.assertRaises(RecursionError, repr, a)
|
||||
|
||||
def test_print(self):
|
||||
d = self.type2test(range(200))
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
# tests common to dict and UserDict
|
||||
import unittest
|
||||
import collections
|
||||
import sys
|
||||
|
||||
|
||||
class BasicTestMappingProtocol(unittest.TestCase):
|
||||
|
@ -619,6 +620,14 @@ class TestHashMappingProtocol(TestMappingProtocol):
|
|||
d = self._full_mapping({1: BadRepr()})
|
||||
self.assertRaises(Exc, repr, d)
|
||||
|
||||
def test_repr_deep(self):
|
||||
d = self._empty_mapping()
|
||||
for i in range(sys.getrecursionlimit() + 100):
|
||||
d0 = d
|
||||
d = self._empty_mapping()
|
||||
d[1] = d0
|
||||
self.assertRaises(RecursionError, repr, d)
|
||||
|
||||
def test_eq(self):
|
||||
self.assertEqual(self._empty_mapping(), self._empty_mapping())
|
||||
self.assertEqual(self._full_mapping({1: 2}),
|
||||
|
|
|
@ -468,6 +468,12 @@ class DictTest(unittest.TestCase):
|
|||
d = {1: BadRepr()}
|
||||
self.assertRaises(Exc, repr, d)
|
||||
|
||||
def test_repr_deep(self):
|
||||
d = {}
|
||||
for i in range(sys.getrecursionlimit() + 100):
|
||||
d = {1: d}
|
||||
self.assertRaises(RecursionError, repr, d)
|
||||
|
||||
def test_eq(self):
|
||||
self.assertEqual({}, {})
|
||||
self.assertEqual({1: 2}, {1: 2})
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
The repr of deeply nested dict now raises a RecursionError instead of
|
||||
crashing due to a stack overflow.
|
|
@ -364,10 +364,7 @@ list_repr(PyListObject *v)
|
|||
goto error;
|
||||
}
|
||||
|
||||
if (Py_EnterRecursiveCall(" while getting the repr of a list"))
|
||||
goto error;
|
||||
s = PyObject_Repr(v->ob_item[i]);
|
||||
Py_LeaveRecursiveCall();
|
||||
if (s == NULL)
|
||||
goto error;
|
||||
|
||||
|
|
|
@ -463,7 +463,12 @@ PyObject_Repr(PyObject *v)
|
|||
assert(!PyErr_Occurred());
|
||||
#endif
|
||||
|
||||
/* It is possible for a type to have a tp_repr representation that loops
|
||||
infinitely. */
|
||||
if (Py_EnterRecursiveCall(" while getting the repr of an object"))
|
||||
return NULL;
|
||||
res = (*v->ob_type->tp_repr)(v);
|
||||
Py_LeaveRecursiveCall();
|
||||
if (res == NULL)
|
||||
return NULL;
|
||||
if (!PyUnicode_Check(res)) {
|
||||
|
|
|
@ -303,10 +303,7 @@ tuplerepr(PyTupleObject *v)
|
|||
goto error;
|
||||
}
|
||||
|
||||
if (Py_EnterRecursiveCall(" while getting the repr of a tuple"))
|
||||
goto error;
|
||||
s = PyObject_Repr(v->ob_item[i]);
|
||||
Py_LeaveRecursiveCall();
|
||||
if (s == NULL)
|
||||
goto error;
|
||||
|
||||
|
|
Loading…
Reference in New Issue