Repository navigation
_pickle crashes when read() returns a bytes subclass for large payloads #158841
Description
Activity
- addedtype-crashA hard crash of the interpreter, possibly with a core dumpA hard crash of the interpreter, possibly with a core dump
on Oct 5, 2026 - changed the title
[-]Crash in _pickle: _PyBytes_Resize on bytes subclass causes SIGSEGV[/-][+]_pickle crashes when read() returns a bytes subclass for large payloads[/+]on Oct 5, 2026 - addedextension-modulesC modules in the Modules dirC modules in the Modules dir3.15pre-release feature fixes, bugs and security fixespre-release feature fixes, bugs and security fixestype-crashA hard crash of the interpreter, possibly with a core dumpA hard crash of the interpreter, possibly with a core dumpand removedextension-modulesC modules in the Modules dirC modules in the Modules dirtype-crashA hard crash of the interpreter, possibly with a core dumpA hard crash of the interpreter, possibly with a core dump
on Oct 5, 2026 cc @vstinner
I guess_PyBytes_IsMutableneedsPyBytes_CheckExact?_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.Oh. It seems like it's a bad idea to accept bytes subclass in
_PyBytes_Resize(). For example, if it's refcount is greater than 1,_PyBytes_Resize()returns a bytes object, not an instance of the subclass.And so, yes, _pickle should not call
_PyBytes_Resize()if PyBytes_CheckExact() is false.Well,
_PyBytes_Resizeis documented, so it might be better to keep the documented behaviour (“creating a new bytes object and destroying the old one, only more efficiently” -- of course, without the optimization in this case)._PyBytes_Resize()returns a bytes object, not an instance of the subclass.IMO, that's fine.
BytesSubclass(...)[:]and most other operations will do the same thing.
@drakeo338, instead of your fix in
pickle.c, could you add a!PyBytes_CheckExact(v)to_PyBytes_ResizeKeepOnError(just before the!_PyObject_IsUniquelyReferenced)?
Metadata
Metadata
Assignees
Labels
Projects
- StatusShow more project fieldsNo status
Crash report
Loading a pickle containing a large string (>= 1MB) using a custom file-like object that returns a
bytessubclass fromread()causes a deterministic segmentation fault in CPython 3.15.PoC
Code Output
Running on Python 3.15.0b1+:
realloc(): invalid old sizeRunning 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:
_PyBytes_Resizeis being called directly on the foreign object returned byself->read().Because
MyBytesis a subclass ofbytes, it passesPyBytes_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_Headbefore the object data. When_PyBytes_ResizecallsPyObject_Realloc(v, PyBytesObject_SIZE + newsize), the pointervis 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