Skip to content

Commit e3a277c

Browse files
vstinnerxuantenghkumaraditya303
authored
[3.13] pythongh-135607: remove null checking of weakref list in dealloc of extension modules and objects (python#135614) (python#136126)
pythongh-135607: remove null checking of weakref list in dealloc of extension modules and objects (python#135614) (cherry picked from commit b1056c2) Co-authored-by: Xuanteng Huang <[email protected]> Co-authored-by: Kumar Aditya <[email protected]>
1 parent 1e3466a commit e3a277c

31 files changed

+75
-73
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 & 2 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

@@ -1521,8 +1522,7 @@ deque_dealloc(dequeobject *deque)
15211522
Py_ssize_t i;
15221523

15231524
PyObject_GC_UnTrack(deque);
1524-
if (deque->weakreflist != NULL)
1525-
PyObject_ClearWeakRefs((PyObject *) deque);
1525+
FT_CLEAR_WEAKREFS((PyObject*)deque, deque->weakreflist);
15261526
if (deque->leftblock != NULL) {
15271527
deque_clear(deque);
15281528
assert(deque->leftblock != NULL);

Modules/_elementtree.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "Python.h"
1919
#include "pycore_import.h" // _PyImport_GetModuleAttrString()
2020
#include "pycore_pyhash.h" // _Py_HashSecret
21+
#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
2122

2223
#include <stddef.h> // offsetof()
2324
#include "expat.h"
@@ -688,8 +689,7 @@ element_dealloc(ElementObject* self)
688689
PyObject_GC_UnTrack(self);
689690
Py_TRASHCAN_BEGIN(self, element_dealloc)
690691

691-
if (self->weakreflist != NULL)
692-
PyObject_ClearWeakRefs((PyObject *) self);
692+
FT_CLEAR_WEAKREFS((PyObject*)self, self->weakreflist);
693693

694694
/* element_gc_clear clears all references and deallocates extra
695695
*/

Modules/_functoolsmodule.c

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "pycore_object.h" // _PyObject_GC_TRACK
77
#include "pycore_pystate.h" // _PyThreadState_GET()
88
#include "pycore_tuple.h" // _PyTuple_ITEMS()
9+
#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
910

1011

1112
#include "clinic/_functoolsmodule.c.h"
@@ -189,9 +190,7 @@ partial_dealloc(partialobject *pto)
189190
PyTypeObject *tp = Py_TYPE(pto);
190191
/* bpo-31095: UnTrack is needed before calling any callbacks */
191192
PyObject_GC_UnTrack(pto);
192-
if (pto->weakreflist != NULL) {
193-
PyObject_ClearWeakRefs((PyObject *) pto);
194-
}
193+
FT_CLEAR_WEAKREFS((PyObject*)pto, pto->weakreflist);
195194
(void)partial_clear(pto);
196195
tp->tp_free(pto);
197196
Py_DECREF(tp);
@@ -1317,9 +1316,7 @@ lru_cache_dealloc(lru_cache_object *obj)
13171316
PyTypeObject *tp = Py_TYPE(obj);
13181317
/* bpo-31095: UnTrack is needed before calling any callbacks */
13191318
PyObject_GC_UnTrack(obj);
1320-
if (obj->weakreflist != NULL) {
1321-
PyObject_ClearWeakRefs((PyObject*)obj);
1322-
}
1319+
FT_CLEAR_WEAKREFS((PyObject*)obj, obj->weakreflist);
13231320

13241321
(void)lru_cache_tp_clear(obj);
13251322
tp->tp_free(obj);

Modules/_io/bufferedio.c

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

1617
#include "_iomodule.h"
1718

@@ -416,8 +417,7 @@ buffered_dealloc(buffered *self)
416417
return;
417418
_PyObject_GC_UNTRACK(self);
418419
self->ok = 0;
419-
if (self->weakreflist != NULL)
420-
PyObject_ClearWeakRefs((PyObject *)self);
420+
FT_CLEAR_WEAKREFS((PyObject*)self, self->weakreflist);
421421
if (self->buffer) {
422422
PyMem_Free(self->buffer);
423423
self->buffer = NULL;
@@ -2299,8 +2299,7 @@ bufferedrwpair_dealloc(rwpair *self)
22992299
{
23002300
PyTypeObject *tp = Py_TYPE(self);
23012301
_PyObject_GC_UNTRACK(self);
2302-
if (self->weakreflist != NULL)
2303-
PyObject_ClearWeakRefs((PyObject *)self);
2302+
FT_CLEAR_WEAKREFS((PyObject *)self, self->weakreflist);
23042303
(void)bufferedrwpair_clear(self);
23052304
tp->tp_free((PyObject *) self);
23062305
Py_DECREF(tp);

Modules/_io/bytesio.c

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

56
#include <stddef.h> // offsetof()
67
#include "_iomodule.h"
@@ -894,8 +895,7 @@ bytesio_dealloc(bytesio *self)
894895
}
895896
Py_CLEAR(self->buf);
896897
Py_CLEAR(self->dict);
897-
if (self->weakreflist != NULL)
898-
PyObject_ClearWeakRefs((PyObject *) self);
898+
FT_CLEAR_WEAKREFS((PyObject *) self, self->weakreflist);
899899
tp->tp_free(self);
900900
Py_DECREF(tp);
901901
}

Modules/_io/fileio.c

Lines changed: 2 additions & 2 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
@@ -545,8 +546,7 @@ fileio_dealloc(fileio *self)
545546
if (_PyIOBase_finalize((PyObject *) self) < 0)
546547
return;
547548
_PyObject_GC_UNTRACK(self);
548-
if (self->weakreflist != NULL)
549-
PyObject_ClearWeakRefs((PyObject *) self);
549+
FT_CLEAR_WEAKREFS((PyObject *) self, self->weakreflist);
550550
(void)fileio_clear(self);
551551
tp->tp_free((PyObject *)self);
552552
Py_DECREF(tp);

Modules/_io/iobase.c

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

1718
#include <stddef.h> // offsetof()
1819
#include "_iomodule.h"
@@ -376,8 +377,7 @@ iobase_dealloc(iobase *self)
376377
}
377378
PyTypeObject *tp = Py_TYPE(self);
378379
_PyObject_GC_UNTRACK(self);
379-
if (self->weakreflist != NULL)
380-
PyObject_ClearWeakRefs((PyObject *) self);
380+
FT_CLEAR_WEAKREFS((PyObject *) self, self->weakreflist);
381381
Py_CLEAR(self->dict);
382382
tp->tp_free((PyObject *)self);
383383
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
@@ -617,9 +618,7 @@ stringio_dealloc(stringio *self)
617618
}
618619
_PyUnicodeWriter_Dealloc(&self->writer);
619620
(void)stringio_clear(self);
620-
if (self->weakreflist != NULL) {
621-
PyObject_ClearWeakRefs((PyObject *) self);
622-
}
621+
FT_CLEAR_WEAKREFS((PyObject *) self, self->weakreflist);
623622
tp->tp_free(self);
624623
Py_DECREF(tp);
625624
}

0 commit comments

Comments
 (0)