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

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


https://hg.python.org/cpython/rev/2e684ce772de
changeset: 94475:2e684ce772de
parent: 94473:651aa21433ba
parent: 94474:1da9630e9b7f
user: Serhiy Storchaka <storchaka at gmail.com>
date: Tue Feb 03 01:25:42 2015 +0200
summary:
 Issue #22896: Avoid to use PyObject_AsCharBuffer(), PyObject_AsReadBuffer()
and PyObject_AsWriteBuffer().
files:
 Include/bytes_methods.h | 2 +-
 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 | 82 +---
 Objects/bytearrayobject.c | 146 ++++-----
 Objects/bytes_methods.c | 46 +--
 Objects/bytesobject.c | 272 +++++++++-------
 Objects/complexobject.c | 9 +-
 Objects/exceptions.c | 32 +-
 Objects/floatobject.c | 8 +-
 Objects/stringlib/join.h | 9 +-
 Python/bltinmodule.c | 38 +-
 18 files changed, 431 insertions(+), 406 deletions(-)
diff --git a/Include/bytes_methods.h b/Include/bytes_methods.h
--- a/Include/bytes_methods.h
+++ b/Include/bytes_methods.h
@@ -22,7 +22,7 @@
 extern void _Py_bytes_swapcase(char *result, char *s, Py_ssize_t len);
 
 /* The maketrans() static method. */
-extern PyObject* _Py_bytes_maketrans(PyObject *frm, PyObject *to);
+extern PyObject* _Py_bytes_maketrans(Py_buffer *frm, Py_buffer *to);
 
 /* Shared __doc__ strings. */
 extern const char _Py_isspace__doc__[];
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
@@ -10,6 +10,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
@@ -288,8 +288,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))
@@ -302,11 +300,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;
 }
 }
 
@@ -731,8 +734,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",
@@ -745,6 +746,7 @@
 
 if (PyUnicode_Check(obj)) {
 Py_UNICODE *u;
+ Py_ssize_t len, size;
 
 if (PyUnicode_READY(obj) < 0)
 return NULL;
@@ -759,9 +761,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
@@ -553,17 +553,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, NULL);
 
- 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;
@@ -571,10 +572,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,27 +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 a bytes-like 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
@@ -294,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 a bytes-like object");
+ 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;
 }
 
@@ -341,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;
 }
 
@@ -352,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,
 "a bytes-like object is required, not '%.100s'",
 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
@@ -676,10 +646,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 *
@@ -1288,8 +1262,7 @@
 {
 PyNumberMethods *m;
 PyObject *trunc_func;
- const char *buffer;
- Py_ssize_t buffer_len;
+ Py_buffer view;
 _Py_IDENTIFIER(__trunc__);
 
 if (o == NULL)
@@ -1327,21 +1300,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);
-
- return type_error("int() argument must be a string or a "
- "number, not '%.200s'", o);
+ PyObject *result = _PyLong_FromBytes(view.buf, view.len, 10);
+ PyBuffer_Release(&view);
+ return result;
+ }
+
+ 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
@@ -80,24 +80,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,
- "a bytes-like object is required, not '%.100s'",
- 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)
 {
@@ -268,8 +250,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;
@@ -335,7 +317,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;
@@ -595,14 +577,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)
@@ -1047,18 +1029,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 */
@@ -1170,7 +1152,7 @@
 return -2;
 
 if (subobj) {
- if (_getbuffer(subobj, &subbuf) < 0)
+ if (PyObject_GetBuffer(subobj, &subbuf, PyBUF_SIMPLE) != 0)
 return -2;
 
 sub = subbuf.buf;
@@ -1238,7 +1220,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;
@@ -1397,7 +1379,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);
@@ -1428,7 +1410,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);
@@ -1621,7 +1603,7 @@
 if (table == Py_None) {
 table_chars = NULL;
 table = NULL;
- } else if (_getbuffer(table, &vtable) < 0) {
+ } else if (PyObject_GetBuffer(table, &vtable, PyBUF_SIMPLE) != 0) {
 return NULL;
 } else {
 if (vtable.len != 256) {
@@ -1634,7 +1616,7 @@
 }
 
 if (deletechars != NULL) {
- if (_getbuffer(deletechars, &vdel) < 0) {
+ if (PyObject_GetBuffer(deletechars, &vdel, PyBUF_SIMPLE) != 0) {
 if (table != NULL)
 PyBuffer_Release(&vtable);
 return NULL;
@@ -1699,8 +1681,8 @@
 @staticmethod
 bytearray.maketrans
 
- frm: object
- to: object
+ frm: Py_buffer
+ to: Py_buffer
 /
 
 Return a translation table useable for the bytes or bytearray translate method.
@@ -1726,28 +1708,35 @@
 {"maketrans", (PyCFunction)bytearray_maketrans, METH_VARARGS|METH_STATIC, bytearray_maketrans__doc__},
 
 static PyObject *
-bytearray_maketrans_impl(PyObject *frm, PyObject *to);
+bytearray_maketrans_impl(Py_buffer *frm, Py_buffer *to);
 
 static PyObject *
 bytearray_maketrans(void *null, PyObject *args)
 {
 PyObject *return_value = NULL;
- PyObject *frm;
- PyObject *to;
-
- if (!PyArg_UnpackTuple(args, "maketrans",
- 2, 2,
+ Py_buffer frm = {NULL, NULL};
+ Py_buffer to = {NULL, NULL};
+
+ if (!PyArg_ParseTuple(args,
+ "y*y*:maketrans",
 &frm, &to))
 goto exit;
- return_value = bytearray_maketrans_impl(frm, to);
+ return_value = bytearray_maketrans_impl(&frm, &to);
 
 exit:
+ /* Cleanup for frm */
+ if (frm.obj)
+ PyBuffer_Release(&frm);
+ /* Cleanup for to */
+ if (to.obj)
+ PyBuffer_Release(&to);
+
 return return_value;
 }
 
 static PyObject *
-bytearray_maketrans_impl(PyObject *frm, PyObject *to)
-/*[clinic end generated code: output=307752019d9b25b5 input=ea9bdc6b328c15e2]*/
+bytearray_maketrans_impl(Py_buffer *frm, Py_buffer *to)
+/*[clinic end generated code: output=d332622814c26f4b input=5925a81d2fbbf151]*/
 {
 return _Py_bytes_maketrans(frm, to);
 }
@@ -2243,8 +2232,8 @@
 /*[clinic input]
 bytearray.replace
 
- old: object
- new: object
+ old: Py_buffer
+ new: Py_buffer
 count: Py_ssize_t = -1
 Maximum number of occurrences to replace.
 -1 (the default value) means replace all occurrences.
@@ -2273,47 +2262,40 @@
 {"replace", (PyCFunction)bytearray_replace, METH_VARARGS, bytearray_replace__doc__},
 
 static PyObject *
-bytearray_replace_impl(PyByteArrayObject *self, PyObject *old, PyObject *new, Py_ssize_t count);
+bytearray_replace_impl(PyByteArrayObject *self, Py_buffer *old, Py_buffer *new, Py_ssize_t count);
 
 static PyObject *
 bytearray_replace(PyByteArrayObject *self, PyObject *args)
 {
 PyObject *return_value = NULL;
- PyObject *old;
- PyObject *new;
+ Py_buffer old = {NULL, NULL};
+ Py_buffer new = {NULL, NULL};
 Py_ssize_t count = -1;
 
 if (!PyArg_ParseTuple(args,
- "OO|n:replace",
+ "y*y*|n:replace",
 &old, &new, &count))
 goto exit;
- return_value = bytearray_replace_impl(self, old, new, count);
+ return_value = bytearray_replace_impl(self, &old, &new, count);
 
 exit:
+ /* Cleanup for old */
+ if (old.obj)
+ PyBuffer_Release(&old);
+ /* Cleanup for new */
+ if (new.obj)
+ PyBuffer_Release(&new);
+
 return return_value;
 }
 
 static PyObject *
-bytearray_replace_impl(PyByteArrayObject *self, PyObject *old, PyObject *new, Py_ssize_t count)
-/*[clinic end generated code: output=4d2e3c9130da0f96 input=9aaaa123608dfc1f]*/
+bytearray_replace_impl(PyByteArrayObject *self, Py_buffer *old, Py_buffer *new, Py_ssize_t count)
+/*[clinic end generated code: output=9997fbbd5bac4883 input=aa379d988637c7fb]*/
 {
- PyObject *res;
- Py_buffer vold, vnew;
-
- if (_getbuffer(old, &vold) < 0)
- return NULL;
- if (_getbuffer(new, &vnew) < 0) {
- PyBuffer_Release(&vold);
- return NULL;
- }
-
- res = (PyObject *)replace((PyByteArrayObject *) self,
- vold.buf, vold.len,
- vnew.buf, vnew.len, count);
-
- PyBuffer_Release(&vold);
- PyBuffer_Release(&vnew);
- return res;
+ return (PyObject *)replace((PyByteArrayObject *) self,
+ old->buf, old->len,
+ new->buf, new->len, count);
 }
 
 /*[clinic input]
@@ -2383,7 +2365,7 @@
 if (sep == Py_None)
 return stringlib_split_whitespace((PyObject*) self, s, len, maxsplit);
 
- if (_getbuffer(sep, &vsub) < 0)
+ if (PyObject_GetBuffer(sep, &vsub, PyBUF_SIMPLE) != 0)
 return NULL;
 sub = vsub.buf;
 n = vsub.len;
@@ -2566,7 +2548,7 @@
 if (sep == Py_None)
 return stringlib_rsplit_whitespace((PyObject*) self, s, len, maxsplit);
 
- if (_getbuffer(sep, &vsub) < 0)
+ if (PyObject_GetBuffer(sep, &vsub, PyBUF_SIMPLE) != 0)
 return NULL;
 sub = vsub.buf;
 n = vsub.len;
@@ -3088,7 +3070,7 @@
 byteslen = 6;
 }
 else {
- if (_getbuffer(bytes, &vbytes) < 0)
+ if (PyObject_GetBuffer(bytes, &vbytes, PyBUF_SIMPLE) != 0)
 return NULL;
 bytesptr = (char *) vbytes.buf;
 byteslen = vbytes.len;
@@ -3159,7 +3141,7 @@
 byteslen = 6;
 }
 else {
- if (_getbuffer(bytes, &vbytes) < 0)
+ if (PyObject_GetBuffer(bytes, &vbytes, PyBUF_SIMPLE) != 0)
 return NULL;
 bytesptr = (char *) vbytes.buf;
 byteslen = vbytes.len;
@@ -3227,7 +3209,7 @@
 byteslen = 6;
 }
 else {
- if (_getbuffer(bytes, &vbytes) < 0)
+ if (PyObject_GetBuffer(bytes, &vbytes, PyBUF_SIMPLE) != 0)
 return NULL;
 bytesptr = (char *) vbytes.buf;
 byteslen = vbytes.len;
diff --git a/Objects/bytes_methods.c b/Objects/bytes_methods.c
--- a/Objects/bytes_methods.c
+++ b/Objects/bytes_methods.c
@@ -363,59 +363,27 @@
 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,
- "a bytes-like object is required, not '%.100s'",
- 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 *frm, PyObject *to)
+_Py_bytes_maketrans(Py_buffer *frm, Py_buffer *to)
 {
 PyObject *res = NULL;
- Py_buffer bfrm, bto;
 Py_ssize_t i;
 char *p;
 
- bfrm.len = -1;
- bto.len = -1;
-
- if (_getbuffer(frm, &bfrm) < 0)
- return NULL;
- if (_getbuffer(to, &bto) < 0)
- goto done;
- if (bfrm.len != bto.len) {
+ if (frm->len != to->len) {
 PyErr_Format(PyExc_ValueError,
 "maketrans arguments must have same length");
- goto done;
+ return NULL;
 }
 res = PyBytes_FromStringAndSize(NULL, 256);
- if (!res) {
- goto done;
- }
+ if (!res)
+ return NULL;
 p = PyBytes_AS_STRING(res);
 for (i = 0; i < 256; i++)
 p[i] = (char) i;
- for (i = 0; i < bfrm.len; i++) {
- p[((unsigned char *)bfrm.buf)[i]] = ((char *)bto.buf)[i];
+ for (i = 0; i < frm->len; i++) {
+ p[((unsigned char *)frm->buf)[i]] = ((char *)to->buf)[i];
 }
 
-done:
- if (bfrm.len != -1)
- PyBuffer_Release(&bfrm);
- if (bto.len != -1)
- PyBuffer_Release(&bto);
 return res;
 }
diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c
--- a/Objects/bytesobject.c
+++ b/Objects/bytesobject.c
@@ -12,33 +12,6 @@
 [clinic start generated code]*/
 /*[clinic end generated code: output=da39a3ee5e6b4b0d input=1a1d9102afc1b00c]*/
 
-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,
- "a bytes-like object is required, not '%.100s'",
- 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
@@ -1349,8 +1322,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;
@@ -1448,7 +1421,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);
@@ -1737,7 +1710,7 @@
 maxsplit = PY_SSIZE_T_MAX;
 if (sep == Py_None)
 return stringlib_split_whitespace((PyObject*) self, s, len, maxsplit);
- if (_getbuffer(sep, &vsub) < 0)
+ if (PyObject_GetBuffer(sep, &vsub, PyBUF_SIMPLE) != 0)
 return NULL;
 sub = vsub.buf;
 n = vsub.len;
@@ -1751,7 +1724,7 @@
 bytes.partition
 
 self: self(type="PyBytesObject *")
- sep: object
+ sep: Py_buffer
 /
 
 Partition the bytes into three parts using the given separator.
@@ -1778,26 +1751,39 @@
 "object and two empty bytes objects.");
 
 #define BYTES_PARTITION_METHODDEF \
- {"partition", (PyCFunction)bytes_partition, METH_O, bytes_partition__doc__},
+ {"partition", (PyCFunction)bytes_partition, METH_VARARGS, bytes_partition__doc__},
 
 static PyObject *
-bytes_partition(PyBytesObject *self, PyObject *sep)
-/*[clinic end generated code: output=b41e119c873c08bc input=6c5b9dcc5a9fd62e]*/
+bytes_partition_impl(PyBytesObject *self, Py_buffer *sep);
+
+static PyObject *
+bytes_partition(PyBytesObject *self, PyObject *args)
 {
- const char *sep_chars;
- Py_ssize_t sep_len;
-
- if (PyBytes_Check(sep)) {
- sep_chars = PyBytes_AS_STRING(sep);
- sep_len = PyBytes_GET_SIZE(sep);
- }
- else if (PyObject_AsCharBuffer(sep, &sep_chars, &sep_len))
- return NULL;
-
+ PyObject *return_value = NULL;
+ Py_buffer sep = {NULL, NULL};
+
+ if (!PyArg_ParseTuple(args,
+ "y*:partition",
+ &sep))
+ goto exit;
+ return_value = bytes_partition_impl(self, &sep);
+
+exit:
+ /* Cleanup for sep */
+ if (sep.obj)
+ PyBuffer_Release(&sep);
+
+ return return_value;
+}
+
+static PyObject *
+bytes_partition_impl(PyBytesObject *self, Py_buffer *sep)
+/*[clinic end generated code: output=3006727cfbf83aa4 input=bc855dc63ca949de]*/
+{
 return stringlib_partition(
 (PyObject*) self,
 PyBytes_AS_STRING(self), PyBytes_GET_SIZE(self),
- sep, sep_chars, sep_len
+ sep->obj, (const char *)sep->buf, sep->len
 );
 }
 
@@ -1805,7 +1791,7 @@
 bytes.rpartition
 
 self: self(type="PyBytesObject *")
- sep: object
+ sep: Py_buffer
 /
 
 Partition the bytes into three parts using the given separator.
@@ -1832,26 +1818,39 @@
 "objects and the original bytes object.");
 
 #define BYTES_RPARTITION_METHODDEF \
- {"rpartition", (PyCFunction)bytes_rpartition, METH_O, bytes_rpartition__doc__},
+ {"rpartition", (PyCFunction)bytes_rpartition, METH_VARARGS, bytes_rpartition__doc__},
 
 static PyObject *
-bytes_rpartition(PyBytesObject *self, PyObject *sep)
-/*[clinic end generated code: output=3a620803657196ee input=79bc2932e78e5ce0]*/
+bytes_rpartition_impl(PyBytesObject *self, Py_buffer *sep);
+
+static PyObject *
+bytes_rpartition(PyBytesObject *self, PyObject *args)
 {
- const char *sep_chars;
- Py_ssize_t sep_len;
-
- if (PyBytes_Check(sep)) {
- sep_chars = PyBytes_AS_STRING(sep);
- sep_len = PyBytes_GET_SIZE(sep);
- }
- else if (PyObject_AsCharBuffer(sep, &sep_chars, &sep_len))
- return NULL;
-
+ PyObject *return_value = NULL;
+ Py_buffer sep = {NULL, NULL};
+
+ if (!PyArg_ParseTuple(args,
+ "y*:rpartition",
+ &sep))
+ goto exit;
+ return_value = bytes_rpartition_impl(self, &sep);
+
+exit:
+ /* Cleanup for sep */
+ if (sep.obj)
+ PyBuffer_Release(&sep);
+
+ return return_value;
+}
+
+static PyObject *
+bytes_rpartition_impl(PyBytesObject *self, Py_buffer *sep)
+/*[clinic end generated code: output=57b169dc47fa90e8 input=6588fff262a9170e]*/
+{
 return stringlib_rpartition(
 (PyObject*) self,
 PyBytes_AS_STRING(self), PyBytes_GET_SIZE(self),
- sep, sep_chars, sep_len
+ sep->obj, (const char *)sep->buf, sep->len
 );
 }
 
@@ -1916,7 +1915,7 @@
 maxsplit = PY_SSIZE_T_MAX;
 if (sep == Py_None)
 return stringlib_rsplit_whitespace((PyObject*) self, s, len, maxsplit);
- if (_getbuffer(sep, &vsub) < 0)
+ if (PyObject_GetBuffer(sep, &vsub, PyBUF_SIMPLE) != 0)
 return NULL;
 sub = vsub.buf;
 n = vsub.len;
@@ -2003,7 +2002,7 @@
 return -2;
 
 if (subobj) {
- if (_getbuffer(subobj, &subbuf) < 0)
+ if (PyObject_GetBuffer(subobj, &subbuf, PyBUF_SIMPLE) != 0)
 return -2;
 
 sub = subbuf.buf;
@@ -2118,7 +2117,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;
@@ -2360,7 +2359,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;
@@ -2450,6 +2449,8 @@
 /*[clinic end generated code: output=f0f29a57f41df5d8 input=d8fa5519d7cc4be7]*/
 {
 char *input, *output;
+ Py_buffer table_view = {NULL, NULL};
+ Py_buffer del_table_view = {NULL, NULL};
 const char *table_chars;
 Py_ssize_t i, c, changed = 0;
 PyObject *input_obj = (PyObject*)self;
@@ -2466,12 +2467,17 @@
 table_chars = NULL;
 tablen = 256;
 }
- else if (PyObject_AsCharBuffer(table, &table_chars, &tablen))
- return NULL;
+ else {
+ if (PyObject_GetBuffer(table, &table_view, PyBUF_SIMPLE) != 0)
+ return NULL;
+ table_chars = 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;
 }
 
@@ -2480,8 +2486,14 @@
 del_table_chars = PyBytes_AS_STRING(deletechars);
 dellen = PyBytes_GET_SIZE(deletechars);
 }
- else if (PyObject_AsCharBuffer(deletechars, &del_table_chars, &dellen))
- return NULL;
+ else {
+ if (PyObject_GetBuffer(deletechars, &del_table_view, PyBUF_SIMPLE) != 0) {
+ PyBuffer_Release(&table_view);
+ return NULL;
+ }
+ del_table_chars = del_table_view.buf;
+ dellen = del_table_view.len;
+ }
 }
 else {
 del_table_chars = NULL;
@@ -2490,8 +2502,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);
 
@@ -2502,11 +2517,14 @@
 if (Py_CHARMASK((*output++ = table_chars[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_chars == NULL) {
@@ -2516,9 +2534,11 @@
 for (i = 0; i < 256; i++)
 trans_table[i] = Py_CHARMASK(table_chars[i]);
 }
+ PyBuffer_Release(&table_view);
 
 for (i = 0; i < dellen; i++)
 trans_table[(int) Py_CHARMASK(del_table_chars[i])] = -1;
+ PyBuffer_Release(&del_table_view);
 
 for (i = inlen; --i >= 0; ) {
 c = Py_CHARMASK(*input++);
@@ -2544,8 +2564,8 @@
 @staticmethod
 bytes.maketrans
 
- frm: object
- to: object
+ frm: Py_buffer
+ to: Py_buffer
 /
 
 Return a translation table useable for the bytes or bytearray translate method.
@@ -2571,28 +2591,35 @@
 {"maketrans", (PyCFunction)bytes_maketrans, METH_VARARGS|METH_STATIC, bytes_maketrans__doc__},
 
 static PyObject *
-bytes_maketrans_impl(PyObject *frm, PyObject *to);
+bytes_maketrans_impl(Py_buffer *frm, Py_buffer *to);
 
 static PyObject *
 bytes_maketrans(void *null, PyObject *args)
 {
 PyObject *return_value = NULL;
- PyObject *frm;
- PyObject *to;
-
- if (!PyArg_UnpackTuple(args, "maketrans",
- 2, 2,
+ Py_buffer frm = {NULL, NULL};
+ Py_buffer to = {NULL, NULL};
+
+ if (!PyArg_ParseTuple(args,
+ "y*y*:maketrans",
 &frm, &to))
 goto exit;
- return_value = bytes_maketrans_impl(frm, to);
+ return_value = bytes_maketrans_impl(&frm, &to);
 
 exit:
+ /* Cleanup for frm */
+ if (frm.obj)
+ PyBuffer_Release(&frm);
+ /* Cleanup for to */
+ if (to.obj)
+ PyBuffer_Release(&to);
+
 return return_value;
 }
 
 static PyObject *
-bytes_maketrans_impl(PyObject *frm, PyObject *to)
-/*[clinic end generated code: output=89a3c3556975e466 input=d204f680f85da382]*/
+bytes_maketrans_impl(Py_buffer *frm, Py_buffer *to)
+/*[clinic end generated code: output=7df47390c476ac60 input=de7a8fc5632bb8f1]*/
 {
 return _Py_bytes_maketrans(frm, to);
 }
@@ -3093,8 +3120,8 @@
 /*[clinic input]
 bytes.replace
 
- old: object
- new: object
+ old: Py_buffer
+ new: Py_buffer
 count: Py_ssize_t = -1
 Maximum number of occurrences to replace.
 -1 (the default value) means replace all occurrences.
@@ -3123,50 +3150,40 @@
 {"replace", (PyCFunction)bytes_replace, METH_VARARGS, bytes_replace__doc__},
 
 static PyObject *
-bytes_replace_impl(PyBytesObject*self, PyObject *old, PyObject *new, Py_ssize_t count);
+bytes_replace_impl(PyBytesObject*self, Py_buffer *old, Py_buffer *new, Py_ssize_t count);
 
 static PyObject *
 bytes_replace(PyBytesObject*self, PyObject *args)
 {
 PyObject *return_value = NULL;
- PyObject *old;
- PyObject *new;
+ Py_buffer old = {NULL, NULL};
+ Py_buffer new = {NULL, NULL};
 Py_ssize_t count = -1;
 
 if (!PyArg_ParseTuple(args,
- "OO|n:replace",
+ "y*y*|n:replace",
 &old, &new, &count))
 goto exit;
- return_value = bytes_replace_impl(self, old, new, count);
+ return_value = bytes_replace_impl(self, &old, &new, count);
 
 exit:
+ /* Cleanup for old */
+ if (old.obj)
+ PyBuffer_Release(&old);
+ /* Cleanup for new */
+ if (new.obj)
+ PyBuffer_Release(&new);
+
 return return_value;
 }
 
 static PyObject *
-bytes_replace_impl(PyBytesObject*self, PyObject *old, PyObject *new, Py_ssize_t count)
-/*[clinic end generated code: output=14ce72f4f9cb91cf input=d3ac254ea50f4ac1]*/
+bytes_replace_impl(PyBytesObject*self, Py_buffer *old, Py_buffer *new, Py_ssize_t count)
+/*[clinic end generated code: output=f07bd9ecf29ee8d8 input=b2fbbf0bf04de8e5]*/
 {
- const char *old_s, *new_s;
- Py_ssize_t old_len, new_len;
-
- if (PyBytes_Check(old)) {
- old_s = PyBytes_AS_STRING(old);
- old_len = PyBytes_GET_SIZE(old);
- }
- else if (PyObject_AsCharBuffer(old, &old_s, &old_len))
- return NULL;
-
- if (PyBytes_Check(new)) {
- new_s = PyBytes_AS_STRING(new);
- new_len = PyBytes_GET_SIZE(new);
- }
- else if (PyObject_AsCharBuffer(new, &new_s, &new_len))
- return NULL;
-
 return (PyObject *)replace((PyBytesObject *) self,
- old_s, old_len,
- new_s, new_len, count);
+ (const char *)old->buf, old->len,
+ (const char *)new->buf, new->len, count);
 }
 
 /** End DALKE **/
@@ -3181,6 +3198,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;
 
@@ -3188,8 +3206,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);
@@ -3197,17 +3219,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;
 }
 
@@ -3978,7 +4008,7 @@
 Py_buffer wb;
 
 wb.len = -1;
- if (_getbuffer(w, &wb) < 0) {
+ if (PyObject_GetBuffer(w, &wb, PyBUF_SIMPLE) != 0) {
 PyErr_Format(PyExc_TypeError, "can't concat %.100s to %.100s",
 Py_TYPE(w)->tp_name, Py_TYPE(*pv)->tp_name);
 Py_CLEAR(*pv);
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
@@ -723,10 +723,10 @@
 }
 
 
-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)) {
@@ -735,19 +735,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_t)size) {
+
+ if (strlen(str) != (size_t)size) {
 PyErr_SetString(PyExc_ValueError,
 "source code string cannot contain null bytes");
+ PyBuffer_Release(view);
 return NULL;
 }
 return str;
@@ -827,7 +829,8 @@
 builtin_compile_impl(PyModuleDef *module, PyObject *source, PyObject *filename, const char *mode, int flags, int dont_inherit, int optimize)
 /*[clinic end generated code: output=c72d197809d178fc input=c6212a9d21472f7e]*/
 {
- char *str;
+ Py_buffer view = {NULL, NULL};
+ const char *str;
 int compile_mode = -1;
 int is_ast;
 PyCompilerFlags cf;
@@ -898,11 +901,12 @@
 goto finally;
 }
 
- str = source_as_string(source, "compile", "string, bytes or AST", &cf);
+ str = source_as_string(source, "compile", "string, bytes or AST", &cf, &view);
 if (str == NULL)
 goto error;
 
 result = Py_CompileStringObject(str, filename, start[compile_mode], &cf, optimize);
+ PyBuffer_Release(&view);
 goto finally;
 
 error:
@@ -1042,7 +1046,8 @@
 /*[clinic end generated code: output=644fd59012538ce6 input=31e42c1d2125b50b]*/
 {
 PyObject *result, *tmp = NULL;
- char *str;
+ Py_buffer view = {NULL, NULL};
+ const char *str;
 PyCompilerFlags cf;
 
 if (locals != Py_None && !PyMapping_Check(locals)) {
@@ -1089,7 +1094,7 @@
 }
 
 cf.cf_flags = PyCF_SOURCE_IS_UTF8;
- str = source_as_string(source, "eval", "string, bytes or code", &cf);
+ str = source_as_string(source, "eval", "string, bytes or code", &cf, &view);
 if (str == NULL)
 return NULL;
 
@@ -1098,6 +1103,7 @@
 
 (void)PyEval_MergeCompilerFlags(&cf);
 result = PyRun_StringFlags(str, Py_eval_input, globals, locals, &cf);
+ PyBuffer_Release(&view);
 Py_XDECREF(tmp);
 return result;
 }
@@ -1204,11 +1210,12 @@
 v = PyEval_EvalCode(source, 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(source, "exec",
- "string, bytes or code", &cf);
+ "string, bytes or code", &cf, &view);
 if (str == NULL)
 return NULL;
 if (PyEval_MergeCompilerFlags(&cf))
@@ -1216,6 +1223,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

AltStyle によって変換されたページ (->オリジナル) /