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)
#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)
--- /dev/null
+Fix potential :mod:`weakref` races in an object's destructor on the :term:`free threaded <free
+threading>` build.
#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>
Py_ssize_t i;
PyObject_GC_UnTrack(deque);
- if (deque->weakreflist != NULL)
- PyObject_ClearWeakRefs((PyObject *) deque);
+ FT_CLEAR_WEAKREFS((PyObject*)deque, deque->weakreflist);
if (deque->leftblock != NULL) {
deque_clear(deque);
assert(deque->leftblock != NULL);
#include "Python.h"
#include "pycore_import.h" // _PyImport_GetModuleAttrString()
#include "pycore_pyhash.h" // _Py_HashSecret
+#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
#include <stddef.h> // offsetof()
#include "expat.h"
PyObject_GC_UnTrack(self);
Py_TRASHCAN_BEGIN(self, element_dealloc)
- if (self->weakreflist != NULL)
- PyObject_ClearWeakRefs((PyObject *) self);
+ FT_CLEAR_WEAKREFS((PyObject*)self, self->weakreflist);
/* element_gc_clear clears all references and deallocates extra
*/
#include "pycore_object.h" // _PyObject_GC_TRACK
#include "pycore_pystate.h" // _PyThreadState_GET()
#include "pycore_tuple.h" // _PyTuple_ITEMS()
+#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
#include "clinic/_functoolsmodule.c.h"
PyTypeObject *tp = Py_TYPE(pto);
/* bpo-31095: UnTrack is needed before calling any callbacks */
PyObject_GC_UnTrack(pto);
- if (pto->weakreflist != NULL) {
- PyObject_ClearWeakRefs((PyObject *) pto);
- }
+ FT_CLEAR_WEAKREFS((PyObject*)pto, pto->weakreflist);
(void)partial_clear(pto);
tp->tp_free(pto);
Py_DECREF(tp);
PyTypeObject *tp = Py_TYPE(obj);
/* bpo-31095: UnTrack is needed before calling any callbacks */
PyObject_GC_UnTrack(obj);
- if (obj->weakreflist != NULL) {
- PyObject_ClearWeakRefs((PyObject*)obj);
- }
+ FT_CLEAR_WEAKREFS((PyObject*)obj, obj->weakreflist);
(void)lru_cache_tp_clear(obj);
tp->tp_free(obj);
#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"
return;
_PyObject_GC_UNTRACK(self);
self->ok = 0;
- if (self->weakreflist != NULL)
- PyObject_ClearWeakRefs((PyObject *)self);
+ FT_CLEAR_WEAKREFS((PyObject*)self, self->weakreflist);
if (self->buffer) {
PyMem_Free(self->buffer);
self->buffer = NULL;
{
PyTypeObject *tp = Py_TYPE(self);
_PyObject_GC_UNTRACK(self);
- if (self->weakreflist != NULL)
- PyObject_ClearWeakRefs((PyObject *)self);
+ FT_CLEAR_WEAKREFS((PyObject *)self, self->weakreflist);
(void)bufferedrwpair_clear(self);
tp->tp_free((PyObject *) self);
Py_DECREF(tp);
#include "Python.h"
#include "pycore_object.h"
#include "pycore_sysmodule.h" // _PySys_GetSizeOf()
+#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
#include <stddef.h> // offsetof()
#include "_iomodule.h"
}
Py_CLEAR(self->buf);
Py_CLEAR(self->dict);
- if (self->weakreflist != NULL)
- PyObject_ClearWeakRefs((PyObject *) self);
+ FT_CLEAR_WEAKREFS((PyObject *) self, self->weakreflist);
tp->tp_free(self);
Py_DECREF(tp);
}
#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
if (_PyIOBase_finalize((PyObject *) self) < 0)
return;
_PyObject_GC_UNTRACK(self);
- if (self->weakreflist != NULL)
- PyObject_ClearWeakRefs((PyObject *) self);
+ FT_CLEAR_WEAKREFS((PyObject *) self, self->weakreflist);
(void)fileio_clear(self);
tp->tp_free((PyObject *)self);
Py_DECREF(tp);
#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"
}
PyTypeObject *tp = Py_TYPE(self);
_PyObject_GC_UNTRACK(self);
- if (self->weakreflist != NULL)
- PyObject_ClearWeakRefs((PyObject *) self);
+ FT_CLEAR_WEAKREFS((PyObject *) self, self->weakreflist);
Py_CLEAR(self->dict);
tp->tp_free((PyObject *)self);
Py_DECREF(tp);
#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
}
_PyUnicodeWriter_Dealloc(&self->writer);
(void)stringio_clear(self);
- if (self->weakreflist != NULL) {
- PyObject_ClearWeakRefs((PyObject *) self);
- }
+ FT_CLEAR_WEAKREFS((PyObject *) self, self->weakreflist);
tp->tp_free(self);
Py_DECREF(tp);
}
#include "pycore_object.h" // _PyObject_GC_UNTRACK()
#include "pycore_pyerrors.h" // _PyErr_ChainExceptions1()
#include "pycore_pystate.h" // _PyInterpreterState_GET()
+#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
#include "_iomodule.h"
return;
self->ok = 0;
_PyObject_GC_UNTRACK(self);
- if (self->weakreflist != NULL)
- PyObject_ClearWeakRefs((PyObject *)self);
+ FT_CLEAR_WEAKREFS((PyObject *)self, self->weakreflist);
(void)textiowrapper_clear(self);
tp->tp_free((PyObject *)self);
Py_DECREF(tp);
#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
if (_PyIOBase_finalize((PyObject *) self) < 0)
return;
_PyObject_GC_UNTRACK(self);
- if (self->weakreflist != NULL)
- PyObject_ClearWeakRefs((PyObject *) self);
+ FT_CLEAR_WEAKREFS((PyObject *) self, self->weakreflist);
Py_CLEAR(self->dict);
tp->tp_free((PyObject *)self);
Py_DECREF(tp);
#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()
PyObject_GC_UnTrack(self);
(void)simplequeue_clear(self);
- if (self->weakreflist != NULL)
- PyObject_ClearWeakRefs((PyObject *) self);
+ FT_CLEAR_WEAKREFS((PyObject *) self, self->weakreflist);
Py_TYPE(self)->tp_free(self);
Py_DECREF(tp);
}
#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"
close_blob(self);
- if (self->in_weakreflist != NULL) {
- PyObject_ClearWeakRefs((PyObject*)self);
- }
+ FT_CLEAR_WEAKREFS((PyObject*)self, self->in_weakreflist);
tp->tp_clear((PyObject *)self);
tp->tp_free(self);
Py_DECREF(tp);
#include "util.h"
#include "pycore_pyerrors.h" // _PyErr_FormatFromCause()
+#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
typedef enum {
TYPE_LONG,
{
PyTypeObject *tp = Py_TYPE(self);
PyObject_GC_UnTrack(self);
- if (self->in_weakreflist != NULL) {
- PyObject_ClearWeakRefs((PyObject*)self);
- }
+ FT_CLEAR_WEAKREFS((PyObject*)self, self->in_weakreflist);
tp->tp_clear((PyObject *)self);
tp->tp_free(self);
Py_DECREF(tp);
#include "pycore_dict.h" // _PyDict_Next()
#include "pycore_long.h" // _PyLong_GetZero()
#include "pycore_moduleobject.h" // _PyModule_GetState()
+#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
#include "sre.h" // SRE_CODE
PyTypeObject *tp = Py_TYPE(self);
PyObject_GC_UnTrack(self);
- if (self->weakreflist != NULL) {
- PyObject_ClearWeakRefs((PyObject *) self);
- }
+ FT_CLEAR_WEAKREFS((PyObject *) self, self->weakreflist);
(void)pattern_clear(self);
tp->tp_free(self);
Py_DECREF(tp);
#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()
{
PyTypeObject *tp = Py_TYPE(s);
PyObject_GC_UnTrack(s);
- if (s->weakreflist != NULL)
- PyObject_ClearWeakRefs((PyObject *)s);
+ FT_CLEAR_WEAKREFS((PyObject *)s, s->weakreflist);
if (s->s_codes != NULL) {
PyMem_Free(s->s_codes);
}
static void
localdummy_dealloc(localdummyobject *self)
{
- if (self->weakreflist != NULL)
- PyObject_ClearWeakRefs((PyObject *) self);
+ FT_CLEAR_WEAKREFS((PyObject *) self, self->weakreflist);
PyTypeObject *tp = Py_TYPE(self);
tp->tp_free((PyObject*)self);
Py_DECREF(tp);
#include "pycore_critical_section.h" // _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED()
#include "pycore_long.h" // _PyLong_GetOne()
#include "pycore_pyerrors.h" // _PyErr_ChainExceptions1()
+#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
#include "datetime.h" // PyDateTime_TZInfo
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);
#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>
PyTypeObject *tp = Py_TYPE(op);
PyObject_GC_UnTrack(op);
- if (op->weakreflist != NULL)
- PyObject_ClearWeakRefs((PyObject *) op);
+ FT_CLEAR_WEAKREFS((PyObject *) op, op->weakreflist);
if (op->ob_item != NULL)
PyMem_Free(op->ob_item);
tp->tp_free(op);
#include "pycore_abstract.h" // _Py_convert_optional_to_ssize_t()
#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
Py_END_ALLOW_THREADS
#endif /* UNIX */
- if (m_obj->weakreflist != NULL)
- PyObject_ClearWeakRefs((PyObject *) m_obj);
+ FT_CLEAR_WEAKREFS((PyObject *) m_obj, m_obj->weakreflist);
tp->tp_free(m_obj);
Py_DECREF(tp);
#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"
method_dealloc(PyMethodObject *im)
{
_PyObject_GC_UNTRACK(im);
- if (im->im_weakreflist != NULL)
- PyObject_ClearWeakRefs((PyObject *)im);
+ FT_CLEAR_WEAKREFS((PyObject*)im, im->im_weakreflist);
Py_DECREF(im->im_func);
Py_XDECREF(im->im_self);
PyObject_GC_Del(im);
#include "pycore_pystate.h" // _PyInterpreterState_GET()
#include "pycore_setobject.h" // _PySet_NextEntry()
#include "pycore_tuple.h" // _PyTuple_ITEMS()
+#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
#include "clinic/codeobject.c.h"
#include <stdbool.h>
Py_XDECREF(co->_co_cached->_co_varnames);
PyMem_Free(co->_co_cached);
}
- if (co->co_weakreflist != NULL) {
- PyObject_ClearWeakRefs((PyObject*)co);
- }
+ FT_CLEAR_WEAKREFS((PyObject*)co, co->co_weakreflist);
free_monitoring_data(co->_co_monitoring);
PyObject_Free(co);
}
#include "pycore_modsupport.h" // _PyArg_NoKeywords()
#include "pycore_object.h" // _PyObject_GC_UNTRACK()
#include "pycore_pyerrors.h" // _PyErr_Occurred()
+#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
static const char *
return;
}
_PyObject_GC_UNTRACK(op);
- if (op->func_weakreflist != NULL) {
- PyObject_ClearWeakRefs((PyObject *) op);
- }
+ FT_CLEAR_WEAKREFS((PyObject *) op, op->func_weakreflist);
_PyFunction_SetVersion(op, 0);
(void)func_clear(op);
// These aren't cleared by func_clear().
#include "pycore_modsupport.h" // _PyArg_NoKeywords()
#include "pycore_object.h"
#include "pycore_unionobject.h" // _Py_union_type_or, _PyGenericAlias_Check
+#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
#include <stdbool.h>
gaobject *alias = (gaobject *)self;
_PyObject_GC_UNTRACK(self);
- if (alias->weakreflist != NULL) {
- PyObject_ClearWeakRefs((PyObject *)alias);
- }
+ FT_CLEAR_WEAKREFS((PyObject *)alias, alias->weakreflist);
Py_XDECREF(alias->origin);
Py_XDECREF(alias->args);
Py_XDECREF(alias->parameters);
#include "pycore_pyatomic_ft_wrappers.h" // FT_ATOMIC_*
#include "pycore_pyerrors.h" // _PyErr_ClearExcState()
#include "pycore_pystate.h" // _PyThreadState_GET()
+#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
#include "pystats.h"
_PyObject_GC_UNTRACK(gen);
- if (gen->gi_weakreflist != NULL)
- PyObject_ClearWeakRefs(self);
+ FT_CLEAR_WEAKREFS(self, gen->gi_weakreflist);
_PyObject_GC_TRACK(self);
#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 */
// call PyObject_GC_UnTrack twice on an object.
PyObject_GC_UnTrack(m);
Py_TRASHCAN_BEGIN(m, meth_dealloc);
- if (m->m_weakreflist != NULL) {
- PyObject_ClearWeakRefs((PyObject*) m);
- }
+ FT_CLEAR_WEAKREFS((PyObject*) m, m->m_weakreflist);
// Dereference class before m_self: PyCFunction_GET_CLASS accesses
// PyMethodDef m_ml, which could be kept alive by m_self
Py_XDECREF(PyCFunction_GET_CLASS(m));
#include "pycore_pyerrors.h" // _PyErr_FormatFromCause()
#include "pycore_pystate.h" // _PyInterpreterState_GET()
#include "pycore_sysmodule.h" // _PySys_GetOptionalAttrString()
+#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
#include "osdefs.h" // MAXPATHLEN
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((PyObject *) m, 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
&& (m->md_def->m_size <= 0 || m->md_state != NULL))
#include "pycore_object.h" // _PyObject_GC_UNTRACK()
#include "pycore_pyerrors.h" // _PyErr_ChainExceptions1()
#include <stddef.h> // offsetof()
+#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
#include "clinic/odictobject.c.h"
Py_TRASHCAN_BEGIN(self, odict_dealloc)
Py_XDECREF(self->od_inst_dict);
- if (self->od_weakreflist != NULL)
- PyObject_ClearWeakRefs((PyObject *)self);
+ FT_CLEAR_WEAKREFS((PyObject*)self, self->od_weakreflist);
_odict_clear_nodes(self);
PyDict_Type.tp_dealloc((PyObject *)self);
/* PickleBuffer object implementation */
#include "Python.h"
+#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
#include <stddef.h>
typedef struct {
picklebuf_dealloc(PyPickleBufferObject *self)
{
PyObject_GC_UnTrack(self);
- if (self->weakreflist != NULL)
- PyObject_ClearWeakRefs((PyObject *) self);
+ FT_CLEAR_WEAKREFS((PyObject*)self, self->weakreflist);
PyBuffer_Release(&self->view);
Py_TYPE(self)->tp_free((PyObject *) self);
}
#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 <stddef.h> // offsetof()
#include "clinic/setobject.c.h"
/* bpo-31095: UnTrack is needed before calling any callbacks */
PyObject_GC_UnTrack(so);
Py_TRASHCAN_BEGIN(so, set_dealloc)
- if (so->weakreflist != NULL)
- PyObject_ClearWeakRefs((PyObject *) so);
+ FT_CLEAR_WEAKREFS((PyObject *) so, so->weakreflist);
for (entry = so->table; used > 0; entry++) {
if (entry->key && entry->key != dummy) {