Skip to content

PyObject_ClearManagedDict() loses the propagating exception on MemoryError #159283

Description

@christianaurichzm

Crash report

When an object whose __dict__ has been materialized, but still points at the object's inline values, is freed while an exception is propagating, and the allocation in detach_dict_from_object() fails, the propagating exception is lost.

PyObject_ClearManagedDict() in Objects/dictobject.c calls detach_dict_from_object(), which calls PyErr_NoMemory() when copy_values() fails. That replaces the exception in flight, and the PyErr_FormatUnraisable() call that follows clears it. A debug build aborts, and a release build carries on with no exception set, which ends in SystemError.

import _testcapi

class A:
    pass

def make():
    a = A()
    a.x = 1
    a.__dict__  # materialize a dict that still points at the inline values
    return a

def f(holder, start):
    _testcapi.set_nomemory(start, start + 1)
    # The A instance is only referenced from the evaluation stack,
    # so it is freed while ZeroDivisionError propagates.
    [holder.pop(), 1/0]

for start in range(20):
    try:
        f([make()], start)
    except (ZeroDivisionError, MemoryError):
        pass
    except BaseException as exc:
        _testcapi.remove_mem_hooks()
        print(start, repr(exc))
    finally:
        _testcapi.remove_mem_hooks()

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

Fatal Python error: py_dealloc: Deallocator of type 'A' cleared the current exception

In a release build of the same commit, one iteration gets SystemError instead of ZeroDivisionError:

Exception ignored while clearing an object managed dict:
Traceback (most recent call last):
  File "repro.py", line 16, in f
    [holder.pop(), 1/0]
                   ~^~
MemoryError
4 SystemError('error return without exception set')

The same code is in 3.14 and 3.15. This is not the same problem as gh-152254, which is about the ownership assertion in the fallback that clears the dict.

Saving the current exception before detaching the dict and restoring it afterwards fixes both builds. I have a patch.

CPython versions tested on:

CPython main branch

Operating systems tested on:

Linux

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

Python 3.16.0a0 (remotes/upstream/main:64018ac45cb, Oct 12 2026, 23:09:28) [GCC 13.3.0]

Linked PRs

Metadata

Metadata

Assignees

No one assigned

    Labels

    interpreter-core(Objects, Python, Grammar, and Parser dirs)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