mirror of
https://github.com/pybind/pybind11.git
synced 2026-05-19 12:30:31 +00:00
Fix memory leak: clear managed dict in pybind11_object_dealloc on Python 3.13+ (#5999)
* fix: clear managed dict in pybind11_object_dealloc on Python 3.13+ On Python 3.14, PyObject_GC_Del (tp_free) no longer implicitly clears the managed dict of objects with Py_TPFLAGS_MANAGED_DICT. Without an explicit PyObject_ClearManagedDict() call before tp_free(), objects stored in the __dict__ of py::dynamic_attr() instances have their refcounts permanently abandoned, causing memory leaks — capsule destructors for numpy arrays (and other objects) never run. Adds a regression test: stores a py::capsule in the __dict__ of a DynamicClass instance and asserts the capsule destructor is called when the instance is deleted. * [tests]: mark test_dynamic_attr_dealloc_frees_dict_contents to be strict=False xfail on PYPY * [docs]: clarify Python version comments in pybind11_object_dealloc Distinguish between when the API is available (3.13+, where PyObject_ClearManagedDict was introduced) and when the leak actually manifests (3.14+, where tp_free stopped implicitly clearing the managed dict). --------- Co-authored-by: Yury Matveev <yury.matveev@desy.de>
This commit is contained in:
@@ -503,6 +503,17 @@ extern "C" inline void pybind11_object_dealloc(PyObject *self) {
|
||||
PyObject_GC_UnTrack(self);
|
||||
}
|
||||
|
||||
#if PY_VERSION_HEX >= 0x030D0000
|
||||
// PyObject_ClearManagedDict() is available from Python 3.13+. It must be
|
||||
// called before tp_free() because on Python 3.14+ tp_free no longer
|
||||
// implicitly clears the managed dict, which would abandon the refcounts of
|
||||
// objects stored in __dict__ of py::dynamic_attr() types, causing permanent
|
||||
// memory leaks.
|
||||
if (PyType_HasFeature(type, Py_TPFLAGS_MANAGED_DICT)) {
|
||||
PyObject_ClearManagedDict(self);
|
||||
}
|
||||
#endif
|
||||
|
||||
clear_instance(self);
|
||||
|
||||
type->tp_free(self);
|
||||
|
||||
Reference in New Issue
Block a user