Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

zope.copy cannot handle BTreeContainers with more than ~7800 items #8

Open
mgedmin opened this issue Nov 30, 2022 · 2 comments
Open

Comments

@mgedmin
Copy link
Member

mgedmin commented Nov 30, 2022

What I did:

N_ITEMS = 8000   # 7761 was the smallest value that raised RuntimeError


def test_clone_large_btree_container():
    obj = BTreeContainer()
    for n in range(N_ITEMS):
        obj[str(n)] = None
    zope.copy.clone(obj)   # raises RuntimeError: maximum recursion depth exceeded

What I expect to happen:

Copy the container

What actually happened:

Traceback (most recent call last):
  File "/home/mg/src/zope-copy-stack-overflow-error/repro.py", line 16, in <module>
    test_clone_large_btree_container()
  File "/home/mg/src/zope-copy-stack-overflow-error/repro.py", line 12, in test_clone_large_btree_container
    zope.copy.clone(obj)
  File "/home/mg/src/zope-copy-stack-overflow-error/.tox/py39/lib/python3.9/site-packages/zope/copy/__init__.py", line 31, in clone
    pickler.dump(obj)
  File "/home/mg/src/zope-copy-stack-overflow-error/.tox/py39/lib/python3.9/site-packages/zope/copy/__init__.py", line 85, in id
    hook = interfaces.ICopyHook(obj, None)
  File "/home/mg/src/zope-copy-stack-overflow-error/.tox/py39/lib/python3.9/site-packages/zope/component/_api.py", line 152, in adapter_hook
    return sitemanager.queryAdapter(object, interface, name, default)
  File "/home/mg/src/zope-copy-stack-overflow-error/.tox/py39/lib/python3.9/site-packages/zope/interface/registry.py", line 354, in queryAdapter
    return self.adapters.queryAdapter(object, interface, name, default)
  File "/home/mg/src/zope-copy-stack-overflow-error/.tox/py39/lib/python3.9/site-packages/zope/proxy/__init__.py", line 573, in <lambda>
    return property(lambda self: func.__get__(self))
  File "/home/mg/src/zope-copy-stack-overflow-error/.tox/py39/lib/python3.9/site-packages/zope/container/contained.py", line 932, in __get__
    for iface in list(provided):
  File "/home/mg/src/zope-copy-stack-overflow-error/.tox/py39/lib/python3.9/site-packages/zope/interface/interface.py", line 516, in interfaces
    for base in self.__bases__:
RecursionError: maximum recursion depth exceeded

What version of Python and Zope/Addons I am using:

Python on Linux (Python 3.9 on Ubuntu 22.10, among other combinations)

zope.container 4.10, zope.copy 4.3

@mgedmin
Copy link
Member Author

mgedmin commented Nov 30, 2022

Probably relevant upstream issue: python/cpython#47369.

If I do import pickle; pickle.dumps(obj) I get the same runtime error on this BTreeContainer.

(Since I wondered and looked it up, here's a factlet: zope.copy does not use zodbpickle for this, it uses the stdlib pickle.)

@mgedmin
Copy link
Member Author

mgedmin commented Nov 30, 2022

A OOBucket holds up to 20 items by default. The buckets in an OOBTree constitue a singly-linked list, with the OOBTree itself holding additional direct references to all the buckets. Here's a tree with 100 items:

image

An OOBTree with 8000 items has a bit over 500 buckets, depending on the order of insertion. sys.getrecursionlimit() is 1000 by default. If pickle uses up two stack frames per object, a depth-first graph traversal starting from the first bucket will hit the limit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant