diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-07-27-14-05-07.gh-issue-95324.28Q5u7.rst b/Misc/NEWS.d/next/Core and Builtins/2022-07-27-14-05-07.gh-issue-95324.28Q5u7.rst new file mode 100644 index 00000000000000..250385270e9487 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-07-27-14-05-07.gh-issue-95324.28Q5u7.rst @@ -0,0 +1,2 @@ +Emit a warning in debug mode if an object does not call +:c:func:`PyObject_GC_UnTrack` before deallocation. Patch by Pablo Galindo. diff --git a/Modules/_abc.c b/Modules/_abc.c index 641d6198d1fec4..b22daa81e3ae19 100644 --- a/Modules/_abc.c +++ b/Modules/_abc.c @@ -63,6 +63,7 @@ abc_data_clear(_abc_data *self) static void abc_data_dealloc(_abc_data *self) { + PyObject_GC_UnTrack(self); PyTypeObject *tp = Py_TYPE(self); (void)abc_data_clear(self); tp->tp_free(self); diff --git a/Modules/_ctypes/cfield.c b/Modules/_ctypes/cfield.c index c7234fbb18a0fa..13ed8b7eda6555 100644 --- a/Modules/_ctypes/cfield.c +++ b/Modules/_ctypes/cfield.c @@ -279,6 +279,7 @@ PyCField_clear(CFieldObject *self) static void PyCField_dealloc(PyObject *self) { + PyObject_GC_UnTrack(self); PyCField_clear((CFieldObject *)self); Py_TYPE(self)->tp_free((PyObject *)self); } diff --git a/Modules/_threadmodule.c b/Modules/_threadmodule.c index ace0282ea6fce6..4ac90dc8068934 100644 --- a/Modules/_threadmodule.c +++ b/Modules/_threadmodule.c @@ -57,6 +57,7 @@ lock_traverse(lockobject *self, visitproc visit, void *arg) static void lock_dealloc(lockobject *self) { + PyObject_GC_UnTrack(self); if (self->in_weakreflist != NULL) { PyObject_ClearWeakRefs((PyObject *) self); } @@ -333,6 +334,7 @@ rlock_traverse(rlockobject *self, visitproc visit, void *arg) static void rlock_dealloc(rlockobject *self) { + PyObject_GC_UnTrack(self); if (self->in_weakreflist != NULL) PyObject_ClearWeakRefs((PyObject *) self); /* self->rlock_lock can be NULL if PyThread_allocate_lock() failed diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 3bda6e4bb8c021..dcd46feff0cc48 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -2347,6 +2347,13 @@ PyObject_GC_Del(void *op) size_t presize = _PyType_PreHeaderSize(((PyObject *)op)->ob_type); PyGC_Head *g = AS_GC(op); if (_PyObject_GC_IS_TRACKED(op)) { +#ifdef Py_DEBUG + if (PyErr_WarnExplicitFormat(PyExc_ResourceWarning, "gc", 0, + "gc", NULL, "Object of type %s is not untracked before destruction", + ((PyObject*)op)->ob_type->tp_name)) { + PyErr_WriteUnraisable(NULL); + } +#endif gc_list_remove(g); } GCState *gcstate = get_gc_state(); diff --git a/Modules/xxlimited.c b/Modules/xxlimited.c index 5177ecd6b515d7..e234504e331945 100644 --- a/Modules/xxlimited.c +++ b/Modules/xxlimited.c @@ -138,6 +138,7 @@ Xxo_finalize(PyObject *self_obj) static void Xxo_dealloc(PyObject *self) { + PyObject_GC_UnTrack(self); Xxo_finalize(self); PyTypeObject *tp = Py_TYPE(self); freefunc free = PyType_GetSlot(tp, Py_tp_free); diff --git a/Objects/exceptions.c b/Objects/exceptions.c index cf8258b0e244bb..c6af82a4668550 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -3222,6 +3222,7 @@ MemoryError_new(PyTypeObject *type, PyObject *args, PyObject *kwds) self = state->memerrors_freelist; self->args = PyTuple_New(0); /* This shouldn't happen since the empty tuple is persistent */ + if (self->args == NULL) { return NULL; } @@ -3237,6 +3238,8 @@ MemoryError_new(PyTypeObject *type, PyObject *args, PyObject *kwds) static void MemoryError_dealloc(PyBaseExceptionObject *self) { + _PyObject_GC_UNTRACK(self); + BaseException_clear(self); /* If this is a subclass of MemoryError, we don't need to @@ -3246,8 +3249,6 @@ MemoryError_dealloc(PyBaseExceptionObject *self) return; } - _PyObject_GC_UNTRACK(self); - struct _Py_exc_state *state = get_exc_state(); if (state->memerrors_numfree >= MEMERRORS_SAVE) { Py_TYPE(self)->tp_free((PyObject *)self); diff --git a/Objects/weakrefobject.c b/Objects/weakrefobject.c index 2b4361e63ca413..d26fc9e8d09d71 100644 --- a/Objects/weakrefobject.c +++ b/Objects/weakrefobject.c @@ -558,6 +558,7 @@ proxy_bool(PyWeakReference *proxy) static void proxy_dealloc(PyWeakReference *self) { + PyObject_GC_UnTrack(self); if (self->wr_callback != NULL) PyObject_GC_UnTrack((PyObject *)self); clear_weakref(self);