Issue #29028: Fixed possible use-after-free bugs in the subscription of the
buffer object with custom index object.
diff --git a/Objects/bufferobject.c b/Objects/bufferobject.c
index bcfab71..65857bf 100644
--- a/Objects/bufferobject.c
+++ b/Objects/bufferobject.c
@@ -462,17 +462,23 @@
}
static PyObject *
+buffer_item_impl(void *ptr, Py_ssize_t size, Py_ssize_t idx)
+{
+ if ( idx < 0 || idx >= size ) {
+ PyErr_SetString(PyExc_IndexError, "buffer index out of range");
+ return NULL;
+ }
+ return PyString_FromStringAndSize((char *)ptr + idx, 1);
+}
+
+static PyObject *
buffer_item(PyBufferObject *self, Py_ssize_t idx)
{
void *ptr;
Py_ssize_t size;
if (!get_buf(self, &ptr, &size, ANY_BUFFER))
return NULL;
- if ( idx < 0 || idx >= size ) {
- PyErr_SetString(PyExc_IndexError, "buffer index out of range");
- return NULL;
- }
- return PyString_FromStringAndSize((char *)ptr + idx, 1);
+ return buffer_item_impl(ptr, size, idx);
}
static PyObject *
@@ -500,24 +506,27 @@
void *p;
Py_ssize_t size;
- if (!get_buf(self, &p, &size, ANY_BUFFER))
- return NULL;
if (PyIndex_Check(item)) {
Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
if (i == -1 && PyErr_Occurred())
return NULL;
- if (i < 0)
+ if (!get_buf(self, &p, &size, ANY_BUFFER))
+ return NULL;
+
+ if (i < 0) {
i += size;
- return buffer_item(self, i);
+ }
+ return buffer_item_impl(p, size, i);
}
else if (PySlice_Check(item)) {
Py_ssize_t start, stop, step, slicelength, cur, i;
- if (PySlice_GetIndicesEx((PySliceObject*)item, size,
- &start, &stop, &step, &slicelength) < 0) {
+ if (_PySlice_Unpack(item, &start, &stop, &step) < 0)
return NULL;
- }
+ if (!get_buf(self, &p, &size, ANY_BUFFER))
+ return NULL;
+ slicelength = _PySlice_AdjustIndices(size, &start, &stop, step);
if (slicelength <= 0)
return PyString_FromStringAndSize("", 0);
else if (step == 1)
@@ -550,22 +559,12 @@
}
static int
-buffer_ass_item(PyBufferObject *self, Py_ssize_t idx, PyObject *other)
+buffer_ass_item_impl(void *ptr1, Py_ssize_t size, Py_ssize_t idx, PyObject *other)
{
PyBufferProcs *pb;
- void *ptr1, *ptr2;
- Py_ssize_t size;
+ void *ptr2;
Py_ssize_t count;
- if ( self->b_readonly ) {
- PyErr_SetString(PyExc_TypeError,
- "buffer is read-only");
- return -1;
- }
-
- if (!get_buf(self, &ptr1, &size, ANY_BUFFER))
- return -1;
-
if (idx < 0 || idx >= size) {
PyErr_SetString(PyExc_IndexError,
"buffer assignment index out of range");
@@ -601,6 +600,23 @@
}
static int
+buffer_ass_item(PyBufferObject *self, Py_ssize_t idx, PyObject *other)
+{
+ void *ptr1;
+ Py_ssize_t size;
+
+ if ( self->b_readonly ) {
+ PyErr_SetString(PyExc_TypeError,
+ "buffer is read-only");
+ return -1;
+ }
+
+ if (!get_buf(self, &ptr1, &size, ANY_BUFFER))
+ return -1;
+ return buffer_ass_item_impl(ptr1, size, idx, other);
+}
+
+static int
buffer_ass_slice(PyBufferObject *self, Py_ssize_t left, Py_ssize_t right, PyObject *other)
{
PyBufferProcs *pb;
@@ -687,23 +703,26 @@
"single-segment buffer object expected");
return -1;
}
- if (!get_buf(self, &ptr1, &selfsize, ANY_BUFFER))
- return -1;
if (PyIndex_Check(item)) {
Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
if (i == -1 && PyErr_Occurred())
return -1;
+ if (!get_buf(self, &ptr1, &selfsize, ANY_BUFFER))
+ return -1;
+
if (i < 0)
i += selfsize;
- return buffer_ass_item(self, i, value);
+ return buffer_ass_item_impl(ptr1, selfsize, i, value);
}
else if (PySlice_Check(item)) {
Py_ssize_t start, stop, step, slicelength;
- if (PySlice_GetIndicesEx((PySliceObject *)item, selfsize,
- &start, &stop, &step, &slicelength) < 0)
+ if (_PySlice_Unpack(item, &start, &stop, &step) < 0)
+ return -1;
+ if (!get_buf(self, &ptr1, &selfsize, ANY_BUFFER))
return -1;
+ slicelength = _PySlice_AdjustIndices(selfsize, &start, &stop, step);
if ((othersize = (*pb->bf_getreadbuffer)(value, 0, &ptr2)) < 0)
return -1;