Skip to content

Commit 503a3a7

Browse files
[3.11] gh-95324: Emit a warning if an object doesn't call PyObject_GC_UnTrack during deallocation in debug mode (GH-95325) (#95336)
Co-authored-by: Pablo Galindo Salgado <[email protected]>
1 parent 25086f1 commit 503a3a7

File tree

8 files changed

+18
-2
lines changed

8 files changed

+18
-2
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Emit a warning in debug mode if an object does not call
2+
:c:func:`PyObject_GC_UnTrack` before deallocation. Patch by Pablo Galindo.

Modules/_abc.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ abc_data_clear(_abc_data *self)
6363
static void
6464
abc_data_dealloc(_abc_data *self)
6565
{
66+
PyObject_GC_UnTrack(self);
6667
PyTypeObject *tp = Py_TYPE(self);
6768
(void)abc_data_clear(self);
6869
tp->tp_free(self);

Modules/_ctypes/cfield.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,7 @@ PyCField_clear(CFieldObject *self)
279279
static void
280280
PyCField_dealloc(PyObject *self)
281281
{
282+
PyObject_GC_UnTrack(self);
282283
PyCField_clear((CFieldObject *)self);
283284
Py_TYPE(self)->tp_free((PyObject *)self);
284285
}

Modules/_threadmodule.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ lock_traverse(lockobject *self, visitproc visit, void *arg)
5757
static void
5858
lock_dealloc(lockobject *self)
5959
{
60+
PyObject_GC_UnTrack(self);
6061
if (self->in_weakreflist != NULL) {
6162
PyObject_ClearWeakRefs((PyObject *) self);
6263
}
@@ -333,6 +334,7 @@ rlock_traverse(rlockobject *self, visitproc visit, void *arg)
333334
static void
334335
rlock_dealloc(rlockobject *self)
335336
{
337+
PyObject_GC_UnTrack(self);
336338
if (self->in_weakreflist != NULL)
337339
PyObject_ClearWeakRefs((PyObject *) self);
338340
/* self->rlock_lock can be NULL if PyThread_allocate_lock() failed

Modules/gcmodule.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2347,6 +2347,13 @@ PyObject_GC_Del(void *op)
23472347
size_t presize = _PyType_PreHeaderSize(((PyObject *)op)->ob_type);
23482348
PyGC_Head *g = AS_GC(op);
23492349
if (_PyObject_GC_IS_TRACKED(op)) {
2350+
#ifdef Py_DEBUG
2351+
if (PyErr_WarnExplicitFormat(PyExc_ResourceWarning, "gc", 0,
2352+
"gc", NULL, "Object of type %s is not untracked before destruction",
2353+
((PyObject*)op)->ob_type->tp_name)) {
2354+
PyErr_WriteUnraisable(NULL);
2355+
}
2356+
#endif
23502357
gc_list_remove(g);
23512358
}
23522359
GCState *gcstate = get_gc_state();

Modules/xxlimited.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ Xxo_finalize(PyObject *self_obj)
138138
static void
139139
Xxo_dealloc(PyObject *self)
140140
{
141+
PyObject_GC_UnTrack(self);
141142
Xxo_finalize(self);
142143
PyTypeObject *tp = Py_TYPE(self);
143144
freefunc free = PyType_GetSlot(tp, Py_tp_free);

Objects/exceptions.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3222,6 +3222,7 @@ MemoryError_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
32223222
self = state->memerrors_freelist;
32233223
self->args = PyTuple_New(0);
32243224
/* This shouldn't happen since the empty tuple is persistent */
3225+
32253226
if (self->args == NULL) {
32263227
return NULL;
32273228
}
@@ -3237,6 +3238,8 @@ MemoryError_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
32373238
static void
32383239
MemoryError_dealloc(PyBaseExceptionObject *self)
32393240
{
3241+
_PyObject_GC_UNTRACK(self);
3242+
32403243
BaseException_clear(self);
32413244

32423245
/* If this is a subclass of MemoryError, we don't need to
@@ -3246,8 +3249,6 @@ MemoryError_dealloc(PyBaseExceptionObject *self)
32463249
return;
32473250
}
32483251

3249-
_PyObject_GC_UNTRACK(self);
3250-
32513252
struct _Py_exc_state *state = get_exc_state();
32523253
if (state->memerrors_numfree >= MEMERRORS_SAVE) {
32533254
Py_TYPE(self)->tp_free((PyObject *)self);

Objects/weakrefobject.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -558,6 +558,7 @@ proxy_bool(PyWeakReference *proxy)
558558
static void
559559
proxy_dealloc(PyWeakReference *self)
560560
{
561+
PyObject_GC_UnTrack(self);
561562
if (self->wr_callback != NULL)
562563
PyObject_GC_UnTrack((PyObject *)self);
563564
clear_weakref(self);

0 commit comments

Comments
 (0)