]> granicus.if.org Git - python/commitdiff
Issue #23001: Few functions in modules mmap, ossaudiodev, socket, ssl, and
authorSerhiy Storchaka <storchaka@gmail.com>
Fri, 20 Mar 2015 07:00:36 +0000 (09:00 +0200)
committerSerhiy Storchaka <storchaka@gmail.com>
Fri, 20 Mar 2015 07:00:36 +0000 (09:00 +0200)
codecs, that accepted only read-only bytes-like object now accept writable
bytes-like object too.

14 files changed:
Doc/library/mmap.rst
Doc/library/ossaudiodev.rst
Doc/library/socket.rst
Doc/library/ssl.rst
Lib/test/test_codecs.py
Lib/test/test_mmap.py
Lib/test/test_socket.py
Lib/test/test_ssl.py
Misc/NEWS
Modules/_codecsmodule.c
Modules/_ssl.c
Modules/mmapmodule.c
Modules/ossaudiodev.c
Modules/socketmodule.c

index 18e05e31f751089b31907ae6f734108976cb1fb0..b74a8231ea929a900952bb9b3835ec796f7b15b9 100644 (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.
       Returns ``-1`` on failure.
 
+      .. versionchanged: 3.5
+         Writable :term:`bytes-like object` is now accepted.
+
 
    .. 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.
       Returns ``-1`` on failure.
 
+      .. versionchanged: 3.5
+         Writable :term:`bytes-like object` is now accepted.
+
 
    .. 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
       writing to it will raise a :exc:`TypeError` exception.
 
+      .. versionchanged: 3.5
+         Writable :term:`bytes-like object` is now accepted.
+
 
    .. method:: write_byte(byte)
 
index bb5081afde8b2c245862311c90d0c27335821469..c60d596506c217d4409106e7c3c71991bd6b429b 100644 (file)
@@ -148,21 +148,30 @@ and (read-only) attributes:
 
 .. method:: oss_audio_device.write(data)
 
-   Write the Python string *data* to the audio device and return the number of
-   bytes written.  If the audio device is in blocking mode (the default), the
-   entire string is always written (again, this is different from usual Unix device
-   semantics).  If the device is in non-blocking mode, some data may not be written
+   Write a :term:`bytes-like object` *data* to the audio device and return the
+   number of bytes written.  If the audio device is in blocking mode (the
+   default), the entire data is always written (again, this is different from
+   usual Unix device semantics).  If the device is in non-blocking mode, some
+   data may not be written
    ---see :meth:`writeall`.
 
+   .. versionchanged: 3.5
+      Writable :term:`bytes-like object` is now accepted.
+
 
 .. method:: oss_audio_device.writeall(data)
 
-   Write the entire Python string *data* to the audio device: waits until the audio
-   device is able to accept data, writes as much data as it will accept, and
-   repeats until *data* has been completely written. If the device is in blocking
-   mode (the default), this has the same effect as :meth:`write`; :meth:`writeall`
-   is only useful in non-blocking mode.  Has no return value, since the amount of
-   data written is always equal to the amount of data supplied.
+   Write a :term:`bytes-like object` *data* to the audio device: waits until
+   the audio device is able to accept data, writes as much data as it will
+   accept, and repeats until *data* has been completely written. If the device
+   is in blocking mode (the default), this has the same effect as
+   :meth:`write`; :meth:`writeall` is only useful in non-blocking mode.  Has
+   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
    Audio device objects also support the context management protocol, i.e. they can
index e330f0add1b28ea05ccbe879d5b87efb23732cb4..e8ff716e135d9687bcb874f42b970d9d85771eb7 100644 (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
   is represented as a string, using the file system encoding and the
   ``'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
   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
-  :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.
 
    .. versionchanged:: 3.3
       Previously, :const:`AF_UNIX` socket paths were assumed to use UTF-8
       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,
   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'``,
@@ -609,8 +612,8 @@ The :mod:`socket` module also offers various network-related services:
 
 .. function:: inet_ntoa(packed_ip)
 
-   Convert a 32-bit packed IPv4 address (a bytes object four characters in
-   length) to its standard dotted-quad string representation (for example,
+   Convert a 32-bit packed IPv4 address (a :term:`bytes-like object` four
+   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
    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
@@ -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
    stack support.
 
+   .. versionchanged: 3.5
+      Writable :term:`bytes-like object` is now accepted.
+
 
 .. 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)
 
-   Convert a packed IP address (a bytes object of some number of characters) to its
-   standard, family-specific string representation (for example, ``'7.10.0.5'`` or
-   ``'5aef:2b::8'``). :func:`inet_ntop` is useful when a library or network protocol
-   returns an object of type :c:type:`struct in_addr` (similar to :func:`inet_ntoa`)
-   or :c:type:`struct in6_addr`.
+   Convert a packed IP address (a :term:`bytes-like object` of some number of
+   bytes) to its standard, family-specific string representation (for
+   example, ``'7.10.0.5'`` or ``'5aef:2b::8'``).
+   :func:`inet_ntop` is useful when a library or network protocol returns an
+   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
-   :const:`AF_INET6`. If the string *packed_ip* is not the correct length for the
-   specified address family, :exc:`ValueError` will be raised.  A
-   :exc:`OSError` is raised for errors from the call to :func:`inet_ntop`.
+   :const:`AF_INET6`. If the bytes object *packed_ip* is not the correct
+   length for the specified address family, :exc:`ValueError` will be raised.
+   :exc:`OSError` is raised for errors from the call to :func:`inet_ntop`.
 
    Availability: Unix (maybe not all platforms), Windows.
 
    .. versionchanged:: 3.4
       Windows support added
 
+   .. versionchanged: 3.5
+      Writable :term:`bytes-like object` is now accepted.
+
 
 ..
    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
    :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
-   bytes object representing a buffer.  In the latter case it is up to the caller to
+   :mod:`socket` module (:const:`SO_\*` etc.).  The value can be an integer or
+   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
    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)
 
index 6ab11b2a214795bdddc379cb11095d3677555af2..ef8540c0f712885361b9d7a3e6d89b732eb25821 100644 (file)
@@ -340,6 +340,9 @@ Random generation
    string (so you can always use :const:`0.0`).  See :rfc:`1750` for more
    information on sources of entropy.
 
+   .. versionchanged: 3.5
+      Writable :term:`bytes-like object` is now accepted.
+
 Certificate handling
 ^^^^^^^^^^^^^^^^^^^^
 
index 4d5d7bbba831ee00fd86c47318a7b3e755404370..fb3db77a92e2e35a01f5205a288adffa627513c3 100644 (file)
@@ -1086,6 +1086,7 @@ class UTF8SigTest(UTF8Test, unittest.TestCase):
 class EscapeDecodeTest(unittest.TestCase):
     def test_empty(self):
         self.assertEqual(codecs.escape_decode(b""), (b"", 0))
+        self.assertEqual(codecs.escape_decode(bytearray()), (b"", 0))
 
     def test_raw(self):
         decode = codecs.escape_decode
index 4d23f16890793774817617e18561f4c81f45739d..3de84e8befa7153dc955155e21d02ed0f6744b06 100644 (file)
@@ -282,6 +282,7 @@ class MmapTests(unittest.TestCase):
         self.assertEqual(m.find(b'one', 1), 8)
         self.assertEqual(m.find(b'one', 1, -1), 8)
         self.assertEqual(m.find(b'one', 1, -2), -1)
+        self.assertEqual(m.find(bytearray(b'one')), 0)
 
 
     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', 1, -1), 8)
         self.assertEqual(m.rfind(b'one', 1, -2), -1)
+        self.assertEqual(m.rfind(bytearray(b'one')), 8)
 
 
     def test_double_close(self):
@@ -601,8 +603,10 @@ class MmapTests(unittest.TestCase):
         m.write(b"bar")
         self.assertEqual(m.tell(), 6)
         self.assertEqual(m[:], b"012bar6789")
-        m.seek(8)
-        self.assertRaises(ValueError, m.write, b"bar")
+        m.write(bytearray(b"baz"))
+        self.assertEqual(m.tell(), 9)
+        self.assertEqual(m[:], b"012barbaz9")
+        self.assertRaises(ValueError, m.write, b"ba")
 
     def test_non_ascii_byte(self):
         for b in (129, 200, 255): # > 128
index d43e56d45608c0ea6588fc7297092b537a895171..72eac0d1ca23ee650a19d5d7b84fb026eabdd3eb 100644 (file)
@@ -1074,6 +1074,7 @@ class GeneralModuleTests(unittest.TestCase):
         assertInvalid(f, b'\x00' * 3)
         assertInvalid(f, b'\x00' * 5)
         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('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' * 5)
         assertInvalid(g, b'\x00' * 16)
+        self.assertEqual('170.85.170.85', g(bytearray(b'\xaa\x55\xaa\x55')))
 
     @unittest.skipUnless(hasattr(socket, 'inet_ntop'),
                          'test needs socket.inet_ntop()')
@@ -1110,6 +1112,7 @@ class GeneralModuleTests(unittest.TestCase):
             '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')
         )
