Issue #23001: Few functions in modules mmap, ossaudiodev, socket, ssl, and

codecs, that accepted only read-only bytes-like object now accept writable
bytes-like object too.
This commit is contained in:
Serhiy Storchaka 2015-03-20 09:00:36 +02:00
parent 0eac13052c
commit 8490f5acfe
14 changed files with 196 additions and 104 deletions

View File

@ -174,6 +174,9 @@ To map anonymous memory, -1 should be passed as the fileno along with the length
Optional arguments *start* and *end* are interpreted as in slice notation. Optional arguments *start* and *end* are interpreted as in slice notation.
Returns ``-1`` on failure. Returns ``-1`` on failure.
.. versionchanged: 3.5
Writable :term:`bytes-like object` is now accepted.
.. method:: flush([offset[, size]]) .. method:: flush([offset[, size]])
@ -234,6 +237,9 @@ To map anonymous memory, -1 should be passed as the fileno along with the length
Optional arguments *start* and *end* are interpreted as in slice notation. Optional arguments *start* and *end* are interpreted as in slice notation.
Returns ``-1`` on failure. Returns ``-1`` on failure.
.. versionchanged: 3.5
Writable :term:`bytes-like object` is now accepted.
.. method:: seek(pos[, whence]) .. method:: seek(pos[, whence])
@ -261,6 +267,9 @@ To map anonymous memory, -1 should be passed as the fileno along with the length
were written. If the mmap was created with :const:`ACCESS_READ`, then were written. If the mmap was created with :const:`ACCESS_READ`, then
writing to it will raise a :exc:`TypeError` exception. writing to it will raise a :exc:`TypeError` exception.
.. versionchanged: 3.5
Writable :term:`bytes-like object` is now accepted.
.. method:: write_byte(byte) .. method:: write_byte(byte)

View File

@ -148,21 +148,30 @@ and (read-only) attributes:
.. method:: oss_audio_device.write(data) .. method:: oss_audio_device.write(data)
Write the Python string *data* to the audio device and return the number of Write a :term:`bytes-like object` *data* to the audio device and return the
bytes written. If the audio device is in blocking mode (the default), the number of bytes written. If the audio device is in blocking mode (the
entire string is always written (again, this is different from usual Unix device default), the entire data is always written (again, this is different from
semantics). If the device is in non-blocking mode, some data may not be written usual Unix device semantics). If the device is in non-blocking mode, some
data may not be written
---see :meth:`writeall`. ---see :meth:`writeall`.
.. versionchanged: 3.5
Writable :term:`bytes-like object` is now accepted.
.. method:: oss_audio_device.writeall(data) .. method:: oss_audio_device.writeall(data)
Write the entire Python string *data* to the audio device: waits until the audio Write a :term:`bytes-like object` *data* to the audio device: waits until
device is able to accept data, writes as much data as it will accept, and the audio device is able to accept data, writes as much data as it will
repeats until *data* has been completely written. If the device is in blocking accept, and repeats until *data* has been completely written. If the device
mode (the default), this has the same effect as :meth:`write`; :meth:`writeall` is in blocking mode (the default), this has the same effect as
is only useful in non-blocking mode. Has no return value, since the amount of :meth:`write`; :meth:`writeall` is only useful in non-blocking mode. Has
data written is always equal to the amount of data supplied. no return value, since the amount of data written is always equal to the
amount of data supplied.
.. versionchanged: 3.5
Writable :term:`bytes-like object` is now accepted.
.. versionchanged:: 3.2 .. versionchanged:: 3.2
Audio device objects also support the context management protocol, i.e. they can Audio device objects also support the context management protocol, i.e. they can

View File

@ -46,17 +46,20 @@ created. Socket addresses are represented as follows:
- The address of an :const:`AF_UNIX` socket bound to a file system node - The address of an :const:`AF_UNIX` socket bound to a file system node
is represented as a string, using the file system encoding and the is represented as a string, using the file system encoding and the
``'surrogateescape'`` error handler (see :pep:`383`). An address in ``'surrogateescape'`` error handler (see :pep:`383`). An address in
Linux's abstract namespace is returned as a :class:`bytes` object with Linux's abstract namespace is returned as a :term:`bytes-like object` with
an initial null byte; note that sockets in this namespace can an initial null byte; note that sockets in this namespace can
communicate with normal file system sockets, so programs intended to communicate with normal file system sockets, so programs intended to
run on Linux may need to deal with both types of address. A string or run on Linux may need to deal with both types of address. A string or
:class:`bytes` object can be used for either type of address when bytes-like object can be used for either type of address when
passing it as an argument. passing it as an argument.
.. versionchanged:: 3.3 .. versionchanged:: 3.3
Previously, :const:`AF_UNIX` socket paths were assumed to use UTF-8 Previously, :const:`AF_UNIX` socket paths were assumed to use UTF-8
encoding. encoding.
.. versionchanged: 3.5
Writable :term:`bytes-like object` is now accepted.
- A pair ``(host, port)`` is used for the :const:`AF_INET` address family, - A pair ``(host, port)`` is used for the :const:`AF_INET` address family,
where *host* is a string representing either a hostname in Internet domain where *host* is a string representing either a hostname in Internet domain
notation like ``'daring.cwi.nl'`` or an IPv4 address like ``'100.50.200.5'``, notation like ``'daring.cwi.nl'`` or an IPv4 address like ``'100.50.200.5'``,
@ -609,8 +612,8 @@ The :mod:`socket` module also offers various network-related services:
.. function:: inet_ntoa(packed_ip) .. function:: inet_ntoa(packed_ip)
Convert a 32-bit packed IPv4 address (a bytes object four characters in Convert a 32-bit packed IPv4 address (a :term:`bytes-like object` four
length) to its standard dotted-quad string representation (for example, bytes in length) to its standard dotted-quad string representation (for example,
'123.45.67.89'). This is useful when conversing with a program that uses the '123.45.67.89'). This is useful when conversing with a program that uses the
standard C library and needs objects of type :c:type:`struct in_addr`, which standard C library and needs objects of type :c:type:`struct in_addr`, which
is the C type for the 32-bit packed binary data this function takes as an is the C type for the 32-bit packed binary data this function takes as an
@ -621,6 +624,9 @@ The :mod:`socket` module also offers various network-related services:
support IPv6, and :func:`inet_ntop` should be used instead for IPv4/v6 dual support IPv6, and :func:`inet_ntop` should be used instead for IPv4/v6 dual
stack support. stack support.
.. versionchanged: 3.5
Writable :term:`bytes-like object` is now accepted.
.. function:: inet_pton(address_family, ip_string) .. function:: inet_pton(address_family, ip_string)
@ -643,22 +649,26 @@ The :mod:`socket` module also offers various network-related services:
.. function:: inet_ntop(address_family, packed_ip) .. function:: inet_ntop(address_family, packed_ip)
Convert a packed IP address (a bytes object of some number of characters) to its Convert a packed IP address (a :term:`bytes-like object` of some number of
standard, family-specific string representation (for example, ``'7.10.0.5'`` or bytes) to its standard, family-specific string representation (for
``'5aef:2b::8'``). :func:`inet_ntop` is useful when a library or network protocol example, ``'7.10.0.5'`` or ``'5aef:2b::8'``).
returns an object of type :c:type:`struct in_addr` (similar to :func:`inet_ntoa`) :func:`inet_ntop` is useful when a library or network protocol returns an
or :c:type:`struct in6_addr`. object of type :c:type:`struct in_addr` (similar to :func:`inet_ntoa`) or
:c:type:`struct in6_addr`.
Supported values for *address_family* are currently :const:`AF_INET` and Supported values for *address_family* are currently :const:`AF_INET` and
:const:`AF_INET6`. If the string *packed_ip* is not the correct length for the :const:`AF_INET6`. If the bytes object *packed_ip* is not the correct
specified address family, :exc:`ValueError` will be raised. A length for the specified address family, :exc:`ValueError` will be raised.
:exc:`OSError` is raised for errors from the call to :func:`inet_ntop`. A :exc:`OSError` is raised for errors from the call to :func:`inet_ntop`.
Availability: Unix (maybe not all platforms), Windows. Availability: Unix (maybe not all platforms), Windows.
.. versionchanged:: 3.4 .. versionchanged:: 3.4
Windows support added Windows support added
.. versionchanged: 3.5
Writable :term:`bytes-like object` is now accepted.
.. ..
XXX: Are sendmsg(), recvmsg() and CMSG_*() available on any XXX: Are sendmsg(), recvmsg() and CMSG_*() available on any
@ -1207,11 +1217,15 @@ to sockets.
Set the value of the given socket option (see the Unix manual page Set the value of the given socket option (see the Unix manual page
:manpage:`setsockopt(2)`). The needed symbolic constants are defined in the :manpage:`setsockopt(2)`). The needed symbolic constants are defined in the
:mod:`socket` module (:const:`SO_\*` etc.). The value can be an integer or a :mod:`socket` module (:const:`SO_\*` etc.). The value can be an integer or
bytes object representing a buffer. In the latter case it is up to the caller to a :term:`bytes-like object` representing a buffer. In the latter case it is
up to the caller to
ensure that the bytestring contains the proper bits (see the optional built-in ensure that the bytestring contains the proper bits (see the optional built-in
module :mod:`struct` for a way to encode C structures as bytestrings). module :mod:`struct` for a way to encode C structures as bytestrings).
.. versionchanged: 3.5
Writable :term:`bytes-like object` is now accepted.
.. method:: socket.shutdown(how) .. method:: socket.shutdown(how)

View File

@ -340,6 +340,9 @@ Random generation
string (so you can always use :const:`0.0`). See :rfc:`1750` for more string (so you can always use :const:`0.0`). See :rfc:`1750` for more
information on sources of entropy. information on sources of entropy.
.. versionchanged: 3.5
Writable :term:`bytes-like object` is now accepted.
Certificate handling Certificate handling
^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^

View File

@ -1086,6 +1086,7 @@ class UTF8SigTest(UTF8Test, unittest.TestCase):
class EscapeDecodeTest(unittest.TestCase): class EscapeDecodeTest(unittest.TestCase):
def test_empty(self): def test_empty(self):
self.assertEqual(codecs.escape_decode(b""), (b"", 0)) self.assertEqual(codecs.escape_decode(b""), (b"", 0))
self.assertEqual(codecs.escape_decode(bytearray()), (b"", 0))
def test_raw(self): def test_raw(self):
decode = codecs.escape_decode decode = codecs.escape_decode

View File

@ -282,6 +282,7 @@ class MmapTests(unittest.TestCase):
self.assertEqual(m.find(b'one', 1), 8) self.assertEqual(m.find(b'one', 1), 8)
self.assertEqual(m.find(b'one', 1, -1), 8) self.assertEqual(m.find(b'one', 1, -1), 8)
self.assertEqual(m.find(b'one', 1, -2), -1) self.assertEqual(m.find(b'one', 1, -2), -1)
self.assertEqual(m.find(bytearray(b'one')), 0)
def test_rfind(self): def test_rfind(self):
@ -300,6 +301,7 @@ class MmapTests(unittest.TestCase):
self.assertEqual(m.rfind(b'one', 0, -2), 0) self.assertEqual(m.rfind(b'one', 0, -2), 0)
self.assertEqual(m.rfind(b'one', 1, -1), 8) self.assertEqual(m.rfind(b'one', 1, -1), 8)
self.assertEqual(m.rfind(b'one', 1, -2), -1) self.assertEqual(m.rfind(b'one', 1, -2), -1)
self.assertEqual(m.rfind(bytearray(b'one')), 8)
def test_double_close(self): def test_double_close(self):
@ -601,8 +603,10 @@ class MmapTests(unittest.TestCase):
m.write(b"bar") m.write(b"bar")
self.assertEqual(m.tell(), 6) self.assertEqual(m.tell(), 6)
self.assertEqual(m[:], b"012bar6789") self.assertEqual(m[:], b"012bar6789")
m.seek(8) m.write(bytearray(b"baz"))
self.assertRaises(ValueError, m.write, b"bar") self.assertEqual(m.tell(), 9)
self.assertEqual(m[:], b"012barbaz9")
self.assertRaises(ValueError, m.write, b"ba")
def test_non_ascii_byte(self): def test_non_ascii_byte(self):
for b in (129, 200, 255): # > 128 for b in (129, 200, 255): # > 128

View File

@ -1074,6 +1074,7 @@ class GeneralModuleTests(unittest.TestCase):
assertInvalid(f, b'\x00' * 3) assertInvalid(f, b'\x00' * 3)
assertInvalid(f, b'\x00' * 5) assertInvalid(f, b'\x00' * 5)
assertInvalid(f, b'\x00' * 16) assertInvalid(f, b'\x00' * 16)
self.assertEqual('170.85.170.85', f(bytearray(b'\xaa\x55\xaa\x55')))
self.assertEqual('1.0.1.0', g(b'\x01\x00\x01\x00')) self.assertEqual('1.0.1.0', g(b'\x01\x00\x01\x00'))
self.assertEqual('170.85.170.85', g(b'\xaa\x55\xaa\x55')) self.assertEqual('170.85.170.85', g(b'\xaa\x55\xaa\x55'))
@ -1081,6 +1082,7 @@ class GeneralModuleTests(unittest.TestCase):
assertInvalid(g, b'\x00' * 3) assertInvalid(g, b'\x00' * 3)
assertInvalid(g, b'\x00' * 5) assertInvalid(g, b'\x00' * 5)
assertInvalid(g, b'\x00' * 16) assertInvalid(g, b'\x00' * 16)
self.assertEqual('170.85.170.85', g(bytearray(b'\xaa\x55\xaa\x55')))
@unittest.skipUnless(hasattr(socket, 'inet_ntop'), @unittest.skipUnless(hasattr(socket, 'inet_ntop'),
'test needs socket.inet_ntop()') 'test needs socket.inet_ntop()')
@ -1110,6 +1112,7 @@ class GeneralModuleTests(unittest.TestCase):
'aef:b01:506:1001:ffff:9997:55:170', 'aef:b01:506:1001:ffff:9997:55:170',
f(b'\x0a\xef\x0b\x01\x05\x06\x10\x01\xff\xff\x99\x97\x00\x55\x01\x70') f(b'\x0a\xef\x0b\x01\x05\x06\x10\x01\xff\xff\x99\x97\x00\x55\x01\x70')
) )
self.assertEqual('::1', f(bytearray(b'\x00' * 15 + b'\x01')))
assertInvalid(b'\x12' * 15) assertInvalid(b'\x12' * 15)
assertInvalid(b'\x12' * 17) assertInvalid(b'\x12' * 17)
@ -1497,6 +1500,7 @@ class BasicCANTest(unittest.TestCase):
s.setsockopt(socket.SOL_CAN_RAW, socket.CAN_RAW_FILTER, can_filter) s.setsockopt(socket.SOL_CAN_RAW, socket.CAN_RAW_FILTER, can_filter)
self.assertEqual(can_filter, self.assertEqual(can_filter,
s.getsockopt(socket.SOL_CAN_RAW, socket.CAN_RAW_FILTER, 8)) s.getsockopt(socket.SOL_CAN_RAW, socket.CAN_RAW_FILTER, 8))
s.setsockopt(socket.SOL_CAN_RAW, socket.CAN_RAW_FILTER, bytearray(can_filter))
@unittest.skipUnless(HAVE_SOCKET_CAN, 'SocketCan required for this test.') @unittest.skipUnless(HAVE_SOCKET_CAN, 'SocketCan required for this test.')
@ -4508,6 +4512,12 @@ class TestLinuxAbstractNamespace(unittest.TestCase):
finally: finally:
s.close() s.close()
def testBytearrayName(self):
# Check that an abstract name can be passed as a bytearray.
with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as s:
s.bind(bytearray(b"\x00python\x00test\x00"))
self.assertEqual(s.getsockname(), b"\x00python\x00test\x00")
@unittest.skipUnless(hasattr(socket, 'AF_UNIX'), 'test needs socket.AF_UNIX') @unittest.skipUnless(hasattr(socket, 'AF_UNIX'), 'test needs socket.AF_UNIX')
class TestUnixDomain(unittest.TestCase): class TestUnixDomain(unittest.TestCase):

View File

@ -171,6 +171,8 @@ class BasicSocketTests(unittest.TestCase):
self.assertRaises(TypeError, ssl.RAND_egd, 1) self.assertRaises(TypeError, ssl.RAND_egd, 1)
self.assertRaises(TypeError, ssl.RAND_egd, 'foo', 1) self.assertRaises(TypeError, ssl.RAND_egd, 'foo', 1)
ssl.RAND_add("this is a random string", 75.0) ssl.RAND_add("this is a random string", 75.0)
ssl.RAND_add(b"this is a random bytes object", 75.0)
ssl.RAND_add(bytearray(b"this is a random bytearray object"), 75.0)
@unittest.skipUnless(os.name == 'posix', 'requires posix') @unittest.skipUnless(os.name == 'posix', 'requires posix')
def test_random_fork(self): def test_random_fork(self):

View File

@ -21,6 +21,10 @@ Core and Builtins
Library Library
------- -------
- Issue #23001: Few functions in modules mmap, ossaudiodev, socket, ssl, and
codecs, that accepted only read-only bytes-like object now accept writable
bytes-like object too.
- Issue #23646: If time.sleep() is interrupted by a signal, the sleep is now - Issue #23646: If time.sleep() is interrupted by a signal, the sleep is now
retried with the recomputed delay, except if the signal handler raises an retried with the recomputed delay, except if the signal handler raises an
exception (PEP 475). exception (PEP 475).

View File

@ -208,15 +208,18 @@ static PyObject *
escape_decode(PyObject *self, escape_decode(PyObject *self,
PyObject *args) PyObject *args)
{ {
Py_buffer pbuf;
const char *errors = NULL; const char *errors = NULL;
const char *data; PyObject *result;
Py_ssize_t size;
if (!PyArg_ParseTuple(args, "s#|z:escape_decode", if (!PyArg_ParseTuple(args, "s*|z:escape_decode",
&data, &size, &errors)) &pbuf, &errors))
return NULL; return NULL;
return codec_tuple(PyBytes_DecodeEscape(data, size, errors, 0, NULL), result = codec_tuple(
size); PyBytes_DecodeEscape(pbuf.buf, pbuf.len, errors, 0, NULL),
pbuf.len);
PyBuffer_Release(&pbuf);
return result;
} }
static PyObject * static PyObject *

View File

@ -3672,18 +3672,22 @@ static PyTypeObject PySSLMemoryBIO_Type = {
static PyObject * static PyObject *
PySSL_RAND_add(PyObject *self, PyObject *args) PySSL_RAND_add(PyObject *self, PyObject *args)
{ {
char *buf; Py_buffer view;
const char *buf;
Py_ssize_t len, written; Py_ssize_t len, written;
double entropy; double entropy;
if (!PyArg_ParseTuple(args, "s#d:RAND_add", &buf, &len, &entropy)) if (!PyArg_ParseTuple(args, "s*d:RAND_add", &view, &entropy))
return NULL; return NULL;
buf = (const char *)view.buf;
len = view.len;
do { do {
written = Py_MIN(len, INT_MAX); written = Py_MIN(len, INT_MAX);
RAND_add(buf, (int)written, entropy); RAND_add(buf, (int)written, entropy);
buf += written; buf += written;
len -= written; len -= written;
} while (len); } while (len);
PyBuffer_Release(&view);
Py_INCREF(Py_None); Py_INCREF(Py_None);
return Py_None; return Py_None;
} }

View File

@ -301,16 +301,17 @@ mmap_gfind(mmap_object *self,
{ {
Py_ssize_t start = self->pos; Py_ssize_t start = self->pos;
Py_ssize_t end = self->size; Py_ssize_t end = self->size;
const char *needle; Py_buffer view;
Py_ssize_t len;
CHECK_VALID(NULL); CHECK_VALID(NULL);
if (!PyArg_ParseTuple(args, reverse ? "y#|nn:rfind" : "y#|nn:find", if (!PyArg_ParseTuple(args, reverse ? "y*|nn:rfind" : "y*|nn:find",
&needle, &len, &start, &end)) { &view, &start, &end)) {
return NULL; return NULL;
} else { } else {
const char *p, *start_p, *end_p; const char *p, *start_p, *end_p;
int sign = reverse ? -1 : 1; int sign = reverse ? -1 : 1;
const char *needle = view.buf;
Py_ssize_t len = view.len;
if (start < 0) if (start < 0)
start += self->size; start += self->size;
@ -335,9 +336,11 @@ mmap_gfind(mmap_object *self,
for (i = 0; i < len && needle[i] == p[i]; ++i) for (i = 0; i < len && needle[i] == p[i]; ++i)
/* nothing */; /* nothing */;
if (i == len) { if (i == len) {
PyBuffer_Release(&view);
return PyLong_FromSsize_t(p - self->data); return PyLong_FromSsize_t(p - self->data);
} }
} }
PyBuffer_Release(&view);
return PyLong_FromLong(-1); return PyLong_FromLong(-1);
} }
} }
@ -385,22 +388,25 @@ static PyObject *
mmap_write_method(mmap_object *self, mmap_write_method(mmap_object *self,
PyObject *args) PyObject *args)
{ {
Py_ssize_t length; Py_buffer data;
char *data;
CHECK_VALID(NULL); CHECK_VALID(NULL);
if (!PyArg_ParseTuple(args, "y#:write", &data, &length)) if (!PyArg_ParseTuple(args, "y*:write", &data))
return(NULL); return(NULL);
if (!is_writable(self)) if (!is_writable(self)) {
return NULL; PyBuffer_Release(&data);
if ((self->pos + length) > self->size) {
PyErr_SetString(PyExc_ValueError, "data out of range");
return NULL; return NULL;
} }
memcpy(self->data+self->pos, data, length);
self->pos = self->pos+length; if ((self->pos + data.len) > self->size) {
PyErr_SetString(PyExc_ValueError, "data out of range");
PyBuffer_Release(&data);
return NULL;
}
memcpy(self->data + self->pos, data.buf, data.len);
self->pos = self->pos + data.len;
PyBuffer_Release(&data);
Py_INCREF(Py_None); Py_INCREF(Py_None);
return Py_None; return Py_None;
} }

View File

@ -426,17 +426,18 @@ oss_read(oss_audio_t *self, PyObject *args)
static PyObject * static PyObject *
oss_write(oss_audio_t *self, PyObject *args) oss_write(oss_audio_t *self, PyObject *args)
{ {
char *cp; Py_buffer data;
int rv, size; int rv;
if (!_is_fd_valid(self->fd)) if (!_is_fd_valid(self->fd))
return NULL; return NULL;
if (!PyArg_ParseTuple(args, "y#:write", &cp, &size)) { if (!PyArg_ParseTuple(args, "y*:write", &data)) {
return NULL; return NULL;
} }
rv = _Py_write(self->fd, cp, size); rv = _Py_write(self->fd, data.buf, data.len);
PyBuffer_Release(&data);
if (rv == -1) if (rv == -1)
return NULL; return NULL;
@ -447,8 +448,10 @@ oss_write(oss_audio_t *self, PyObject *args)
static PyObject * static PyObject *
oss_writeall(oss_audio_t *self, PyObject *args) oss_writeall(oss_audio_t *self, PyObject *args)
{ {
char *cp; Py_buffer data;
int rv, size; const char *cp;
Py_ssize_t size;
int rv;
fd_set write_set_fds; fd_set write_set_fds;
int select_rv; int select_rv;
@ -462,17 +465,20 @@ oss_writeall(oss_audio_t *self, PyObject *args)
if (!_is_fd_valid(self->fd)) if (!_is_fd_valid(self->fd))
return NULL; return NULL;
if (!PyArg_ParseTuple(args, "y#:write", &cp, &size)) if (!PyArg_ParseTuple(args, "y*:writeall", &data))
return NULL; return NULL;
if (!_PyIsSelectable_fd(self->fd)) { if (!_PyIsSelectable_fd(self->fd)) {
PyErr_SetString(PyExc_ValueError, PyErr_SetString(PyExc_ValueError,
"file descriptor out of range for select"); "file descriptor out of range for select");
PyBuffer_Release(&data);
return NULL; return NULL;
} }
/* use select to wait for audio device to be available */ /* use select to wait for audio device to be available */
FD_ZERO(&write_set_fds); FD_ZERO(&write_set_fds);
FD_SET(self->fd, &write_set_fds); FD_SET(self->fd, &write_set_fds);
cp = (const char *)data.buf;
size = data.len;
while (size > 0) { while (size > 0) {
Py_BEGIN_ALLOW_THREADS Py_BEGIN_ALLOW_THREADS
@ -480,10 +486,12 @@ oss_writeall(oss_audio_t *self, PyObject *args)
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
assert(select_rv != 0); /* no timeout, can't expire */ assert(select_rv != 0); /* no timeout, can't expire */
if (select_rv == -1) if (select_rv == -1) {
PyBuffer_Release(&data);
return PyErr_SetFromErrno(PyExc_IOError); return PyErr_SetFromErrno(PyExc_IOError);
}
rv = _Py_write(self->fd, cp, size); rv = _Py_write(self->fd, , cp, Py_MIN(size, INT_MAX));
if (rv == -1) { if (rv == -1) {
/* buffer is full, try again */ /* buffer is full, try again */
if (errno == EAGAIN) { if (errno == EAGAIN) {
@ -491,6 +499,7 @@ oss_writeall(oss_audio_t *self, PyObject *args)
continue; continue;
} }
/* it's a real error */ /* it's a real error */
PyBuffer_Release(&data);
return NULL; return NULL;
} }
@ -499,6 +508,7 @@ oss_writeall(oss_audio_t *self, PyObject *args)
size -= rv; size -= rv;
cp += rv; cp += rv;
} }
PyBuffer_Release(&data);
Py_INCREF(Py_None); Py_INCREF(Py_None);
return Py_None; return Py_None;
} }

View File

@ -1299,8 +1299,7 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
case AF_UNIX: case AF_UNIX:
{ {
struct sockaddr_un* addr; struct sockaddr_un* addr;
char *path; Py_buffer path;
int len;
int retval = 0; int retval = 0;
/* PEP 383. Not using PyUnicode_FSConverter since we need to /* PEP 383. Not using PyUnicode_FSConverter since we need to
@ -1311,15 +1310,17 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
} }
else else
Py_INCREF(args); Py_INCREF(args);
if (!PyArg_Parse(args, "y#", &path, &len)) if (!PyArg_Parse(args, "y*", &path)) {
goto unix_out; Py_DECREF(args);
assert(len >= 0); return retval;
}
assert(path.len >= 0);
addr = (struct sockaddr_un*)addr_ret; addr = (struct sockaddr_un*)addr_ret;
#ifdef linux #ifdef linux
if (len > 0 && path[0] == 0) { if (path.len > 0 && *(const char *)path.buf == 0) {
/* Linux abstract namespace extension */ /* Linux abstract namespace extension */
if ((size_t)len > sizeof addr->sun_path) { if ((size_t)path.len > sizeof addr->sun_path) {
PyErr_SetString(PyExc_OSError, PyErr_SetString(PyExc_OSError,
"AF_UNIX path too long"); "AF_UNIX path too long");
goto unix_out; goto unix_out;
@ -1329,18 +1330,19 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
#endif /* linux */ #endif /* linux */
{ {
/* regular NULL-terminated string */ /* regular NULL-terminated string */
if ((size_t)len >= sizeof addr->sun_path) { if ((size_t)path.len >= sizeof addr->sun_path) {
PyErr_SetString(PyExc_OSError, PyErr_SetString(PyExc_OSError,
"AF_UNIX path too long"); "AF_UNIX path too long");
goto unix_out; goto unix_out;
} }
addr->sun_path[len] = 0; addr->sun_path[path.len] = 0;
} }
addr->sun_family = s->sock_family; addr->sun_family = s->sock_family;
memcpy(addr->sun_path, path, len); memcpy(addr->sun_path, path.buf, path.len);
*len_ret = len + offsetof(struct sockaddr_un, sun_path); *len_ret = path.len + offsetof(struct sockaddr_un, sun_path);
retval = 1; retval = 1;
unix_out: unix_out:
PyBuffer_Release(&path);
Py_DECREF(args); Py_DECREF(args);
return retval; return retval;
} }
@ -1562,8 +1564,7 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
int protoNumber; int protoNumber;
int hatype = 0; int hatype = 0;
int pkttype = 0; int pkttype = 0;
char *haddr = NULL; Py_buffer haddr = {NULL, NULL};
unsigned int halen = 0;
if (!PyTuple_Check(args)) { if (!PyTuple_Check(args)) {
PyErr_Format( PyErr_Format(
@ -1573,25 +1574,28 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
Py_TYPE(args)->tp_name); Py_TYPE(args)->tp_name);
return 0; return 0;
} }
if (!PyArg_ParseTuple(args, "si|iiy#", &interfaceName, if (!PyArg_ParseTuple(args, "si|iiy*", &interfaceName,
&protoNumber, &pkttype, &hatype, &protoNumber, &pkttype, &hatype,
&haddr, &halen)) &haddr))
return 0; return 0;
strncpy(ifr.ifr_name, interfaceName, sizeof(ifr.ifr_name)); strncpy(ifr.ifr_name, interfaceName, sizeof(ifr.ifr_name));
ifr.ifr_name[(sizeof(ifr.ifr_name))-1] = '\0'; ifr.ifr_name[(sizeof(ifr.ifr_name))-1] = '\0';
if (ioctl(s->sock_fd, SIOCGIFINDEX, &ifr) < 0) { if (ioctl(s->sock_fd, SIOCGIFINDEX, &ifr) < 0) {
s->errorhandler(); s->errorhandler();
PyBuffer_Release(&haddr);
return 0; return 0;
} }
if (halen > 8) { if (haddr.buf && haddr.len > 8) {
PyErr_SetString(PyExc_ValueError, PyErr_SetString(PyExc_ValueError,
"Hardware address must be 8 bytes or less"); "Hardware address must be 8 bytes or less");
PyBuffer_Release(&haddr);
return 0; return 0;
} }
if (protoNumber < 0 || protoNumber > 0xffff) { if (protoNumber < 0 || protoNumber > 0xffff) {
PyErr_SetString( PyErr_SetString(
PyExc_OverflowError, PyExc_OverflowError,
"getsockaddrarg: protoNumber must be 0-65535."); "getsockaddrarg: protoNumber must be 0-65535.");
PyBuffer_Release(&haddr);
return 0; return 0;
} }
addr = (struct sockaddr_ll*)addr_ret; addr = (struct sockaddr_ll*)addr_ret;
@ -1600,11 +1604,14 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
addr->sll_ifindex = ifr.ifr_ifindex; addr->sll_ifindex = ifr.ifr_ifindex;
addr->sll_pkttype = pkttype; addr->sll_pkttype = pkttype;
addr->sll_hatype = hatype; addr->sll_hatype = hatype;
if (halen != 0) { if (haddr.buf) {
memcpy(&addr->sll_addr, haddr, halen); memcpy(&addr->sll_addr, haddr.buf, haddr.len);
addr->sll_halen = haddr.len;
} }
addr->sll_halen = halen; else
addr->sll_halen = 0;
*len_ret = sizeof *addr; *len_ret = sizeof *addr;
PyBuffer_Release(&haddr);
return 1; return 1;
} }
#endif #endif
@ -2230,22 +2237,21 @@ sock_setsockopt(PySocketSockObject *s, PyObject *args)
int level; int level;
int optname; int optname;
int res; int res;
char *buf; Py_buffer optval;
int buflen;
int flag; int flag;
if (PyArg_ParseTuple(args, "iii:setsockopt", if (PyArg_ParseTuple(args, "iii:setsockopt",
&level, &optname, &flag)) { &level, &optname, &flag)) {
buf = (char *) &flag; res = setsockopt(s->sock_fd, level, optname, &flag, sizeof flag);
buflen = sizeof flag;
} }
else { else {
PyErr_Clear(); PyErr_Clear();
if (!PyArg_ParseTuple(args, "iiy#:setsockopt", if (!PyArg_ParseTuple(args, "iiy*:setsockopt",
&level, &optname, &buf, &buflen)) &level, &optname, &optval))
return NULL; return NULL;
res = setsockopt(s->sock_fd, level, optname, optval.buf, optval.len);
PyBuffer_Release(&optval);
} }
res = setsockopt(s->sock_fd, level, optname, (void *)buf, buflen);
if (res < 0) if (res < 0)
return s->errorhandler(); return s->errorhandler();
Py_INCREF(Py_None); Py_INCREF(Py_None);
@ -5037,21 +5043,22 @@ Convert an IP address from 32-bit packed binary format to string format");
static PyObject* static PyObject*
socket_inet_ntoa(PyObject *self, PyObject *args) socket_inet_ntoa(PyObject *self, PyObject *args)
{ {
char *packed_str; Py_buffer packed_ip;
int addr_len;
struct in_addr packed_addr; struct in_addr packed_addr;
if (!PyArg_ParseTuple(args, "y#:inet_ntoa", &packed_str, &addr_len)) { if (!PyArg_ParseTuple(args, "y*:inet_ntoa", &packed_ip)) {
return NULL; return NULL;
} }
if (addr_len != sizeof(packed_addr)) { if (packed_ip.len != sizeof(packed_addr)) {
PyErr_SetString(PyExc_OSError, PyErr_SetString(PyExc_OSError,
"packed IP wrong length for inet_ntoa"); "packed IP wrong length for inet_ntoa");
PyBuffer_Release(&packed_ip);
return NULL; return NULL;
} }
memcpy(&packed_addr, packed_str, addr_len); memcpy(&packed_addr, packed_ip.buf, packed_ip.len);
PyBuffer_Release(&packed_ip);
return PyUnicode_FromString(inet_ntoa(packed_addr)); return PyUnicode_FromString(inet_ntoa(packed_addr));
} }
@ -5162,8 +5169,7 @@ static PyObject *
socket_inet_ntop(PyObject *self, PyObject *args) socket_inet_ntop(PyObject *self, PyObject *args)
{ {
int af; int af;
char* packed; Py_buffer packed_ip;
int len;
const char* retval; const char* retval;
#ifdef ENABLE_IPV6 #ifdef ENABLE_IPV6
char ip[Py_MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN) + 1]; char ip[Py_MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN) + 1];
@ -5174,31 +5180,35 @@ socket_inet_ntop(PyObject *self, PyObject *args)
/* Guarantee NUL-termination for PyUnicode_FromString() below */ /* Guarantee NUL-termination for PyUnicode_FromString() below */
memset((void *) &ip[0], '\0', sizeof(ip)); memset((void *) &ip[0], '\0', sizeof(ip));
if (!PyArg_ParseTuple(args, "iy#:inet_ntop", &af, &packed, &len)) { if (!PyArg_ParseTuple(args, "iy*:inet_ntop", &af, &packed_ip)) {
return NULL; return NULL;
} }
if (af == AF_INET) { if (af == AF_INET) {
if (len != sizeof(struct in_addr)) { if (packed_ip.len != sizeof(struct in_addr)) {
PyErr_SetString(PyExc_ValueError, PyErr_SetString(PyExc_ValueError,
"invalid length of packed IP address string"); "invalid length of packed IP address string");
PyBuffer_Release(&packed_ip);
return NULL; return NULL;
} }
#ifdef ENABLE_IPV6 #ifdef ENABLE_IPV6
} else if (af == AF_INET6) { } else if (af == AF_INET6) {
if (len != sizeof(struct in6_addr)) { if (packed_ip.len != sizeof(struct in6_addr)) {
PyErr_SetString(PyExc_ValueError, PyErr_SetString(PyExc_ValueError,
"invalid length of packed IP address string"); "invalid length of packed IP address string");
PyBuffer_Release(&packed_ip);
return NULL; return NULL;
} }
#endif #endif
} else { } else {
PyErr_Format(PyExc_ValueError, PyErr_Format(PyExc_ValueError,
"unknown address family %d", af); "unknown address family %d", af);
PyBuffer_Release(&packed_ip);
return NULL; return NULL;
} }
retval = inet_ntop(af, packed, ip, sizeof(ip)); retval = inet_ntop(af, packed_ip.buf, ip, sizeof(ip));
PyBuffer_Release(&packed_ip);
if (!retval) { if (!retval) {
PyErr_SetFromErrno(PyExc_OSError); PyErr_SetFromErrno(PyExc_OSError);
return NULL; return NULL;
@ -5217,8 +5227,7 @@ static PyObject *
socket_inet_ntop(PyObject *self, PyObject *args) socket_inet_ntop(PyObject *self, PyObject *args)
{ {
int af; int af;
char* packed; Py_buffer packed_ip;
int len;
struct sockaddr_in6 addr; struct sockaddr_in6 addr;
DWORD addrlen, ret, retlen; DWORD addrlen, ret, retlen;
#ifdef ENABLE_IPV6 #ifdef ENABLE_IPV6
@ -5230,38 +5239,42 @@ socket_inet_ntop(PyObject *self, PyObject *args)
/* Guarantee NUL-termination for PyUnicode_FromString() below */ /* Guarantee NUL-termination for PyUnicode_FromString() below */
memset((void *) &ip[0], '\0', sizeof(ip)); memset((void *) &ip[0], '\0', sizeof(ip));
if (!PyArg_ParseTuple(args, "iy#:inet_ntop", &af, &packed, &len)) { if (!PyArg_ParseTuple(args, "iy*:inet_ntop", &af, &packed_ip)) {
return NULL; return NULL;
} }
if (af == AF_INET) { if (af == AF_INET) {
struct sockaddr_in * addr4 = (struct sockaddr_in *)&addr; struct sockaddr_in * addr4 = (struct sockaddr_in *)&addr;
if (len != sizeof(struct in_addr)) { if (packed_ip.len != sizeof(struct in_addr)) {
PyErr_SetString(PyExc_ValueError, PyErr_SetString(PyExc_ValueError,
"invalid length of packed IP address string"); "invalid length of packed IP address string");
PyBuffer_Release(&packed_ip);
return NULL; return NULL;
} }
memset(addr4, 0, sizeof(struct sockaddr_in)); memset(addr4, 0, sizeof(struct sockaddr_in));
addr4->sin_family = AF_INET; addr4->sin_family = AF_INET;
memcpy(&(addr4->sin_addr), packed, sizeof(addr4->sin_addr)); memcpy(&(addr4->sin_addr), packed_ip.buf, sizeof(addr4->sin_addr));
addrlen = sizeof(struct sockaddr_in); addrlen = sizeof(struct sockaddr_in);
} else if (af == AF_INET6) { } else if (af == AF_INET6) {
if (len != sizeof(struct in6_addr)) { if (packed_ip.len != sizeof(struct in6_addr)) {
PyErr_SetString(PyExc_ValueError, PyErr_SetString(PyExc_ValueError,
"invalid length of packed IP address string"); "invalid length of packed IP address string");
PyBuffer_Release(&packed_ip);
return NULL; return NULL;
} }
memset(&addr, 0, sizeof(addr)); memset(&addr, 0, sizeof(addr));
addr.sin6_family = AF_INET6; addr.sin6_family = AF_INET6;
memcpy(&(addr.sin6_addr), packed, sizeof(addr.sin6_addr)); memcpy(&(addr.sin6_addr), packed_ip.buf, sizeof(addr.sin6_addr));
addrlen = sizeof(addr); addrlen = sizeof(addr);
} else { } else {
PyErr_Format(PyExc_ValueError, PyErr_Format(PyExc_ValueError,
"unknown address family %d", af); "unknown address family %d", af);
PyBuffer_Release(&packed_ip);
return NULL; return NULL;
} }
PyBuffer_Release(&packed_ip);
retlen = sizeof(ip); retlen = sizeof(ip);
ret = WSAAddressToStringA((struct sockaddr*)&addr, addrlen, NULL, ret = WSAAddressToStringA((struct sockaddr*)&addr, addrlen, NULL,