From 94fbaac58def9d3c289e5904e82a1598d4577f9a Mon Sep 17 00:00:00 2001 From: Antoine Pitrou Date: Thu, 24 Jun 2010 22:49:57 +0000 Subject: Merged revisions 82204 via svnmerge from svn+ssh://pythondev@svn.python.org/python/branches/py3k ........ r82204 | antoine.pitrou | 2010-06-25 00:34:04 +0200 (ven., 25 juin 2010) | 5 lines 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. ........ --- Misc/NEWS | 4 +++ Modules/_ssl.c | 80 ++++++++++++++++++++++++++++++++++++++-------------------- 2 files changed, 57 insertions(+), 27 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS index e63f266..0a1dffd 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -72,6 +72,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. diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 5bc2e50..52fd3f9 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -199,8 +199,11 @@ PySSL_SetError(PySSLObject *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"; @@ -454,6 +457,7 @@ static PyObject *PySSL_SSLdo_handshake(PySSLObject *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); @@ -468,9 +472,8 @@ static PyObject *PySSL_SSLdo_handshake(PySSLObject *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) { @@ -481,19 +484,20 @@ static PyObject *PySSL_SSLdo_handshake(PySSLObject *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; @@ -506,6 +510,10 @@ static PyObject *PySSL_SSLdo_handshake(PySSLObject *self) Py_INCREF(Py_None); return Py_None; + +error: + Py_DECREF(sock); + return NULL; } static PyObject * @@ -1175,9 +1183,12 @@ static PyObject *PySSL_SSLwrite(PySSLObject *self, PyObject *args) PY_SSL_ERROR_NO_SOCKET, __FILE__, __LINE__); return NULL; } + Py_INCREF(sock); - if (!PyArg_ParseTuple(args, "y#:write", &data, &count)) + if (!PyArg_ParseTuple(args, "y#:write", &data, &count)) { + Py_DECREF(sock); return NULL; + } /* just in case the blocking state of the socket has been changed */ nonblocking = (sock->sock_timeout >= 0.0); @@ -1188,15 +1199,15 @@ static PyObject *PySSL_SSLwrite(PySSLObject *self, PyObject *args) if (sockstate == SOCKET_HAS_TIMED_OUT) { PyErr_SetString(PySSLErrorObject, "The write operation timed out"); - return NULL; + goto error; } else if (sockstate == SOCKET_HAS_BEEN_CLOSED) { PyErr_SetString(PySSLErrorObject, "Underlying socket has been closed."); - 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; } do { err = 0; @@ -1204,9 +1215,8 @@ static PyObject *PySSL_SSLwrite(PySSLObject *self, PyObject *args) len = SSL_write(self->ssl, data, count); err = SSL_get_error(self->ssl, len); 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) { @@ -1217,19 +1227,25 @@ static PyObject *PySSL_SSLwrite(PySSLObject *self, PyObject *args) if (sockstate == SOCKET_HAS_TIMED_OUT) { PyErr_SetString(PySSLErrorObject, "The write operation timed out"); - return NULL; + goto error; } else if (sockstate == SOCKET_HAS_BEEN_CLOSED) { PyErr_SetString(PySSLErrorObject, "Underlying socket has been closed."); - 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 (len > 0) return PyLong_FromLong(len); else return PySSL_SetError(self, len, __FILE__, __LINE__); + +error: + Py_DECREF(sock); + return NULL; } PyDoc_STRVAR(PySSL_SSLwrite_doc, @@ -1277,21 +1293,23 @@ static PyObject *PySSL_SSLread(PySSLObject *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)) @@ -1358,6 +1376,7 @@ static PyObject *PySSL_SSLread(PySSLObject *self, PyObject *args) goto error; } done: + Py_DECREF(sock); if (!buf_passed) { PyObject *res = PyBytes_FromStringAndSize(mem, count); Py_DECREF(dest); @@ -1367,8 +1386,9 @@ static PyObject *PySSL_SSLread(PySSLObject *self, PyObject *args) return PyLong_FromLong(count); } error: + Py_DECREF(sock); if (!buf_passed) { - Py_DECREF(dest); + Py_XDECREF(dest); } else { PyBuffer_Release(&buf); } @@ -1393,6 +1413,7 @@ static PyObject *PySSL_SSLshutdown(PySSLObject *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); @@ -1442,24 +1463,29 @@ static PyObject *PySSL_SSLshutdown(PySSLObject *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, -- cgit v0.12