]> granicus.if.org Git - python/commitdiff
Issue #8682: The ssl module now temporary increments the reference count of
authorAntoine Pitrou <solipsis@pitrou.net>
Thu, 24 Jun 2010 22:34:04 +0000 (22:34 +0000)
committerAntoine Pitrou <solipsis@pitrou.net>
Thu, 24 Jun 2010 22:34:04 +0000 (22:34 +0000)
a socket object got through `PyWeakref_GetObject`, so as to avoid possible
deallocation while the object is still being used.

Misc/NEWS
Modules/_ssl.c

index 46583e999a1ad452b38680763349f6c3f4363200..c6a8c6ebbb5dd0d4f7084aabd2527e78c021fc92 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -451,6 +451,10 @@ C-API
 Library
 -------
 
+- Issue #8682: The ssl module now temporary increments the reference count of
+  a socket object got through ``PyWeakref_GetObject``, so as to avoid possible
+  deallocation while the object is still being used.
+
 - Issue #1368368: FancyURLOpener class changed to throw an Exception on wrong
   password instead of presenting an interactive prompt. Older behavior can be
   obtained by passing retry=True to http_error_xxx methods of FancyURLOpener.
index a9c772aa9e41f430788dff5a868940b33fc60c25..31bf6263683b5f08f05c0625f4e7f280fc21c99e 100644 (file)
@@ -212,8 +212,11 @@ PySSL_SetError(PySSLSocket *obj, int ret, char *filename, int lineno)
                     errstr = "EOF occurred in violation of protocol";
                 } else if (ret == -1) {
                     /* underlying BIO reported an I/O error */
+                    Py_INCREF(s);
                     ERR_clear_error();
-                    return s->errorhandler();
+                    v = s->errorhandler();
+                    Py_DECREF(s);
+                    return v;
                 } else { /* possible? */
                     p = PY_SSL_ERROR_SYSCALL;
                     errstr = "Some I/O error occurred";
@@ -334,6 +337,7 @@ static PyObject *PySSL_SSLdo_handshake(PySSLSocket *self)
                      PY_SSL_ERROR_NO_SOCKET, __FILE__, __LINE__);
         return NULL;
     }
+    Py_INCREF(sock);
 
     /* just in case the blocking state of the socket has been changed */
     nonblocking = (sock->sock_timeout >= 0.0);
@@ -348,9 +352,8 @@ static PyObject *PySSL_SSLdo_handshake(PySSLSocket *self)
         ret = SSL_do_handshake(self->ssl);
         err = SSL_get_error(self->ssl, ret);
         PySSL_END_ALLOW_THREADS
-        if(PyErr_CheckSignals()) {
-            return NULL;
-        }
+        if (PyErr_CheckSignals())
+            goto error;
         if (err == SSL_ERROR_WANT_READ) {
             sockstate = check_socket_and_wait_for_timeout(sock, 0);
         } else if (err == SSL_ERROR_WANT_WRITE) {
@@ -361,19 +364,20 @@ static PyObject *PySSL_SSLdo_handshake(PySSLSocket *self)
         if (sockstate == SOCKET_HAS_TIMED_OUT) {
             PyErr_SetString(PySSLErrorObject,
                             ERRSTR("The handshake operation timed out"));
-            return NULL;
+            goto error;
         } else if (sockstate == SOCKET_HAS_BEEN_CLOSED) {
             PyErr_SetString(PySSLErrorObject,
                             ERRSTR("Underlying socket has been closed."));
-            return NULL;
+            goto error;
         } else if (sockstate == SOCKET_TOO_LARGE_FOR_SELECT) {
             PyErr_SetString(PySSLErrorObject,
                             ERRSTR("Underlying socket too large for select()."));
-            return NULL;
+            goto error;
         } else if (sockstate == SOCKET_IS_NONBLOCKING) {
             break;
         }
     } while (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE);
+    Py_DECREF(sock);
     if (ret < 1)
         return PySSL_SetError(self, ret, __FILE__, __LINE__);
     self->ssl->debug = 1;
@@ -386,6 +390,10 @@ static PyObject *PySSL_SSLdo_handshake(PySSLSocket *self)
 
     Py_INCREF(Py_None);
     return Py_None;
+
+error:
+    Py_DECREF(sock);
+    return NULL;
 }
 
 static PyObject *
@@ -1051,9 +1059,12 @@ static PyObject *PySSL_SSLwrite(PySSLSocket *self, PyObject *args)
                      PY_SSL_ERROR_NO_SOCKET, __FILE__, __LINE__);
         return NULL;
     }
