diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index 0f56d94229fbaf..1705b1866bf1c3 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -510,16 +510,25 @@ remove_unusable_flags(PyObject *m) /* XXX There's a problem here: *static* functions are not supposed to have a Py prefix (or use CapitalizedWords). Later... */ -/* Global variable holding the exception type for errors detected - by this module (but not argument type or memory errors, etc.). */ -static PyObject *socket_herror; -static PyObject *socket_gaierror; +typedef struct { + /* Variable holding the exception type for errors detected + by this module (but not argument type or memory errors, etc.). */ + PyObject *socket_herror; + PyObject *socket_gaierror; + + /* The sock_type variable contains pointers to various functions, + some of which call new_sockobject(), which uses sock_type, so + there has to be a circular reference. */ + PyTypeObject *sock_type; +} socket_state; + +static socket_state global_state; -/* A forward reference to the socket type object. - The sock_type variable contains pointers to various functions, - some of which call new_sockobject(), which uses sock_type, so - there has to be a circular reference. */ -static PyTypeObject sock_type; +socket_state * +socket_get_state(void) +{ + return &global_state; +} #if defined(HAVE_POLL_H) #include @@ -619,7 +628,8 @@ set_herror(int h_error) v = Py_BuildValue("(is)", h_error, "host not found"); #endif if (v != NULL) { - PyErr_SetObject(socket_herror, v); + socket_state *state = socket_get_state(); + PyErr_SetObject(state->socket_herror, v); Py_DECREF(v); } @@ -644,7 +654,8 @@ set_gaierror(int error) v = Py_BuildValue("(is)", error, "getaddrinfo failed"); #endif if (v != NULL) { - PyErr_SetObject(socket_gaierror, v); + socket_state *state = socket_get_state(); + PyErr_SetObject(state->socket_gaierror, v); Py_DECREF(v); } @@ -1008,8 +1019,9 @@ static PySocketSockObject * new_sockobject(SOCKET_T fd, int family, int type, int proto) { PySocketSockObject *s; + socket_state *state = socket_get_state(); s = (PySocketSockObject *) - PyType_GenericNew(&sock_type, NULL, NULL); + PyType_GenericNew(state->sock_type, NULL, NULL); if (s == NULL) return NULL; if (init_sockobject(s, fd, family, type, proto) == -1) { @@ -5026,10 +5038,13 @@ sock_finalize(PySocketSockObject *s) static void sock_dealloc(PySocketSockObject *s) { + PyTypeObject *tp = Py_TYPE(s); + if (PyObject_CallFinalizerFromDealloc((PyObject *)s) < 0) return; - Py_TYPE(s)->tp_free((PyObject *)s); + tp->tp_free(s); + Py_DECREF(tp); } @@ -5314,56 +5329,27 @@ sock_initobj(PyObject *self, PyObject *args, PyObject *kwds) /* Type object for socket objects. */ +static PyType_Slot sock_slots[] = { + {Py_tp_dealloc, sock_dealloc}, + {Py_tp_repr, sock_repr}, + {Py_tp_getattro, PyObject_GenericGetAttr}, + {Py_tp_doc, (void *)sock_doc}, + {Py_tp_methods, sock_methods}, + {Py_tp_members, sock_memberlist}, + {Py_tp_getset, sock_getsetlist}, + {Py_tp_init, sock_initobj}, + {Py_tp_alloc, PyType_GenericAlloc}, + {Py_tp_new, sock_new}, + {Py_tp_free, PyObject_Del}, + {Py_tp_finalize, sock_finalize}, + {0, NULL}, +}; -static PyTypeObject sock_type = { - PyVarObject_HEAD_INIT(0, 0) /* Must fill in type value later */ - "_socket.socket", /* tp_name */ - sizeof(PySocketSockObject), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)sock_dealloc, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_as_async */ - (reprfunc)sock_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - sock_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - sock_methods, /* tp_methods */ - sock_memberlist, /* tp_members */ - sock_getsetlist, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - sock_initobj, /* tp_init */ - PyType_GenericAlloc, /* tp_alloc */ - sock_new, /* tp_new */ - PyObject_Del, /* tp_free */ - 0, /* tp_is_gc */ - 0, /* tp_bases */ - 0, /* tp_mro */ - 0, /* tp_cache */ - 0, /* tp_subclasses */ - 0, /* tp_weaklist */ - 0, /* tp_del */ - 0, /* tp_version_tag */ - (destructor)sock_finalize, /* tp_finalize */ +static PyType_Spec sock_spec = { + .name = "_socket.socket", + .basicsize = sizeof(PySocketSockObject), + .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + .slots = sock_slots, }; @@ -7058,7 +7044,8 @@ sock_get_api(void) return NULL; } - capi->Sock_Type = (PyTypeObject *)Py_NewRef(&sock_type); + socket_state *state = socket_get_state(); + capi->Sock_Type = (PyTypeObject *)Py_NewRef(state->sock_type); capi->error = Py_NewRef(PyExc_OSError); capi->timeout_error = Py_NewRef(PyExc_TimeoutError); return capi; @@ -7092,13 +7079,56 @@ static struct PyModuleDef socketmodule = { NULL }; +static void +socket_free_state(PyObject *Py_UNUSED(module)) +{ + socket_state *state = socket_get_state(); + Py_CLEAR(state->sock_type); + Py_CLEAR(state->socket_herror); + Py_CLEAR(state->socket_gaierror); +} + +static int +socket_init_state(PyObject *module) +{ + socket_state *state = socket_get_state(); + state->sock_type = (PyTypeObject *)PyType_FromModuleAndSpec(module, &sock_spec, NULL); + if (state->sock_type == NULL) { + goto error; + } + + state->socket_herror = PyErr_NewException("socket.herror", PyExc_OSError, NULL); + if (state->socket_herror == NULL) { + goto error; + } + + state->socket_gaierror = PyErr_NewException("socket.gaierror", PyExc_OSError, NULL); + if (state->socket_gaierror == NULL) { + goto error; + } + + return 0; + +error: + socket_free_state(module); + return -1; +} + +#define ADD_OBJ_REF(module, name, obj) \ + do { \ + if (PyModule_AddObjectRef(module, name, obj) < 0) { \ + goto error; \ + } \ + } while (0) + PyMODINIT_FUNC PyInit__socket(void) { - PyObject *m, *has_ipv6; + PyObject *m = NULL, *has_ipv6; - if (!os_init()) - return NULL; + if (!os_init()) { + goto error; + } #ifdef MS_WINDOWS if (support_wsa_no_inherit == -1) { @@ -7106,35 +7136,22 @@ PyInit__socket(void) } #endif - Py_SET_TYPE(&sock_type, &PyType_Type); m = PyModule_Create(&socketmodule); - if (m == NULL) - return NULL; + if (m == NULL) { + goto error; + } - Py_INCREF(PyExc_OSError); - PyModule_AddObject(m, "error", PyExc_OSError); - socket_herror = PyErr_NewException("socket.herror", - PyExc_OSError, NULL); - if (socket_herror == NULL) - return NULL; - Py_INCREF(socket_herror); - PyModule_AddObject(m, "herror", socket_herror); - socket_gaierror = PyErr_NewException("socket.gaierror", PyExc_OSError, - NULL); - if (socket_gaierror == NULL) - return NULL; - Py_INCREF(socket_gaierror); - PyModule_AddObject(m, "gaierror", socket_gaierror); - PyModule_AddObjectRef(m, "timeout", PyExc_TimeoutError); + if (socket_init_state(m)) { + goto error; + } - Py_INCREF((PyObject *)&sock_type); - if (PyModule_AddObject(m, "SocketType", - (PyObject *)&sock_type) != 0) - return NULL; - Py_INCREF((PyObject *)&sock_type); - if (PyModule_AddObject(m, "socket", - (PyObject *)&sock_type) != 0) - return NULL; + socket_state *state = socket_get_state(); + ADD_OBJ_REF(m, "SocketType", (PyObject *)state->sock_type); + ADD_OBJ_REF(m, "socket", (PyObject *)state->sock_type); + ADD_OBJ_REF(m, "herror", (PyObject *)state->socket_herror); + ADD_OBJ_REF(m, "gaierror", (PyObject *)state->socket_gaierror); + ADD_OBJ_REF(m, "error", PyExc_OSError); + ADD_OBJ_REF(m, "timeout", PyExc_TimeoutError); #ifdef ENABLE_IPV6 has_ipv6 = Py_True; @@ -8400,4 +8417,10 @@ PyInit__socket(void) #endif return m; + +error: + socket_free_state(m); + Py_XDECREF(m); + return NULL; } +#undef ADD_OBJ_REF