Skip to content

pickle: pure-Python _Unpickler._instantiate mangles a constructor TypeError (traceback in args, no chaining) #154002

Description

@fedonman

The pure-Python pickle._Unpickler mishandles a constructor failure while unpickling old-style instances (the INST and OBJ opcodes). If the class constructor raises TypeError, _instantiate does:

raise TypeError("in constructor for %s: %s" %
                (klass.__name__, str(err)), err.__traceback__)

Passing err.__traceback__ as a second positional argument puts the traceback object into the exception's args, so it leaks into str(), and there is no real chaining (__cause__ stays None).

import pickle, io
class Bad:
    def __init__(self, *a):
        raise TypeError("boom")
u = pickle._Unpickler(io.BytesIO())
try:
    u._instantiate(Bad, (1,))
except TypeError as e:
    print(e.args)       # ('in constructor for Bad: boom', <traceback object ...>)
    print(e.__cause__)  # None

The C _pickle unpickler does not wrap the error at all, it just lets the original TypeError propagate, so this only affects the pure-Python implementation.

The fix is to chain properly and drop the traceback argument:

raise TypeError("in constructor for %s: %s" %
                (klass.__name__, str(err))) from err

This is a leftover from the Python 2 way of carrying a traceback. It used to be sys.exc_info()[2] and gh-102799 mechanically turned that into err.__traceback__ without noticing the value was being passed as a constructor argument.

Found while going through devdanzin's audit of the standard library, item 15: https://gist.github.com/devdanzin/3198710e3c0128fda5e0a7b4e0768e5f

Linked PRs

Metadata

Metadata

Assignees

No one assigned

    Labels

    stdlibStandard Library Python modules in the Lib/ directorytype-bugAn unexpected behavior, bug, or error

    Fields

    No fields configured for issues without a type.

    Projects

    Status
    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions