Merged revisions 65654 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk

........
  r65654 | martin.v.loewis | 2008-08-12 16:49:50 +0200 (Tue, 12 Aug 2008) | 6 lines

  Issue #3139: Make buffer-interface thread-safe wrt. PyArg_ParseTuple,
  by denying s# to parse objects that have a releasebuffer procedure,
  and introducing s*.

  More module might need to get converted to use s*.
........
diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c
index de802ae..7d91af2 100644
--- a/Modules/socketmodule.c
+++ b/Modules/socketmodule.c
@@ -2251,15 +2251,19 @@
 
 	int recvlen = 0, flags = 0;
         ssize_t readlen;
+	Py_buffer pbuf;
 	char *buf;
 	int buflen;
 
 	/* Get the buffer's memory */
-	if (!PyArg_ParseTupleAndKeywords(args, kwds, "w#|ii:recv_into", kwlist,
-					 &buf, &buflen, &recvlen, &flags))
+	if (!PyArg_ParseTupleAndKeywords(args, kwds, "w*|ii:recv_into", kwlist,
+					 &pbuf, &recvlen, &flags))
 		return NULL;
+	buf = pbuf.buf;
+	buflen = pbuf.len;
 
 	if (recvlen < 0) {
+		PyBuffer_Release(&pbuf);
 		PyErr_SetString(PyExc_ValueError,
 				"negative buffersize in recv_into");
 		return NULL;
@@ -2271,6 +2275,7 @@
 
 	/* Check if the buffer is large enough */
 	if (buflen < recvlen) {
+		PyBuffer_Release(&pbuf);
 		PyErr_SetString(PyExc_ValueError,
 				"buffer too small for requested bytes");
 		return NULL;
@@ -2280,9 +2285,11 @@
 	readlen = sock_recv_guts(s, buf, recvlen, flags);
 	if (readlen < 0) {
 		/* Return an error. */
+		PyBuffer_Release(&pbuf);
 		return NULL;
 	}
 
+	PyBuffer_Release(&pbuf);
 	/* Return the number of bytes read.  Note that we do not do anything
 	   special here in the case that readlen < recvlen. */
 	return PyLong_FromSsize_t(readlen);
@@ -2424,18 +2431,22 @@
 
 	int recvlen = 0, flags = 0;
         ssize_t readlen;
+	Py_buffer pbuf;
 	char *buf;
 	int buflen;
 
 	PyObject *addr = NULL;
 
-	if (!PyArg_ParseTupleAndKeywords(args, kwds, "w#|ii:recvfrom_into",
-					 kwlist, &buf, &buflen,
+	if (!PyArg_ParseTupleAndKeywords(args, kwds, "w*|ii:recvfrom_into",
+					 kwlist, &pbuf,
 					 &recvlen, &flags))
 		return NULL;
+	buf = pbuf.buf;
+	buflen = pbuf.len;
 	assert(buf != 0 && buflen > 0);
 
 	if (recvlen < 0) {
+		PyBuffer_Release(&pbuf);
 		PyErr_SetString(PyExc_ValueError,
 				"negative buffersize in recvfrom_into");
 		return NULL;
@@ -2447,11 +2458,13 @@
 
 	readlen = sock_recvfrom_guts(s, buf, recvlen, flags, &addr);
 	if (readlen < 0) {
+		PyBuffer_Release(&pbuf);
 		/* Return an error */
 		Py_XDECREF(addr);
 		return NULL;
 	}
 
+	PyBuffer_Release(&pbuf);
 	/* Return the number of bytes read and the address.  Note that we do
 	   not do anything special here in the case that readlen < recvlen. */
  	return Py_BuildValue("lN", readlen, addr);
@@ -2470,12 +2483,17 @@
 {
 	char *buf;
 	int len, n = -1, flags = 0, timeout;
+	Py_buffer pbuf;
 
-	if (!PyArg_ParseTuple(args, "y#|i:send", &buf, &len, &flags))
+	if (!PyArg_ParseTuple(args, "y*|i:send", &pbuf, &flags))
 		return NULL;
 
-	if (!IS_SELECTABLE(s))
+	if (!IS_SELECTABLE(s)) {
+		PyBuffer_Release(&pbuf);
 		return select_error();
+	}
+	buf = pbuf.buf;
+	len = pbuf.len;
 
 	Py_BEGIN_ALLOW_THREADS
 	timeout = internal_select(s, 1);
@@ -2487,6 +2505,8 @@
 #endif
 	Py_END_ALLOW_THREADS
 
+	PyBuffer_Release(&pbuf);
+
 	if (timeout == 1) {
 		PyErr_SetString(socket_timeout, "timed out");
 		return NULL;
@@ -2511,12 +2531,17 @@
 {
 	char *buf;
 	int len, n = -1, flags = 0, timeout;
+	Py_buffer pbuf;
 
-	if (!PyArg_ParseTuple(args, "y#|i:sendall", &buf, &len, &flags))
+	if (!PyArg_ParseTuple(args, "y*|i:sendall", &pbuf, &flags))
 		return NULL;
+	buf = pbuf.buf;
+	len = pbuf.len;
 
-	if (!IS_SELECTABLE(s))
+	if (!IS_SELECTABLE(s)) {
+		PyBuffer_Release(&pbuf);
 		return select_error();
+	}
 
 	Py_BEGIN_ALLOW_THREADS
 	do {
@@ -2535,6 +2560,7 @@
 		len -= n;
 	} while (len > 0);
 	Py_END_ALLOW_THREADS
+	PyBuffer_Release(&pbuf);
 
 	if (timeout == 1) {
 		PyErr_SetString(socket_timeout, "timed out");
@@ -2561,24 +2587,32 @@
 static PyObject *
 sock_sendto(PySocketSockObject *s, PyObject *args)
 {
+	Py_buffer pbuf;
 	PyObject *addro;
 	char *buf;
+	Py_ssize_t len;
 	sock_addr_t addrbuf;
-	int addrlen, len, n = -1, flags, timeout;
+	int addrlen, n = -1, flags, timeout;
 
 	flags = 0;
-	if (!PyArg_ParseTuple(args, "y#O:sendto", &buf, &len, &addro)) {
+	if (!PyArg_ParseTuple(args, "y*O:sendto", &pbuf, &addro)) {
 		PyErr_Clear();
-		if (!PyArg_ParseTuple(args, "y#iO:sendto",
-				      &buf, &len, &flags, &addro))
+		if (!PyArg_ParseTuple(args, "y*iO:sendto",
+				      &pbuf, &flags, &addro))
 			return NULL;
 	}
+	buf = pbuf.buf;
+	len = pbuf.len;
 
-	if (!IS_SELECTABLE(s))
+	if (!IS_SELECTABLE(s)) {
+		PyBuffer_Release(&pbuf);
 		return select_error();
+	}
 
-	if (!getsockaddrarg(s, addro, SAS2SA(&addrbuf), &addrlen))
+	if (!getsockaddrarg(s, addro, SAS2SA(&addrbuf), &addrlen)) {
+		PyBuffer_Release(&pbuf);
 		return NULL;
+	}
 
 	Py_BEGIN_ALLOW_THREADS
 	timeout = internal_select(s, 1);
@@ -2586,6 +2620,7 @@
 		n = sendto(s->sock_fd, buf, len, flags, SAS2SA(&addrbuf), addrlen);
 	Py_END_ALLOW_THREADS
 
+	PyBuffer_Release(&pbuf);
 	if (timeout == 1) {
 		PyErr_SetString(socket_timeout, "timed out");
 		return NULL;