+        self.assertEqual('::1', f(bytearray(b'\x00' * 15 + b'\x01')))
 
         assertInvalid(b'\x12' * 15)
         assertInvalid(b'\x12' * 17)
@@ -1497,6 +1500,7 @@ class BasicCANTest(unittest.TestCase):
             s.setsockopt(socket.SOL_CAN_RAW, socket.CAN_RAW_FILTER, can_filter)
             self.assertEqual(can_filter,
                     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.')
@@ -4508,6 +4512,12 @@ class TestLinuxAbstractNamespace(unittest.TestCase):
         finally:
             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')
 class TestUnixDomain(unittest.TestCase):
 
index 0cf9cc2b2eb314bf0a9199bb54234ca20b549726..15d6b821a20bf134305d84c8101db2044054f133 100644 (file)
@@ -171,6 +171,8 @@ class BasicSocketTests(unittest.TestCase):
             self.assertRaises(TypeError, ssl.RAND_egd, 1)
             self.assertRaises(TypeError, ssl.RAND_egd, 'foo', 1)
         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')
     def test_random_fork(self):
index 33751e7745b181a540ac564b37ac5a0e8857174d..8b9d314a71bca4d49213c8f6a5f2e8d49487bf34 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -21,6 +21,10 @@ Core and Builtins
 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
   retried with the recomputed delay, except if the signal handler raises an
   exception (PEP 475).
index bf408afeca983b9df8cd07eb0ce4317167a335d6..b9268cec2f146bde8d212ae595e5a7ec62d567a7 100644 (file)
@@ -208,15 +208,18 @@ static PyObject *
 escape_decode(PyObject *self,
               PyObject *args)
 {
+    Py_buffer pbuf;
     const char *errors = NULL;
-    const char *data;
-    Py_ssize_t size;
+    PyObject *result;
 
-    if (!PyArg_ParseTuple(args, "s#|z:escape_decode",
-                          &data, &size, &errors))
+    if (!PyArg_ParseTuple(args, "s*|z:escape_decode",
+                          &pbuf, &errors))
         return NULL;
-    return codec_tuple(PyBytes_DecodeEscape(data, size, errors, 0, NULL),
-                       size);
+    result = codec_tuple(
+            PyBytes_DecodeEscape(pbuf.buf, pbuf.len, errors, 0, NULL),
+            pbuf.len);
+    PyBuffer_Release(&pbuf);
+    return result;
 }
 
 static PyObject *
index fb03513d89b02ddafe5fa8631a285ff49aa49711..be6fca3c672b209354965532ecc8b4a17d096606 100644 (file)
@@ -3672,18 +3672,22 @@ static PyTypeObject PySSLMemoryBIO_Type = {
 static PyObject *
 PySSL_RAND_add(PyObject *self, PyObject *args)
 {
-    char *buf;
+    Py_buffer view;
+    const char *buf;
     Py_ssize_t len, written;
     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;
+    buf = (const char *)view.buf;
+    len = view.len;
     do {
         written = Py_MIN(len, INT_MAX);
         RAND_add(buf, (int)written, entropy);
         buf += written;
         len -= written;
     } while (len);
+    PyBuffer_Release(&view);
     Py_INCREF(Py_None);
     return Py_None;
 }
index d043bb38d665140cc03b0990dea1bbfe29fca213..63e93b730aa1c2d4e5c2f98f583f3501f46742e5 100644 (file)
@@ -301,16 +301,17 @@ mmap_gfind(mmap_object *self,
 {
     Py_ssize_t start = self->pos;
     Py_ssize_t end = self->size;
-    const char *needle;
-    Py_ssize_t len;
+    Py_buffer view;
 
     CHECK_VALID(NULL);
-    if (!PyArg_ParseTuple(args, reverse ? "y#|nn:rfind" : "y#|nn:find",
-                          &needle, &len, &start, &end)) {
+    if (!PyArg_ParseTuple(args, reverse ? "y*|nn:rfind" : "y*|nn:find",
+                          &view, &start, &end)) {
         return NULL;
     } else {
         const char *p, *start_p, *end_p;
         int sign = reverse ? -1 : 1;
+        const char *needle = view.buf;
+        Py_ssize_t len = view.len;
 
         if (start < 0)
             start += self->size;
@@ -335,9 +336,11 @@ mmap_gfind(mmap_object *self,
             for (i = 0; i < len && needle[i] == p[i]; ++i)
                 /* nothing */;
             if (i == len) {
+                PyBuffer_Release(&view);
                 return PyLong_FromSsize_t(p - self->data);
             }
         }
+        PyBuffer_Release(&view);
         return PyLong_FromLong(-1);
     }
 }
@@ -385,22 +388,25 @@ static PyObject *
 mmap_write_method(mmap_object *self,
                   PyObject *args)
 {
-    Py_ssize_t length;
-    char *data;
+    Py_buffer data;
 
     CHECK_VALID(NULL);
-    if (!PyArg_ParseTuple(args, "y#:write", &data, &length))
+    if (!PyArg_ParseTuple(args, "y*:write", &data))
         return(NULL);
 
-    if (!is_writable(self))
+    if (!is_writable(self)) {
+        PyBuffer_Release(&data);
         return NULL;
+    }
 
-    if ((self->pos + length) > self->size) {
+    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, length);
-    self->pos = self->pos+length;
+    memcpy(self->data + self->pos, data.buf, data.len);
+    self->pos = self->pos + data.len;
+    PyBuffer_Release(&data);
     Py_INCREF(Py_None);
     return Py_None;
 }
index 9bc7641e79b592139e952a2b132c1dbdc67e90b1..f6ad216f81fc748864b82d139b46ab990e5bdb78 100644 (file)
@@ -426,17 +426,18 @@ oss_read(oss_audio_t *self, PyObject *args)
 static PyObject *
 oss_write(oss_audio_t *self, PyObject *args)
 {
-    char *cp;
-    int rv, size;
+    Py_buffer data;
+    int rv;
 
     if (!_is_fd_valid(self->fd))
         return NULL;
 
-    if (!PyArg_ParseTuple(args, "y#:write", &cp, &size)) {
+    if (!PyArg_ParseTuple(args, "y*:write", &data)) {
         return NULL;
     }
 
-    rv = _Py_write(self->fd, cp, size);
+    rv = _Py_write(self->fd, data.buf, data.len);
+    PyBuffer_Release(&data);
     if (rv == -1)
         return NULL;
 
@@ -447,8 +448,10 @@ oss_write(oss_audio_t *self, PyObject *args)
 static PyObject *
 oss_writeall(oss_audio_t *self, PyObject *args)
 {
-    char *cp;
-    int rv, size;
+    Py_buffer data;
+    const char *cp;
+    Py_ssize_t size;
+    int rv;
     fd_set write_set_fds;
     int select_rv;
 
@@ -462,17 +465,20 @@ oss_writeall(oss_audio_t *self, PyObject *args)
     if (!_is_fd_valid(self->fd))
         return NULL;
 
-    if (!PyArg_ParseTuple(args, "y#:write", &cp, &size))
+    if (!PyArg_ParseTuple(args, "y*:writeall", &data))
         return NULL;
 
     if (!_PyIsSelectable_fd(self->fd)) {
         PyErr_SetString(PyExc_ValueError,
                         "file descriptor out of range for select");
+        PyBuffer_Release(&data);
         return NULL;
     }
     /* use select to wait for audio device to be available */
     FD_ZERO(&write_set_fds);
     FD_SET(self->fd, &write_set_fds);
+    cp = (const char *)data.buf;
+    size = data.len;
 
     while (size > 0) {
         Py_BEGIN_ALLOW_THREADS
@@ -480,10 +486,12 @@ oss_writeall(oss_audio_t *self, PyObject *args)
         Py_END_ALLOW_THREADS
 
         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);
+        }
 
-        rv = _Py_write(self->fd, cp, size);
+        rv = _Py_write(self->fd, , cp, Py_MIN(size, INT_MAX));
         if (rv == -1) {
             /* buffer is full, try again */
             if (errno == EAGAIN) {
@@ -491,6 +499,7 @@ oss_writeall(oss_audio_t *self, PyObject *args)
                 continue;
             }
             /* it's a real error */
+            PyBuffer_Release(&data);
             return NULL;
         }
 
@@ -499,6 +508,7 @@ oss_writeall(oss_audio_t *self, PyObject *args)
         size -= rv;
         cp += rv;
     }
+    PyBuffer_Release(&data);
     Py_INCREF(Py_None);
     return Py_None;
 }
index 480ee5ab4ec538006595e53270a1294d4915b310..147b48ee0edca2d00290e9cf20c5852b47975ebf 100644 (file)
@@ -1299,8 +1299,7 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
     case AF_UNIX:
     {
         struct sockaddr_un* addr;
-        char *path;
-        int len;
+        Py_buffer path;
         int retval = 0;
 
         /* PEP 383.  Not using PyUnicode_FSConverter since we need to
@@ -1311,15 +1310,17 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
         }
         else
             Py_INCREF(args);
-        if (!PyArg_Parse(args, "y#", &path, &len))
-            goto unix_out;
-        assert(len >= 0);
+        if (!PyArg_Parse(args, "y*", &path)) {
+            Py_DECREF(args);
+            return retval;
+        }
+        assert(path.len >= 0);
 
         addr = (struct sockaddr_un*)addr_ret;
 #ifdef linux
-        if (len > 0 && path[0] == 0) {
+        if (path.len > 0 && *(const char *)path.buf == 0) {
             /* 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,
                                 "AF_UNIX path too long");
                 goto unix_out;
@@ -1329,18 +1330,19 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
 #endif /* linux */
         {
             /* 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,
                                 "AF_UNIX path too long");
                 goto unix_out;
             }
-            addr->sun_path[len] = 0;
+            addr->sun_path[path.len] = 0;
         }
         addr->sun_family = s->sock_family;
-        memcpy(addr->sun_path, pathlen);
-        *len_ret = len + offsetof(struct sockaddr_un, sun_path);
+        memcpy(addr->sun_path, path.buf, path.len);
+        *len_ret = path.len + offsetof(struct sockaddr_un, sun_path);
         retval = 1;
     unix_out:
+        PyBuffer_Release(&path);
         Py_DECREF(args);
         return retval;
     }
@@ -1562,8 +1564,7 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
         int protoNumber;
         int hatype = 0;
         int pkttype = 0;
-        char *haddr = NULL;
-        unsigned int halen = 0;
+        Py_buffer haddr = {NULL, NULL};
 
         if (!PyTuple_Check(args)) {
             PyErr_Format(
@@ -1573,25 +1574,28 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
                 Py_TYPE(args)->tp_name);
             return 0;
         }
-        if (!PyArg_ParseTuple(args, "si|iiy#", &interfaceName,
+        if (!PyArg_ParseTuple(args, "si|iiy*", &interfaceName,
                               &protoNumber, &pkttype, &hatype,
-                              &haddr, &halen))
+                              &haddr))
             return 0;
         strncpy(ifr.ifr_name, interfaceName, sizeof(ifr.ifr_name));
         ifr.ifr_name[(sizeof(ifr.ifr_name))-1] = '\0';
         if (ioctl(s->sock_fd, SIOCGIFINDEX, &ifr) < 0) {
             s->errorhandler();
+            PyBuffer_Release(&haddr);
             return 0;
         }
-        if (halen > 8) {
-          PyErr_SetString(PyExc_ValueError,
-                          "Hardware address must be 8 bytes or less");
-          return 0;
+        if (haddr.buf && haddr.len > 8) {
+            PyErr_SetString(PyExc_ValueError,
+                            "Hardware address must be 8 bytes or less");
+            PyBuffer_Release(&haddr);
+            return 0;
         }
         if (protoNumber < 0 || protoNumber > 0xffff) {
             PyErr_SetString(
                 PyExc_OverflowError,
                 "getsockaddrarg: protoNumber must be 0-65535.");
+            PyBuffer_Release(&haddr);
             return 0;
         }
         addr = (struct sockaddr_ll*)addr_ret;
@@ -1600,11 +1604,14 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
         addr->sll_ifindex = ifr.ifr_ifindex;
         addr->sll_pkttype = pkttype;
         addr->sll_hatype = hatype;
-        if (halen != 0) {
-          memcpy(&addr->sll_addr, haddr, halen);
+        if (haddr.buf) {
+            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;
+        PyBuffer_Release(&haddr);
         return 1;
     }
 #endif
@@ -2230,22 +2237,21 @@ sock_setsockopt(PySocketSockObject *s, PyObject *args)
     int level;
     int optname;
     int res;
-    char *buf;
-    int buflen;
+    Py_buffer optval;
     int flag;
 
     if (PyArg_ParseTuple(args, "iii:setsockopt",
                          &level, &optname, &flag)) {
-        buf = (char *) &flag;
-        buflen = sizeof flag;
+        res = setsockopt(s->sock_fd, level, optname, &flag, sizeof flag);
     }
     else {
         PyErr_Clear();
-        if (!PyArg_ParseTuple(args, "iiy#:setsockopt",
-                              &level, &optname, &buf, &buflen))
+        if (!PyArg_ParseTuple(args, "iiy*:setsockopt",
+                              &level, &optname, &optval))
             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)
         return s->errorhandler();
     Py_INCREF(Py_None);
@@ -5037,21 +5043,22 @@ Convert an IP address from 32-bit packed binary format to string format");
 static PyObject*
 socket_inet_ntoa(PyObject *self, PyObject *args)
 {
-    char *packed_str;
-    int addr_len;
+    Py_buffer packed_ip;
     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;
     }
 
-    if (addr_len != sizeof(packed_addr)) {
+    if (packed_ip.len != sizeof(packed_addr)) {
         PyErr_SetString(PyExc_OSError,
             "packed IP wrong length for inet_ntoa");
+        PyBuffer_Release(&packed_ip);
         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));
 }
@@ -5162,8 +5169,7 @@ static PyObject *
 socket_inet_ntop(PyObject *self, PyObject *args)
 {
     int af;
-    char* packed;
-    int len;
+    Py_buffer packed_ip;
     const char* retval;
 #ifdef ENABLE_IPV6
     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 */
     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;
     }
 
     if (af == AF_INET) {
-        if (len != sizeof(struct in_addr)) {
+        if (packed_ip.len != sizeof(struct in_addr)) {
             PyErr_SetString(PyExc_ValueError,
                 "invalid length of packed IP address string");
+            PyBuffer_Release(&packed_ip);
             return NULL;
         }
 #ifdef ENABLE_IPV6
     } else if (af == AF_INET6) {
-        if (len != sizeof(struct in6_addr)) {
+        if (packed_ip.len != sizeof(struct in6_addr)) {
             PyErr_SetString(PyExc_ValueError,
                 "invalid length of packed IP address string");
+            PyBuffer_Release(&packed_ip);
             return NULL;
         }
 #endif
     } else {
         PyErr_Format(PyExc_ValueError,
             "unknown address family %d", af);
+        PyBuffer_Release(&packed_ip);
         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) {
         PyErr_SetFromErrno(PyExc_OSError);
         return NULL;
@@ -5217,8 +5227,7 @@ static PyObject *
 socket_inet_ntop(PyObject *self, PyObject *args)
 {
     int af;
-    char* packed;
-    int len;
+    Py_buffer packed_ip;
     struct sockaddr_in6 addr;
     DWORD addrlen, ret, retlen;
 #ifdef ENABLE_IPV6
@@ -5230,38 +5239,42 @@ socket_inet_ntop(PyObject *self, PyObject *args)
     /* Guarantee NUL-termination for PyUnicode_FromString() below */
     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;
     }
 
     if (af == AF_INET) {
         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,
                 "invalid length of packed IP address string");
+            PyBuffer_Release(&packed_ip);
             return NULL;
         }
         memset(addr4, 0, sizeof(struct sockaddr_in));
         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);
     } else if (af == AF_INET6) {
-        if (len != sizeof(struct in6_addr)) {
+        if (packed_ip.len != sizeof(struct in6_addr)) {
             PyErr_SetString(PyExc_ValueError,
                 "invalid length of packed IP address string");
+            PyBuffer_Release(&packed_ip);
             return NULL;
         }
 
         memset(&addr, 0, sizeof(addr));
         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);
     } else {
         PyErr_Format(PyExc_ValueError,
             "unknown address family %d", af);
+        PyBuffer_Release(&packed_ip);
         return NULL;
     }
+    PyBuffer_Release(&packed_ip);
 
     retlen = sizeof(ip);
     ret = WSAAddressToStringA((struct sockaddr*)&addr, addrlen, NULL,