]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Fix the leaks in test_ssl. Issue 1469. Patch by Christian Heimes:
authorGuido van Rossum <guido@python.org>
Thu, 6 Dec 2007 18:39:46 +0000 (18:39 +0000)
committerGuido van Rossum <guido@python.org>
Thu, 6 Dec 2007 18:39:46 +0000 (18:39 +0000)
(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.

Lib/ssl.py
Modules/_ssl.c

index be138661112d6ca55e2e3a48e8aac5f5eddb3173..a6619d643e98b497c1d6579f48a34010bcceb819 100644 (file)
@@ -148,6 +148,10 @@ class SSLSocket(socket):
         self.do_handshake_on_connect = do_handshake_on_connect
         self.suppress_ragged_eofs = suppress_ragged_eofs
 
+    # See Modules/_ssl.c:PySSL_dealloc()
+    # def __del__(self):
+    #    self._real_close()
+
     def dup(self):
         raise NotImplemented("Can't dup() %s instances" %
                              self.__class__.__name__)
@@ -300,6 +304,7 @@ class SSLSocket(socket):
         socket.shutdown(self, how)
 
     def _real_close(self):
+        # real close is called by Modules/_ssl.c:PySSL_dealloc()
         self._sslobj = None
         # self._closed = True
         if self._base:
@@ -348,10 +353,6 @@ class SSLSocket(socket):
                               self.do_handshake_on_connect),
                 addr)
 
-
-    def __del__(self):
-        self._real_close()
-
 def wrap_socket(sock, keyfile=None, certfile=None,
                 server_side=False, cert_reqs=CERT_NONE,
                 ssl_version=PROTOCOL_SSLv23, ca_certs=None,
index bd3f17262ae87ef73a036ea82b29705f5d2fcea2..1aedaf8a7aed0e730c27bea411a48bff172a909a 100644 (file)
@@ -266,7 +266,7 @@ newPySSLObject(PySocketSockObject *Sock, char *key_file, char *cert_file,
        int ret;
        int verification_mode;
 
-       self = PyObject_New(PySSLObject, &PySSL_Type); /* Create new object */
+       self = PyObject_GC_New(PySSLObject, &PySSL_Type); /* Create new object */
        if (self == NULL)
                return NULL;
        self->peer_cert = NULL;
@@ -385,6 +385,7 @@ newPySSLObject(PySocketSockObject *Sock, char *key_file, char *cert_file,
 
        self->Socket = Sock;
        Py_INCREF(self->Socket);
+       _PyObject_GC_TRACK(self);
        return self;
  fail:
        if (errstr)
@@ -1050,16 +1051,41 @@ static PyObject *PySSL_cipher (PySSLObject *self) {
        return NULL;
 }
 
-static void PySSL_dealloc(PySSLObject *self)
+/* GC support. */
+static int
+PySSL_traverse(PySSLObject *self, visitproc visit, void *arg)
+{
+       Py_VISIT(self->Socket);
+       return 0;
+}
+
+static int
+PySSL_clear(PySSLObject *self)
+{
+       Py_CLEAR(self->Socket);
+       return 0;
+}
+
+static void
+PySSL_dealloc(PySSLObject *self)
 {
+       PyObject *o;
+       PyObject *exc_type, *exc_value, *exc_tb;
+
+       PyErr_Fetch(&exc_type, &exc_value, &exc_tb);
+       o = PyObject_CallMethod((PyObject*)self, "_real_close", NULL);
+       Py_XDECREF(o);
+       PyErr_Restore(exc_type, exc_value, exc_tb);
+       
+       PyObject_GC_UnTrack(self);
        if (self->peer_cert)    /* Possible not to have one? */
-               X509_free (self->peer_cert);
+               X509_free(self->peer_cert);
        if (self->ssl)
                SSL_free(self->ssl);
        if (self->ctx)
                SSL_CTX_free(self->ctx);
-       Py_XDECREF(self->Socket);
-       PyObject_Del(self);
+       Py_CLEAR(self->Socket);
+       Py_Type(self)->tp_free((PyObject *)self);
 }
 
 /* If the socket has a timeout, do a select()/poll() on the socket.
@@ -1359,20 +1385,15 @@ static PyMethodDef PySSLMethods[] = {
        {NULL, NULL}
 };
 
-static PyObject *PySSL_getattr(PySSLObject *self, char *name)
-{
-       return Py_FindMethod(PySSLMethods, (PyObject *)self, name);
-}
-
 static PyTypeObject PySSL_Type = {
        PyVarObject_HEAD_INIT(NULL, 0)
-       "ssl.SSLContext",               /*tp_name*/
+       "_ssl.SSLContext",              /*tp_name*/
        sizeof(PySSLObject),            /*tp_basicsize*/
        0,                              /*tp_itemsize*/
        /* methods */
        (destructor)PySSL_dealloc,      /*tp_dealloc*/
        0,                              /*tp_print*/
-       (getattrfunc)PySSL_getattr,     /*tp_getattr*/
+       0,                              /*tp_getattr*/
        0,                              /*tp_setattr*/
        0,                              /*tp_compare*/
        0,                              /*tp_repr*/
@@ -1380,6 +1401,32 @@ static PyTypeObject PySSL_Type = {
        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_HAVE_GC,     /* tp_flags */
+       0,                              /* tp_doc */
+       (traverseproc)PySSL_traverse,   /* tp_traverse */
+       (inquiry)PySSL_clear,           /* tp_clear */
+       0,                              /* tp_richcompare */
+       0,                              /* tp_weaklistoffset */
+       0,                              /* tp_iter */
+       0,                              /* tp_iternext */
+       PySSLMethods,                   /* tp_methods */
+       0,                              /* tp_members */
+       0,                              /* tp_getset */
+       0,                              /* tp_base */
+       0,                              /* tp_dict */
+       0,                              /* tp_descr_get */
+       0,                              /* tp_descr_set */
+       0,                              /* tp_dictoffset */
+       0,                              /* tp_init */
+       PyType_GenericAlloc,            /* tp_alloc */
+       PyType_GenericNew,              /* tp_new */
+       PyObject_GC_Del,                /* tp_free */
 };
 
 #ifdef HAVE_OPENSSL_RAND