gh-135607: remove null checking of weakref list in dealloc of extension modules and objects (#135614)

Co-authored-by: Kumar Aditya <kumaraditya@python.org>
Co-authored-by: Victor Stinner <vstinner@python.org>
This commit is contained in:
Xuanteng Huang 2025-06-30 19:14:31 +08:00 committed by GitHub
parent 0533c1faf2
commit b1056c2a44
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
32 changed files with 77 additions and 83 deletions

View file

@ -29,6 +29,12 @@ extern "C" {
PyMutex_LockFlags(wr->weakrefs_lock, _Py_LOCK_DONT_DETACH)
#define UNLOCK_WEAKREFS_FOR_WR(wr) PyMutex_Unlock(wr->weakrefs_lock)
#define FT_CLEAR_WEAKREFS(obj, weakref_list) \
do { \
assert(Py_REFCNT(obj) == 0); \
PyObject_ClearWeakRefs(obj); \
} while (0)
#else
#define LOCK_WEAKREFS(obj)
@ -37,6 +43,14 @@ extern "C" {
#define LOCK_WEAKREFS_FOR_WR(wr)
#define UNLOCK_WEAKREFS_FOR_WR(wr)
#define FT_CLEAR_WEAKREFS(obj, weakref_list) \
do { \
assert(Py_REFCNT(obj) == 0); \
if (weakref_list != NULL) { \
PyObject_ClearWeakRefs(obj); \
} \
} while (0)
#endif
static inline int _is_dead(PyObject *obj)

View file

@ -0,0 +1,2 @@
Fix potential :mod:`weakref` races in an object's destructor on the :term:`free threaded <free
threading>` build.

View file

@ -5,6 +5,7 @@
#include "pycore_moduleobject.h" // _PyModule_GetState()
#include "pycore_pyatomic_ft_wrappers.h"
#include "pycore_typeobject.h" // _PyType_GetModuleState()
#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
#include <stddef.h>
@ -1532,9 +1533,7 @@ deque_dealloc(PyObject *self)
Py_ssize_t i;
PyObject_GC_UnTrack(deque);
if (deque->weakreflist != NULL) {
PyObject_ClearWeakRefs(self);
}
FT_CLEAR_WEAKREFS(self, deque->weakreflist);
if (deque->leftblock != NULL) {
(void)deque_clear(self);
assert(deque->leftblock != NULL);

View file

@ -17,6 +17,7 @@
#include "Python.h"
#include "pycore_pyhash.h" // _Py_HashSecret
#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
#include <stddef.h> // offsetof()
#include "expat.h"
@ -690,8 +691,7 @@ element_dealloc(PyObject *op)
/* bpo-31095: UnTrack is needed before calling any callbacks */
PyObject_GC_UnTrack(self);
if (self->weakreflist != NULL)
PyObject_ClearWeakRefs(op);
FT_CLEAR_WEAKREFS(op, self->weakreflist);
/* element_gc_clear clears all references and deallocates extra
*/

View file

@ -7,6 +7,7 @@
#include "pycore_pyatomic_ft_wrappers.h"
#include "pycore_pystate.h" // _PyThreadState_GET()
#include "pycore_tuple.h" // _PyTuple_ITEMS()
#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
#include "clinic/_functoolsmodule.c.h"
@ -351,9 +352,7 @@ partial_dealloc(PyObject *self)
PyTypeObject *tp = Py_TYPE(self);
/* bpo-31095: UnTrack is needed before calling any callbacks */
PyObject_GC_UnTrack(self);
if (partialobject_CAST(self)->weakreflist != NULL) {
PyObject_ClearWeakRefs(self);
}
FT_CLEAR_WEAKREFS(self, partialobject_CAST(self)->weakreflist);
(void)partial_clear(self);
tp->tp_free(self);
Py_DECREF(tp);
@ -1621,9 +1620,7 @@ lru_cache_dealloc(PyObject *op)
PyTypeObject *tp = Py_TYPE(obj);
/* bpo-31095: UnTrack is needed before calling any callbacks */
PyObject_GC_UnTrack(obj);
if (obj->weakreflist != NULL) {
PyObject_ClearWeakRefs(op);
}
FT_CLEAR_WEAKREFS(op, obj->weakreflist);
(void)lru_cache_tp_clear(op);
tp->tp_free(obj);

View file

@ -13,6 +13,7 @@
#include "pycore_object.h" // _PyObject_GC_UNTRACK()
#include "pycore_pyerrors.h" // _Py_FatalErrorFormat()
#include "pycore_pylifecycle.h" // _Py_IsInterpreterFinalizing()
#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
#include "_iomodule.h"
@ -421,8 +422,7 @@ buffered_dealloc(PyObject *op)
return;
_PyObject_GC_UNTRACK(self);
self->ok = 0;
if (self->weakreflist != NULL)
PyObject_ClearWeakRefs(op);
FT_CLEAR_WEAKREFS(op, self->weakreflist);
if (self->buffer) {
PyMem_Free(self->buffer);
self->buffer = NULL;
@ -2312,8 +2312,7 @@ bufferedrwpair_dealloc(PyObject *op)
rwpair *self = rwpair_CAST(op);
PyTypeObject *tp = Py_TYPE(self);
_PyObject_GC_UNTRACK(self);
if (self->weakreflist != NULL)
PyObject_ClearWeakRefs(op);
FT_CLEAR_WEAKREFS(op, self->weakreflist);
(void)bufferedrwpair_clear(op);
tp->tp_free(self);
Py_DECREF(tp);

View file

@ -3,6 +3,7 @@
#include "pycore_object.h"
#include "pycore_pyatomic_ft_wrappers.h"
#include "pycore_sysmodule.h" // _PySys_GetSizeOf()
#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
#include <stddef.h> // offsetof()
#include "_iomodule.h"
@ -979,8 +980,7 @@ bytesio_dealloc(PyObject *op)
}
Py_CLEAR(self->buf);
Py_CLEAR(self->dict);
if (self->weakreflist != NULL)
PyObject_ClearWeakRefs(op);
FT_CLEAR_WEAKREFS(op, self->weakreflist);
tp->tp_free(self);
Py_DECREF(tp);
}

View file

@ -4,6 +4,7 @@
#include "pycore_fileutils.h" // _Py_BEGIN_SUPPRESS_IPH
#include "pycore_object.h" // _PyObject_GC_UNTRACK()
#include "pycore_pyerrors.h" // _PyErr_ChainExceptions1()
#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
#include <stdbool.h> // bool
#ifdef HAVE_UNISTD_H
@ -570,9 +571,7 @@ fileio_dealloc(PyObject *op)
PyMem_Free(self->stat_atopen);
self->stat_atopen = NULL;
}
if (self->weakreflist != NULL) {
PyObject_ClearWeakRefs(op);
}
FT_CLEAR_WEAKREFS(op, self->weakreflist);
(void)fileio_clear(op);
PyTypeObject *tp = Py_TYPE(op);

View file

@ -14,6 +14,7 @@
#include "pycore_long.h" // _PyLong_GetOne()
#include "pycore_object.h" // _PyType_HasFeature()
#include "pycore_pyerrors.h" // _PyErr_ChainExceptions1()
#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
#include <stddef.h> // offsetof()
#include "_iomodule.h"
@ -383,8 +384,7 @@ iobase_dealloc(PyObject *op)
}
PyTypeObject *tp = Py_TYPE(self);
_PyObject_GC_UNTRACK(self);
if (self->weakreflist != NULL)
PyObject_ClearWeakRefs(op);
FT_CLEAR_WEAKREFS(op, self->weakreflist);
Py_CLEAR(self->dict);
tp->tp_free(self);
Py_DECREF(tp);

View file

@ -1,6 +1,7 @@
#include "Python.h"
#include <stddef.h> // offsetof()
#include "pycore_object.h"
#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
#include "_iomodule.h"
/* Implementation note: the buffer is always at least one character longer
@ -638,9 +639,7 @@ stringio_dealloc(PyObject *op)
}
PyUnicodeWriter_Discard(self->writer);
(void)stringio_clear(op);
if (self->weakreflist != NULL) {
PyObject_ClearWeakRefs(op);
}
FT_CLEAR_WEAKREFS(op, self->weakreflist);
tp->tp_free(self);
Py_DECREF(tp);
}

View file

@ -16,6 +16,7 @@
#include "pycore_pyerrors.h" // _PyErr_ChainExceptions1()
#include "pycore_pystate.h" // _PyInterpreterState_GET()
#include "pycore_unicodeobject.h" // _PyUnicode_AsASCIIString()
#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
#include "_iomodule.h"
@ -1469,8 +1470,7 @@ textiowrapper_dealloc(PyObject *op)
return;
self->ok = 0;
_PyObject_GC_UNTRACK(self);
if (self->weakreflist != NULL)
PyObject_ClearWeakRefs(op);
FT_CLEAR_WEAKREFS(op, self->weakreflist);
(void)textiowrapper_clear(op);
tp->tp_free(self);
Py_DECREF(tp);

View file

@ -10,6 +10,7 @@
#include "pycore_fileutils.h" // _Py_BEGIN_SUPPRESS_IPH
#include "pycore_object.h" // _PyObject_GC_UNTRACK()
#include "pycore_pyerrors.h" // _PyErr_ChainExceptions1()
#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
#ifdef HAVE_WINDOWS_CONSOLE_IO
@ -518,8 +519,7 @@ winconsoleio_dealloc(PyObject *op)
if (_PyIOBase_finalize(op) < 0)
return;
_PyObject_GC_UNTRACK(self);
if (self->weakreflist != NULL)
PyObject_ClearWeakRefs(op);
FT_CLEAR_WEAKREFS(op, self->weakreflist);
Py_CLEAR(self->dict);
tp->tp_free(self);
Py_DECREF(tp);

View file

@ -7,6 +7,7 @@
#include "pycore_moduleobject.h" // _PyModule_GetState()
#include "pycore_parking_lot.h"
#include "pycore_time.h" // _PyTime_FromSecondsObject()
#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
#include <stdbool.h>
#include <stddef.h> // offsetof()
@ -221,9 +222,7 @@ simplequeue_dealloc(PyObject *op)
PyObject_GC_UnTrack(self);
(void)simplequeue_clear(op);
if (self->weakreflist != NULL) {
PyObject_ClearWeakRefs(op);
}
FT_CLEAR_WEAKREFS(op, self->weakreflist);
tp->tp_free(self);
Py_DECREF(tp);
}

View file

@ -4,6 +4,7 @@
#include "blob.h"
#include "util.h"
#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
#define clinic_state() (pysqlite_get_state_by_type(Py_TYPE(self)))
#include "clinic/blob.c.h"
@ -56,9 +57,7 @@ blob_dealloc(PyObject *op)
close_blob(self);
if (self->in_weakreflist != NULL) {
PyObject_ClearWeakRefs(op);
}
FT_CLEAR_WEAKREFS(op, self->in_weakreflist);
(void)tp->tp_clear(op);
tp->tp_free(self);
Py_DECREF(tp);

View file

@ -31,6 +31,7 @@
#include "util.h"
#include "pycore_pyerrors.h" // _PyErr_FormatFromCause()
#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
typedef enum {
TYPE_LONG,
@ -185,9 +186,7 @@ cursor_dealloc(PyObject *op)
pysqlite_Cursor *self = _pysqlite_Cursor_CAST(op);
PyTypeObject *tp = Py_TYPE(self);
PyObject_GC_UnTrack(self);
if (self->in_weakreflist != NULL) {
PyObject_ClearWeakRefs(op);
}
FT_CLEAR_WEAKREFS(op, self->in_weakreflist);
(void)tp->tp_clear(op);
tp->tp_free(self);
Py_DECREF(tp);

View file

@ -44,6 +44,7 @@ static const char copyright[] =
#include "pycore_long.h" // _PyLong_GetZero()
#include "pycore_moduleobject.h" // _PyModule_GetState()
#include "pycore_unicodeobject.h" // _PyUnicode_Copy
#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
#include "sre.h" // SRE_CODE
@ -736,10 +737,7 @@ pattern_dealloc(PyObject *self)
{
PyTypeObject *tp = Py_TYPE(self);
PyObject_GC_UnTrack(self);
PatternObject *obj = _PatternObject_CAST(self);
if (obj->weakreflist != NULL) {
PyObject_ClearWeakRefs(self);
}
FT_CLEAR_WEAKREFS(self, _PatternObject_CAST(self)->weakreflist);
(void)pattern_clear(self);
tp->tp_free(self);
Py_DECREF(tp);

View file

@ -11,6 +11,7 @@
#include "pycore_bytesobject.h" // _PyBytesWriter
#include "pycore_long.h" // _PyLong_AsByteArray()
#include "pycore_moduleobject.h" // _PyModule_GetState()
#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
#include <stddef.h> // offsetof()
@ -1794,9 +1795,7 @@ s_dealloc(PyObject *op)
PyStructObject *s = PyStructObject_CAST(op);
PyTypeObject *tp = Py_TYPE(s);
PyObject_GC_UnTrack(s);
if (s->weakreflist != NULL) {
PyObject_ClearWeakRefs(op);
}
FT_CLEAR_WEAKREFS(op, s->weakreflist);
if (s->s_codes != NULL) {
PyMem_Free(s->s_codes);
}

View file

@ -1365,9 +1365,7 @@ static void
localdummy_dealloc(PyObject *op)
{
localdummyobject *self = localdummyobject_CAST(op);
if (self->weakreflist != NULL) {
PyObject_ClearWeakRefs(op);
}
FT_CLEAR_WEAKREFS(op, self->weakreflist);
PyTypeObject *tp = Py_TYPE(self);
tp->tp_free(self);
Py_DECREF(tp);

View file

@ -7,6 +7,7 @@
#include "pycore_long.h" // _PyLong_GetOne()
#include "pycore_pyerrors.h" // _PyErr_ChainExceptions1()
#include "pycore_typeobject.h" // _PyType_GetModuleState()
#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
#include "datetime.h" // PyDateTime_TZInfo
@ -375,9 +376,7 @@ zoneinfo_dealloc(PyObject *obj_self)
PyTypeObject *tp = Py_TYPE(self);
PyObject_GC_UnTrack(self);
if (self->weakreflist != NULL) {
PyObject_ClearWeakRefs(obj_self);
}
FT_CLEAR_WEAKREFS(obj_self, self->weakreflist);
if (self->trans_list_utc != NULL) {
PyMem_Free(self->trans_list_utc);

View file

@ -13,6 +13,7 @@
#include "pycore_ceval.h" // _PyEval_GetBuiltin()
#include "pycore_modsupport.h" // _PyArg_NoKeywords()
#include "pycore_moduleobject.h" // _PyModule_GetState()
#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
#include <stddef.h> // offsetof()
#include <stdbool.h>
@ -728,9 +729,7 @@ array_dealloc(PyObject *op)
PyObject_GC_UnTrack(op);
arrayobject *self = arrayobject_CAST(op);
if (self->weakreflist != NULL) {
PyObject_ClearWeakRefs(op);
}
FT_CLEAR_WEAKREFS(op, self->weakreflist);
if (self->ob_item != NULL) {
PyMem_Free(self->ob_item);
}

View file

@ -25,6 +25,7 @@
#include <Python.h>
#include "pycore_bytesobject.h" // _PyBytes_Find()
#include "pycore_fileutils.h" // _Py_stat_struct
#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
#include <stddef.h> // offsetof()
#ifndef MS_WINDOWS
@ -163,8 +164,7 @@ mmap_object_dealloc(PyObject *op)
Py_END_ALLOW_THREADS
#endif /* UNIX */
if (m_obj->weakreflist != NULL)
PyObject_ClearWeakRefs(op);
FT_CLEAR_WEAKREFS(op, m_obj->weakreflist);
tp->tp_free(m_obj);
Py_DECREF(tp);

View file

@ -7,6 +7,7 @@
#include "pycore_object.h"
#include "pycore_pyerrors.h"
#include "pycore_pystate.h" // _PyThreadState_GET()
#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
#include "clinic/classobject.c.h"
@ -245,8 +246,7 @@ method_dealloc(PyObject *self)
{
PyMethodObject *im = _PyMethodObject_CAST(self);
_PyObject_GC_UNTRACK(im);
if (im->im_weakreflist != NULL)
PyObject_ClearWeakRefs((PyObject *)im);
FT_CLEAR_WEAKREFS(self, im->im_weakreflist);
Py_DECREF(im->im_func);
Py_XDECREF(im->im_self);
assert(Py_IS_TYPE(self, &PyMethod_Type));

View file

@ -17,6 +17,7 @@
#include "pycore_tuple.h" // _PyTuple_ITEMS()
#include "pycore_unicodeobject.h" // _PyUnicode_InternImmortal()
#include "pycore_uniqueid.h" // _PyObject_AssignUniqueId()
#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
#include "clinic/codeobject.c.h"
#include <stdbool.h>
@ -2436,9 +2437,7 @@ code_dealloc(PyObject *self)
Py_XDECREF(co->_co_cached->_co_varnames);
PyMem_Free(co->_co_cached);
}
if (co->co_weakreflist != NULL) {
PyObject_ClearWeakRefs(self);
}
FT_CLEAR_WEAKREFS(self, co->co_weakreflist);
free_monitoring_data(co->_co_monitoring);
#ifdef Py_GIL_DISABLED
// The first element always points to the mutable bytecode at the end of

View file

@ -10,6 +10,7 @@
#include "pycore_pyerrors.h" // _PyErr_Occurred()
#include "pycore_setobject.h" // _PySet_NextEntry()
#include "pycore_stats.h"
#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
static const char *
@ -1148,9 +1149,7 @@ func_dealloc(PyObject *self)
return;
}
_PyObject_GC_UNTRACK(op);
if (op->func_weakreflist != NULL) {
PyObject_ClearWeakRefs((PyObject *) op);
}
FT_CLEAR_WEAKREFS(self, op->func_weakreflist);
(void)func_clear((PyObject*)op);
// These aren't cleared by func_clear().
_Py_DECREF_CODE((PyCodeObject *)op->func_code);

View file

@ -7,6 +7,7 @@
#include "pycore_typevarobject.h" // _Py_typing_type_repr
#include "pycore_unicodeobject.h" // _PyUnicode_EqualToASCIIString()
#include "pycore_unionobject.h" // _Py_union_type_or, _PyGenericAlias_Check
#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
#include <stdbool.h>
@ -33,9 +34,7 @@ ga_dealloc(PyObject *self)
gaobject *alias = (gaobject *)self;
_PyObject_GC_UNTRACK(self);
if (alias->weakreflist != NULL) {
PyObject_ClearWeakRefs((PyObject *)alias);
}
FT_CLEAR_WEAKREFS(self, alias->weakreflist);
Py_XDECREF(alias->origin);
Py_XDECREF(alias->args);
Py_XDECREF(alias->parameters);

View file

@ -17,6 +17,7 @@
#include "pycore_pyerrors.h" // _PyErr_ClearExcState()
#include "pycore_pystate.h" // _PyThreadState_GET()
#include "pycore_warnings.h" // _PyErr_WarnUnawaitedCoroutine()
#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
#include "opcode_ids.h" // RESUME, etc
@ -161,8 +162,7 @@ gen_dealloc(PyObject *self)
_PyObject_GC_UNTRACK(gen);
if (gen->gi_weakreflist != NULL)
PyObject_ClearWeakRefs(self);
FT_CLEAR_WEAKREFS(self, gen->gi_weakreflist);
_PyObject_GC_TRACK(self);

View file

@ -8,6 +8,7 @@
#include "pycore_object.h"
#include "pycore_pyerrors.h"
#include "pycore_pystate.h" // _PyThreadState_GET()
#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
/* undefine macro trampoline to PyCFunction_NewEx */
@ -167,9 +168,7 @@ meth_dealloc(PyObject *self)
{
PyCFunctionObject *m = _PyCFunctionObject_CAST(self);
PyObject_GC_UnTrack(m);
if (m->m_weakreflist != NULL) {
PyObject_ClearWeakRefs((PyObject*) m);
}
FT_CLEAR_WEAKREFS(self, m->m_weakreflist);
// We need to access ml_flags here rather than later.
// `m->m_ml` might have the same lifetime
// as `m_self` when it's dynamically allocated.

View file

@ -13,6 +13,7 @@
#include "pycore_pyerrors.h" // _PyErr_FormatFromCause()
#include "pycore_pystate.h" // _PyInterpreterState_GET()
#include "pycore_unicodeobject.h" // _PyUnicode_EqualToASCIIString()
#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
#include "osdefs.h" // MAXPATHLEN
@ -826,8 +827,7 @@ module_dealloc(PyObject *self)
if (verbose && m->md_name) {
PySys_FormatStderr("# destroy %U\n", m->md_name);
}
if (m->md_weaklist != NULL)
PyObject_ClearWeakRefs((PyObject *) m);
FT_CLEAR_WEAKREFS(self, m->md_weaklist);
/* bpo-39824: Don't call m_free() if m_size > 0 and md_state=NULL */
if (m->md_def && m->md_def->m_free

View file

@ -473,6 +473,7 @@ later:
#include "pycore_pyerrors.h" // _PyErr_ChainExceptions1()
#include "pycore_tuple.h" // _PyTuple_Recycle()
#include <stddef.h> // offsetof()
#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
#include "clinic/odictobject.c.h"
@ -1391,8 +1392,7 @@ odict_dealloc(PyObject *op)
PyObject_GC_UnTrack(self);
Py_XDECREF(self->od_inst_dict);
if (self->od_weakreflist != NULL)
PyObject_ClearWeakRefs((PyObject *)self);
FT_CLEAR_WEAKREFS(op, self->od_weakreflist);
_odict_clear_nodes(self);
PyDict_Type.tp_dealloc((PyObject *)self);

View file

@ -1,6 +1,7 @@
/* PickleBuffer object implementation */
#include "Python.h"
#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
#include <stddef.h>
typedef struct {
@ -111,8 +112,7 @@ picklebuf_dealloc(PyObject *op)
{
PyPickleBufferObject *self = (PyPickleBufferObject*)op;
PyObject_GC_UnTrack(self);
if (self->weakreflist != NULL)
PyObject_ClearWeakRefs((PyObject *) self);
FT_CLEAR_WEAKREFS(op, self->weakreflist);
PyBuffer_Release(&self->view);
Py_TYPE(self)->tp_free((PyObject *) self);
}

View file

@ -40,6 +40,7 @@
#include "pycore_pyatomic_ft_wrappers.h" // FT_ATOMIC_LOAD_SSIZE_RELAXED()
#include "pycore_pyerrors.h" // _PyErr_SetKeyError()
#include "pycore_setobject.h" // _PySet_NextEntry() definition
#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
#include "stringlib/eq.h" // unicode_eq()
#include <stddef.h> // offsetof()
@ -536,8 +537,7 @@ set_dealloc(PyObject *self)
/* bpo-31095: UnTrack is needed before calling any callbacks */
PyObject_GC_UnTrack(so);
if (so->weakreflist != NULL)
PyObject_ClearWeakRefs((PyObject *) so);
FT_CLEAR_WEAKREFS(self, so->weakreflist);
for (entry = so->table; used > 0; entry++) {
if (entry->key && entry->key != dummy) {

View file

@ -4,6 +4,7 @@
#include "pycore_typevarobject.h" // _PyTypeAlias_Type, _Py_typing_type_repr
#include "pycore_unicodeobject.h" // _PyUnicode_EqualToASCIIString
#include "pycore_unionobject.h"
#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
typedef struct {
@ -21,9 +22,7 @@ unionobject_dealloc(PyObject *self)
unionobject *alias = (unionobject *)self;
_PyObject_GC_UNTRACK(self);
if (alias->weakreflist != NULL) {
PyObject_ClearWeakRefs((PyObject *)alias);
}
FT_CLEAR_WEAKREFS(self, alias->weakreflist);
Py_XDECREF(alias->args);
Py_XDECREF(alias->hashable_args);