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

_pickle.UnpicklingError: Memo value not found at index 1 #125756

Open
erik895 opened this issue Oct 20, 2024 · 2 comments
Open

_pickle.UnpicklingError: Memo value not found at index 1 #125756

erik895 opened this issue Oct 20, 2024 · 2 comments
Labels
3.12 bugs and security fixes 3.13 bugs and security fixes 3.14 new features, bugs and security fixes docs Documentation in the Doc dir stdlib Python modules in the Lib dir type-bug An unexpected behavior, bug, or error

Comments

@erik895
Copy link

erik895 commented Oct 20, 2024

Bug report

Bug description:

When pickling a container object. The pickler class will store child-objects to its self.memo even if the container could not be fully pickled (and not written to the output).
This can cause references to memo objects that are not in the output stream.

import sys
import pickle
import io

buf = io.BytesIO()
pickler = pickle.Pickler(buf)
i_will_be_memorized = 'qqqqqqqqqqqq'
i_cant_be_pickled = sys

try:
    pickler.dump([i_will_be_memorized, i_cant_be_pickled])
except TypeError:
    # i_will_be_memorized is now in pickler memory despite the exception
    pass

# this dump will use the memo
pickler.dump(i_will_be_memorized)

data = buf.getbuffer().tobytes()

# so this will fail with:
#   _pickle.UnpicklingError: Memo value not found at index 1
pickle.loads(data)

CPython versions tested on:

3.12

Operating systems tested on:

Windows

Linked PRs

@erik895 erik895 added the type-bug An unexpected behavior, bug, or error label Oct 20, 2024
@tomasr8 tomasr8 added 3.12 bugs and security fixes 3.13 bugs and security fixes 3.14 new features, bugs and security fixes labels Oct 20, 2024
@tomasr8
Copy link
Member

tomasr8 commented Oct 20, 2024

There's an undocumented clear_memo function which seems to be intended for this exact case:

This method is useful when re-using picklers

cpython/Lib/pickle.py

Lines 478 to 486 in b3c6b2c

def clear_memo(self):
"""Clears the pickler's "memo".
The memo is the data structure that remembers which objects the
pickler has already seen, so that shared or recursive objects
are pickled by reference and not by value. This method is
useful when re-using picklers.
"""
self.memo.clear()

In your case, you could probably do something like this:

try:
    pickler.dump([i_will_be_memorized, i_cant_be_pickled])
except TypeError:
    # i_will_be_memorized is now in pickler memory despite the exception
    pickler.clear_memo()

@willingc willingc added docs Documentation in the Doc dir stdlib Python modules in the Lib dir labels Oct 20, 2024
@erik895
Copy link
Author

erik895 commented Oct 21, 2024

Thanks for the quick reply! I thought clear_memo was not documented because it’s dangerous to use. When you clear the memo, I don’t think that 'action' gets written to the output, so the loader won’t clear its own memo (I have't checked any code, this is just my observation).

As a result, loading a stream where clear_memo was used could lead to loading the wrong objects. If clear_memo is used publicly, I think it deserves its own issue.

import pickle
import io

buf = io.BytesIO()
pickler = pickle.Pickler(buf)

pickler.dump("foo")
pickler.clear_memo()
pickler.dump("bar")
pickler.dump("bar")

buf.seek(0)
loader = pickle.Unpickler(buf)
print(loader.load()) # prints foo
print(loader.load()) # prints bar
print(loader.load()) # prints foo (I wanted bar)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
3.12 bugs and security fixes 3.13 bugs and security fixes 3.14 new features, bugs and security fixes docs Documentation in the Doc dir stdlib Python modules in the Lib dir type-bug An unexpected behavior, bug, or error
Projects
Status: No status
Development

No branches or pull requests

3 participants