From 5c1533b1047c51f984e7be1d017904038d8df7a7 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Mon, 28 Dec 2020 23:27:18 +0100 Subject: [PATCH 1/3] Convert socket to heap type --- Modules/socketmodule.c | 103 +++++++++++++++++------------------------ 1 file changed, 43 insertions(+), 60 deletions(-) diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index 0f56d94229fbaf..0d0041d785d01b 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -519,7 +519,7 @@ static 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. */ -static PyTypeObject sock_type; +static PyTypeObject *sock_type; #if defined(HAVE_POLL_H) #include @@ -1009,7 +1009,7 @@ new_sockobject(SOCKET_T fd, int family, int type, int proto) { PySocketSockObject *s; s = (PySocketSockObject *) - PyType_GenericNew(&sock_type, NULL, NULL); + PyType_GenericNew(sock_type, NULL, NULL); if (s == NULL) return NULL; if (init_sockobject(s, fd, family, type, proto) == -1) { @@ -5026,10 +5026,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,58 +5317,31 @@ 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, }; +static PyTypeObject *sock_type; + /* Python interface to gethostname(). */ @@ -7058,7 +7034,7 @@ sock_get_api(void) return NULL; } - capi->Sock_Type = (PyTypeObject *)Py_NewRef(&sock_type); + capi->Sock_Type = (PyTypeObject *)Py_NewRef(sock_type); capi->error = Py_NewRef(PyExc_OSError); capi->timeout_error = Py_NewRef(PyExc_TimeoutError); return capi; @@ -7106,11 +7082,16 @@ PyInit__socket(void) } #endif - Py_SET_TYPE(&sock_type, &PyType_Type); m = PyModule_Create(&socketmodule); if (m == NULL) return NULL; + sock_type = (PyTypeObject *)PyType_FromModuleAndSpec(m, &sock_spec, NULL); + if (!sock_type) { + Py_DECREF(m); + return NULL; + } + Py_INCREF(PyExc_OSError); PyModule_AddObject(m, "error", PyExc_OSError); socket_herror = PyErr_NewException("socket.herror", @@ -7127,14 +7108,16 @@ PyInit__socket(void) PyModule_AddObject(m, "gaierror", socket_gaierror); PyModule_AddObjectRef(m, "timeout", PyExc_TimeoutError); - Py_INCREF((PyObject *)&sock_type); - if (PyModule_AddObject(m, "SocketType", - (PyObject *)&sock_type) != 0) + Py_INCREF(sock_type); + if (PyModule_AddObject(m, "SocketType", (PyObject *)sock_type) < 0) { + Py_CLEAR(sock_type); return NULL; - Py_INCREF((PyObject *)&sock_type); - if (PyModule_AddObject(m, "socket", - (PyObject *)&sock_type) != 0) + } + Py_INCREF((PyObject *)sock_type); + if (PyModule_AddObject(m, "socket", (PyObject *)sock_type) < 0) { + Py_CLEAR(sock_type); return NULL; + } #ifdef ENABLE_IPV6 has_ipv6 = Py_True; From fc923e70455c1ddff7b7473a3454e22d16419ba8 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 6 Jan 2021 21:30:03 +0100 Subject: [PATCH 2/3] Establish global state --- Modules/socketmodule.c | 74 ++++++++++++++++++++++++------------------ 1 file changed, 43 insertions(+), 31 deletions(-) diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index 0d0041d785d01b..09755d75a0de3a 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) { @@ -5340,8 +5352,6 @@ static PyType_Spec sock_spec = { .slots = sock_slots, }; -static PyTypeObject *sock_type; - /* Python interface to gethostname(). */ @@ -7034,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; @@ -7086,36 +7097,37 @@ PyInit__socket(void) if (m == NULL) return NULL; - sock_type = (PyTypeObject *)PyType_FromModuleAndSpec(m, &sock_spec, NULL); - if (!sock_type) { + socket_state *state = socket_get_state(); + state->sock_type = (PyTypeObject *)PyType_FromModuleAndSpec(m, &sock_spec, NULL); + if (!state->sock_type) { Py_DECREF(m); return NULL; } Py_INCREF(PyExc_OSError); PyModule_AddObject(m, "error", PyExc_OSError); - socket_herror = PyErr_NewException("socket.herror", + state->socket_herror = PyErr_NewException("socket.herror", PyExc_OSError, NULL); - if (socket_herror == NULL) + if (state->socket_herror == NULL) return NULL; - Py_INCREF(socket_herror); - PyModule_AddObject(m, "herror", socket_herror); - socket_gaierror = PyErr_NewException("socket.gaierror", PyExc_OSError, + Py_INCREF(state->socket_herror); + PyModule_AddObject(m, "herror", state->socket_herror); + state->socket_gaierror = PyErr_NewException("socket.gaierror", PyExc_OSError, NULL); - if (socket_gaierror == NULL) + if (state->socket_gaierror == NULL) return NULL; - Py_INCREF(socket_gaierror); - PyModule_AddObject(m, "gaierror", socket_gaierror); + Py_INCREF(state->socket_gaierror); + PyModule_AddObject(m, "gaierror", state->socket_gaierror); PyModule_AddObjectRef(m, "timeout", PyExc_TimeoutError); - Py_INCREF(sock_type); - if (PyModule_AddObject(m, "SocketType", (PyObject *)sock_type) < 0) { - Py_CLEAR(sock_type); + Py_INCREF(state->sock_type); + if (PyModule_AddObject(m, "SocketType", (PyObject *)state->sock_type) < 0) { + Py_CLEAR(state->sock_type); return NULL; } - Py_INCREF((PyObject *)sock_type); - if (PyModule_AddObject(m, "socket", (PyObject *)sock_type) < 0) { - Py_CLEAR(sock_type); + Py_INCREF((PyObject *)state->sock_type); + if (PyModule_AddObject(m, "socket", (PyObject *)state->sock_type) < 0) { + Py_CLEAR(state->sock_type); return NULL; } From b41d9aaba196b6fbe2a37d7e745552e4f2b3a01d Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Fri, 8 Jan 2021 23:28:01 +0100 Subject: [PATCH 3/3] Clean up first part of init function --- Modules/socketmodule.c | 100 ++++++++++++++++++++++++++--------------- 1 file changed, 64 insertions(+), 36 deletions(-) diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index 09755d75a0de3a..1705b1866bf1c3 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -7079,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) { @@ -7094,43 +7137,22 @@ PyInit__socket(void) #endif m = PyModule_Create(&socketmodule); - if (m == NULL) - return NULL; - - socket_state *state = socket_get_state(); - state->sock_type = (PyTypeObject *)PyType_FromModuleAndSpec(m, &sock_spec, NULL); - if (!state->sock_type) { - Py_DECREF(m); - return NULL; + if (m == NULL) { + goto error; } - Py_INCREF(PyExc_OSError); - PyModule_AddObject(m, "error", PyExc_OSError); - state->socket_herror = PyErr_NewException("socket.herror", - PyExc_OSError, NULL); - if (state->socket_herror == NULL) - return NULL; - Py_INCREF(state->socket_herror); - PyModule_AddObject(m, "herror", state->socket_herror); - state->socket_gaierror = PyErr_NewException("socket.gaierror", PyExc_OSError, - NULL); - if (state->socket_gaierror == NULL) - return NULL; - Py_INCREF(state->socket_gaierror); - PyModule_AddObject(m, "gaierror", state->socket_gaierror); - PyModule_AddObjectRef(m, "timeout", PyExc_TimeoutError); - - Py_INCREF(state->sock_type); - if (PyModule_AddObject(m, "SocketType", (PyObject *)state->sock_type) < 0) { - Py_CLEAR(state->sock_type); - return NULL; - } - Py_INCREF((PyObject *)state->sock_type); - if (PyModule_AddObject(m, "socket", (PyObject *)state->sock_type) < 0) { - Py_CLEAR(state->sock_type); - return NULL; + if (socket_init_state(m)) { + goto error; } + 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; #else @@ -8395,4 +8417,10 @@ PyInit__socket(void) #endif return m; + +error: + socket_free_state(m); + Py_XDECREF(m); + return NULL; } +#undef ADD_OBJ_REF