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.
diff --git a/Modules/_codecsmodule.c b/Modules/_codecsmodule.c
index bf408af..b9268ce 100644
--- a/Modules/_codecsmodule.c
+++ b/Modules/_codecsmodule.c
@@ -208,15 +208,18 @@
 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 *
diff --git a/Modules/_ssl.c b/Modules/_ssl.c
index fb03513..be6fca3 100644
--- a/Modules/_ssl.c
+++ b/Modules/_ssl.c
@@ -3672,18 +3672,22 @@
 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;
 }
diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c
index d043bb3..63e93b7 100644
--- a/Modules/mmapmodule.c
+++ b/Modules/mmapmodule.c
@@ -301,16 +301,17 @@
 {
     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 @@
             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 @@
 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))
-        return NULL;
-
-    if ((self->pos + length) > self->size) {
-        PyErr_SetString(PyExc_ValueError, "data out of range");
+    if (!is_writable(self)) {
+        PyBuffer_Release(&data);
         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);
     return Py_None;
 }
diff --git a/Modules/ossaudiodev.c b/Modules/ossaudiodev.c
index 9bc7641..f6ad216 100644
--- a/Modules/ossaudiodev.c
+++ b/Modules/ossaudiodev.c
@@ -426,17 +426,18 @@
 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 @@
 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 @@
     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 @@
         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 @@
                 continue;
             }
             /* it's a real error */
+            PyBuffer_Release(&data);
             return NULL;
         }
 
@@ -499,6 +508,7 @@
         size -= rv;
         cp += rv;
     }
+    PyBuffer_Release(&data);
     Py_INCREF(Py_None);
     return Py_None;
 }
diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c
index 480ee5a..147b48e 100644
--- a/Modules/socketmodule.c
+++ b/Modules/socketmodule.c
@@ -1299,8 +1299,7 @@
     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 @@
         }
         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 @@
 #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, path, len);
-        *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 @@
         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 @@
                 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 @@
         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 @@
     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 @@
 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 @@
 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 @@
     /* 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 @@
 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 @@
     /* 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,