From 8598eb52d96a97a36f773a3c429c0e468ad6c08e Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Mon, 1 Sep 2025 10:06:43 -0400 Subject: [PATCH 01/17] Add the utility. Also use it in _bz2. --- Include/cpython/object.h | 4 ++++ Modules/_bz2module.c | 18 ++---------------- Objects/object.c | 7 +++++++ 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/Include/cpython/object.h b/Include/cpython/object.h index 973d358ed8e4ec..b244c062c7679e 100644 --- a/Include/cpython/object.h +++ b/Include/cpython/object.h @@ -491,3 +491,7 @@ PyAPI_FUNC(int) PyUnstable_TryIncRef(PyObject *); PyAPI_FUNC(void) PyUnstable_EnableTryIncRef(PyObject *); PyAPI_FUNC(int) PyUnstable_Object_IsUniquelyReferenced(PyObject *); + +/* Utility for the tp_traverse slot of mutable heap types that have no other + * references. */ +PyAPI_FUNC(int) _PyObject_VisitType(PyObject *op, visitproc visit, void *arg); diff --git a/Modules/_bz2module.c b/Modules/_bz2module.c index 914172684158a1..73c5546af60b64 100644 --- a/Modules/_bz2module.c +++ b/Modules/_bz2module.c @@ -391,13 +391,6 @@ BZ2Compressor_dealloc(PyObject *op) Py_DECREF(tp); } -static int -BZ2Compressor_traverse(PyObject *self, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(self)); - return 0; -} - static PyMethodDef BZ2Compressor_methods[] = { _BZ2_BZ2COMPRESSOR_COMPRESS_METHODDEF _BZ2_BZ2COMPRESSOR_FLUSH_METHODDEF @@ -409,7 +402,7 @@ static PyType_Slot bz2_compressor_type_slots[] = { {Py_tp_methods, BZ2Compressor_methods}, {Py_tp_new, _bz2_BZ2Compressor}, {Py_tp_doc, (char *)_bz2_BZ2Compressor__doc__}, - {Py_tp_traverse, BZ2Compressor_traverse}, + {Py_tp_traverse, _PyObject_VisitType}, {0, 0} }; @@ -703,13 +696,6 @@ BZ2Decompressor_dealloc(PyObject *op) Py_DECREF(tp); } -static int -BZ2Decompressor_traverse(PyObject *self, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(self)); - return 0; -} - static PyMethodDef BZ2Decompressor_methods[] = { _BZ2_BZ2DECOMPRESSOR_DECOMPRESS_METHODDEF {NULL} @@ -740,7 +726,7 @@ static PyType_Slot bz2_decompressor_type_slots[] = { {Py_tp_doc, (char *)_bz2_BZ2Decompressor__doc__}, {Py_tp_members, BZ2Decompressor_members}, {Py_tp_new, _bz2_BZ2Decompressor}, - {Py_tp_traverse, BZ2Decompressor_traverse}, + {Py_tp_traverse, _PyObject_VisitType}, {0, 0} }; diff --git a/Objects/object.c b/Objects/object.c index fba86e63cd4a11..c8dc7acecea0bd 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -3384,3 +3384,10 @@ PyUnstable_Object_IsUniquelyReferenced(PyObject *op) assert(op != NULL); return _PyObject_IsUniquelyReferenced(op); } + +int _PyObject_VisitType(PyObject *op, visitproc visit, void *arg) +{ + assert(op != NULL); + Py_VISIT(Py_TYPE(op)); + return 0; +} From 856026024897968bcf9d1de15caf57390b5f7d58 Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Mon, 1 Sep 2025 10:07:29 -0400 Subject: [PATCH 02/17] Remove boilerplate in _dbm. --- Modules/_dbmmodule.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/Modules/_dbmmodule.c b/Modules/_dbmmodule.c index 0cd0f043de453d..17aca2f00a13c0 100644 --- a/Modules/_dbmmodule.c +++ b/Modules/_dbmmodule.c @@ -96,12 +96,6 @@ newdbmobject(_dbm_state *state, const char *file, int flags, int mode) } /* Methods */ -static int -dbm_traverse(PyObject *dp, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(dp)); - return 0; -} static void dbm_dealloc(PyObject *self) @@ -540,7 +534,7 @@ static PyMethodDef dbm_methods[] = { static PyType_Slot dbmtype_spec_slots[] = { {Py_tp_dealloc, dbm_dealloc}, - {Py_tp_traverse, dbm_traverse}, + {Py_tp_traverse, _PyObject_VisitType}, {Py_tp_methods, dbm_methods}, {Py_sq_contains, dbm_contains}, {Py_mp_length, dbm_length}, From d7a5fd8e6674b33ab2494f41ffd1df8154f1e890 Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Mon, 1 Sep 2025 10:07:56 -0400 Subject: [PATCH 03/17] Remove boilerplate in _functools. --- Modules/_functoolsmodule.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/Modules/_functoolsmodule.c b/Modules/_functoolsmodule.c index f077a0ed329516..257d5c6d53611c 100644 --- a/Modules/_functoolsmodule.c +++ b/Modules/_functoolsmodule.c @@ -108,20 +108,13 @@ placeholder_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) return placeholder; } -static int -placeholder_traverse(PyObject *self, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(self)); - return 0; -} - static PyType_Slot placeholder_type_slots[] = { {Py_tp_dealloc, placeholder_dealloc}, {Py_tp_repr, placeholder_repr}, {Py_tp_doc, (void *)placeholder_doc}, {Py_tp_methods, placeholder_methods}, {Py_tp_new, placeholder_new}, - {Py_tp_traverse, placeholder_traverse}, + {Py_tp_traverse, _PyObject_VisitType}, {0, 0} }; From b9751b3989abe0de8c4924c99a055eca0d8afb31 Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Mon, 1 Sep 2025 10:09:14 -0400 Subject: [PATCH 04/17] Use it in _gdbm, _lzma, and _ssl. --- Modules/_gdbmmodule.c | 8 +------- Modules/_lzmamodule.c | 18 ++---------------- Modules/_pickle.c | 9 +-------- Modules/_ssl.c | 9 +-------- 4 files changed, 5 insertions(+), 39 deletions(-) diff --git a/Modules/_gdbmmodule.c b/Modules/_gdbmmodule.c index 76072ca60cf6cd..87f62b945b2923 100644 --- a/Modules/_gdbmmodule.c +++ b/Modules/_gdbmmodule.c @@ -122,12 +122,6 @@ newgdbmobject(_gdbm_state *state, const char *file, int flags, int mode) } /* Methods */ -static int -gdbm_traverse(PyObject *op, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(op)); - return 0; -} static void gdbm_dealloc(PyObject *op) @@ -714,7 +708,7 @@ static PyMethodDef gdbm_methods[] = { static PyType_Slot gdbmtype_spec_slots[] = { {Py_tp_dealloc, gdbm_dealloc}, - {Py_tp_traverse, gdbm_traverse}, + {Py_tp_traverse, _PyObject_VisitType}, {Py_tp_methods, gdbm_methods}, {Py_sq_contains, gdbm_contains}, {Py_mp_length, gdbm_length}, diff --git a/Modules/_lzmamodule.c b/Modules/_lzmamodule.c index 0b0b1bc765bbc9..30a42ccb0082b8 100644 --- a/Modules/_lzmamodule.c +++ b/Modules/_lzmamodule.c @@ -882,13 +882,6 @@ static PyMethodDef Compressor_methods[] = { {NULL} }; -static int -Compressor_traverse(PyObject *self, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(self)); - return 0; -} - PyDoc_STRVAR(Compressor_doc, "LZMACompressor(format=FORMAT_XZ, check=-1, preset=None, filters=None)\n" "\n" @@ -922,7 +915,7 @@ static PyType_Slot lzma_compressor_type_slots[] = { {Py_tp_methods, Compressor_methods}, {Py_tp_new, Compressor_new}, {Py_tp_doc, (char *)Compressor_doc}, - {Py_tp_traverse, Compressor_traverse}, + {Py_tp_traverse, _PyObject_VisitType}, {0, 0} }; @@ -1328,13 +1321,6 @@ Decompressor_dealloc(PyObject *op) Py_DECREF(tp); } -static int -Decompressor_traverse(PyObject *self, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(self)); - return 0; -} - static PyMethodDef Decompressor_methods[] = { _LZMA_LZMADECOMPRESSOR_DECOMPRESS_METHODDEF {NULL} @@ -1369,7 +1355,7 @@ static PyType_Slot lzma_decompressor_type_slots[] = { {Py_tp_methods, Decompressor_methods}, {Py_tp_new, _lzma_LZMADecompressor}, {Py_tp_doc, (char *)_lzma_LZMADecompressor__doc__}, - {Py_tp_traverse, Decompressor_traverse}, + {Py_tp_traverse, _PyObject_VisitType}, {Py_tp_members, Decompressor_members}, {0, 0} }; diff --git a/Modules/_pickle.c b/Modules/_pickle.c index bc06478799345a..0774e91039ec41 100644 --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -413,13 +413,6 @@ typedef struct { #define Pdata_CAST(op) ((Pdata *)(op)) -static int -Pdata_traverse(PyObject *self, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(self)); - return 0; -} - static void Pdata_dealloc(PyObject *op) { @@ -437,7 +430,7 @@ Pdata_dealloc(PyObject *op) static PyType_Slot pdata_slots[] = { {Py_tp_dealloc, Pdata_dealloc}, - {Py_tp_traverse, Pdata_traverse}, + {Py_tp_traverse, _PyObject_VisitType}, {0, NULL}, }; diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 2388bbb3bae631..048e640283638b 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -5692,13 +5692,6 @@ _ssl_MemoryBIO_impl(PyTypeObject *type) return (PyObject *) self; } -static int -memory_bio_traverse(PyObject *self, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(self)); - return 0; -} - static void memory_bio_dealloc(PyObject *op) { @@ -5869,7 +5862,7 @@ static PyType_Slot PySSLMemoryBIO_slots[] = { {Py_tp_getset, memory_bio_getsetlist}, {Py_tp_new, _ssl_MemoryBIO}, {Py_tp_dealloc, memory_bio_dealloc}, - {Py_tp_traverse, memory_bio_traverse}, + {Py_tp_traverse, _PyObject_VisitType}, {0, 0}, }; From 55c530c3791e8acf58d00c5dc5bfa11bf9a5206d Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Mon, 1 Sep 2025 10:10:00 -0400 Subject: [PATCH 05/17] Use it in _thread. --- Modules/_threadmodule.c | 27 +++------------------------ 1 file changed, 3 insertions(+), 24 deletions(-) diff --git a/Modules/_threadmodule.c b/Modules/_threadmodule.c index 0a22907375b0dd..1a64289ea01fdb 100644 --- a/Modules/_threadmodule.c +++ b/Modules/_threadmodule.c @@ -655,13 +655,6 @@ PyThreadHandleObject_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds) return (PyObject *)PyThreadHandleObject_new(type); } -static int -PyThreadHandleObject_traverse(PyObject *self, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(self)); - return 0; -} - static void PyThreadHandleObject_dealloc(PyObject *op) { @@ -751,7 +744,7 @@ static PyType_Slot ThreadHandle_Type_slots[] = { {Py_tp_dealloc, PyThreadHandleObject_dealloc}, {Py_tp_repr, PyThreadHandleObject_repr}, {Py_tp_getset, ThreadHandle_getsetlist}, - {Py_tp_traverse, PyThreadHandleObject_traverse}, + {Py_tp_traverse, _PyObject_VisitType}, {Py_tp_methods, ThreadHandle_methods}, {Py_tp_new, PyThreadHandleObject_tp_new}, {0, 0} @@ -767,13 +760,6 @@ static PyType_Spec ThreadHandle_Type_spec = { /* Lock objects */ -static int -lock_traverse(PyObject *self, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(self)); - return 0; -} - static void lock_dealloc(PyObject *self) { @@ -1045,7 +1031,7 @@ static PyType_Slot lock_type_slots[] = { {Py_tp_repr, lock_repr}, {Py_tp_doc, (void *)lock_doc}, {Py_tp_methods, lock_methods}, - {Py_tp_traverse, lock_traverse}, + {Py_tp_traverse, _PyObject_VisitType}, {Py_tp_new, lock_new}, {0, 0} }; @@ -1060,13 +1046,6 @@ static PyType_Spec lock_type_spec = { /* Recursive lock objects */ -static int -rlock_traverse(PyObject *self, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(self)); - return 0; -} - static int rlock_locked_impl(rlockobject *self) { @@ -1359,7 +1338,7 @@ static PyType_Slot rlock_type_slots[] = { {Py_tp_methods, rlock_methods}, {Py_tp_alloc, PyType_GenericAlloc}, {Py_tp_new, rlock_new}, - {Py_tp_traverse, rlock_traverse}, + {Py_tp_traverse, _PyObject_VisitType}, {0, 0}, }; From 21b3024964802ed6afa8958d2026843c75fe2af8 Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Mon, 1 Sep 2025 10:11:47 -0400 Subject: [PATCH 06/17] Use it in array, blake2, hmac, and md5. --- Modules/arraymodule.c | 9 +-------- Modules/blake2module.c | 11 ++--------- Modules/hmacmodule.c | 9 +-------- Modules/md5module.c | 8 +------- 4 files changed, 5 insertions(+), 32 deletions(-) diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c index 654e9445985d84..e2c239d1f8b285 100644 --- a/Modules/arraymodule.c +++ b/Modules/arraymodule.c @@ -715,13 +715,6 @@ ins1(arrayobject *self, Py_ssize_t where, PyObject *v) /* Methods */ -static int -array_tp_traverse(PyObject *op, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(op)); - return 0; -} - static void array_dealloc(PyObject *op) { @@ -2968,7 +2961,7 @@ static PyType_Slot array_slots[] = { {Py_tp_getset, array_getsets}, {Py_tp_alloc, PyType_GenericAlloc}, {Py_tp_new, array_new}, - {Py_tp_traverse, array_tp_traverse}, + {Py_tp_traverse, _PyObject_VisitType}, /* as sequence */ {Py_sq_length, array_length}, diff --git a/Modules/blake2module.c b/Modules/blake2module.c index 163f238a4268d0..4921e8f945ef37 100644 --- a/Modules/blake2module.c +++ b/Modules/blake2module.c @@ -1008,17 +1008,10 @@ py_blake2_dealloc(PyObject *self) Py_DECREF(type); } -static int -py_blake2_traverse(PyObject *self, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(self)); - return 0; -} - static PyType_Slot blake2b_type_slots[] = { {Py_tp_clear, py_blake2_clear}, {Py_tp_dealloc, py_blake2_dealloc}, - {Py_tp_traverse, py_blake2_traverse}, + {Py_tp_traverse, _PyObject_VisitType}, {Py_tp_doc, (char *)py_blake2b_new__doc__}, {Py_tp_methods, py_blake2b_methods}, {Py_tp_getset, py_blake2b_getsetters}, @@ -1029,7 +1022,7 @@ static PyType_Slot blake2b_type_slots[] = { static PyType_Slot blake2s_type_slots[] = { {Py_tp_clear, py_blake2_clear}, {Py_tp_dealloc, py_blake2_dealloc}, - {Py_tp_traverse, py_blake2_traverse}, + {Py_tp_traverse, _PyObject_VisitType}, {Py_tp_doc, (char *)py_blake2s_new__doc__}, {Py_tp_methods, py_blake2b_methods}, {Py_tp_getset, py_blake2b_getsetters}, diff --git a/Modules/hmacmodule.c b/Modules/hmacmodule.c index 680c93a04cac17..b30dda501a0716 100644 --- a/Modules/hmacmodule.c +++ b/Modules/hmacmodule.c @@ -1032,13 +1032,6 @@ HMACObject_dealloc(PyObject *op) Py_DECREF(type); } -static int -HMACObject_traverse(PyObject *op, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(op)); - return 0; -} - static PyMethodDef HMACObject_methods[] = { _HMAC_HMAC_COPY_METHODDEF _HMAC_HMAC_UPDATE_METHODDEF @@ -1060,7 +1053,7 @@ static PyType_Slot HMACObject_Type_slots[] = { {Py_tp_getset, HMACObject_getsets}, {Py_tp_clear, HMACObject_clear}, {Py_tp_dealloc, HMACObject_dealloc}, - {Py_tp_traverse, HMACObject_traverse}, + {Py_tp_traverse, _PyObject_VisitType}, {0, NULL} /* sentinel */ }; diff --git a/Modules/md5module.c b/Modules/md5module.c index 8b6dd4a8195dfb..7b3902483bbfcb 100644 --- a/Modules/md5module.c +++ b/Modules/md5module.c @@ -82,12 +82,6 @@ newMD5object(MD5State * st) } /* Internal methods for a hash object */ -static int -MD5_traverse(PyObject *ptr, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(ptr)); - return 0; -} static void MD5_dealloc(PyObject *op) @@ -246,7 +240,7 @@ static PyType_Slot md5_type_slots[] = { {Py_tp_dealloc, MD5_dealloc}, {Py_tp_methods, MD5_methods}, {Py_tp_getset, MD5_getseters}, - {Py_tp_traverse, MD5_traverse}, + {Py_tp_traverse, _PyObject_VisitType}, {0,0} }; From d8ea9e023c3c84f385ec0f40c94240dd16eb0ba0 Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Mon, 1 Sep 2025 10:12:47 -0400 Subject: [PATCH 07/17] Use it in mmap, sha1, sha2, and sha3. --- Modules/mmapmodule.c | 9 +-------- Modules/sha1module.c | 8 +------- Modules/sha2module.c | 11 ++--------- Modules/sha3module.c | 9 +-------- 4 files changed, 5 insertions(+), 32 deletions(-) diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c index 0cb4b62d734550..8413ebe668dffe 100644 --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -128,13 +128,6 @@ typedef struct { #define mmap_object_CAST(op) ((mmap_object *)(op)) -static int -mmap_object_traverse(PyObject *op, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(op)); - return 0; -} - static void mmap_object_dealloc(PyObject *op) { @@ -1499,7 +1492,7 @@ static PyType_Slot mmap_object_slots[] = { {Py_tp_members, mmap_object_members}, {Py_tp_getset, mmap_object_getset}, {Py_tp_getattro, PyObject_GenericGetAttr}, - {Py_tp_traverse, mmap_object_traverse}, + {Py_tp_traverse, _PyObject_VisitType}, /* as sequence */ {Py_sq_length, mmap_length}, diff --git a/Modules/sha1module.c b/Modules/sha1module.c index faa9dcccc5755b..289372371e45a8 100644 --- a/Modules/sha1module.c +++ b/Modules/sha1module.c @@ -81,12 +81,6 @@ newSHA1object(SHA1State *st) /* Internal methods for a hash object */ -static int -SHA1_traverse(PyObject *ptr, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(ptr)); - return 0; -} static void SHA1_dealloc(PyObject *op) @@ -247,7 +241,7 @@ static PyType_Slot sha1_type_slots[] = { {Py_tp_dealloc, SHA1_dealloc}, {Py_tp_methods, SHA1_methods}, {Py_tp_getset, SHA1_getseters}, - {Py_tp_traverse, SHA1_traverse}, + {Py_tp_traverse, _PyObject_VisitType}, {0,0} }; diff --git a/Modules/sha2module.c b/Modules/sha2module.c index 36300ba899fd44..f8408eec5b2989 100644 --- a/Modules/sha2module.c +++ b/Modules/sha2module.c @@ -165,13 +165,6 @@ newSHA512object(sha2_state *state) /* Internal methods for our hash objects. */ -static int -SHA2_traverse(PyObject *ptr, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(ptr)); - return 0; -} - static void SHA256_dealloc(PyObject *op) { @@ -519,7 +512,7 @@ static PyType_Slot sha256_types_slots[] = { {Py_tp_dealloc, SHA256_dealloc}, {Py_tp_methods, SHA256_methods}, {Py_tp_getset, SHA256_getseters}, - {Py_tp_traverse, SHA2_traverse}, + {Py_tp_traverse, _PyObject_VisitType}, {0,0} }; @@ -527,7 +520,7 @@ static PyType_Slot sha512_type_slots[] = { {Py_tp_dealloc, SHA512_dealloc}, {Py_tp_methods, SHA512_methods}, {Py_tp_getset, SHA512_getseters}, - {Py_tp_traverse, SHA2_traverse}, + {Py_tp_traverse, _PyObject_VisitType}, {0,0} }; diff --git a/Modules/sha3module.c b/Modules/sha3module.c index 5764556bb680f3..de4bf09b8e7e0b 100644 --- a/Modules/sha3module.c +++ b/Modules/sha3module.c @@ -226,13 +226,6 @@ SHA3_dealloc(PyObject *self) Py_DECREF(tp); } -static int -SHA3_traverse(PyObject *self, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(self)); - return 0; -} - /* External methods for a hash object */ @@ -424,7 +417,7 @@ static PyGetSetDef SHA3_getseters[] = { static PyType_Slot type_slots_obj[] = { \ {Py_tp_clear, SHA3_clear}, \ {Py_tp_dealloc, SHA3_dealloc}, \ - {Py_tp_traverse, SHA3_traverse}, \ + {Py_tp_traverse, _PyObject_VisitType}, \ {Py_tp_doc, (char*)type_doc}, \ {Py_tp_methods, type_methods}, \ {Py_tp_getset, type_getseters}, \ From 0cb7f4cc0a8abf6bf1ded1f54059f0205051a9b6 Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Mon, 1 Sep 2025 10:13:15 -0400 Subject: [PATCH 08/17] Use it in socket and unicodedata. --- Modules/socketmodule.c | 9 +-------- Modules/unicodedata.c | 9 +-------- 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index c5b16dc4fe4c5f..dc8e08ac3e522e 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -5538,13 +5538,6 @@ sock_finalize(PyObject *self) PyErr_SetRaisedException(exc); } -static int -sock_traverse(PyObject *s, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(s)); - return 0; -} - static void sock_dealloc(PyObject *s) { @@ -5843,7 +5836,7 @@ sock_initobj_impl(PySocketSockObject *self, int family, int type, int proto, static PyType_Slot sock_slots[] = { {Py_tp_dealloc, sock_dealloc}, - {Py_tp_traverse, sock_traverse}, + {Py_tp_traverse, _PyObject_VisitType}, {Py_tp_repr, sock_repr}, {Py_tp_doc, (void *)sock_doc}, {Py_tp_methods, sock_methods}, diff --git a/Modules/unicodedata.c b/Modules/unicodedata.c index 2a30030a2a1153..41725e5aec1641 100644 --- a/Modules/unicodedata.c +++ b/Modules/unicodedata.c @@ -1594,13 +1594,6 @@ static PyMethodDef unicodedata_functions[] = { {NULL, NULL} /* sentinel */ }; -static int -ucd_traverse(PyObject *self, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(self)); - return 0; -} - static void ucd_dealloc(PyObject *self) { @@ -1612,7 +1605,7 @@ ucd_dealloc(PyObject *self) static PyType_Slot ucd_type_slots[] = { {Py_tp_dealloc, ucd_dealloc}, - {Py_tp_traverse, ucd_traverse}, + {Py_tp_traverse, _PyObject_VisitType}, {Py_tp_getattro, PyObject_GenericGetAttr}, {Py_tp_methods, unicodedata_functions}, {Py_tp_members, DB_members}, From a05d9d083734cdef6aa49ae45b0fdf05d1b3747c Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Mon, 1 Sep 2025 10:13:52 -0400 Subject: [PATCH 09/17] Use it in _decimal. --- Modules/_decimal/_decimal.c | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index de7200af8c158b..50994be2968d35 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -746,13 +746,6 @@ signaldict_setitem(PyObject *self, PyObject *key, PyObject *value) return 0; } -static int -signaldict_traverse(PyObject *self, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(self)); - return 0; -} - static void signaldict_dealloc(PyObject *self) { @@ -845,7 +838,7 @@ static PyMethodDef signaldict_methods[] = { static PyType_Slot signaldict_slots[] = { {Py_tp_dealloc, signaldict_dealloc}, - {Py_tp_traverse, signaldict_traverse}, + {Py_tp_traverse, _PyObject_VisitType}, {Py_tp_repr, signaldict_repr}, {Py_tp_hash, PyObject_HashNotImplemented}, {Py_tp_getattro, PyObject_GenericGetAttr}, @@ -2194,13 +2187,6 @@ PyDecType_New(decimal_state *state, PyTypeObject *type) } #define dec_alloc(st) PyDecType_New(st, (st)->PyDec_Type) -static int -dec_traverse(PyObject *dec, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(dec)); - return 0; -} - static void dec_dealloc(PyObject *dec) { @@ -6032,7 +6018,7 @@ static PyType_Slot dec_slots[] = { {Py_tp_token, Py_TP_USE_SPEC}, {Py_tp_dealloc, dec_dealloc}, {Py_tp_getattro, PyObject_GenericGetAttr}, - {Py_tp_traverse, dec_traverse}, + {Py_tp_traverse, _PyObject_VisitType}, {Py_tp_repr, dec_repr}, {Py_tp_hash, dec_hash}, {Py_tp_str, dec_str}, From e86e0d6655d5040310af6ee70ca7f59f539d7b5e Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Mon, 1 Sep 2025 10:14:33 -0400 Subject: [PATCH 10/17] Use it in _multiprocessing and _sqlite. --- Modules/_multiprocessing/semaphore.c | 9 +-------- Modules/_sqlite/prepare_protocol.c | 9 +-------- Modules/_sqlite/statement.c | 9 +-------- 3 files changed, 3 insertions(+), 24 deletions(-) diff --git a/Modules/_multiprocessing/semaphore.c b/Modules/_multiprocessing/semaphore.c index a4a2a866ccbfce..d5a1f27e9ff4ff 100644 --- a/Modules/_multiprocessing/semaphore.c +++ b/Modules/_multiprocessing/semaphore.c @@ -720,13 +720,6 @@ _multiprocessing_SemLock___exit___impl(SemLockObject *self, return _multiprocessing_SemLock_release_impl(self); } -static int -semlock_traverse(PyObject *s, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(s)); - return 0; -} - /* * Semaphore methods */ @@ -773,7 +766,7 @@ static PyType_Slot _PyMp_SemLockType_slots[] = { {Py_tp_members, semlock_members}, {Py_tp_alloc, PyType_GenericAlloc}, {Py_tp_new, _multiprocessing_SemLock}, - {Py_tp_traverse, semlock_traverse}, + {Py_tp_traverse, _PyObject_VisitType}, {Py_tp_free, PyObject_GC_Del}, {Py_tp_doc, (void *)PyDoc_STR("Semaphore/Mutex type")}, {0, 0}, diff --git a/Modules/_sqlite/prepare_protocol.c b/Modules/_sqlite/prepare_protocol.c index 31092417cb480d..d7ac09e3947a77 100644 --- a/Modules/_sqlite/prepare_protocol.c +++ b/Modules/_sqlite/prepare_protocol.c @@ -29,13 +29,6 @@ pysqlite_prepare_protocol_init(PyObject *self, PyObject *args, PyObject *kwargs) return 0; } -static int -pysqlite_prepare_protocol_traverse(PyObject *self, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(self)); - return 0; -} - static void pysqlite_prepare_protocol_dealloc(PyObject *self) { @@ -50,7 +43,7 @@ PyDoc_STRVAR(doc, "PEP 246 style object adaption protocol type."); static PyType_Slot type_slots[] = { {Py_tp_dealloc, pysqlite_prepare_protocol_dealloc}, {Py_tp_init, pysqlite_prepare_protocol_init}, - {Py_tp_traverse, pysqlite_prepare_protocol_traverse}, + {Py_tp_traverse, _PyObject_VisitType}, {Py_tp_doc, (void *)doc}, {0, NULL}, }; diff --git a/Modules/_sqlite/statement.c b/Modules/_sqlite/statement.c index 736e60fd778287..77181104eda10b 100644 --- a/Modules/_sqlite/statement.c +++ b/Modules/_sqlite/statement.c @@ -116,13 +116,6 @@ stmt_dealloc(PyObject *op) Py_DECREF(tp); } -static int -stmt_traverse(PyObject *self, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(self)); - return 0; -} - /* * Strip leading whitespace and comments from incoming SQL (null terminated C * string) and return a pointer to the first non-whitespace, non-comment @@ -183,7 +176,7 @@ lstrip_sql(const char *sql) static PyType_Slot stmt_slots[] = { {Py_tp_dealloc, stmt_dealloc}, - {Py_tp_traverse, stmt_traverse}, + {Py_tp_traverse, _PyObject_VisitType}, {0, NULL}, }; From 68f0b412b619be0e92c31f3576ffbc949be2a453 Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Mon, 1 Sep 2025 10:15:23 -0400 Subject: [PATCH 11/17] Use it in the remaining files. --- Objects/typevarobject.c | 9 +-------- PC/winreg.c | 9 +-------- 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/Objects/typevarobject.c b/Objects/typevarobject.c index cead6e69af5451..522e9fd9c955af 100644 --- a/Objects/typevarobject.c +++ b/Objects/typevarobject.c @@ -2304,20 +2304,13 @@ generic_dealloc(PyObject *self) Py_DECREF(tp); } -static int -generic_traverse(PyObject *self, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(self)); - return 0; -} - static PyType_Slot generic_slots[] = { {Py_tp_doc, (void *)generic_doc}, {Py_tp_methods, generic_methods}, {Py_tp_dealloc, generic_dealloc}, {Py_tp_alloc, PyType_GenericAlloc}, {Py_tp_free, PyObject_GC_Del}, - {Py_tp_traverse, generic_traverse}, + {Py_tp_traverse, _PyObject_VisitType}, {0, NULL}, }; diff --git a/PC/winreg.c b/PC/winreg.c index 05a33006c32326..9bbacb0f50bd63 100644 --- a/PC/winreg.c +++ b/PC/winreg.c @@ -161,13 +161,6 @@ PyHKEY_deallocFunc(PyObject *ob) Py_DECREF(tp); } -static int -PyHKEY_traverseFunc(PyObject *self, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(self)); - return 0; -} - static int PyHKEY_boolFunc(PyObject *ob) { @@ -369,7 +362,7 @@ static PyType_Slot pyhkey_type_slots[] = { {Py_tp_members, PyHKEY_memberlist}, {Py_tp_methods, PyHKEY_methods}, {Py_tp_doc, (char *)PyHKEY_doc}, - {Py_tp_traverse, PyHKEY_traverseFunc}, + {Py_tp_traverse, _PyObject_VisitType}, {Py_tp_hash, PyHKEY_hashFunc}, {Py_tp_str, PyHKEY_strFunc}, From c58e4d0c117cc6ee47de9b7e465d411fc5076791 Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Mon, 1 Sep 2025 10:19:18 -0400 Subject: [PATCH 12/17] Add some more assertions to _PyObject_VisitType. --- Objects/object.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Objects/object.c b/Objects/object.c index c8dc7acecea0bd..e2e29500d558e4 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -3388,6 +3388,9 @@ PyUnstable_Object_IsUniquelyReferenced(PyObject *op) int _PyObject_VisitType(PyObject *op, visitproc visit, void *arg) { assert(op != NULL); - Py_VISIT(Py_TYPE(op)); + PyTypeObject *tp = Py_TYPE(op); + assert(PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE)); + assert(!PyType_HasFeature(tp, Py_TPFLAGS_IMMUTABLETYPE)); + Py_VISIT(tp); return 0; } From bb72a79333a06728cc6c466b6ce6bb46e4ee2863 Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Mon, 1 Sep 2025 10:24:17 -0400 Subject: [PATCH 13/17] Relax assertion. --- Objects/object.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Objects/object.c b/Objects/object.c index e2e29500d558e4..90630f16a57c6e 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -3389,8 +3389,7 @@ int _PyObject_VisitType(PyObject *op, visitproc visit, void *arg) { assert(op != NULL); PyTypeObject *tp = Py_TYPE(op); - assert(PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE)); - assert(!PyType_HasFeature(tp, Py_TPFLAGS_IMMUTABLETYPE)); + _PyObject_ASSERT((PyObject *)tp, PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE)); Py_VISIT(tp); return 0; } From be0abd98b8fb5930300bd09cfefe261bc7991c08 Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Mon, 1 Sep 2025 10:52:54 -0400 Subject: [PATCH 14/17] Formatting. --- Objects/object.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Objects/object.c b/Objects/object.c index 90630f16a57c6e..bd3ba02f8eb255 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -3385,7 +3385,8 @@ PyUnstable_Object_IsUniquelyReferenced(PyObject *op) return _PyObject_IsUniquelyReferenced(op); } -int _PyObject_VisitType(PyObject *op, visitproc visit, void *arg) +int +_PyObject_VisitType(PyObject *op, visitproc visit, void *arg) { assert(op != NULL); PyTypeObject *tp = Py_TYPE(op); From 6ae2f1d802764b2452e8b40c5a2e2d4675a904d5 Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Mon, 1 Sep 2025 11:42:14 -0400 Subject: [PATCH 15/17] Fix whitespace. Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Modules/_gdbmmodule.c | 1 - Modules/arraymodule.c | 1 - Modules/md5module.c | 1 - Modules/sha1module.c | 1 - Modules/sha2module.c | 1 - 5 files changed, 5 deletions(-) diff --git a/Modules/_gdbmmodule.c b/Modules/_gdbmmodule.c index 87f62b945b2923..7bef6ae7f0c43e 100644 --- a/Modules/_gdbmmodule.c +++ b/Modules/_gdbmmodule.c @@ -122,7 +122,6 @@ newgdbmobject(_gdbm_state *state, const char *file, int flags, int mode) } /* Methods */ - static void gdbm_dealloc(PyObject *op) { diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c index e2c239d1f8b285..d9ac5b97f8258f 100644 --- a/Modules/arraymodule.c +++ b/Modules/arraymodule.c @@ -714,7 +714,6 @@ ins1(arrayobject *self, Py_ssize_t where, PyObject *v) } /* Methods */ - static void array_dealloc(PyObject *op) { diff --git a/Modules/md5module.c b/Modules/md5module.c index 7b3902483bbfcb..6b6457427b6b5e 100644 --- a/Modules/md5module.c +++ b/Modules/md5module.c @@ -82,7 +82,6 @@ newMD5object(MD5State * st) } /* Internal methods for a hash object */ - static void MD5_dealloc(PyObject *op) { diff --git a/Modules/sha1module.c b/Modules/sha1module.c index 289372371e45a8..d64eb91458cae8 100644 --- a/Modules/sha1module.c +++ b/Modules/sha1module.c @@ -81,7 +81,6 @@ newSHA1object(SHA1State *st) /* Internal methods for a hash object */ - static void SHA1_dealloc(PyObject *op) { diff --git a/Modules/sha2module.c b/Modules/sha2module.c index f8408eec5b2989..66259fe47a0fd3 100644 --- a/Modules/sha2module.c +++ b/Modules/sha2module.c @@ -164,7 +164,6 @@ newSHA512object(sha2_state *state) } /* Internal methods for our hash objects. */ - static void SHA256_dealloc(PyObject *op) { From 74eb905f0d2f585eb6ece21b6df66e1830464ec6 Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Mon, 1 Sep 2025 11:45:16 -0400 Subject: [PATCH 16/17] Remove changes that will be reverted. --- Modules/_bz2module.c | 1 - Modules/_lzmamodule.c | 1 - 2 files changed, 2 deletions(-) diff --git a/Modules/_bz2module.c b/Modules/_bz2module.c index 73c5546af60b64..507bdb52d42411 100644 --- a/Modules/_bz2module.c +++ b/Modules/_bz2module.c @@ -402,7 +402,6 @@ static PyType_Slot bz2_compressor_type_slots[] = { {Py_tp_methods, BZ2Compressor_methods}, {Py_tp_new, _bz2_BZ2Compressor}, {Py_tp_doc, (char *)_bz2_BZ2Compressor__doc__}, - {Py_tp_traverse, _PyObject_VisitType}, {0, 0} }; diff --git a/Modules/_lzmamodule.c b/Modules/_lzmamodule.c index 30a42ccb0082b8..f7360fe897c03e 100644 --- a/Modules/_lzmamodule.c +++ b/Modules/_lzmamodule.c @@ -915,7 +915,6 @@ static PyType_Slot lzma_compressor_type_slots[] = { {Py_tp_methods, Compressor_methods}, {Py_tp_new, Compressor_new}, {Py_tp_doc, (char *)Compressor_doc}, - {Py_tp_traverse, _PyObject_VisitType}, {0, 0} }; From 1b03df5dfee1dc7e84ccd622556e1f69b8deb4aa Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Mon, 1 Sep 2025 11:51:20 -0400 Subject: [PATCH 17/17] Remove changes to existing code. --- Modules/_bz2module.c | 17 ++++++++++++++++- Modules/_lzmamodule.c | 17 ++++++++++++++++- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/Modules/_bz2module.c b/Modules/_bz2module.c index 507bdb52d42411..914172684158a1 100644 --- a/Modules/_bz2module.c +++ b/Modules/_bz2module.c @@ -391,6 +391,13 @@ BZ2Compressor_dealloc(PyObject *op) Py_DECREF(tp); } +static int +BZ2Compressor_traverse(PyObject *self, visitproc visit, void *arg) +{ + Py_VISIT(Py_TYPE(self)); + return 0; +} + static PyMethodDef BZ2Compressor_methods[] = { _BZ2_BZ2COMPRESSOR_COMPRESS_METHODDEF _BZ2_BZ2COMPRESSOR_FLUSH_METHODDEF @@ -402,6 +409,7 @@ static PyType_Slot bz2_compressor_type_slots[] = { {Py_tp_methods, BZ2Compressor_methods}, {Py_tp_new, _bz2_BZ2Compressor}, {Py_tp_doc, (char *)_bz2_BZ2Compressor__doc__}, + {Py_tp_traverse, BZ2Compressor_traverse}, {0, 0} }; @@ -695,6 +703,13 @@ BZ2Decompressor_dealloc(PyObject *op) Py_DECREF(tp); } +static int +BZ2Decompressor_traverse(PyObject *self, visitproc visit, void *arg) +{ + Py_VISIT(Py_TYPE(self)); + return 0; +} + static PyMethodDef BZ2Decompressor_methods[] = { _BZ2_BZ2DECOMPRESSOR_DECOMPRESS_METHODDEF {NULL} @@ -725,7 +740,7 @@ static PyType_Slot bz2_decompressor_type_slots[] = { {Py_tp_doc, (char *)_bz2_BZ2Decompressor__doc__}, {Py_tp_members, BZ2Decompressor_members}, {Py_tp_new, _bz2_BZ2Decompressor}, - {Py_tp_traverse, _PyObject_VisitType}, + {Py_tp_traverse, BZ2Decompressor_traverse}, {0, 0} }; diff --git a/Modules/_lzmamodule.c b/Modules/_lzmamodule.c index f7360fe897c03e..0b0b1bc765bbc9 100644 --- a/Modules/_lzmamodule.c +++ b/Modules/_lzmamodule.c @@ -882,6 +882,13 @@ static PyMethodDef Compressor_methods[] = { {NULL} }; +static int +Compressor_traverse(PyObject *self, visitproc visit, void *arg) +{ + Py_VISIT(Py_TYPE(self)); + return 0; +} + PyDoc_STRVAR(Compressor_doc, "LZMACompressor(format=FORMAT_XZ, check=-1, preset=None, filters=None)\n" "\n" @@ -915,6 +922,7 @@ static PyType_Slot lzma_compressor_type_slots[] = { {Py_tp_methods, Compressor_methods}, {Py_tp_new, Compressor_new}, {Py_tp_doc, (char *)Compressor_doc}, + {Py_tp_traverse, Compressor_traverse}, {0, 0} }; @@ -1320,6 +1328,13 @@ Decompressor_dealloc(PyObject *op) Py_DECREF(tp); } +static int +Decompressor_traverse(PyObject *self, visitproc visit, void *arg) +{ + Py_VISIT(Py_TYPE(self)); + return 0; +} + static PyMethodDef Decompressor_methods[] = { _LZMA_LZMADECOMPRESSOR_DECOMPRESS_METHODDEF {NULL} @@ -1354,7 +1369,7 @@ static PyType_Slot lzma_decompressor_type_slots[] = { {Py_tp_methods, Decompressor_methods}, {Py_tp_new, _lzma_LZMADecompressor}, {Py_tp_doc, (char *)_lzma_LZMADecompressor__doc__}, - {Py_tp_traverse, _PyObject_VisitType}, + {Py_tp_traverse, Decompressor_traverse}, {Py_tp_members, Decompressor_members}, {0, 0} };