New submission from Serhiy Storchaka <storchaka+cpyt...@gmail.com>:

repr() of deeply nested dicts and dictviews can cause a stack overflow.

>>> x = {}
>>> for i in range(100000):
...     x = {1: x}
... 
>>> repr(x)
Segmentation fault

>>> x = {}
>>> for i in range(100000):
...     x = {1: x}
... 
>>> repr(x.values())
Segmentation fault

repr() of virtually all other deeply nested collections are guarded by using 
Py_EnterRecursiveCall().

>>> x = ()
>>> for i in range(100000):
...     x = (x,)
... 
>>> repr(x)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
RecursionError: maximum recursion depth exceeded while getting the repr of a 
tuple

>>> x = []
>>> for i in range(100000):
...     x = [x]
... 
>>> repr(x)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
RecursionError: maximum recursion depth exceeded while getting the repr of a 
list

>>> x = frozenset()
>>> for i in range(100000):
...     x = frozenset({x})
... 
>>> repr(x)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
RecursionError: maximum recursion depth exceeded while getting the repr of a 
list

>>> from collections import OrderedDict
>>> x = {}
>>> for i in range(100000):
...     x = OrderedDict({1: x})
... 
>>> repr(x)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
RecursionError: maximum recursion depth exceeded while getting the repr of a 
list

>>> from collections import deque
>>> x = deque()
>>> for i in range(100000):
...     x = deque([x])
... 
>>> repr(x)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
RecursionError: maximum recursion depth exceeded while getting the repr of a 
list

But the case of infinite recursion already is handled:

>>> x = {}
>>> x[1] = x
>>> repr(x)
'{1: {...}}'

Only finite but very deep recursion causes a crash.

The one possible solution -- add Py_EnterRecursiveCall() in the implementation 
of dict.__repr__(), like it already is added in list.__repr__() and 
tuple.__repr__().

The more general solution -- add Py_EnterRecursiveCall() in PyObject_Repr(). In 
any case it is called before calling PyObject_Repr() for every item in the repr 
of most collections except dict. And it is already added in PyObject_Str(). 
Therefore adding it will not add much overhead, but can handle more corner 
cases.

See also issue18533 and issue25240.

----------
components: Interpreter Core
messages: 306997
nosy: serhiy.storchaka
priority: normal
severity: normal
status: open
title: Stack overflow in repr of deeply nested dicts
type: crash
versions: Python 2.7, Python 3.6, Python 3.7

_______________________________________
Python tracker <rep...@bugs.python.org>
<https://bugs.python.org/issue32137>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to