From d478acfbe41db2a5a637dc0b5efb337db49382d3 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 21 Aug 2023 22:47:50 +0200 Subject: [PATCH] gh-108240: Fix a reference cycle in _socket.CAPI capsule _socket.CAPI capsule contains a strong reference to _socket.socket type. The garbage collector cannot visit this reference and so cannot create the reference cycle involving _socket.socket (a heap type creates a reference cycle to inside, via MRO and methods). At Python, _PyImport_ClearModules() sets _socket attributes to None which works around the issue. If the module is cleared from sys.modules manually, _PyImport_ClearModules() cannot set _socket.CAPI to None and so the issue cannot be worked around. Change _socket.CAPI to use a borrowed reference instead of a strong reference to allow clearing _socket.socket in this case. Co-authored-by: Kirill Podoprigora --- Modules/socketmodule.c | 3 +-- Modules/socketmodule.h | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index bb5edc368decb3..9a4dcd863bba52 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -7317,7 +7317,6 @@ os_init(void) static void sock_free_api(PySocketModule_APIObject *capi) { - Py_DECREF(capi->Sock_Type); Py_DECREF(capi->error); Py_DECREF(capi->timeout_error); PyMem_Free(capi); @@ -7339,7 +7338,7 @@ sock_get_api(socket_state *state) return NULL; } - capi->Sock_Type = (PyTypeObject *)Py_NewRef(state->sock_type); + capi->Sock_Type = state->sock_type; capi->error = Py_NewRef(PyExc_OSError); capi->timeout_error = Py_NewRef(PyExc_TimeoutError); return capi; diff --git a/Modules/socketmodule.h b/Modules/socketmodule.h index 47146a28e02c8f..51a4b8de3931b4 100644 --- a/Modules/socketmodule.h +++ b/Modules/socketmodule.h @@ -382,7 +382,7 @@ typedef struct { /* C API for usage by other Python modules. * Always add new things to the end for binary compatibility. */ typedef struct { - PyTypeObject *Sock_Type; + PyTypeObject *Sock_Type; // borrowed reference (gh-108240) PyObject *error; PyObject *timeout_error; } PySocketModule_APIObject;