diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-10-20-20-38-38.gh-issue-159101.vFwrZY.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-10-20-20-38-38.gh-issue-159101.vFwrZY.rst new file mode 100644 index 000000000000000..33beb8d571d7eca --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-10-20-20-38-38.gh-issue-159101.vFwrZY.rst @@ -0,0 +1,2 @@ +Fix use-after-free when :meth:`~object.__del__` changes the base class. Patch by +Sergey Miryanov. diff --git a/Objects/object.c b/Objects/object.c index f8206e5d3eca329..f1f10ea58b89ef5 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -583,13 +583,13 @@ PyObject_CallFinalizer(PyObject *self) if (tp->tp_finalize == NULL) return; /* tp_finalize should only be called once. */ - if (_PyType_IS_GC(tp) && _PyGC_FINALIZED(self)) - return; - - tp->tp_finalize(self); if (_PyType_IS_GC(tp)) { + if (_PyGC_FINALIZED(self)) + return; + _PyGC_SET_FINALIZED(self); } + tp->tp_finalize(self); } int diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 87da481f0a5f60c..ad79ed85993545b 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -2771,6 +2771,10 @@ subtype_dealloc(PyObject *self) } _PyObject_GC_UNTRACK(self); } + + /* Extract the type again; tp_finalize may have changed it */ + type = Py_TYPE(self); + /* If we added a weaklist, we clear it. Do this *before* calling tp_del, clearing slots, or clearing the instance dict.