metaopt / optree

OpTree: Optimized PyTree Utilities
https://optree.readthedocs.io
Apache License 2.0
136 stars 6 forks source link

[BUG] Potential infinite recursion on `repr(treespec)` / `hash(treespec)` when the node metadata references the `treespec` itself #81

Closed XuehaiPan closed 12 months ago

XuehaiPan commented 12 months ago

Required prerequisites

What version of OpTree are you using?

0.9.2

System information

Problem description

The treespec representation calls repr / hash for the node metadata for each node. When the node metadata references the treespec itself, this will cause infinite recursion of calling repr(treespec) / hash(treespec).

Note that this situation is almost impossible to happen in the real world.

Reproducible example code

The Python snippets:

import optree

class Holder:
    def __init__(self, value):
        self.value = value

    def __eq__(self, other):
        return isinstance(other, Holder) and self.value == other.value

    def __hash__(self):
        return hash(self.value)

    def __repr__(self):
        return f'Holder({self.value!r})'

key = Holder('a')

treespec = optree.tree_structure({key: 0})
print(treespec)  # -> PyTreeSpec({Holder('a'): *})

key.value = 'b'
print(treespec)  # -> PyTreeSpec({Holder('b'): *})

key.value = treespec  # self reference
print(treespec)  # -> RecursionError
print(hash(treespec))  # -> RecursionError

Traceback

Traceback (most recent call last):
  File "/Users/PanXuehai/Projects/optree/test.py", line 27, in <module>
    print(treespec)  # -> RecursionError
    ^^^^^^^^^^^^^^^
  File "/Users/PanXuehai/Projects/optree/test.py", line 15, in __repr__
    return f'Holder({self.value!r})'
           ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/PanXuehai/Projects/optree/test.py", line 15, in __repr__
    return f'Holder({self.value!r})'
           ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/PanXuehai/Projects/optree/test.py", line 15, in __repr__
    return f'Holder({self.value!r})'
           ^^^^^^^^^^^^^^^^^^^^^^^^^
  [Previous line repeated 246 more times]
RecursionError: maximum recursion depth exceeded while getting the repr of an object

Traceback (most recent call last):
  File "/Users/PanXuehai/Projects/optree/test.py", line 27, in <module>
    print(hash(treespec))  # -> RecursionError
          ^^^^^^^^^^^^^^
  File "/Users/PanXuehai/Projects/optree/test.py", line 12, in __hash__
    return hash(self.value)
           ^^^^^^^^^^^^^^^^
  File "/Users/PanXuehai/Projects/optree/test.py", line 12, in __hash__
    return hash(self.value)
           ^^^^^^^^^^^^^^^^
  File "/Users/PanXuehai/Projects/optree/test.py", line 12, in __hash__
    return hash(self.value)
           ^^^^^^^^^^^^^^^^
  [Previous line repeated 330 more times]
RecursionError: maximum recursion depth exceeded while calling a Python object

Expected behavior

No response

Additional context

No response

XuehaiPan commented 12 months ago

Opened a discussion on the Python Forum: