mirror of
https://github.com/python/cpython.git
synced 2025-09-14 04:37:29 +00:00
Add socket finalizer
Issue #26590: Implement a safe finalizer for the _socket.socket type. It now releases the GIL to close the socket. Use PyErr_ResourceWarning() to raise the ResourceWarning to pass the socket object to the warning logger, to get the traceback where the socket was created (allocated).
This commit is contained in:
parent
322bc12c31
commit
19a8e844e4
2 changed files with 58 additions and 20 deletions
|
@ -232,6 +232,9 @@ Core and Builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue #26590: Implement a safe finalizer for the _socket.socket type. It now
|
||||||
|
releases the GIL to close the socket.
|
||||||
|
|
||||||
- Issue #18787: spwd.getspnam() now raises a PermissionError if the user
|
- Issue #18787: spwd.getspnam() now raises a PermissionError if the user
|
||||||
doesn't have privileges.
|
doesn't have privileges.
|
||||||
|
|
||||||
|
|
|
@ -2564,12 +2564,14 @@ sock_close(PySocketSockObject *s)
|
||||||
{
|
{
|
||||||
SOCKET_T fd;
|
SOCKET_T fd;
|
||||||
|
|
||||||
/* We do not want to retry upon EINTR: see http://lwn.net/Articles/576478/
|
fd = s->sock_fd;
|
||||||
* and http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
|
if (fd != -1) {
|
||||||
* for more details.
|
|
||||||
*/
|
|
||||||
if ((fd = s->sock_fd) != -1) {
|
|
||||||
s->sock_fd = -1;
|
s->sock_fd = -1;
|
||||||
|
|
||||||
|
/* We do not want to retry upon EINTR: see
|
||||||
|
http://lwn.net/Articles/576478/ and
|
||||||
|
http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
|
||||||
|
for more details. */
|
||||||
Py_BEGIN_ALLOW_THREADS
|
Py_BEGIN_ALLOW_THREADS
|
||||||
(void) SOCKETCLOSE(fd);
|
(void) SOCKETCLOSE(fd);
|
||||||
Py_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS
|
||||||
|
@ -4162,23 +4164,46 @@ static PyGetSetDef sock_getsetlist[] = {
|
||||||
/* Deallocate a socket object in response to the last Py_DECREF().
|
/* Deallocate a socket object in response to the last Py_DECREF().
|
||||||
First close the file description. */
|
First close the file description. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
sock_finalize(PySocketSockObject *s)
|
||||||
|
{
|
||||||
|
SOCKET_T fd;
|
||||||
|
PyObject *error_type, *error_value, *error_traceback;
|
||||||
|
|
||||||
|
/* Save the current exception, if any. */
|
||||||
|
PyErr_Fetch(&error_type, &error_value, &error_traceback);
|
||||||
|
|
||||||
|
if (s->sock_fd != -1) {
|
||||||
|
if (PyErr_ResourceWarning((PyObject *)s, 1, "unclosed %R", s)) {
|
||||||
|
/* Spurious errors can appear at shutdown */
|
||||||
|
if (PyErr_ExceptionMatches(PyExc_Warning)) {
|
||||||
|
PyErr_WriteUnraisable((PyObject *)s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Only close the socket *after* logging the ResourceWarning warning
|
||||||
|
to allow the logger to call socket methods like
|
||||||
|
socket.getsockname(). If the socket is closed before, socket
|
||||||
|
methods fails with the EBADF error. */
|
||||||
|
fd = s->sock_fd;
|
||||||
|
s->sock_fd = -1;
|
||||||
|
|
||||||
|
/* We do not want to retry upon EINTR: see sock_close() */
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
|
(void) SOCKETCLOSE(fd);
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Restore the saved exception. */
|
||||||
|
PyErr_Restore(error_type, error_value, error_traceback);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
sock_dealloc(PySocketSockObject *s)
|
sock_dealloc(PySocketSockObject *s)
|
||||||
{
|
{
|
||||||
if (s->sock_fd != -1) {
|
if (PyObject_CallFinalizerFromDealloc((PyObject *)s) < 0)
|
||||||
PyObject *exc, *val, *tb;
|
return;
|
||||||
Py_ssize_t old_refcount = Py_REFCNT(s);
|
|
||||||
++Py_REFCNT(s);
|
|
||||||
PyErr_Fetch(&exc, &val, &tb);
|
|
||||||
if (PyErr_WarnFormat(PyExc_ResourceWarning, 1,
|
|
||||||
"unclosed %R", s))
|
|
||||||
/* Spurious errors can appear at shutdown */
|
|
||||||
if (PyErr_ExceptionMatches(PyExc_Warning))
|
|
||||||
PyErr_WriteUnraisable((PyObject *) s);
|
|
||||||
PyErr_Restore(exc, val, tb);
|
|
||||||
(void) SOCKETCLOSE(s->sock_fd);
|
|
||||||
Py_REFCNT(s) = old_refcount;
|
|
||||||
}
|
|
||||||
Py_TYPE(s)->tp_free((PyObject *)s);
|
Py_TYPE(s)->tp_free((PyObject *)s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4395,7 +4420,8 @@ static PyTypeObject sock_type = {
|
||||||
PyObject_GenericGetAttr, /* tp_getattro */
|
PyObject_GenericGetAttr, /* tp_getattro */
|
||||||
0, /* tp_setattro */
|
0, /* tp_setattro */
|
||||||
0, /* tp_as_buffer */
|
0, /* tp_as_buffer */
|
||||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
|
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
|
||||||
|
| Py_TPFLAGS_HAVE_FINALIZE, /* tp_flags */
|
||||||
sock_doc, /* tp_doc */
|
sock_doc, /* tp_doc */
|
||||||
0, /* tp_traverse */
|
0, /* tp_traverse */
|
||||||
0, /* tp_clear */
|
0, /* tp_clear */
|
||||||
|
@ -4415,6 +4441,15 @@ static PyTypeObject sock_type = {
|
||||||
PyType_GenericAlloc, /* tp_alloc */
|
PyType_GenericAlloc, /* tp_alloc */
|
||||||
sock_new, /* tp_new */
|
sock_new, /* tp_new */
|
||||||
PyObject_Del, /* tp_free */
|
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 */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue