Skip to content

gh-159283: Keep the propagating exception in PyObject_ClearManagedDict() - #159284

Open
christianaurichzm wants to merge 1 commit into
python:mainfrom
christianaurichzm:gh-159283-clear-managed-dict-exception
Open

christianaurichzm wants to merge 1 commit into
python:mainfrom
christianaurichzm:gh-159283-clear-managed-dict-exception

Conversation

@christianaurichzm

@christianaurichzm christianaurichzm commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #159283

PyObject_ClearManagedDict() runs when an object is freed. If the object's __dict__ has been materialized but still points at the inline values, it calls detach_dict_from_object(), which calls PyErr_NoMemory() when copy_values() fails. When the object is freed while an exception is propagating, for example a temporary on the evaluation stack during unwinding, that MemoryError replaces the propagating exception, and the PyErr_FormatUnraisable() call that follows clears it. A debug build aborts in py_dealloc(), and a release build goes on with no exception set and ends in SystemError('error return without exception set').

This change saves the current exception with PyErr_GetRaisedException() before detaching the dict and restores it afterwards. The MemoryError is still reported as unraisable, and the original exception keeps propagating. The extra calls are only on the path that detaches a materialized dict.

The same code is in 3.14 and 3.15.

Verification

  • The new test in test_class aborts an unpatched debug build with Fatal Python error: py_dealloc: Deallocator of type 'A' cleared the current exception and passes with the fix. The reproducer from the issue gets SystemError on an unpatched release build and ZeroDivisionError with the fix.
  • test_class, test_dict, test_capi.test_dict, test_descr, test_gc, test_exceptions and test_unittest pass on a debug build, and the new test passes with -R 3:3.

…gedDict()

When an object whose __dict__ still pointed at its inline values was
freed while an exception was propagating, a failed allocation while
detaching the dict called PyErr_NoMemory(), which replaced that
exception, and PyErr_FormatUnraisable() then cleared it. A debug build
aborted in py_dealloc() and a release build went on with no exception
set, which ended in SystemError.

Save the current exception before detaching the dict and restore it
afterwards.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

PyObject_ClearManagedDict() loses the propagating exception on MemoryError

1 participant