summaryrefslogtreecommitdiffstats
path: root/Modules
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@redhat.com>2019-01-11 13:35:14 (GMT)
committerGitHub <noreply@github.com>2019-01-11 13:35:14 (GMT)
commit5485085b324a45307c1ff4ec7d85b5998d7d5e0d (patch)
treea1183c6a4bec97b23d427ed6425603e3db5ff4c2 /Modules
parentfd7d539be3ce1cc098a4f104b7a7816ca00add16 (diff)
downloadcpython-5485085b324a45307c1ff4ec7d85b5998d7d5e0d.zip
cpython-5485085b324a45307c1ff4ec7d85b5998d7d5e0d.tar.gz
cpython-5485085b324a45307c1ff4ec7d85b5998d7d5e0d.tar.bz2
bpo-32710: Fix _overlapped.Overlapped memory leaks (GH-11489)
Fix memory leaks in asyncio ProactorEventLoop on overlapped operation failures. Changes: * Implement the tp_traverse slot in the _overlapped.Overlapped type to help to break reference cycles and identify referrers in the garbage collector. * Always clear overlapped on failure: not only set type to TYPE_NOT_STARTED, but release also resources.
Diffstat (limited to 'Modules')
-rw-r--r--Modules/overlapped.c78
1 files changed, 54 insertions, 24 deletions
diff --git a/Modules/overlapped.c b/Modules/overlapped.c
index bbaa4fb..ef4390b 100644
--- a/Modules/overlapped.c
+++ b/Modules/overlapped.c
@@ -561,6 +561,28 @@ Overlapped_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
return (PyObject *)self;
}
+
+/* Note (bpo-32710): OverlappedType.tp_clear is not defined to not release
+ buffers while overlapped are still running, to prevent a crash. */
+static int
+Overlapped_clear(OverlappedObject *self)
+{
+ switch (self->type) {
+ case TYPE_READ:
+ case TYPE_ACCEPT:
+ Py_CLEAR(self->allocated_buffer);
+ break;
+ case TYPE_WRITE:
+ case TYPE_READINTO:
+ if (self->user_buffer.obj) {
+ PyBuffer_Release(&self->user_buffer);
+ }
+ break;
+ }
+ self->type = TYPE_NOT_STARTED;
+ return 0;
+}
+
static void
Overlapped_dealloc(OverlappedObject *self)
{
@@ -594,20 +616,11 @@ Overlapped_dealloc(OverlappedObject *self)
}
}
- if (self->overlapped.hEvent != NULL)
+ if (self->overlapped.hEvent != NULL) {
CloseHandle(self->overlapped.hEvent);
-
- switch (self->type) {
- case TYPE_READ:
- case TYPE_ACCEPT:
- Py_CLEAR(self->allocated_buffer);
- break;
- case TYPE_WRITE:
- case TYPE_READINTO:
- if (self->user_buffer.obj)
- PyBuffer_Release(&self->user_buffer);
- break;
}
+
+ Overlapped_clear(self);
PyObject_Del(self);
SetLastError(olderr);
}
@@ -723,8 +736,7 @@ do_ReadFile(OverlappedObject *self, HANDLE handle,
case ERROR_IO_PENDING:
Py_RETURN_NONE;
default:
- PyBuffer_Release(&self->user_buffer);
- self->type = TYPE_NOT_STARTED;
+ Overlapped_clear(self);
return SetFromWindowsErr(err);
}
}
@@ -827,7 +839,7 @@ do_WSARecv(OverlappedObject *self, HANDLE handle,
case ERROR_IO_PENDING:
Py_RETURN_NONE;
default:
- self->type = TYPE_NOT_STARTED;
+ Overlapped_clear(self);
return SetFromWindowsErr(err);
}
}
@@ -955,7 +967,7 @@ Overlapped_WriteFile(OverlappedObject *self, PyObject *args)
case ERROR_IO_PENDING:
Py_RETURN_NONE;
default:
- self->type = TYPE_NOT_STARTED;
+ Overlapped_clear(self);
return SetFromWindowsErr(err);
}
}
@@ -1012,8 +1024,7 @@ Overlapped_WSASend(OverlappedObject *self, PyObject *args)
case ERROR_IO_PENDING:
Py_RETURN_NONE;
default:
- PyBuffer_Release(&self->user_buffer);
- self->type = TYPE_NOT_STARTED;
+ Overlapped_clear(self);
return SetFromWindowsErr(err);
}
}
@@ -1063,7 +1074,7 @@ Overlapped_AcceptEx(OverlappedObject *self, PyObject *args)
case ERROR_IO_PENDING:
Py_RETURN_NONE;
default:
- self->type = TYPE_NOT_STARTED;
+ Overlapped_clear(self);
return SetFromWindowsErr(err);
}
}
@@ -1155,7 +1166,7 @@ Overlapped_ConnectEx(OverlappedObject *self, PyObject *args)
case ERROR_IO_PENDING:
Py_RETURN_NONE;
default:
- self->type = TYPE_NOT_STARTED;
+ Overlapped_clear(self);
return SetFromWindowsErr(err);
}
}
@@ -1194,7 +1205,7 @@ Overlapped_DisconnectEx(OverlappedObject *self, PyObject *args)
case ERROR_IO_PENDING:
Py_RETURN_NONE;
default:
- self->type = TYPE_NOT_STARTED;
+ Overlapped_clear(self);
return SetFromWindowsErr(err);
}
}
@@ -1249,7 +1260,7 @@ Overlapped_TransmitFile(OverlappedObject *self, PyObject *args)
case ERROR_IO_PENDING:
Py_RETURN_NONE;
default:
- self->type = TYPE_NOT_STARTED;
+ Overlapped_clear(self);
return SetFromWindowsErr(err);
}
}
@@ -1290,7 +1301,7 @@ Overlapped_ConnectNamedPipe(OverlappedObject *self, PyObject *args)
case ERROR_IO_PENDING:
Py_RETURN_FALSE;
default:
- self->type = TYPE_NOT_STARTED;
+ Overlapped_clear(self);
return SetFromWindowsErr(err);
}
}
@@ -1340,6 +1351,25 @@ Overlapped_getpending(OverlappedObject *self)
self->type != TYPE_NOT_STARTED);
}
+static int
+Overlapped_traverse(OverlappedObject *self, visitproc visit, void *arg)
+{
+ switch (self->type) {
+ case TYPE_READ:
+ case TYPE_ACCEPT:
+ Py_VISIT(self->allocated_buffer);
+ break;
+ case TYPE_WRITE:
+ case TYPE_READINTO:
+ if (self->user_buffer.obj) {
+ Py_VISIT(&self->user_buffer.obj);
+ }
+ break;
+ }
+ return 0;
+}
+
+
static PyMethodDef Overlapped_methods[] = {
{"getresult", (PyCFunction) Overlapped_getresult,
METH_VARARGS, Overlapped_getresult_doc},
@@ -1410,7 +1440,7 @@ PyTypeObject OverlappedType = {
/* tp_as_buffer */ 0,
/* tp_flags */ Py_TPFLAGS_DEFAULT,
/* tp_doc */ "OVERLAPPED structure wrapper",
- /* tp_traverse */ 0,
+ /* tp_traverse */ (traverseproc)Overlapped_traverse,
/* tp_clear */ 0,
/* tp_richcompare */ 0,
/* tp_weaklistoffset */ 0,