[Python-checkins] cpython (3.4): Issue #22896: Avoid to use PyObject_AsCharBuffer(), PyObject_AsReadBuffer()

serhiy.storchaka python-checkins at python.org
Tue Feb 3 01:05:58 CET 2015


https://hg.python.org/cpython/rev/1da9630e9b7f
changeset:   94474:1da9630e9b7f
branch:      3.4
parent:      94472:b883bb8bd744
user:        Serhiy Storchaka <storchaka at gmail.com>
date:        Tue Feb 03 01:21:08 2015 +0200
summary:
  Issue #22896: Avoid to use PyObject_AsCharBuffer(), PyObject_AsReadBuffer()
and PyObject_AsWriteBuffer().

files:
  Lib/ctypes/test/test_frombuffer.py |   50 +++-
  Misc/NEWS                          |    3 +
  Modules/_codecsmodule.c            |   24 +-
  Modules/_ctypes/_ctypes.c          |   59 +++--
  Modules/_io/bytesio.c              |   10 +-
  Modules/_sqlite/connection.c       |   11 +-
  Modules/_sqlite/statement.c        |   13 +-
  Modules/_struct.c                  |   23 +-
  Objects/abstract.c                 |   81 ++-----
  Objects/bytearrayobject.c          |   98 +++-----
  Objects/bytes_methods.c            |   33 +--
  Objects/bytesobject.c              |  179 ++++++++--------
  Objects/complexobject.c            |    9 +-
  Objects/exceptions.c               |   32 +-
  Objects/floatobject.c              |    8 +-
  Objects/stringlib/join.h           |    9 +-
  Python/bltinmodule.c               |   34 +-
  17 files changed, 334 insertions(+), 342 deletions(-)


diff --git a/Lib/ctypes/test/test_frombuffer.py b/Lib/ctypes/test/test_frombuffer.py
--- a/Lib/ctypes/test/test_frombuffer.py
+++ b/Lib/ctypes/test/test_frombuffer.py
@@ -10,7 +10,7 @@
         self._init_called = True
 
 class Test(unittest.TestCase):
-    def test_fom_buffer(self):
+    def test_from_buffer(self):
         a = array.array("i", range(16))
         x = (c_int * 16).from_buffer(a)
 
@@ -23,25 +23,37 @@
         a[0], a[-1] = 200, -200
         self.assertEqual(x[:], a.tolist())
 
-        self.assertIn(a, x._objects.values())
+        self.assertRaises(BufferError, a.append, 100)
+        self.assertRaises(BufferError, a.pop)
 
-        self.assertRaises(ValueError,
-                          c_int.from_buffer, a, -1)
+        del x; del y; gc.collect(); gc.collect(); gc.collect()
+        a.append(100)
+        a.pop()
+        x = (c_int * 16).from_buffer(a)
+
+        self.assertIn(a, [obj.obj if isinstance(obj, memoryview) else obj
+                          for obj in x._objects.values()])
 
         expected = x[:]
         del a; gc.collect(); gc.collect(); gc.collect()
         self.assertEqual(x[:], expected)
 
-        self.assertRaises(TypeError,
-                          (c_char * 16).from_buffer, "a" * 16)
+        with self.assertRaises(TypeError):
+            (c_char * 16).from_buffer(b"a" * 16)
+        with self.assertRaises(TypeError):
+            (c_char * 16).from_buffer("a" * 16)
 
-    def test_fom_buffer_with_offset(self):
+    def test_from_buffer_with_offset(self):
         a = array.array("i", range(16))
         x = (c_int * 15).from_buffer(a, sizeof(c_int))
 
         self.assertEqual(x[:], a.tolist()[1:])
-        self.assertRaises(ValueError, lambda: (c_int * 16).from_buffer(a, sizeof(c_int)))
-        self.assertRaises(ValueError, lambda: (c_int * 1).from_buffer(a, 16 * sizeof(c_int)))
+        with self.assertRaises(ValueError):
+            c_int.from_buffer(a, -1)
+        with self.assertRaises(ValueError):
+            (c_int * 16).from_buffer(a, sizeof(c_int))
+        with self.assertRaises(ValueError):
+            (c_int * 1).from_buffer(a, 16 * sizeof(c_int))
 
     def test_from_buffer_copy(self):
         a = array.array("i", range(16))
@@ -56,26 +68,30 @@
         a[0], a[-1] = 200, -200
         self.assertEqual(x[:], list(range(16)))
 
+        a.append(100)
+        self.assertEqual(x[:], list(range(16)))
+
         self.assertEqual(x._objects, None)
 
-        self.assertRaises(ValueError,
-                          c_int.from_buffer, a, -1)
-
         del a; gc.collect(); gc.collect(); gc.collect()
         self.assertEqual(x[:], list(range(16)))
 
         x = (c_char * 16).from_buffer_copy(b"a" * 16)
         self.assertEqual(x[:], b"a" * 16)
+        with self.assertRaises(TypeError):
+            (c_char * 16).from_buffer_copy("a" * 16)
 
-    def test_fom_buffer_copy_with_offset(self):
+    def test_from_buffer_copy_with_offset(self):
         a = array.array("i", range(16))
         x = (c_int * 15).from_buffer_copy(a, sizeof(c_int))
 
         self.assertEqual(x[:], a.tolist()[1:])
-        self.assertRaises(ValueError,
-                          (c_int * 16).from_buffer_copy, a, sizeof(c_int))
-        self.assertRaises(ValueError,
-                          (c_int * 1).from_buffer_copy, a, 16 * sizeof(c_int))
+        with self.assertRaises(ValueError):
+            c_int.from_buffer_copy(a, -1)
+        with self.assertRaises(ValueError):
+            (c_int * 16).from_buffer_copy(a, sizeof(c_int))
+        with self.assertRaises(ValueError):
+            (c_int * 1).from_buffer_copy(a, 16 * sizeof(c_int))
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -11,6 +11,9 @@
 Core and Builtins
 -----------------
 
+- Issue #22896: Avoid using PyObject_AsCharBuffer(), PyObject_AsReadBuffer()
+  and PyObject_AsWriteBuffer().
+
 - Issue #21295: Revert some changes (issue #16795) to AST line numbers and
   column offsets that constituted a regression.
 
diff --git a/Modules/_codecsmodule.c b/Modules/_codecsmodule.c
--- a/Modules/_codecsmodule.c
+++ b/Modules/_codecsmodule.c
@@ -284,8 +284,6 @@
 {
     PyObject *obj;
     const char *errors = NULL;
-    const char *data;
-    Py_ssize_t size;
 
     if (!PyArg_ParseTuple(args, "O|z:unicode_internal_decode",
                           &obj, &errors))
@@ -298,11 +296,16 @@
         return codec_tuple(obj, PyUnicode_GET_LENGTH(obj));
     }
     else {
-        if (PyObject_AsReadBuffer(obj, (const void **)&data, &size))
+        Py_buffer view;
+        PyObject *result;
+        if (PyObject_GetBuffer(obj, &view, PyBUF_SIMPLE) != 0)
             return NULL;
 
-        return codec_tuple(_PyUnicode_DecodeUnicodeInternal(data, size, errors),
-                           size);
+        result = codec_tuple(
+                _PyUnicode_DecodeUnicodeInternal(view.buf, view.len, errors),
+                view.len);
+        PyBuffer_Release(&view);
+        return result;
     }
 }
 
