Skip to content

Copying an empty dict segfaults on MemoryError in debug builds #159285

Closed

Description

@christianaurichzm

Crash report

In a debug build, copying an empty dict segfaults when the allocation of the new dict fails. copy_lock_held_untracked() in Objects/dictobject.c handles the empty case with:

d = dict_new_untracked(&PyDict_Type);
assert(!_PyObject_GC_IS_TRACKED(d));
return d;

The assertion dereferences d, which is NULL when dict_new_untracked() fails.

from test.support import inject_memory_error_cm

with inject_memory_error_cm():
    {}.copy()

On main (64018ac) built with --with-pydebug:

Fatal Python error: Segmentation fault
#0  copy_lock_held_untracked (o=0x7ffff73bd970, as_frozendict=as_frozendict@entry=0) at ./Include/internal/pycore_gc.h:78
#1  0x00005555556e2b0d in PyDict_Copy (o=<optimized out>) at Objects/dictobject.c:4605
#2  0x00005555556e2b53 in dict_copy_impl (self=<optimized out>) at Objects/dictobject.c:4455

_PyDict_CopyAsDict() goes through the same code, and type() uses it for the class namespace, so type("C", (), {}) crashes the same way. A release build raises MemoryError as expected. The assertion came with gh-151722 and is also in 3.15.

Changing it to assert(d == NULL || !_PyObject_GC_IS_TRACKED(d)) fixes it.

CPython versions tested on:

CPython main branch

Operating systems tested on:

Linux

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

No response

Linked PRs

Activity

  1. added a commit that references this issue on Oct 13, 2026
  2. added a commit that references this issue on Oct 13, 2026
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

    type-crashA hard crash of the interpreter, possibly with a core dump

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions