Skip to content

Commit b1056c2

Browse files
xuantenghkumaraditya303vstinner
authored
gh-135607: remove null checking of weakref list in dealloc of extension modules and objects (#135614)
Co-authored-by: Kumar Aditya <[email protected]> Co-authored-by: Victor Stinner <[email protected]>
1 parent 0533c1f commit b1056c2

32 files changed

+77
-83
lines changed

Include/internal/pycore_weakref.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@ extern "C" {
2929
PyMutex_LockFlags(wr->weakrefs_lock, _Py_LOCK_DONT_DETACH)
3030
#define UNLOCK_WEAKREFS_FOR_WR(wr) PyMutex_Unlock(wr->weakrefs_lock)
3131

32+
#define FT_CLEAR_WEAKREFS(obj, weakref_list) \
33+
do { \
34+
assert(Py_REFCNT(obj) == 0); \
35+
PyObject_ClearWeakRefs(obj); \
36+
} while (0)
37+
3238
#else
3339

3440
#define LOCK_WEAKREFS(obj)
@@ -37,6 +43,14 @@ extern "C" {
3743
#define LOCK_WEAKREFS_FOR_WR(wr)
3844
#define UNLOCK_WEAKREFS_FOR_WR(wr)
3945

46+
#define FT_CLEAR_WEAKREFS(obj, weakref_list) \
47+
do { \
48+
assert(Py_REFCNT(obj) == 0); \
49+
if (weakref_list != NULL) { \
50+
PyObject_ClearWeakRefs(obj); \
51+
} \
52+
} while (0)
53+
4054
#endif
4155

4256
static inline int _is_dead(PyObject *obj)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix potential :mod:`weakref` races in an object's destructor on the :term:`free threaded <free
2+
threading>` build.

Modules/_collectionsmodule.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "pycore_moduleobject.h" // _PyModule_GetState()
66
#include "pycore_pyatomic_ft_wrappers.h"
77
#include "pycore_typeobject.h" // _PyType_GetModuleState()
8+
#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
89

910
#include <stddef.h>
1011

@@ -1532,9 +1533,7 @@ deque_dealloc(PyObject *self)
15321533
Py_ssize_t i;
15331534

15341535
PyObject_GC_UnTrack(deque);
1535-
if (deque->weakreflist != NULL) {
1536-
PyObject_ClearWeakRefs(self);
1537-
}
1536+
FT_CLEAR_WEAKREFS(self, deque->weakreflist);
15381537
if (deque->leftblock != NULL) {
15391538
(void)deque_clear(self);
15401539
assert(deque->leftblock != NULL);

Modules/_elementtree.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
#include "Python.h"
1919
#include "pycore_pyhash.h" // _Py_HashSecret
20+
#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
2021

2122
#include <stddef.h> // offsetof()
2223
#include "expat.h"
@@ -690,8 +691,7 @@ element_dealloc(PyObject *op)
690691
/* bpo-31095: UnTrack is needed before calling any callbacks */
691692
PyObject_GC_UnTrack(self);
692693

693-
if (self->weakreflist != NULL)
694-
PyObject_ClearWeakRefs(op);
694+
FT_CLEAR_WEAKREFS(op, self->weakreflist);
695695

696696
/* element_gc_clear clears all references and deallocates extra
697697
*/

Modules/_functoolsmodule.c

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "pycore_pyatomic_ft_wrappers.h"
88
#include "pycore_pystate.h" // _PyThreadState_GET()
99
#include "pycore_tuple.h" // _PyTuple_ITEMS()
10+
#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
1011

1112

1213
#include "clinic/_functoolsmodule.c.h"
@@ -351,9 +352,7 @@ partial_dealloc(PyObject *self)
351352
PyTypeObject *tp = Py_TYPE(self);
352353
/* bpo-31095: UnTrack is needed before calling any callbacks */
353354
PyObject_GC_UnTrack(self);
354-
if (partialobject_CAST(self)->weakreflist != NULL) {
355-
PyObject_ClearWeakRefs(self);
356-
}
355+
FT_CLEAR_WEAKREFS(self, partialobject_CAST(self)->weakreflist);
357356
(void)partial_clear(self);
358357
tp->tp_free(self);
359358
Py_DECREF(tp);
@@ -1621,9 +1620,7 @@ lru_cache_dealloc(PyObject *op)
16211620
PyTypeObject *tp = Py_TYPE(obj);
16221621
/* bpo-31095: UnTrack is needed before calling any callbacks */
16231622
PyObject_GC_UnTrack(obj);
1624-
if (obj->weakreflist != NULL) {
1625-
PyObject_ClearWeakRefs(op);
1626-
}
1623+
FT_CLEAR_WEAKREFS(op, obj->weakreflist);
16271624

16281625
(void)lru_cache_tp_clear(op);
16291626
tp->tp_free(obj);

Modules/_io/bufferedio.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "pycore_object.h" // _PyObject_GC_UNTRACK()
1414
#include "pycore_pyerrors.h" // _Py_FatalErrorFormat()
1515
#include "pycore_pylifecycle.h" // _Py_IsInterpreterFinalizing()
16+
#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
1617

1718
#include "_iomodule.h"
1819

@@ -421,8 +422,7 @@ buffered_dealloc(PyObject *op)
421422
return;
422423
_PyObject_GC_UNTRACK(self);
423424
self->ok = 0;
424-
if (self->weakreflist != NULL)
425-
PyObject_ClearWeakRefs(op);
425+
FT_CLEAR_WEAKREFS(op, self->weakreflist);
426426
if (self->buffer) {
427427
PyMem_Free(self->buffer);
428428
self->buffer = NULL;
@@ -2312,8 +2312,7 @@ bufferedrwpair_dealloc(PyObject *op)
23122312
rwpair *self = rwpair_CAST(op);
23132313
PyTypeObject *tp = Py_TYPE(self);
23142314
_PyObject_GC_UNTRACK(self);
2315-
if (self->weakreflist != NULL)
2316-
PyObject_ClearWeakRefs(op);
2315+
FT_CLEAR_WEAKREFS(op, self->weakreflist);
23172316
(void)bufferedrwpair_clear(op);
23182317
tp->tp_free(self);
23192318
Py_DECREF(tp);

Modules/_io/bytesio.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include "pycore_object.h"
44
#include "pycore_pyatomic_ft_wrappers.h"
55
#include "pycore_sysmodule.h" // _PySys_GetSizeOf()
6+
#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
67

78
#include <stddef.h> // offsetof()
89
#include "_iomodule.h"
@@ -979,8 +980,7 @@ bytesio_dealloc(PyObject *op)
979980
}
980981
Py_CLEAR(self->buf);
981982
Py_CLEAR(self->dict);
982-
if (self->weakreflist != NULL)
983-
PyObject_ClearWeakRefs(op);
983+
FT_CLEAR_WEAKREFS(op, self->weakreflist);
984984
tp->tp_free(self);
985985
Py_DECREF(tp);
986986
}

Modules/_io/fileio.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include "pycore_fileutils.h" // _Py_BEGIN_SUPPRESS_IPH
55
#include "pycore_object.h" // _PyObject_GC_UNTRACK()
66
#include "pycore_pyerrors.h" // _PyErr_ChainExceptions1()
7+
#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
78

89
#include <stdbool.h> // bool
910
#ifdef HAVE_UNISTD_H
@@ -570,9 +571,7 @@ fileio_dealloc(PyObject *op)
570571
PyMem_Free(self->stat_atopen);
571572
self->stat_atopen = NULL;
572573
}
573-
if (self->weakreflist != NULL) {
574-
PyObject_ClearWeakRefs(op);
575-
}
574+
FT_CLEAR_WEAKREFS(op, self->weakreflist);
576575
(void)fileio_clear(op);
577576

578577
PyTypeObject *tp = Py_TYPE(op);

Modules/_io/iobase.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "pycore_long.h" // _PyLong_GetOne()
1515
#include "pycore_object.h" // _PyType_HasFeature()
1616
#include "pycore_pyerrors.h" // _PyErr_ChainExceptions1()
17+
#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
1718

1819
#include <stddef.h> // offsetof()
1920
#include "_iomodule.h"
@@ -383,8 +384,7 @@ iobase_dealloc(PyObject *op)
383384
}
384385
PyTypeObject *tp = Py_TYPE(self);
385386
_PyObject_GC_UNTRACK(self);
386-
if (self->weakreflist != NULL)
387-
PyObject_ClearWeakRefs(op);
387+
FT_CLEAR_WEAKREFS(op, self->weakreflist);
388388
Py_CLEAR(self->dict);
389389
tp->tp_free(self);
390390
Py_DECREF(tp);

Modules/_io/stringio.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "Python.h"
22
#include <stddef.h> // offsetof()
33
#include "pycore_object.h"
4+
#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
45
#include "_iomodule.h"
56

67
/* Implementation note: the buffer is always at least one character longer
@@ -638,9 +639,7 @@ stringio_dealloc(PyObject *op)
638639
}
639640
PyUnicodeWriter_Discard(self->writer);
640641
(void)stringio_clear(op);
641-
if (self->weakreflist != NULL) {
642-
PyObject_ClearWeakRefs(op);
643-
}
642+
FT_CLEAR_WEAKREFS(op, self->weakreflist);
644643
tp->tp_free(self);
645644
Py_DECREF(tp);
646645
}

0 commit comments

Comments
 (0)