@@ -727,8 +730,6 @@
 {
     PyObject *obj;
     const char *errors = NULL;
-    const char *data;
-    Py_ssize_t len, size;
 
     if (PyErr_WarnEx(PyExc_DeprecationWarning,
                      "unicode_internal codec has been deprecated",
@@ -741,6 +742,7 @@
 
     if (PyUnicode_Check(obj)) {
         Py_UNICODE *u;
+        Py_ssize_t len, size;
 
         if (PyUnicode_READY(obj) < 0)
             return NULL;
@@ -755,9 +757,13 @@
                            PyUnicode_GET_LENGTH(obj));
     }
     else {
-        if (PyObject_AsReadBuffer(obj, (const void **)&data, &size))
+        Py_buffer view;
+        PyObject *result;
+        if (PyObject_GetBuffer(obj, &view, PyBUF_SIMPLE) != 0)
             return NULL;
-        return codec_tuple(PyBytes_FromStringAndSize(data, size), size);
+        result = codec_tuple(PyBytes_FromStringAndSize(view.buf, view.len), view.len);
+        PyBuffer_Release(&view);
+        return result;
     }
 }
 
diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c
--- a/Modules/_ctypes/_ctypes.c
+++ b/Modules/_ctypes/_ctypes.c
@@ -463,39 +463,45 @@
 static PyObject *
 CDataType_from_buffer(PyObject *type, PyObject *args)
 {
-    void *buffer;
-    Py_ssize_t buffer_len;
+    Py_buffer buffer;
     Py_ssize_t offset = 0;
-    PyObject *obj, *result;
+    PyObject *result, *mv;
     StgDictObject *dict = PyType_stgdict(type);
     assert (dict);
 
-    if (!PyArg_ParseTuple(args, "O|n:from_buffer", &obj, &offset))
-        return NULL;
-
-    if (-1 == PyObject_AsWriteBuffer(obj, &buffer, &buffer_len))
+    if (!PyArg_ParseTuple(args, "w*|n:from_buffer", &buffer, &offset))
         return NULL;
 
     if (offset < 0) {
         PyErr_SetString(PyExc_ValueError,
                         "offset cannot be negative");
+        PyBuffer_Release(&buffer);
         return NULL;
     }
-    if (dict->size > buffer_len - offset) {
+    if (dict->size > buffer.len - offset) {
         PyErr_Format(PyExc_ValueError,
                      "Buffer size too small (%zd instead of at least %zd bytes)",
-                     buffer_len, dict->size + offset);
+                     buffer.len, dict->size + offset);
+        PyBuffer_Release(&buffer);
         return NULL;
     }
 
-    result = PyCData_AtAddress(type, (char *)buffer + offset);
-    if (result == NULL)
+    result = PyCData_AtAddress(type, (char *)buffer.buf + offset);
+    if (result == NULL) {
+        PyBuffer_Release(&buffer);
         return NULL;
-
-    Py_INCREF(obj);
-    if (-1 == KeepRef((CDataObject *)result, -1, obj)) {
+    }
+
+    mv = PyMemoryView_FromBuffer(&buffer);
+    if (mv == NULL) {
+        PyBuffer_Release(&buffer);
         return NULL;
     }
+    /* Hack the memoryview so that it will release the buffer. */
+    ((PyMemoryViewObject *)mv)->mbuf->master.obj = buffer.obj;
+    ((PyMemoryViewObject *)mv)->view.obj = buffer.obj;
+    if (-1 == KeepRef((CDataObject *)result, -1, mv))
+        result = NULL;
     return result;
 }
 
@@ -508,37 +514,36 @@
 static PyObject *
 CDataType_from_buffer_copy(PyObject *type, PyObject *args)
 {
-    const void *buffer;
-    Py_ssize_t buffer_len;
+    Py_buffer buffer;
     Py_ssize_t offset = 0;
-    PyObject *obj, *result;
+    PyObject *result;
     StgDictObject *dict = PyType_stgdict(type);
     assert (dict);
 
-    if (!PyArg_ParseTuple(args, "O|n:from_buffer", &obj, &offset))
-        return NULL;
-
-    if (-1 == PyObject_AsReadBuffer(obj, (const void**)&buffer, &buffer_len))
+    if (!PyArg_ParseTuple(args, "y*|n:from_buffer", &buffer, &offset))
         return NULL;
 
     if (offset < 0) {
         PyErr_SetString(PyExc_ValueError,
                         "offset cannot be negative");
+        PyBuffer_Release(&buffer);
         return NULL;
     }
 
-    if (dict->size > buffer_len - offset) {
+    if (dict->size > buffer.len - offset) {
         PyErr_Format(PyExc_ValueError,
                      "Buffer size too small (%zd instead of at least %zd bytes)",
-                     buffer_len, dict->size + offset);
+                     buffer.len, dict->size + offset);
+        PyBuffer_Release(&buffer);
         return NULL;
     }
 
     result = GenericPyCData_new((PyTypeObject *)type, NULL, NULL);
-    if (result == NULL)
-        return NULL;
-    memcpy(((CDataObject *)result)->b_ptr,
-           (char *)buffer+offset, dict->size);
+    if (result != NULL) {
+        memcpy(((CDataObject *)result)->b_ptr,
+               (char *)buffer.buf + offset, dict->size);
+    }
+    PyBuffer_Release(&buffer);
     return result;
 }
 
diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c
--- a/Modules/_io/bytesio.c
+++ b/Modules/_io/bytesio.c
@@ -437,17 +437,18 @@
 "is set not to block as has no data to read.");
 
 static PyObject *
-bytesio_readinto(bytesio *self, PyObject *buffer)
+bytesio_readinto(bytesio *self, PyObject *arg)
 {
-    void *raw_buffer;
+    Py_buffer buffer;
     Py_ssize_t len, n;
 
     CHECK_CLOSED(self);
 
-    if (PyObject_AsWriteBuffer(buffer, &raw_buffer, &len) == -1)
+    if (!PyArg_Parse(arg, "w*", &buffer))
         return NULL;
 
     /* adjust invalid sizes */
+    len = buffer.len;
     n = self->string_size - self->pos;
     if (len > n) {
         len = n;
@@ -455,10 +456,11 @@
             len = 0;
     }
 
-    memcpy(raw_buffer, self->buf + self->pos, len);
+    memcpy(buffer.buf, self->buf + self->pos, len);
     assert(self->pos + len < PY_SSIZE_T_MAX);
     assert(len >= 0);
     self->pos += len;
+    PyBuffer_Release(&buffer);
 
     return PyLong_FromSsize_t(len);
 }
diff --git a/Modules/_sqlite/connection.c b/Modules/_sqlite/connection.c
--- a/Modules/_sqlite/connection.c
+++ b/Modules/_sqlite/connection.c
@@ -522,19 +522,20 @@
             return -1;
         sqlite3_result_text(context, str, -1, SQLITE_TRANSIENT);
     } else if (PyObject_CheckBuffer(py_val)) {
-        const char* buffer;
-        Py_ssize_t buflen;
-        if (PyObject_AsCharBuffer(py_val, &buffer, &buflen) != 0) {
+        Py_buffer view;
+        if (PyObject_GetBuffer(py_val, &view, PyBUF_SIMPLE) != 0) {
             PyErr_SetString(PyExc_ValueError,
                             "could not convert BLOB to buffer");
             return -1;
         }
-        if (buflen > INT_MAX) {
+        if (view.len > INT_MAX) {
             PyErr_SetString(PyExc_OverflowError,
                             "BLOB longer than INT_MAX bytes");
+            PyBuffer_Release(&view);
             return -1;
         }
-        sqlite3_result_blob(context, buffer, (int)buflen, SQLITE_TRANSIENT);
+        sqlite3_result_blob(context, view.buf, (int)view.len, SQLITE_TRANSIENT);
+        PyBuffer_Release(&view);
     } else {
         return -1;
     }
diff --git a/Modules/_sqlite/statement.c b/Modules/_sqlite/statement.c
--- a/Modules/_sqlite/statement.c
+++ b/Modules/_sqlite/statement.c
@@ -94,7 +94,6 @@
 int pysqlite_statement_bind_parameter(pysqlite_Statement* self, int pos, PyObject* parameter)
 {
     int rc = SQLITE_OK;
-    const char* buffer;
     char* string;
     Py_ssize_t buflen;
     parameter_type paramtype;
@@ -145,18 +144,22 @@
             }
             rc = sqlite3_bind_text(self->st, pos, string, (int)buflen, SQLITE_TRANSIENT);
             break;
-        case TYPE_BUFFER:
-            if (PyObject_AsCharBuffer(parameter, &buffer, &buflen) != 0) {
+        case TYPE_BUFFER: {
+            Py_buffer view;
+            if (PyObject_GetBuffer(parameter, &view, PyBUF_SIMPLE) != 0) {
                 PyErr_SetString(PyExc_ValueError, "could not convert BLOB to buffer");
                 return -1;
             }
-            if (buflen > INT_MAX) {
+            if (view.len > INT_MAX) {
                 PyErr_SetString(PyExc_OverflowError,
                                 "BLOB longer than INT_MAX bytes");
+                PyBuffer_Release(&view);
                 return -1;
             }
-            rc = sqlite3_bind_blob(self->st, pos, buffer, buflen, SQLITE_TRANSIENT);
+            rc = sqlite3_bind_blob(self->st, pos, view.buf, (int)view.len, SQLITE_TRANSIENT);
+            PyBuffer_Release(&view);
             break;
+        }
         case TYPE_UNKNOWN:
             rc = -1;
     }
diff --git a/Modules/_struct.c b/Modules/_struct.c
--- a/Modules/_struct.c
+++ b/Modules/_struct.c
@@ -1842,8 +1842,8 @@
 s_pack_into(PyObject *self, PyObject *args)
 {
     PyStructObject *soself;
-    char *buffer;
-    Py_ssize_t buffer_len, offset;
+    Py_buffer buffer;
+    Py_ssize_t offset;
 
     /* Validate arguments.  +1 is for the first arg as buffer. */
     soself = (PyStructObject *)self;
@@ -1868,34 +1868,37 @@
     }
 
     /* Extract a writable memory buffer from the first argument */
-    if ( PyObject_AsWriteBuffer(PyTuple_GET_ITEM(args, 0),
-                                                            (void**)&buffer, &buffer_len) == -1 ) {
+    if (!PyArg_Parse(PyTuple_GET_ITEM(args, 0), "w*", &buffer))
         return NULL;
-    }
-    assert( buffer_len >= 0 );
+    assert(buffer.len >= 0);
 
     /* Extract the offset from the first argument */
     offset = PyNumber_AsSsize_t(PyTuple_GET_ITEM(args, 1), PyExc_IndexError);
-    if (offset == -1 && PyErr_Occurred())
+    if (offset == -1 && PyErr_Occurred()) {
+        PyBuffer_Release(&buffer);
         return NULL;
+    }
 
     /* Support negative offsets. */
     if (offset < 0)
-        offset += buffer_len;
+        offset += buffer.len;
 
     /* Check boundaries */
-    if (offset < 0 || (buffer_len - offset) < soself->s_size) {
+    if (offset < 0 || (buffer.len - offset) < soself->s_size) {
         PyErr_Format(StructError,
                      "pack_into requires a buffer of at least %zd bytes",
                      soself->s_size);
+        PyBuffer_Release(&buffer);
         return NULL;
     }
 
     /* Call the guts */
-    if ( s_pack_internal(soself, args, 2, buffer + offset) != 0 ) {
+    if (s_pack_internal(soself, args, 2, (char*)buffer.buf + offset) != 0) {
+        PyBuffer_Release(&buffer);
         return NULL;
     }
 
+    PyBuffer_Release(&buffer);
     Py_RETURN_NONE;
 }
 
diff --git a/Objects/abstract.c b/Objects/abstract.c
--- a/Objects/abstract.c
+++ b/Objects/abstract.c
@@ -250,28 +250,7 @@
                       const char **buffer,
                       Py_ssize_t *buffer_len)
 {
-    PyBufferProcs *pb;
-    Py_buffer view;
-
-    if (obj == NULL || buffer == NULL || buffer_len == NULL) {
-        null_error();
-        return -1;
-    }
-    pb = obj->ob_type->tp_as_buffer;
-    if (pb == NULL || pb->bf_getbuffer == NULL) {
-        PyErr_SetString(PyExc_TypeError,
-                        "expected bytes, bytearray "
-                        "or buffer compatible object");
-        return -1;
-    }
-    if ((*pb->bf_getbuffer)(obj, &view, PyBUF_SIMPLE)) return -1;
-
-    *buffer = view.buf;
-    *buffer_len = view.len;
-    if (pb->bf_releasebuffer != NULL)
-        (*pb->bf_releasebuffer)(obj, &view);
-    Py_XDECREF(view.obj);
-    return 0;
+    return PyObject_AsReadBuffer(obj, (const void **)buffer, buffer_len);
 }
 
 int
@@ -295,28 +274,18 @@
                           const void **buffer,
                           Py_ssize_t *buffer_len)
 {
-    PyBufferProcs *pb;
     Py_buffer view;
 
     if (obj == NULL || buffer == NULL || buffer_len == NULL) {
         null_error();
         return -1;
     }
-    pb = obj->ob_type->tp_as_buffer;
-    if (pb == NULL ||
-        pb->bf_getbuffer == NULL) {
-        PyErr_SetString(PyExc_TypeError,
-                        "expected an object with a buffer interface");
+    if (PyObject_GetBuffer(obj, &view, PyBUF_SIMPLE) != 0)
         return -1;
-    }
-
-    if ((*pb->bf_getbuffer)(obj, &view, PyBUF_SIMPLE)) return -1;
 
     *buffer = view.buf;
     *buffer_len = view.len;
-    if (pb->bf_releasebuffer != NULL)
-        (*pb->bf_releasebuffer)(obj, &view);
-    Py_XDECREF(view.obj);
+    PyBuffer_Release(&view);
     return 0;
 }
 
@@ -342,9 +311,7 @@
 
     *buffer = view.buf;
     *buffer_len = view.len;
-    if (pb->bf_releasebuffer != NULL)
-        (*pb->bf_releasebuffer)(obj, &view);
-    Py_XDECREF(view.obj);
+    PyBuffer_Release(&view);
     return 0;
 }
 
@@ -353,13 +320,15 @@
 int
 PyObject_GetBuffer(PyObject *obj, Py_buffer *view, int flags)
 {
-    if (!PyObject_CheckBuffer(obj)) {
+    PyBufferProcs *pb = obj->ob_type->tp_as_buffer;
+
+    if (pb == NULL || pb->bf_getbuffer == NULL) {
         PyErr_Format(PyExc_TypeError,
                      "'%.100s' does not support the buffer interface",
                      Py_TYPE(obj)->tp_name);
         return -1;
     }
-    return (*(obj->ob_type->tp_as_buffer->bf_getbuffer))(obj, view, flags);
+    return (*pb->bf_getbuffer)(obj, view, flags);
 }
 
 static int
@@ -652,10 +621,14 @@
 PyBuffer_Release(Py_buffer *view)
 {
     PyObject *obj = view->obj;
-    if (obj && Py_TYPE(obj)->tp_as_buffer && Py_TYPE(obj)->tp_as_buffer->bf_releasebuffer)
-        Py_TYPE(obj)->tp_as_buffer->bf_releasebuffer(obj, view);
-    Py_XDECREF(obj);
+    PyBufferProcs *pb;
+    if (obj == NULL)
+        return;
+    pb = Py_TYPE(obj)->tp_as_buffer;
+    if (pb && pb->bf_releasebuffer)
+        pb->bf_releasebuffer(obj, view);
     view->obj = NULL;
+    Py_DECREF(obj);
 }
 
 PyObject *
@@ -1249,8 +1222,7 @@
 {
     PyNumberMethods *m;
     PyObject *trunc_func;
-    const char *buffer;
-    Py_ssize_t buffer_len;
+    Py_buffer view;
     _Py_IDENTIFIER(__trunc__);
 
     if (o == NULL)
@@ -1288,21 +1260,22 @@
     if (PyErr_Occurred())
         return NULL;
 
-    if (PyBytes_Check(o))
+    if (PyUnicode_Check(o))
+        /* The below check is done in PyLong_FromUnicode(). */
+        return PyLong_FromUnicodeObject(o, 10);
+
+    if (PyObject_GetBuffer(o, &view, PyBUF_SIMPLE) == 0) {
         /* need to do extra error checking that PyLong_FromString()
          * doesn't do.  In particular int('9\x005') must raise an
          * exception, not truncate at the null.
          */
-        return _PyLong_FromBytes(PyBytes_AS_STRING(o),
-                                 PyBytes_GET_SIZE(o), 10);
-    if (PyUnicode_Check(o))
-        /* The above check is done in PyLong_FromUnicode(). */
-        return PyLong_FromUnicodeObject(o, 10);
-    if (!PyObject_AsCharBuffer(o, &buffer, &buffer_len))
-        return _PyLong_FromBytes(buffer, buffer_len, 10);
+        PyObject *result = _PyLong_FromBytes(view.buf, view.len, 10);
+        PyBuffer_Release(&view);
+        return result;
+    }
 
-    return type_error("int() argument must be a string or a "
-                      "number, not '%.200s'", o);
+    return type_error("int() argument must be a string, a bytes-like object "
+                      "or a number, not '%.200s'", o);
 }
 
 PyObject *
diff --git a/Objects/bytearrayobject.c b/Objects/bytearrayobject.c
--- a/Objects/bytearrayobject.c
+++ b/Objects/bytearrayobject.c
@@ -74,24 +74,6 @@
     obj->ob_exports--;
 }
 
-static Py_ssize_t
-_getbuffer(PyObject *obj, Py_buffer *view)
-{
-    PyBufferProcs *buffer = Py_TYPE(obj)->tp_as_buffer;
-
-    if (buffer == NULL || buffer->bf_getbuffer == NULL)
-    {
-        PyErr_Format(PyExc_TypeError,
-                     "Type %.100s doesn't support the buffer API",
-                     Py_TYPE(obj)->tp_name);
-        return -1;
-    }
-
-    if (buffer->bf_getbuffer(obj, view, PyBUF_SIMPLE) < 0)
-            return -1;
-    return view->len;
-}
-
 static int
 _canresize(PyByteArrayObject *self)
 {
@@ -262,8 +244,8 @@
 
     va.len = -1;
     vb.len = -1;
-    if (_getbuffer(a, &va) < 0  ||
-        _getbuffer(b, &vb) < 0) {
+    if (PyObject_GetBuffer(a, &va, PyBUF_SIMPLE) != 0 ||
+        PyObject_GetBuffer(b, &vb, PyBUF_SIMPLE) != 0) {
             PyErr_Format(PyExc_TypeError, "can't concat %.100s to %.100s",
                          Py_TYPE(a)->tp_name, Py_TYPE(b)->tp_name);
             goto done;
@@ -304,7 +286,7 @@
     Py_ssize_t size;
     Py_buffer vo;
 
-    if (_getbuffer(other, &vo) < 0) {
+    if (PyObject_GetBuffer(other, &vo, PyBUF_SIMPLE) != 0) {
         PyErr_Format(PyExc_TypeError, "can't concat %.100s to %.100s",
                      Py_TYPE(other)->tp_name, Py_TYPE(self)->tp_name);
         return NULL;
@@ -562,14 +544,14 @@
         needed = 0;
     }
     else {
-            if (_getbuffer(values, &vbytes) < 0) {
-                    PyErr_Format(PyExc_TypeError,
-                                 "can't set bytearray slice from %.100s",
-                                 Py_TYPE(values)->tp_name);
-                    return -1;
-            }
-            needed = vbytes.len;
-            bytes = vbytes.buf;
+        if (PyObject_GetBuffer(values, &vbytes, PyBUF_SIMPLE) != 0) {
+            PyErr_Format(PyExc_TypeError,
+                         "can't set bytearray slice from %.100s",
+                         Py_TYPE(values)->tp_name);
+            return -1;
+        }
+        needed = vbytes.len;
+        bytes = vbytes.buf;
     }
 
     if (lo < 0)
@@ -1012,18 +994,18 @@
         Py_RETURN_NOTIMPLEMENTED;
     }
 
-    self_size = _getbuffer(self, &self_bytes);
-    if (self_size < 0) {
+    if (PyObject_GetBuffer(self, &self_bytes, PyBUF_SIMPLE) != 0) {
         PyErr_Clear();
         Py_RETURN_NOTIMPLEMENTED;
     }
-
-    other_size = _getbuffer(other, &other_bytes);
-    if (other_size < 0) {
+    self_size = self_bytes.len;
+
+    if (PyObject_GetBuffer(other, &other_bytes, PyBUF_SIMPLE) != 0) {
         PyErr_Clear();
         PyBuffer_Release(&self_bytes);
         Py_RETURN_NOTIMPLEMENTED;
     }
+    other_size = other_bytes.len;
 
     if (self_size != other_size && (op == Py_EQ || op == Py_NE)) {
         /* Shortcut: if the lengths differ, the objects differ */
@@ -1135,7 +1117,7 @@
         return -2;
 
     if (subobj) {
-        if (_getbuffer(subobj, &subbuf) < 0)
+        if (PyObject_GetBuffer(subobj, &subbuf, PyBUF_SIMPLE) != 0)
             return -2;
 
         sub = subbuf.buf;
@@ -1203,7 +1185,7 @@
         return NULL;
 
     if (sub_obj) {
-        if (_getbuffer(sub_obj, &vsub) < 0)
+        if (PyObject_GetBuffer(sub_obj, &vsub, PyBUF_SIMPLE) != 0)
             return NULL;
 
         sub = vsub.buf;
@@ -1318,7 +1300,7 @@
         Py_buffer varg;
         Py_ssize_t pos;
         PyErr_Clear();
-        if (_getbuffer(arg, &varg) < 0)
+        if (PyObject_GetBuffer(arg, &varg, PyBUF_SIMPLE) != 0)
             return -1;
         pos = stringlib_find(PyByteArray_AS_STRING(self), Py_SIZE(self),
                              varg.buf, varg.len, 0);
@@ -1349,7 +1331,7 @@
 
     str = PyByteArray_AS_STRING(self);
 
-    if (_getbuffer(substr, &vsubstr) < 0)
+    if (PyObject_GetBuffer(substr, &vsubstr, PyBUF_SIMPLE) != 0)
         return -1;
 
     ADJUST_INDICES(start, end, len);
@@ -1493,7 +1475,7 @@
     if (tableobj == Py_None) {
         table = NULL;
         tableobj = NULL;
-    } else if (_getbuffer(tableobj, &vtable) < 0) {
+    } else if (PyObject_GetBuffer(tableobj, &vtable, PyBUF_SIMPLE) != 0) {
         return NULL;
     } else {
         if (vtable.len != 256) {
@@ -1506,7 +1488,7 @@
     }
 
     if (delobj != NULL) {
-        if (_getbuffer(delobj, &vdel) < 0) {
+        if (PyObject_GetBuffer(delobj, &vdel, PyBUF_SIMPLE) != 0) {
             if (tableobj != NULL)
                 PyBuffer_Release(&vtable);
             return NULL;
@@ -2070,26 +2052,20 @@
 static PyObject *
 bytearray_replace(PyByteArrayObject *self, PyObject *args)
 {
+    PyObject *res;
+    Py_buffer old = {NULL, NULL};
+    Py_buffer new = {NULL, NULL};
     Py_ssize_t count = -1;
-    PyObject *from, *to, *res;
-    Py_buffer vfrom, vto;
-
-    if (!PyArg_ParseTuple(args, "OO|n:replace", &from, &to, &count))
+
+    if (!PyArg_ParseTuple(args, "y*y*|n:replace", &old, &new, &count))
         return NULL;
 
-    if (_getbuffer(from, &vfrom) < 0)
-        return NULL;
-    if (_getbuffer(to, &vto) < 0) {
-        PyBuffer_Release(&vfrom);
-        return NULL;
-    }
-
     res = (PyObject *)replace((PyByteArrayObject *) self,
-                              vfrom.buf, vfrom.len,
-                              vto.buf, vto.len, count);
-
-    PyBuffer_Release(&vfrom);
-    PyBuffer_Release(&vto);
+                              (const char *)old.buf, old.len,
+                              (const char *)new.buf, new.len, count);
+
+    PyBuffer_Release(&old);
+    PyBuffer_Release(&new);
     return res;
 }
 
@@ -2120,7 +2096,7 @@
     if (subobj == Py_None)
         return stringlib_split_whitespace((PyObject*) self, s, len, maxsplit);
 
-    if (_getbuffer(subobj, &vsub) < 0)
+    if (PyObject_GetBuffer(subobj, &vsub, PyBUF_SIMPLE) != 0)
         return NULL;
     sub = vsub.buf;
     n = vsub.len;
@@ -2215,7 +2191,7 @@
     if (subobj == Py_None)
         return stringlib_rsplit_whitespace((PyObject*) self, s, len, maxsplit);
 
-    if (_getbuffer(subobj, &vsub) < 0)
+    if (PyObject_GetBuffer(subobj, &vsub, PyBUF_SIMPLE) != 0)
         return NULL;
     sub = vsub.buf;
     n = vsub.len;
@@ -2503,7 +2479,7 @@
         argsize = 6;
     }
     else {
-        if (_getbuffer(arg, &varg) < 0)
+        if (PyObject_GetBuffer(arg, &varg, PyBUF_SIMPLE) != 0)
             return NULL;
         argptr = (char *) varg.buf;
         argsize = varg.len;
@@ -2540,7 +2516,7 @@
         argsize = 6;
     }
     else {
-        if (_getbuffer(arg, &varg) < 0)
+        if (PyObject_GetBuffer(arg, &varg, PyBUF_SIMPLE) != 0)
             return NULL;
         argptr = (char *) varg.buf;
         argsize = varg.len;
@@ -2574,7 +2550,7 @@
         argsize = 6;
     }
     else {
-        if (_getbuffer(arg, &varg) < 0)
+        if (PyObject_GetBuffer(arg, &varg, PyBUF_SIMPLE) != 0)
             return NULL;
         argptr = (char *) varg.buf;
         argsize = varg.len;
diff --git a/Objects/bytes_methods.c b/Objects/bytes_methods.c
--- a/Objects/bytes_methods.c
+++ b/Objects/bytes_methods.c
@@ -363,41 +363,20 @@
 in frm is mapped to the byte at the same position in to.\n\
 The bytes objects frm and to must be of the same length.");
 
-static Py_ssize_t
-_getbuffer(PyObject *obj, Py_buffer *view)
-{
-    PyBufferProcs *buffer = Py_TYPE(obj)->tp_as_buffer;
-
-    if (buffer == NULL || buffer->bf_getbuffer == NULL)
-    {
-        PyErr_Format(PyExc_TypeError,
-                     "Type %.100s doesn't support the buffer API",
-                     Py_TYPE(obj)->tp_name);
-        return -1;
-    }
-
-    if (buffer->bf_getbuffer(obj, view, PyBUF_SIMPLE) < 0)
-        return -1;
-    return view->len;
-}
-
 PyObject *
 _Py_bytes_maketrans(PyObject *args)
 {
-    PyObject *frm, *to, *res = NULL;
-    Py_buffer bfrm, bto;
+    PyObject *res = NULL;
+    Py_buffer bfrm = {NULL, NULL};
+    Py_buffer bto = {NULL, NULL};
     Py_ssize_t i;
     char *p;
 
     bfrm.len = -1;
     bto.len = -1;
 
-    if (!PyArg_ParseTuple(args, "OO:maketrans", &frm, &to))
+    if (!PyArg_ParseTuple(args, "y*y*:maketrans", &bfrm, &bto))
         return NULL;
-    if (_getbuffer(frm, &bfrm) < 0)
-        return NULL;
-    if (_getbuffer(to, &bto) < 0)
-        goto done;
     if (bfrm.len != bto.len) {
         PyErr_Format(PyExc_ValueError,
                      "maketrans arguments must have same length");
@@ -415,9 +394,9 @@
     }
 
 done:
-    if (bfrm.len != -1)
+    if (bfrm.obj != NULL)
         PyBuffer_Release(&bfrm);
-    if (bto.len != -1)
+    if (bfrm.obj != NULL)
         PyBuffer_Release(&bto);
     return res;
 }
diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c
--- a/Objects/bytesobject.c
+++ b/Objects/bytesobject.c
@@ -7,33 +7,6 @@
 #include "bytes_methods.h"
 #include <stddef.h>
 
-static Py_ssize_t
-_getbuffer(PyObject *obj, Py_buffer *view)
-{
-    PyBufferProcs *bufferprocs;
-    if (PyBytes_CheckExact(obj)) {
-        /* Fast path, e.g. for .join() of many bytes objects */
-        Py_INCREF(obj);
-        view->obj = obj;
-        view->buf = PyBytes_AS_STRING(obj);
-        view->len = PyBytes_GET_SIZE(obj);
-        return view->len;
-    }
-
-    bufferprocs = Py_TYPE(obj)->tp_as_buffer;
-    if (bufferprocs == NULL || bufferprocs->bf_getbuffer == NULL)
-    {
-        PyErr_Format(PyExc_TypeError,
-                     "Type %.100s doesn't support the buffer API",
-                     Py_TYPE(obj)->tp_name);
-        return -1;
-    }
-
-    if (bufferprocs->bf_getbuffer(obj, view, PyBUF_SIMPLE) < 0)
-        return -1;
-    return view->len;
-}
-
 #ifdef COUNT_ALLOCS
 Py_ssize_t null_strings, one_strings;
 #endif
@@ -695,8 +668,8 @@
 
     va.len = -1;
     vb.len = -1;
-    if (_getbuffer(a, &va) < 0  ||
-        _getbuffer(b, &vb) < 0) {
+    if (PyObject_GetBuffer(a, &va, PyBUF_SIMPLE) != 0 ||
+        PyObject_GetBuffer(b, &vb, PyBUF_SIMPLE) != 0) {
         PyErr_Format(PyExc_TypeError, "can't concat %.100s to %.100s",
                      Py_TYPE(a)->tp_name, Py_TYPE(b)->tp_name);
         goto done;
@@ -794,7 +767,7 @@
         Py_buffer varg;
         Py_ssize_t pos;
         PyErr_Clear();
-        if (_getbuffer(arg, &varg) < 0)
+        if (PyObject_GetBuffer(arg, &varg, PyBUF_SIMPLE) != 0)
             return -1;
         pos = stringlib_find(PyBytes_AS_STRING(self), Py_SIZE(self),
                              varg.buf, varg.len, 0);
@@ -1048,7 +1021,7 @@
         maxsplit = PY_SSIZE_T_MAX;
     if (subobj == Py_None)
         return stringlib_split_whitespace((PyObject*) self, s, len, maxsplit);
-    if (_getbuffer(subobj, &vsub) < 0)
+    if (PyObject_GetBuffer(subobj, &vsub, PyBUF_SIMPLE) != 0)
         return NULL;
     sub = vsub.buf;
     n = vsub.len;
@@ -1068,21 +1041,19 @@
 static PyObject *
 bytes_partition(PyBytesObject *self, PyObject *sep_obj)
 {
-    const char *sep;
-    Py_ssize_t sep_len;
-
-    if (PyBytes_Check(sep_obj)) {
-        sep = PyBytes_AS_STRING(sep_obj);
-        sep_len = PyBytes_GET_SIZE(sep_obj);
-    }
-    else if (PyObject_AsCharBuffer(sep_obj, &sep, &sep_len))
+    Py_buffer sep = {NULL, NULL};
+    PyObject *res;
+
+    if (PyObject_GetBuffer(sep_obj, &sep, PyBUF_SIMPLE) != 0)
         return NULL;
 
-    return stringlib_partition(
+    res = stringlib_partition(
         (PyObject*) self,
         PyBytes_AS_STRING(self), PyBytes_GET_SIZE(self),
-        sep_obj, sep, sep_len
+        sep_obj, sep.buf, sep.len
         );
+    PyBuffer_Release(&sep);
+    return res;
 }
 
 PyDoc_STRVAR(rpartition__doc__,
@@ -1096,21 +1067,19 @@
 static PyObject *
 bytes_rpartition(PyBytesObject *self, PyObject *sep_obj)
 {
-    const char *sep;
-    Py_ssize_t sep_len;
-
-    if (PyBytes_Check(sep_obj)) {
-        sep = PyBytes_AS_STRING(sep_obj);
-        sep_len = PyBytes_GET_SIZE(sep_obj);
-    }
-    else if (PyObject_AsCharBuffer(sep_obj, &sep, &sep_len))
+    Py_buffer sep = {NULL, NULL};
+    PyObject *res;
+
+    if (PyObject_GetBuffer(sep_obj, &sep, PyBUF_SIMPLE) != 0)
         return NULL;
 
-    return stringlib_rpartition(
+    res = stringlib_rpartition(
         (PyObject*) self,
         PyBytes_AS_STRING(self), PyBytes_GET_SIZE(self),
-        sep_obj, sep, sep_len
+        sep_obj, sep.buf, sep.len
         );
+    PyBuffer_Release(&sep);
+    return res;
 }
 
 PyDoc_STRVAR(rsplit__doc__,
@@ -1140,7 +1109,7 @@
         maxsplit = PY_SSIZE_T_MAX;
     if (subobj == Py_None)
         return stringlib_rsplit_whitespace((PyObject*) self, s, len, maxsplit);
-    if (_getbuffer(subobj, &vsub) < 0)
+    if (PyObject_GetBuffer(subobj, &vsub, PyBUF_SIMPLE) != 0)
         return NULL;
     sub = vsub.buf;
     n = vsub.len;
@@ -1202,7 +1171,7 @@
         return -2;
 
     if (subobj) {
-        if (_getbuffer(subobj, &subbuf) < 0)
+        if (PyObject_GetBuffer(subobj, &subbuf, PyBUF_SIMPLE) != 0)
             return -2;
 
         sub = subbuf.buf;
@@ -1317,7 +1286,7 @@
     Py_ssize_t seplen;
     Py_ssize_t i, j;
 
-    if (_getbuffer(sepobj, &vsep) < 0)
+    if (PyObject_GetBuffer(sepobj, &vsep, PyBUF_SIMPLE) != 0)
         return NULL;
     sep = vsep.buf;
     seplen = vsep.len;
@@ -1462,7 +1431,7 @@
         return NULL;
 
     if (sub_obj) {
-        if (_getbuffer(sub_obj, &vsub) < 0)
+        if (PyObject_GetBuffer(sub_obj, &vsub, PyBUF_SIMPLE) != 0)
             return NULL;
 
         sub = vsub.buf;
@@ -1498,6 +1467,8 @@
 bytes_translate(PyBytesObject *self, PyObject *args)
 {
     char *input, *output;
+    Py_buffer table_view = {NULL, NULL};
+    Py_buffer del_table_view = {NULL, NULL};
     const char *table;
     Py_ssize_t i, c, changed = 0;
     PyObject *input_obj = (PyObject*)self;
@@ -1519,12 +1490,17 @@
         table = NULL;
         tablen = 256;
     }
-    else if (PyObject_AsCharBuffer(tableobj, &table, &tablen))
-        return NULL;
+    else {
+        if (PyObject_GetBuffer(tableobj, &table_view, PyBUF_SIMPLE) != 0)
+            return NULL;
+        table = table_view.buf;
+        tablen = table_view.len;
+    }
 
     if (tablen != 256) {
         PyErr_SetString(PyExc_ValueError,
           "translation table must be 256 characters long");
+        PyBuffer_Release(&table_view);
         return NULL;
     }
 
@@ -1533,8 +1509,14 @@
             del_table = PyBytes_AS_STRING(delobj);
             dellen = PyBytes_GET_SIZE(delobj);
         }
-        else if (PyObject_AsCharBuffer(delobj, &del_table, &dellen))
-            return NULL;
+        else {
+            if (PyObject_GetBuffer(delobj, &del_table_view, PyBUF_SIMPLE) != 0) {
+                PyBuffer_Release(&table_view);
+                return NULL;
+            }
+            del_table = del_table_view.buf;
+            dellen = del_table_view.len;
+        }
     }
     else {
         del_table = NULL;
@@ -1543,8 +1525,11 @@
 
     inlen = PyBytes_GET_SIZE(input_obj);
     result = PyBytes_FromStringAndSize((char *)NULL, inlen);
-    if (result == NULL)
+    if (result == NULL) {
+        PyBuffer_Release(&del_table_view);
+        PyBuffer_Release(&table_view);
         return NULL;
+    }
     output_start = output = PyBytes_AsString(result);
     input = PyBytes_AS_STRING(input_obj);
 
@@ -1555,11 +1540,14 @@
             if (Py_CHARMASK((*output++ = table[c])) != c)
                 changed = 1;
         }
-        if (changed || !PyBytes_CheckExact(input_obj))
-            return result;
-        Py_DECREF(result);
-        Py_INCREF(input_obj);
-        return input_obj;
+        if (!changed && PyBytes_CheckExact(input_obj)) {
+            Py_INCREF(input_obj);
+            Py_DECREF(result);
+            result = input_obj;
+        }
+        PyBuffer_Release(&del_table_view);
+        PyBuffer_Release(&table_view);
+        return result;
     }
 
     if (table == NULL) {
@@ -1569,9 +1557,11 @@
         for (i = 0; i < 256; i++)
             trans_table[i] = Py_CHARMASK(table[i]);
     }
+    PyBuffer_Release(&table_view);
 
     for (i = 0; i < dellen; i++)
         trans_table[(int) Py_CHARMASK(del_table[i])] = -1;
+    PyBuffer_Release(&del_table_view);
 
     for (i = inlen; --i >= 0; ) {
         c = Py_CHARMASK(*input++);
@@ -2100,31 +2090,21 @@
 static PyObject *
 bytes_replace(PyBytesObject *self, PyObject *args)
 {
+    PyObject *res;
+    Py_buffer old = {NULL, NULL};
+    Py_buffer new = {NULL, NULL};
     Py_ssize_t count = -1;
-    PyObject *from, *to;
-    const char *from_s, *to_s;
-    Py_ssize_t from_len, to_len;
-
-    if (!PyArg_ParseTuple(args, "OO|n:replace", &from, &to, &count))
+
+    if (!PyArg_ParseTuple(args, "y*y*|n:replace", &old, &new, &count))
         return NULL;
 
-    if (PyBytes_Check(from)) {
-        from_s = PyBytes_AS_STRING(from);
-        from_len = PyBytes_GET_SIZE(from);
-    }
-    else if (PyObject_AsCharBuffer(from, &from_s, &from_len))
-        return NULL;
-
-    if (PyBytes_Check(to)) {
-        to_s = PyBytes_AS_STRING(to);
-        to_len = PyBytes_GET_SIZE(to);
-    }
-    else if (PyObject_AsCharBuffer(to, &to_s, &to_len))
-        return NULL;
-
-    return (PyObject *)replace((PyBytesObject *) self,
-                               from_s, from_len,
-                               to_s, to_len, count);
+    res = (PyObject *)replace((PyBytesObject *) self,
+                              (const char *)old.buf, old.len,
+                              (const char *)new.buf, new.len, count);
+
+    PyBuffer_Release(&old);
+    PyBuffer_Release(&new);
+    return res;
 }
 
 /** End DALKE **/
@@ -2139,6 +2119,7 @@
 {
     Py_ssize_t len = PyBytes_GET_SIZE(self);
     Py_ssize_t slen;
+    Py_buffer sub_view = {NULL, NULL};
     const char* sub;
     const char* str;
 
@@ -2146,8 +2127,12 @@
         sub = PyBytes_AS_STRING(substr);
         slen = PyBytes_GET_SIZE(substr);
     }
-    else if (PyObject_AsCharBuffer(substr, &sub, &slen))
-        return -1;
+    else {
+        if (PyObject_GetBuffer(substr, &sub_view, PyBUF_SIMPLE) != 0)
+            return -1;
+        sub = sub_view.buf;
+        slen = sub_view.len;
+    }
     str = PyBytes_AS_STRING(self);
 
     ADJUST_INDICES(start, end, len);
@@ -2155,17 +2140,25 @@
     if (direction < 0) {
         /* startswith */
         if (start+slen > len)
-            return 0;
+            goto notfound;
     } else {
         /* endswith */
         if (end-start < slen || start > len)
-            return 0;
+            goto notfound;
 
         if (end-slen > start)
             start = end - slen;
     }
-    if (end-start >= slen)
-        return ! memcmp(str+start, sub, slen);
+    if (end-start < slen)
+        goto notfound;
+    if (memcmp(str+start, sub, slen) != 0)
+        goto notfound;
+
+    PyBuffer_Release(&sub_view);
+    return 1;
+
+notfound:
+    PyBuffer_Release(&sub_view);
     return 0;
 }
 
diff --git a/Objects/complexobject.c b/Objects/complexobject.c
--- a/Objects/complexobject.c
+++ b/Objects/complexobject.c
@@ -767,6 +767,7 @@
     int got_bracket=0;
     PyObject *s_buffer = NULL;
     Py_ssize_t len;
+    Py_buffer view = {NULL, NULL};
 
     if (PyUnicode_Check(v)) {
         s_buffer = _PyUnicode_TransformDecimalAndSpaceToASCII(v);
@@ -776,7 +777,11 @@
         if (s == NULL)
             goto error;
     }
-    else if (PyObject_AsCharBuffer(v, &s, &len)) {
+    else if (PyObject_GetBuffer(v, &view, PyBUF_SIMPLE) == 0) {
+        s = (const char *)view.buf;
+        len = view.len;
+    }
+    else {
         PyErr_Format(PyExc_TypeError,
             "complex() argument must be a string or a number, not '%.200s'",
             Py_TYPE(v)->tp_name);
@@ -890,6 +895,7 @@
     if (s-start != len)
         goto parse_error;
 
+    PyBuffer_Release(&view);
     Py_XDECREF(s_buffer);
     return complex_subtype_from_doubles(type, x, y);
 
@@ -897,6 +903,7 @@
     PyErr_SetString(PyExc_ValueError,
                     "complex() arg is a malformed string");
   error:
+    PyBuffer_Release(&view);
     Py_XDECREF(s_buffer);
     return NULL;
 }
diff --git a/Objects/exceptions.c b/Objects/exceptions.c
--- a/Objects/exceptions.c
+++ b/Objects/exceptions.c
@@ -1922,8 +1922,6 @@
 UnicodeDecodeError_init(PyObject *self, PyObject *args, PyObject *kwds)
 {
     PyUnicodeErrorObject *ude;
-    const char *data;
-    Py_ssize_t size;
 
     if (BaseException_init((PyBaseExceptionObject *)self, args, kwds) == -1)
         return -1;
@@ -1944,21 +1942,27 @@
              return -1;
     }
 
+    Py_INCREF(ude->encoding);
+    Py_INCREF(ude->object);
+    Py_INCREF(ude->reason);
+
     if (!PyBytes_Check(ude->object)) {
-        if (PyObject_AsReadBuffer(ude->object, (const void **)&data, &size)) {
-            ude->encoding = ude->object = ude->reason = NULL;
-            return -1;
-        }
-        ude->object = PyBytes_FromStringAndSize(data, size);
+        Py_buffer view;
+        if (PyObject_GetBuffer(ude->object, &view, PyBUF_SIMPLE) != 0)
+            goto error;
+        Py_CLEAR(ude->object);
+        ude->object = PyBytes_FromStringAndSize(view.buf, view.len);
+        PyBuffer_Release(&view);
+        if (!ude->object)
+            goto error;
     }
-    else {
-        Py_INCREF(ude->object);
-    }
-
-    Py_INCREF(ude->encoding);
-    Py_INCREF(ude->reason);
-
     return 0;
+
+error:
+    Py_CLEAR(ude->encoding);
+    Py_CLEAR(ude->object);
+    Py_CLEAR(ude->reason);
+    return -1;
 }
 
 static PyObject *
diff --git a/Objects/floatobject.c b/Objects/floatobject.c
--- a/Objects/floatobject.c
+++ b/Objects/floatobject.c
@@ -131,6 +131,7 @@
     double x;
     PyObject *s_buffer = NULL;
     Py_ssize_t len;
+    Py_buffer view = {NULL, NULL};
     PyObject *result = NULL;
 
     if (PyUnicode_Check(v)) {
@@ -143,7 +144,11 @@
             return NULL;
         }
     }
-    else if (PyObject_AsCharBuffer(v, &s, &len)) {
+    else if (PyObject_GetBuffer(v, &view, PyBUF_SIMPLE) == 0) {
+        s = (const char *)view.buf;
+        len = view.len;
+    }
+    else {
         PyErr_Format(PyExc_TypeError,
             "float() argument must be a string or a number, not '%.200s'",
             Py_TYPE(v)->tp_name);
@@ -170,6 +175,7 @@
     else
         result = PyFloat_FromDouble(x);
 
+    PyBuffer_Release(&view);
     Py_XDECREF(s_buffer);
     return result;
 }
diff --git a/Objects/stringlib/join.h b/Objects/stringlib/join.h
--- a/Objects/stringlib/join.h
+++ b/Objects/stringlib/join.h
@@ -58,7 +58,14 @@
     for (i = 0, nbufs = 0; i < seqlen; i++) {
         Py_ssize_t itemlen;
         item = PySequence_Fast_GET_ITEM(seq, i);
-        if (_getbuffer(item, &buffers[i]) < 0) {
+        if (PyBytes_CheckExact(item)) {
+            /* Fast path. */
+            Py_INCREF(item);
+            buffers[i].obj = item;
+            buffers[i].buf = PyBytes_AS_STRING(item);
+            buffers[i].len = PyBytes_GET_SIZE(item);
+        }
+        else if (PyObject_GetBuffer(item, &buffers[i], PyBUF_SIMPLE) != 0) {
             PyErr_Format(PyExc_TypeError,
                          "sequence item %zd: expected a bytes-like object, "
                          "%.80s found",
diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c
--- a/Python/bltinmodule.c
+++ b/Python/bltinmodule.c
@@ -559,10 +559,10 @@
 Return a Unicode string of one character with ordinal i; 0 <= i <= 0x10ffff.");
 
 
-static char *
-source_as_string(PyObject *cmd, char *funcname, char *what, PyCompilerFlags *cf)
+static const char *
+source_as_string(PyObject *cmd, const char *funcname, const char *what, PyCompilerFlags *cf, Py_buffer *view)
 {
-    char *str;
+    const char *str;
     Py_ssize_t size;
 
     if (PyUnicode_Check(cmd)) {
@@ -571,19 +571,21 @@
         if (str == NULL)
             return NULL;
     }
-    else if (!PyObject_CheckReadBuffer(cmd)) {
+    else if (PyObject_GetBuffer(cmd, view, PyBUF_SIMPLE) == 0) {
+        str = (const char *)view->buf;
+        size = view->len;
+    }
+    else {
         PyErr_Format(PyExc_TypeError,
           "%s() arg 1 must be a %s object",
           funcname, what);
         return NULL;
     }
-    else if (PyObject_AsReadBuffer(cmd, (const void **)&str, &size) < 0) {
-        return NULL;
-    }
 
     if (strlen(str) != size) {
         PyErr_SetString(PyExc_TypeError,
                         "source code string cannot contain null bytes");
+        PyBuffer_Release(view);
         return NULL;
     }
     return str;
@@ -592,7 +594,8 @@
 static PyObject *
 builtin_compile(PyObject *self, PyObject *args, PyObject *kwds)
 {
-    char *str;
+    Py_buffer view = {NULL, NULL};
+    const char *str;
     PyObject *filename;
     char *startstr;
     int mode = -1;
@@ -678,11 +681,12 @@
         goto finally;
     }
 
-    str = source_as_string(cmd, "compile", "string, bytes or AST", &cf);
+    str = source_as_string(cmd, "compile", "string, bytes or AST", &cf, &view);
     if (str == NULL)
         goto error;
 
     result = Py_CompileStringObject(str, filename, start[mode], &cf, optimize);
+    PyBuffer_Release(&view);
     goto finally;
 
 error:
@@ -752,7 +756,8 @@
 {
     PyObject *cmd, *result, *tmp = NULL;
     PyObject *globals = Py_None, *locals = Py_None;
-    char *str;
+    Py_buffer view = {NULL, NULL};
+    const char *str;
     PyCompilerFlags cf;
 
     if (!PyArg_UnpackTuple(args, "eval", 1, 3, &cmd, &globals, &locals))
@@ -801,7 +806,7 @@
     }
 
     cf.cf_flags = PyCF_SOURCE_IS_UTF8;
-    str = source_as_string(cmd, "eval", "string, bytes or code", &cf);
+    str = source_as_string(cmd, "eval", "string, bytes or code", &cf, &view);
     if (str == NULL)
         return NULL;
 
@@ -810,6 +815,7 @@
 
     (void)PyEval_MergeCompilerFlags(&cf);
     result = PyRun_StringFlags(str, Py_eval_input, globals, locals, &cf);
+    PyBuffer_Release(&view);
     Py_XDECREF(tmp);
     return result;
 }
@@ -876,11 +882,12 @@
         v = PyEval_EvalCode(prog, globals, locals);
     }
     else {
-        char *str;
+        Py_buffer view = {NULL, NULL};
+        const char *str;
         PyCompilerFlags cf;
         cf.cf_flags = PyCF_SOURCE_IS_UTF8;
         str = source_as_string(prog, "exec",
-                                     "string, bytes or code", &cf);
+                                     "string, bytes or code", &cf, &view);
         if (str == NULL)
             return NULL;
         if (PyEval_MergeCompilerFlags(&cf))
@@ -888,6 +895,7 @@
                                   locals, &cf);
         else
             v = PyRun_String(str, Py_file_input, globals, locals);
+        PyBuffer_Release(&view);
     }
     if (v == NULL)
         return NULL;

-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list