Repository navigation
Double free corruption when allocation failures occur in assemble_init #151112
Copy link
Copy link
Closed
Labels
interpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)type-crashA hard crash of the interpreter, possibly with a core dumpA hard crash of the interpreter, possibly with a core dump
Description
Crash report
What happened?
import _testcapi
compile("pass", "<warmup>", "single")
_testcapi.set_nomemory(64, 65)
try:
compile("pass", "<trigger>", "single")
except MemoryError:
pass
first = bytes(128)
second = bytes(128)Job 1, './python.exe reproduce_assemble…' terminated by signal SIGSEGV (Address boundary error)
Note, this reproducer only works if the allocation sizes are exactly the same as on my mac! the nomemory values may need tweaking.
The chain is:
_PyAssemble_MakeCodeObjectis called- this calls assemble_emit which calls
RETURN_IF_ERROR(assemble_init(a, first_lineno));passing the assembler by ref as an argument. - An allocation failure happens in
assemble_init, when allocating the linetable or the except table. assemble_initcleans up by decreffing all members, BUT the assembler fields are left populated with the old pointers, and the caller has the assembler reference.assemble_emitsees the error code and returns to_PyAssemble_MakeCodeObject- The result != SUCCESS, so makecode isn't called, but
assemble_freeIS called, causing a double free of at leasta->a_bytecode.
The error manifests itself as heap corruption from the double free.
CPython versions tested on:
CPython main branch
Operating systems tested on:
macOS
Output from running 'python -VV' on the command line:
Python 3.16.0a0 (heads/main-dirty:f051c68923b, Jun 8 2026, 16:26:15) [Clang 21.0.0 (clang-2100.1.1.101)]
Linked PRs
- gh-151112: Fix double free in
assemble_initwhen out of memory #151142 - gh-151112: Move an
assertthat may fail incfg_builder_check#151153 - [3.15] gh-151112: Fix double free in
assemble_initwhen out of memory (GH-151142) #151205 - [3.14] gh-151112: Fix double free in
assemble_initwhen out of memory (GH-151142) #151206 - [3.13] gh-151112: Fix double free in
assemble_initwhen out of memory (GH-151142) #151207 - gh-151112: Fix crash in
compiler_mod()when entering the current compilation unit fails #151234 - [3.15] gh-151112: Move an
assertthat may fail incfg_builder_check(GH-151153) #151313 - [3.14] gh-151112: Move an
assertthat may fail incfg_builder_check(GH-151153) #151314 - [3.13] gh-151112: Move an
assertthat may fail incfg_builder_check(GH-151153) #151315 - [3.15] gh-151112: Fix crash in
compiler_mod()when entering the current compilation unit fails (GH-151234) #151350 - [3.14] gh-151112: Fix crash in
compiler_mod()when entering the current compilation unit fails (GH-151234) #151351
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
interpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)type-crashA hard crash of the interpreter, possibly with a core dumpA hard crash of the interpreter, possibly with a core dump
Activity
stestagg commentedon Jun 8, 2026
ISTM that the easy fix here is to explicitly reset a->a_bytecode et-al to 0 during the error branch of assemble_init?
gh-151112: Fix double free in `assemble_init` when out of memory (#15…
[3.13] gh-151112: Fix double free in `assemble_init` when out of memo…
[3.14] gh-151112: Fix double free in `assemble_init` when out of memo…
[3.15] gh-151112: Fix double free in `assemble_init` when out of memo…
gh-151112: Move an `assert` that may fail in `cfg_builder_check` (#15…
[3.13] gh-151112: Move an `assert` that may fail in `cfg_builder_chec…
[3.14] gh-151112: Move an `assert` that may fail in `cfg_builder_chec…
[3.15] gh-151112: Move an `assert` that may fail in `cfg_builder_chec…
gh-151112: Fix crash in `compiler_mod()` when entering the current co…
StanFromIreland commentedon Jun 11, 2026
Thanks for the report! This reproducer was a Pandora's box, running it trying to find the start and stop for
set_nomemorythat work for me, I ran into two more bugs! They've all been fixed now.stestagg commentedon Jun 11, 2026
Thanks for jumping on it so quickly!
Yeah, I came across it when testing a custom fault-injecting allocator for for python, It was literally the first time I ran the code, and immediately hit that, took me a while to realise it wasn't an issue in the allocator code, so I imagine there are lots of bugs hidden. I guess sometimes a smaller allocation may hide behind a larger one, so a synthetic allocation failure is going to trigger random codepaths that don't make much sense.
[3.14] gh-151112: Fix crash in `compiler_mod()` when entering the cur…
[3.15] gh-151112: Fix crash in `compiler_mod()` when entering the cur…
pythongh-151112: Fix double free in `assemble_init` when out of memory (
pythongh-151112: Move an `assert` that may fail in `cfg_builder_check` (
pythongh-151112: Fix crash in `compiler_mod()` when entering the curr…