mirror of https://github.com/python/cpython
bpo-34973: Fix crash in bytes constructor. (GH-9841)
Constructing bytes from mutating list could cause a crash.
This commit is contained in:
parent
a323cdcb33
commit
914f9a078f
|
@ -113,6 +113,23 @@ class BaseBytesTest:
|
||||||
b = self.type2test([1, 2, 3])
|
b = self.type2test([1, 2, 3])
|
||||||
self.assertEqual(b, b"\x01\x02\x03")
|
self.assertEqual(b, b"\x01\x02\x03")
|
||||||
|
|
||||||
|
def test_from_mutating_list(self):
|
||||||
|
# Issue #34973: Crash in bytes constructor with mutating list.
|
||||||
|
class X:
|
||||||
|
def __index__(self):
|
||||||
|
a.clear()
|
||||||
|
return 42
|
||||||
|
a = [X(), X()]
|
||||||
|
self.assertEqual(bytes(a), b'*')
|
||||||
|
|
||||||
|
class Y:
|
||||||
|
def __index__(self):
|
||||||
|
if len(a) < 1000:
|
||||||
|
a.append(self)
|
||||||
|
return 42
|
||||||
|
a = [Y()]
|
||||||
|
self.assertEqual(bytes(a), b'*' * 1000) # should not crash
|
||||||
|
|
||||||
def test_from_index(self):
|
def test_from_index(self):
|
||||||
b = self.type2test([Indexable(), Indexable(1), Indexable(254),
|
b = self.type2test([Indexable(), Indexable(1), Indexable(254),
|
||||||
Indexable(255)])
|
Indexable(255)])
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Fixed crash in :func:`bytes` when the :class:`list` argument is mutated
|
||||||
|
while it is iterated.
|
|
@ -2639,49 +2639,83 @@ fail:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define _PyBytes_FROM_LIST_BODY(x, GET_ITEM) \
|
|
||||||
do { \
|
|
||||||
PyObject *bytes; \
|
|
||||||
Py_ssize_t i; \
|
|
||||||
Py_ssize_t value; \
|
|
||||||
char *str; \
|
|
||||||
PyObject *item; \
|
|
||||||
\
|
|
||||||
bytes = PyBytes_FromStringAndSize(NULL, Py_SIZE(x)); \
|
|
||||||
if (bytes == NULL) \
|
|
||||||
return NULL; \
|
|
||||||
str = ((PyBytesObject *)bytes)->ob_sval; \
|
|
||||||
\
|
|
||||||
for (i = 0; i < Py_SIZE(x); i++) { \
|
|
||||||
item = GET_ITEM((x), i); \
|
|
||||||
value = PyNumber_AsSsize_t(item, NULL); \
|
|
||||||
if (value == -1 && PyErr_Occurred()) \
|
|
||||||
goto error; \
|
|
||||||
\
|
|
||||||
if (value < 0 || value >= 256) { \
|
|
||||||
PyErr_SetString(PyExc_ValueError, \
|
|
||||||
"bytes must be in range(0, 256)"); \
|
|
||||||
goto error; \
|
|
||||||
} \
|
|
||||||
*str++ = (char) value; \
|
|
||||||
} \
|
|
||||||
return bytes; \
|
|
||||||
\
|
|
||||||
error: \
|
|
||||||
Py_DECREF(bytes); \
|
|
||||||
return NULL; \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_PyBytes_FromList(PyObject *x)
|
_PyBytes_FromList(PyObject *x)
|
||||||
{
|
{
|
||||||
_PyBytes_FROM_LIST_BODY(x, PyList_GET_ITEM);
|
Py_ssize_t i, size = PyList_GET_SIZE(x);
|
||||||
|
Py_ssize_t value;
|
||||||
|
char *str;
|
||||||
|
PyObject *item;
|
||||||
|
_PyBytesWriter writer;
|
||||||
|
|
||||||
|
_PyBytesWriter_Init(&writer);
|
||||||
|
str = _PyBytesWriter_Alloc(&writer, size);
|
||||||
|
if (str == NULL)
|
||||||
|
return NULL;
|
||||||
|
writer.overallocate = 1;
|
||||||
|
size = writer.allocated;
|
||||||
|
|
||||||
|
for (i = 0; i < PyList_GET_SIZE(x); i++) {
|
||||||
|
item = PyList_GET_ITEM(x, i);
|
||||||
|
Py_INCREF(item);
|
||||||
|
value = PyNumber_AsSsize_t(item, NULL);
|
||||||
|
Py_DECREF(item);
|
||||||
|
if (value == -1 && PyErr_Occurred())
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (value < 0 || value >= 256) {
|
||||||
|
PyErr_SetString(PyExc_ValueError,
|
||||||
|
"bytes must be in range(0, 256)");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i >= size) {
|
||||||
|
str = _PyBytesWriter_Resize(&writer, str, size+1);
|
||||||
|
if (str == NULL)
|
||||||
|
return NULL;
|
||||||
|
size = writer.allocated;
|
||||||
|
}
|
||||||
|
*str++ = (char) value;
|
||||||
|
}
|
||||||
|
return _PyBytesWriter_Finish(&writer, str);
|
||||||
|
|
||||||
|
error:
|
||||||
|
_PyBytesWriter_Dealloc(&writer);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_PyBytes_FromTuple(PyObject *x)
|
_PyBytes_FromTuple(PyObject *x)
|
||||||
{
|
{
|
||||||
_PyBytes_FROM_LIST_BODY(x, PyTuple_GET_ITEM);
|
PyObject *bytes;
|
||||||
|
Py_ssize_t i, size = PyTuple_GET_SIZE(x);
|
||||||
|
Py_ssize_t value;
|
||||||
|
char *str;
|
||||||
|
PyObject *item;
|
||||||
|
|
||||||
|
bytes = PyBytes_FromStringAndSize(NULL, size);
|
||||||
|
if (bytes == NULL)
|
||||||
|
return NULL;
|
||||||
|
str = ((PyBytesObject *)bytes)->ob_sval;
|
||||||
|
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
item = PyTuple_GET_ITEM(x, i);
|
||||||
|
value = PyNumber_AsSsize_t(item, NULL);
|
||||||
|
if (value == -1 && PyErr_Occurred())
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (value < 0 || value >= 256) {
|
||||||
|
PyErr_SetString(PyExc_ValueError,
|
||||||
|
"bytes must be in range(0, 256)");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
*str++ = (char) value;
|
||||||
|
}
|
||||||
|
return bytes;
|
||||||
|
|
||||||
|
error:
|
||||||
|
Py_DECREF(bytes);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
|
|
Loading…
Reference in New Issue