+    Py_INCREF(sock);
 
-    if (!PyArg_ParseTuple(args, "y*:write", &buf))
+    if (!PyArg_ParseTuple(args, "y*:write", &buf)) {
+        Py_DECREF(sock);
         return NULL;
+    }
 
     /* just in case the blocking state of the socket has been changed */
     nonblocking = (sock->sock_timeout >= 0.0);
@@ -1103,6 +1114,7 @@ static PyObject *PySSL_SSLwrite(PySSLSocket *self, PyObject *args)
         }
     } while (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE);
 
+    Py_DECREF(sock);
     PyBuffer_Release(&buf);
     if (len > 0)
         return PyLong_FromLong(len);
@@ -1110,6 +1122,7 @@ static PyObject *PySSL_SSLwrite(PySSLSocket *self, PyObject *args)
         return PySSL_SetError(self, len, __FILE__, __LINE__);
 
 error:
+    Py_DECREF(sock);
     PyBuffer_Release(&buf);
     return NULL;
 }
@@ -1159,21 +1172,23 @@ static PyObject *PySSL_SSLread(PySSLSocket *self, PyObject *args)
                      PY_SSL_ERROR_NO_SOCKET, __FILE__, __LINE__);
         return NULL;
     }
+    Py_INCREF(sock);
 
     if (!PyArg_ParseTuple(args, "|Oi:read", &dest, &count))
-        return NULL;
+        goto error;
+
     if ((dest == NULL) || (dest == Py_None)) {
         if (!(dest = PyByteArray_FromStringAndSize((char *) 0, len)))
-            return NULL;
+            goto error;
         mem = PyByteArray_AS_STRING(dest);
     } else if (PyLong_Check(dest)) {
         len = PyLong_AS_LONG(dest);
         if (!(dest = PyByteArray_FromStringAndSize((char *) 0, len)))
-            return NULL;
+            goto error;
         mem = PyByteArray_AS_STRING(dest);
     } else {
         if (PyObject_GetBuffer(dest, &buf, PyBUF_CONTIG) < 0)
-            return NULL;
+            goto error;
         mem = buf.buf;
         len = buf.len;
         if ((count > 0) && (count <= len))
@@ -1240,6 +1255,7 @@ static PyObject *PySSL_SSLread(PySSLSocket *self, PyObject *args)
         goto error;
     }
   done:
+    Py_DECREF(sock);
     if (!buf_passed) {
         PyObject *res = PyBytes_FromStringAndSize(mem, count);
         Py_DECREF(dest);
@@ -1249,8 +1265,9 @@ static PyObject *PySSL_SSLread(PySSLSocket *self, PyObject *args)
         return PyLong_FromLong(count);
     }
   error:
+    Py_DECREF(sock);
     if (!buf_passed) {
-        Py_DECREF(dest);
+        Py_XDECREF(dest);
     } else {
         PyBuffer_Release(&buf);
     }
@@ -1275,6 +1292,7 @@ static PyObject *PySSL_SSLshutdown(PySSLSocket *self)
                      PY_SSL_ERROR_NO_SOCKET, __FILE__, __LINE__);
         return NULL;
     }
+    Py_INCREF(sock);
 
     /* Just in case the blocking state of the socket has been changed */
     nonblocking = (sock->sock_timeout >= 0.0);
@@ -1324,24 +1342,29 @@ static PyObject *PySSL_SSLshutdown(PySSLSocket *self)
             else
                 PyErr_SetString(PySSLErrorObject,
                                 "The write operation timed out");
-            return NULL;
+            goto error;
         }
         else if (sockstate == SOCKET_TOO_LARGE_FOR_SELECT) {
             PyErr_SetString(PySSLErrorObject,
                             "Underlying socket too large for select().");
-            return NULL;
+            goto error;
         }
         else if (sockstate != SOCKET_OPERATION_OK)
             /* Retain the SSL error code */
             break;
     }
 
-    if (err < 0)
+    if (err < 0) {
+        Py_DECREF(sock);
         return PySSL_SetError(self, err, __FILE__, __LINE__);
-    else {
-        Py_INCREF(sock);
-        return (PyObject *) sock;
     }
+    else
+        /* It's already INCREF'ed */
+        return (PyObject *) sock;
+
+error:
+    Py_DECREF(sock);
+    return NULL;
 }
 
 PyDoc_STRVAR(PySSL_SSLshutdown_doc,