Skip to content

_pickle crashes when read() returns a bytes subclass for large payloads #158841

Description

@error-3317

Crash report

Loading a pickle containing a large string (>= 1MB) using a custom file-like object that returns a bytes subclass from read() causes a deterministic segmentation fault in CPython 3.15.

PoC

import pickle
import gc

# GC-tracked heap type
class MyBytes(bytes):
    def __init__(self, *a): 
        self.tag = "meta"

class ReaderSub:
    def __init__(self, data): 
        self.d = data
        self.p = 0
        
    def read(self, n):
        c = self.d[self.p:self.p + n]
        self.p += len(c)
        return MyBytes(c)
        
    def readline(self):
        i = self.d.find(b'\n', self.p)
        line = self.d[self.p:i+1] if i >= 0 else self.d[self.p:]
        self.p = len(self.d) if i < 0 else i + 1
        return line

doc = pickle.dumps({'v': 'B' * (3 * 1024 * 1024)})

obj = pickle.load(ReaderSub(doc))
print("Successfully loaded.")

Code Output

Running on Python 3.15.0b1+:

realloc(): invalid old size

Running with Python 3.14.7:

Successfully loaded.

Root Cause

The crash occurs in Modules/_pickle.c, specifically within the new chunked read loop in _Unpickler_ReadFromFile (around line 1445).

The loop does this:

data = _Pickle_FastCall(self->read, len);
/* ... */
if (_PyBytes_Resize(&data, cursize) < 0)

_PyBytes_Resize is being called directly on the foreign object returned by self->read().
Because MyBytes is a subclass of bytes, it passes PyBytes_Check(). However, because it is a Python-level subclass, it is a heap type and is therefore tracked by the Garbage Collector.

This means the actual allocation includes a PyGC_Head before the object data. When _PyBytes_Resize calls PyObject_Realloc(v, PyBytesObject_SIZE + newsize), the pointer v is an interior pointer (offset by 32 bytes from the true malloc address). Reallocating an interior pointer corrupts the heap and immediately crashes the interpreter.

CPython versions tested on:

3.15

Operating systems tested on:

Linux

Output from running 'python -VV' on the command line:

Python 3.15.0rc2 (main, Sep 29 2026, 15:02:39) [Clang 22.1.3 ]

Linked PRs

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    3.15pre-release feature fixes, bugs and security fixesextension-modulesC modules in the Modules dirtype-crashA hard crash of the interpreter, possibly with a core dump

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions