Skip to content

Double free corruption when allocation failures occur in assemble_init #151112

@stestagg

Description

@stestagg

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_MakeCodeObject is 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_init cleans up by decreffing all members, BUT the assembler fields are left populated with the old pointers, and the caller has the assembler reference.
  • assemble_emit sees the error code and returns to _PyAssemble_MakeCodeObject
  • The result != SUCCESS, so makecode isn't called, but assemble_free IS called, causing a double free of at least a->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

Metadata

Metadata

Labels

interpreter-core(Objects, Python, Grammar, and Parser dirs)type-crashA hard crash of the interpreter, possibly with a core dump
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions