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

Unpickler failing with PicklingError at frame end on readline due to a broken comparison #67283

Closed
CensoredUsername mannequin opened this issue Dec 20, 2014 · 6 comments
Assignees
Labels
stdlib Python modules in the Lib dir type-bug An unexpected behavior, bug, or error

Comments

@CensoredUsername
Copy link
Mannequin

CensoredUsername mannequin commented Dec 20, 2014

BPO 23094
Nosy @pitrou, @serhiy-storchaka
Files
  • pickle_frame_readline.patch
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = 'https://github.com/serhiy-storchaka'
    closed_at = <Date 2015-01-26.10:27:29.611>
    created_at = <Date 2014-12-20.23:24:31.998>
    labels = ['type-bug', 'library']
    title = 'Unpickler failing with PicklingError at frame end on readline due to a broken comparison'
    updated_at = <Date 2015-01-26.10:27:29.611>
    user = 'https://bugs.python.org/CensoredUsername'

    bugs.python.org fields:

    activity = <Date 2015-01-26.10:27:29.611>
    actor = 'serhiy.storchaka'
    assignee = 'serhiy.storchaka'
    closed = True
    closed_date = <Date 2015-01-26.10:27:29.611>
    closer = 'serhiy.storchaka'
    components = ['Library (Lib)']
    creation = <Date 2014-12-20.23:24:31.998>
    creator = 'CensoredUsername'
    dependencies = []
    files = ['37521']
    hgrepos = []
    issue_num = 23094
    keywords = ['patch', 'needs review']
    message_count = 6.0
    messages = ['232984', '232988', '232991', '232996', '234234', '234724']
    nosy_count = 4.0
    nosy_names = ['pitrou', 'python-dev', 'serhiy.storchaka', 'CensoredUsername']
    pr_nums = []
    priority = 'normal'
    resolution = 'fixed'
    stage = 'resolved'
    status = 'closed'
    superseder = None
    type = 'behavior'
    url = 'https://bugs.python.org/issue23094'
    versions = ['Python 3.4', 'Python 3.5']

    @CensoredUsername
    Copy link
    Mannequin Author

    CensoredUsername mannequin commented Dec 20, 2014

    If a pickle frame ends at the end of a pickle._Unframer.readline() call then an UnpicklingError("pickle exhausted before end of frame") will unconditionally be raised due to a faulty check if the frame ended before the line ended.

    It concerns this conditional in pickle._Unframer.readline, line 245 in pickle.py:

    if data[-1] != b'\n':
        raise UnpicklingError(
            "pickle exhausted before end of frame")

    This comparison will always evaluate to True even if data ends in a newline. This is caused by data being a bytes object, and such data[-1] will evaluate to 10 in case of data ending in a newline. 10 != b'\n' will then always evaluate to True due to the type mismatch, and the UnpicklingError will be raised.

    This error can be corrected by slicing an actual one character bytes object like:

    if data[-1:] != b'\n':
        raise UnpicklingError(
            "pickle exhausted before end of frame")

    Or by comparing against the numeric representation of b'\n':

    if data[-1] != b'\n'[0]:
        raise UnpicklingError(
            "pickle exhausted before end of frame")

    @CensoredUsername CensoredUsername mannequin added the type-bug An unexpected behavior, bug, or error label Dec 20, 2014
    @pitrou
    Copy link
    Member

    pitrou commented Dec 21, 2014

    Thanks for the report. Do you have actual data that can exhibit the problem?

    @serhiy-storchaka
    Copy link
    Member

    readline() is used only when unpickle opcodes PERSID, INT, LONG, FLOAT, STRING, UNICODE, INST, GLOBAL, GET, PUT. These opcodes are not used with protocol 4 (all opcodes except GLOBAL is used only with protocol 0, and GLOBAL is used with protocol <= 3). Frames are used only with protocol 4. So there is very small chance to meet this bug in real data. But it is not zero, artificial pickled data which mixes FRAME with protocol 0 opcodes can be constructed by third-party software for some reasons.

    Artificial example:

    >>> pickletools.dis(b"\x80\x04\x95\x05\x00\x00\x00\x00\x00\x00\x00I42\n.")
        0: \x80 PROTO      4
        2: \x95 FRAME      5
       11: I    INT        42
       15: .    STOP
    highest protocol among opcodes = 4

    @serhiy-storchaka serhiy-storchaka added the stdlib Python modules in the Lib dir label Dec 21, 2014
    @CensoredUsername
    Copy link
    Mannequin Author

    CensoredUsername mannequin commented Dec 21, 2014

    Indeed. In my case the problem was caused a subclassed Pickler which still used GLOBAL instead of STACK_GLOBAL in protocol 4.

    My own minimized test case was:

    data = b"\x80\x04\x95\x11\x00\x00\x00\x00\x00\x00\x00cpickle\nPickler\n."
    >>> pickletools.dis(data)
        0: \x80 PROTO      4
        2: \x95 FRAME      17
       11: c    GLOBAL     'pickle Pickler'
       27: .    STOP
    highest protocol among opcodes = 4

    which should return pickle.Pickler

    @serhiy-storchaka
    Copy link
    Member

    If there are no objections I'm going to commit the patch.

    @serhiy-storchaka serhiy-storchaka self-assigned this Jan 18, 2015
    @python-dev
    Copy link
    Mannequin

    python-dev mannequin commented Jan 26, 2015

    New changeset d5e13b74d377 by Serhiy Storchaka in branch '3.4':
    Issue bpo-23094: Fixed readline with frames in Python implementation of pickle.
    https://hg.python.org/cpython/rev/d5e13b74d377

    New changeset c347c21e5afa by Serhiy Storchaka in branch 'default':
    Issue bpo-23094: Fixed readline with frames in Python implementation of pickle.
    https://hg.python.org/cpython/rev/c347c21e5afa

    @ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    stdlib Python modules in the Lib dir type-bug An unexpected behavior, bug, or error
    Projects
    None yet
    Development

    No branches or pull requests

    2 participants