Issue #22896: Avoid to use PyObject_AsCharBuffer(), PyObject_AsReadBu… · pythoncapi/cpython@4fdb684 · GitHub
Skip to content

Commit 4fdb684

Browse files
Issue python#22896: Avoid to use PyObject_AsCharBuffer(), PyObject_AsReadBuffer()
and PyObject_AsWriteBuffer().
1 parent b0ef785 commit 4fdb684

17 files changed

Lines changed: 325 additions & 333 deletions

File tree

Lib/ctypes/test/test_frombuffer.py

Lines changed: 33 additions & 17 deletions

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ Release date: TBA
1111
Core and Builtins
1212
-----------------
1313

14+
- Issue #22896: Avoid using PyObject_AsCharBuffer(), PyObject_AsReadBuffer()
15+
and PyObject_AsWriteBuffer().
16+
1417
- Issue #21295: Revert some changes (issue #16795) to AST line numbers and
1518
column offsets that constituted a regression.
1619

Modules/_codecsmodule.c

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -284,8 +284,6 @@ unicode_internal_decode(PyObject *self,
284284
{
285285
PyObject *obj;
286286
const char *errors = NULL;
287-
const char *data;
288-
Py_ssize_t size;
289287

290288
if (!PyArg_ParseTuple(args, "O|z:unicode_internal_decode",
291289
&obj, &errors))
@@ -298,11 +296,16 @@ unicode_internal_decode(PyObject *self,
298296
return codec_tuple(obj, PyUnicode_GET_LENGTH(obj));
299297
}
300298
else {
301-
if (PyObject_AsReadBuffer(obj, (const void **)&data, &size))
299+
Py_buffer view;
300+
PyObject *result;
301+
if (PyObject_GetBuffer(obj, &view, PyBUF_SIMPLE) != 0)
302302
return NULL;
303303

304-
return codec_tuple(_PyUnicode_DecodeUnicodeInternal(data, size, errors),
305-
size);
304+
result = codec_tuple(
305+
_PyUnicode_DecodeUnicodeInternal(view.buf, view.len, errors),
306+
view.len);
307+
PyBuffer_Release(&view);
308+
return result;
306309
}
307310
}
308311

@@ -727,8 +730,6 @@ unicode_internal_encode(PyObject *self,
727730
{
728731
PyObject *obj;
729732
const char *errors = NULL;
730-
const char *data;
731-
Py_ssize_t len, size;
732733

733734
if (PyErr_WarnEx(PyExc_DeprecationWarning,
734735
"unicode_internal codec has been deprecated",
@@ -741,6 +742,7 @@ unicode_internal_encode(PyObject *self,
741742

742743
if (PyUnicode_Check(obj)) {
743744
Py_UNICODE *u;
745+
Py_ssize_t len, size;
744746

745747
if (PyUnicode_READY(obj) < 0)
746748
return NULL;
@@ -755,9 +757,13 @@ unicode_internal_encode(PyObject *self,
755757
PyUnicode_GET_LENGTH(obj));
756758
}
757759
else {
758-
if (PyObject_AsReadBuffer(obj, (const void **)&data, &size))
760+
Py_buffer view;
761+
PyObject *result;
762+
if (PyObject_GetBuffer(obj, &view, PyBUF_SIMPLE) != 0)
759763
return NULL;
760-
return codec_tuple(PyBytes_FromStringAndSize(data, size), size);
764+
result = codec_tuple(PyBytes_FromStringAndSize(view.buf, view.len), view.len);
765+
PyBuffer_Release(&view);
766+
return result;
761767
}
762768
}
763769

Modules/_ctypes/_ctypes.c

Lines changed: 31 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -463,39 +463,45 @@ KeepRef(CDataObject *target, Py_ssize_t index, PyObject *keep);
463463
static PyObject *
464464
CDataType_from_buffer(PyObject *type, PyObject *args)
465465
{
466-
void *buffer;
467-
Py_ssize_t buffer_len;
466+
Py_buffer buffer;
468467
Py_ssize_t offset = 0;
469-
PyObject *obj, *result;
468+
PyObject *result, *mv;
470469
StgDictObject *dict = PyType_stgdict(type);
471470
assert (dict);
472471

473-
if (!PyArg_ParseTuple(args, "O|n:from_buffer", &obj, &offset))
474-
return NULL;
475-
476-
if (-1 == PyObject_AsWriteBuffer(obj, &buffer, &buffer_len))
472+
if (!PyArg_ParseTuple(args, "w*|n:from_buffer", &buffer, &offset))
477473
return NULL;
478474

479475
if (offset < 0) {
480476
PyErr_SetString(PyExc_ValueError,
481477
"offset cannot be negative");
478+
PyBuffer_Release(&buffer);
482479
return NULL;
483480
}
484-
if (dict->size > buffer_len - offset) {
481+
if (dict->size > buffer.len - offset) {
485482
PyErr_Format(PyExc_ValueError,
486483
"Buffer size too small (%zd instead of at least %zd bytes)",
487-
buffer_len, dict->size + offset);
484+
buffer.len, dict->size + offset);
485+
PyBuffer_Release(&buffer);
488486
return NULL;
489487
}
490488

491-
result = PyCData_AtAddress(type, (char *)buffer + offset);
492-
if (result == NULL)
489+
result = PyCData_AtAddress(type, (char *)buffer.buf + offset);
490+
if (result == NULL) {
491+
PyBuffer_Release(&buffer);
493492
return NULL;
493+
}
494494

495-
Py_INCREF(obj);
496-
if (-1 == KeepRef((CDataObject *)result, -1, obj)) {
495+
mv = PyMemoryView_FromBuffer(&buffer);
496+
if (mv == NULL) {
497+
PyBuffer_Release(&buffer);
497498
return NULL;
498499
}
500+
/* Hack the memoryview so that it will release the buffer. */
501+
((PyMemoryViewObject *)mv)->mbuf->master.obj = buffer.obj;
502+
((PyMemoryViewObject *)mv)->view.obj = buffer.obj;
503+
if (-1 == KeepRef((CDataObject *)result, -1, mv))
504+
result = NULL;
499505
return result;
500506
}
501507

@@ -508,37 +514,36 @@ GenericPyCData_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
508514
static PyObject *
509515
CDataType_from_buffer_copy(PyObject *type, PyObject *args)
510516
{
511-
const void *buffer;
512-
Py_ssize_t buffer_len;
517+
Py_buffer buffer;
513518
Py_ssize_t offset = 0;
514-
PyObject *obj, *result;
519+
PyObject *result;
515520
StgDictObject *dict = PyType_stgdict(type);
516521
assert (dict);
517522

518-
if (!PyArg_ParseTuple(args, "O|n:from_buffer", &obj, &offset))
519-
return NULL;
520-
521-
if (-1 == PyObject_AsReadBuffer(obj, (const void**)&buffer, &buffer_len))
523+
if (!PyArg_ParseTuple(args, "y*|n:from_buffer", &buffer, &offset))
522524
return NULL;
523525

524526
if (offset < 0) {
525527
PyErr_SetString(PyExc_ValueError,
526528
"offset cannot be negative");
529+
PyBuffer_Release(&buffer);
527530
return NULL;
528531
}
529532

530-
if (dict->size > buffer_len - offset) {
533+
if (dict->size > buffer.len - offset) {
531534
PyErr_Format(PyExc_ValueError,
532535
"Buffer size too small (%zd instead of at least %zd bytes)",
533-
buffer_len, dict->size + offset);
536+
buffer.len, dict->size + offset);
537+
PyBuffer_Release(&buffer);
534538
return NULL;
535539
}
536540

537541
result = GenericPyCData_new((PyTypeObject *)type, NULL, NULL);
538-
if (result == NULL)
539-
return NULL;
540-
memcpy(((CDataObject *)result)->b_ptr,
541-
(char *)buffer+offset, dict->size);
542+
if (result != NULL) {
543+
memcpy(((CDataObject *)result)->b_ptr,
544+
(char *)buffer.buf + offset, dict->size);
545+
}
546+
PyBuffer_Release(&buffer);
542547
return result;
543548
}
544549

Modules/_io/bytesio.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -437,28 +437,30 @@ PyDoc_STRVAR(readinto_doc,
437437
"is set not to block as has no data to read.");
438438

439439
static PyObject *
440-
bytesio_readinto(bytesio *self, PyObject *buffer)
440+
bytesio_readinto(bytesio *self, PyObject *arg)
441441
{
442-
void *raw_buffer;
442+
Py_buffer buffer;
443443
Py_ssize_t len, n;
444444

445445
CHECK_CLOSED(self);
446446

447-
if (PyObject_AsWriteBuffer(buffer, &raw_buffer, &len) == -1)
447+
if (!PyArg_Parse(arg, "w*", &buffer))
448448
return NULL;
449449

450450
/* adjust invalid sizes */
451+
len = buffer.len;
451452
n = self->string_size - self->pos;
452453
if (len > n) {
453454
len = n;
454455
if (len < 0)
455456
len = 0;
456457
}
457458

458-
memcpy(raw_buffer, self->buf + self->pos, len);
459+
memcpy(buffer.buf, self->buf + self->pos, len);
459460
assert(self->pos + len < PY_SSIZE_T_MAX);
460461
assert(len >= 0);
461462
self->pos += len;
463+
PyBuffer_Release(&buffer);
462464

463465
return PyLong_FromSsize_t(len);
464466
}

Modules/_sqlite/connection.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -522,19 +522,20 @@ _pysqlite_set_result(sqlite3_context* context, PyObject* py_val)
522522
return -1;
523523
sqlite3_result_text(context, str, -1, SQLITE_TRANSIENT);
524524
} else if (PyObject_CheckBuffer(py_val)) {
525-
const char* buffer;
526-
Py_ssize_t buflen;
527-
if (PyObject_AsCharBuffer(py_val, &buffer, &buflen) != 0) {
525+
Py_buffer view;
526+
if (PyObject_GetBuffer(py_val, &view, PyBUF_SIMPLE) != 0) {
528527
PyErr_SetString(PyExc_ValueError,
529528
"could not convert BLOB to buffer");
530529
return -1;
531530
}
532-
if (buflen > INT_MAX) {
531+
if (view.len > INT_MAX) {
533532
PyErr_SetString(PyExc_OverflowError,
534533
"BLOB longer than INT_MAX bytes");
534+
PyBuffer_Release(&view);
535535
return -1;
536536
}
537-
sqlite3_result_blob(context, buffer, (int)buflen, SQLITE_TRANSIENT);
537+
sqlite3_result_blob(context, view.buf, (int)view.len, SQLITE_TRANSIENT);
538+
PyBuffer_Release(&view);
538539
} else {
539540
return -1;
540541
}

Modules/_sqlite/statement.c

Lines changed: 8 additions & 5 deletions

0 commit comments

Comments
 (0)