Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 03b5c9a

Browse files
committed
Fix the leaks in test_ssl. Issue 1469. Patch by Christian Heimes:
(a) added GC support to the PySSL object (b) move the call to _real_close() from __del__ methods in Python to PySSL_dealloc(). (c) remove those __del__ methods -- this makes SSL and socket objects GC'able.
1 parent 4b28041 commit 03b5c9a

2 files changed

Lines changed: 64 additions & 16 deletions

File tree

Lib/ssl.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,10 @@ def __init__(self, sock=None, keyfile=None, certfile=None,
148148
self.do_handshake_on_connect = do_handshake_on_connect
149149
self.suppress_ragged_eofs = suppress_ragged_eofs
150150

151+
# See Modules/_ssl.c:PySSL_dealloc()
152+
# def __del__(self):
153+
# self._real_close()
154+
151155
def dup(self):
152156
raise NotImplemented("Can't dup() %s instances" %
153157
self.__class__.__name__)
@@ -300,6 +304,7 @@ def shutdown(self, how):
300304
socket.shutdown(self, how)
301305

302306
def _real_close(self):
307+
# real close is called by Modules/_ssl.c:PySSL_dealloc()
303308
self._sslobj = None
304309
# self._closed = True
305310
if self._base:
@@ -348,10 +353,6 @@ def accept(self):
348353
self.do_handshake_on_connect),
349354
addr)
350355

351-
352-
def __del__(self):
353-
self._real_close()
354-
355356
def wrap_socket(sock, keyfile=None, certfile=None,
356357
server_side=False, cert_reqs=CERT_NONE,
357358
ssl_version=PROTOCOL_SSLv23, ca_certs=None,

Modules/_ssl.c

Lines changed: 59 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ newPySSLObject(PySocketSockObject *Sock, char *key_file, char *cert_file,
266266
int ret;
267267
int verification_mode;
268268

269-
self = PyObject_New(PySSLObject, &PySSL_Type); /* Create new object */
269+
self = PyObject_GC_New(PySSLObject, &PySSL_Type); /* Create new object */
270270
if (self == NULL)
271271
return NULL;
272272
self->peer_cert = NULL;
@@ -385,6 +385,7 @@ newPySSLObject(PySocketSockObject *Sock, char *key_file, char *cert_file,
385385

386386
self->Socket = Sock;
387387
Py_INCREF(self->Socket);
388+
_PyObject_GC_TRACK(self);
388389
return self;
389390
fail:
390391
if (errstr)
@@ -1050,16 +1051,41 @@ static PyObject *PySSL_cipher (PySSLObject *self) {
10501051
return NULL;
10511052
}
10521053

1053-
static void PySSL_dealloc(PySSLObject *self)
1054+
/* GC support. */
1055+
static int
1056+
PySSL_traverse(PySSLObject *self, visitproc visit, void *arg)
1057+
{
1058+
Py_VISIT(self->Socket);
1059+
return 0;
1060+
}
1061+
1062+
static int
1063+
PySSL_clear(PySSLObject *self)
1064+
{
1065+
Py_CLEAR(self->Socket);
1066+
return 0;
1067+
}
1068+
1069+
static void
1070+
PySSL_dealloc(PySSLObject *self)
10541071
{
1072+
PyObject *o;
1073+
PyObject *exc_type, *exc_value, *exc_tb;
1074+
1075+
PyErr_Fetch(&exc_type, &exc_value, &exc_tb);
1076+
o = PyObject_CallMethod((PyObject*)self, "_real_close", NULL);
1077+
Py_XDECREF(o);
1078+
PyErr_Restore(exc_type, exc_value, exc_tb);
1079+
1080+
PyObject_GC_UnTrack(self);
10551081
if (self->peer_cert) /* Possible not to have one? */
1056-
X509_free (self->peer_cert);
1082+
X509_free(self->peer_cert);
10571083
if (self->ssl)
10581084
SSL_free(self->ssl);
10591085
if (self->ctx)
10601086
SSL_CTX_free(self->ctx);
1061-
Py_XDECREF(self->Socket);
1062-
PyObject_Del(self);
1087+
Py_CLEAR(self->Socket);
1088+
Py_Type(self)->tp_free((PyObject *)self);
10631089
}
10641090

10651091
/* If the socket has a timeout, do a select()/poll() on the socket.
@@ -1359,27 +1385,48 @@ static PyMethodDef PySSLMethods[] = {
13591385
{NULL, NULL}
13601386
};
13611387

1362-
static PyObject *PySSL_getattr(PySSLObject *self, char *name)
1363-
{
1364-
return Py_FindMethod(PySSLMethods, (PyObject *)self, name);
1365-
}
1366-
13671388
static PyTypeObject PySSL_Type = {
13681389
PyVarObject_HEAD_INIT(NULL, 0)
1369-
"ssl.SSLContext", /*tp_name*/
1390+
"_ssl.SSLContext", /*tp_name*/
13701391
sizeof(PySSLObject), /*tp_basicsize*/
13711392
0, /*tp_itemsize*/
13721393
/* methods */
13731394
(destructor)PySSL_dealloc, /*tp_dealloc*/
13741395
0, /*tp_print*/
1375-
(getattrfunc)PySSL_getattr, /*tp_getattr*/
1396+
0, /*tp_getattr*/
13761397
0, /*tp_setattr*/
13771398
0, /*tp_compare*/
13781399
0, /*tp_repr*/
13791400
0, /*tp_as_number*/
13801401
0, /*tp_as_sequence*/
13811402
0, /*tp_as_mapping*/
13821403
0, /*tp_hash*/
1404+
0, /* tp_call */
1405+
0, /* tp_str */
1406+
PyObject_GenericGetAttr, /* tp_getattro */
1407+
0, /* tp_setattro */
1408+
0, /* tp_as_buffer */
1409+
Py_TPFLAGS_DEFAULT |
1410+
Py_TPFLAGS_HAVE_GC, /* tp_flags */
1411+
0, /* tp_doc */
1412+
(traverseproc)PySSL_traverse, /* tp_traverse */
1413+
(inquiry)PySSL_clear, /* tp_clear */
1414+
0, /* tp_richcompare */
1415+
0, /* tp_weaklistoffset */
1416+
0, /* tp_iter */
1417+
0, /* tp_iternext */
1418+
PySSLMethods, /* tp_methods */
1419+
0, /* tp_members */
1420+
0, /* tp_getset */
1421+
0, /* tp_base */
1422+
0, /* tp_dict */
1423+
0, /* tp_descr_get */
1424+
0, /* tp_descr_set */
1425+
0, /* tp_dictoffset */
1426+
0, /* tp_init */
1427+
PyType_GenericAlloc, /* tp_alloc */
1428+
PyType_GenericNew, /* tp_new */
1429+
PyObject_GC_Del, /* tp_free */
13831430
};
13841431

13851432
#ifdef HAVE_OPENSSL_RAND

0 commit comments

Comments
 (0)