Kaydet (Commit) 8455723c authored tarafından Victor Stinner's avatar Victor Stinner

Close #19568: Fix bytearray_setslice_linear(), fix handling of

PyByteArray_Resize() failure: leave the bytearray object in an consistent state.

If growth < 0, handling the memory allocation failure is tricky here because
the bytearray object has already been modified.  If lo != 0, the operation is
completed, but a MemoryError is still raised and the memory block is not
shrinked. If lo == 0, the bytearray is restored in its previous state and a
MemoryError is raised.
üst 35f2803a
...@@ -453,54 +453,80 @@ bytearray_setslice_linear(PyByteArrayObject *self, ...@@ -453,54 +453,80 @@ bytearray_setslice_linear(PyByteArrayObject *self,
Py_ssize_t avail = hi - lo; Py_ssize_t avail = hi - lo;
char *buf = PyByteArray_AS_STRING(self); char *buf = PyByteArray_AS_STRING(self);
Py_ssize_t growth = bytes_len - avail; Py_ssize_t growth = bytes_len - avail;
int res = 0;
assert(avail >= 0); assert(avail >= 0);
if (growth != 0) { if (growth < 0) {
if (growth < 0) { if (!_canresize(self))
if (!_canresize(self)) return -1;
return -1;
if (lo == 0) {
/* Shrink the buffer by advancing its logical start */
self->ob_start -= growth;
/*
0 lo hi old_size
| |<----avail----->|<-----tail------>|
| |<-bytes_len->|<-----tail------>|
0 new_lo new_hi new_size
*/
}
else {
/*
0 lo hi old_size
| |<----avail----->|<-----tomove------>|
| |<-bytes_len->|<-----tomove------>|
0 lo new_hi new_size
*/
memmove(buf + lo + bytes_len, buf + hi,
Py_SIZE(self) - hi);
}
if (PyByteArray_Resize((PyObject *)self,
Py_SIZE(self) + growth) < 0) {
/* Issue #19578: Handling the memory allocation failure here is
tricky here because the bytearray object has already been
modified. Depending on growth and lo, the behaviour is
different.
If growth < 0 and lo != 0, the operation is completed, but a
MemoryError is still raised and the memory block is not
shrinked. Otherwise, the bytearray is restored in its previous
state and a MemoryError is raised. */
if (lo == 0) { if (lo == 0) {
/* Shrink the buffer by advancing its logical start */ self->ob_start += growth;
self->ob_start -= growth; return -1;
/*
0 lo hi old_size
| |<----avail----->|<-----tail------>|
| |<-bytes_len->|<-----tail------>|
0 new_lo new_hi new_size
*/
}
else {
/*
0 lo hi old_size
| |<----avail----->|<-----tomove------>|
| |<-bytes_len->|<-----tomove------>|
0 lo new_hi new_size
*/
memmove(buf + lo + bytes_len, buf + hi,
Py_SIZE(self) - hi);
} }
/* memmove() removed bytes, the bytearray object cannot be
restored in its previous state. */
Py_SIZE(self) += growth;
res = -1;
} }
/* XXX(nnorwitz): need to verify this can't overflow! */
if (PyByteArray_Resize(
(PyObject *)self, Py_SIZE(self) + growth) < 0)
return -1;
buf = PyByteArray_AS_STRING(self); buf = PyByteArray_AS_STRING(self);
if (growth > 0) { }
/* Make the place for the additional bytes */ else if (growth > 0) {
/* if (Py_SIZE(self) > (Py_ssize_t)PY_SSIZE_T_MAX - growth) {
0 lo hi old_size PyErr_NoMemory();
| |<-avail->|<-----tomove------>| return -1;
| |<---bytes_len-->|<-----tomove------>|
0 lo new_hi new_size
*/
memmove(buf + lo + bytes_len, buf + hi,
Py_SIZE(self) - lo - bytes_len);
} }
if (PyByteArray_Resize((PyObject *)self,
Py_SIZE(self) + growth) < 0) {
return -1;
}
buf = PyByteArray_AS_STRING(self);
/* Make the place for the additional bytes */
/*
0 lo hi old_size
| |<-avail->|<-----tomove------>|
| |<---bytes_len-->|<-----tomove------>|
0 lo new_hi new_size
*/
memmove(buf + lo + bytes_len, buf + hi,
Py_SIZE(self) - lo - bytes_len);
} }
if (bytes_len > 0) if (bytes_len > 0)
memcpy(buf + lo, bytes, bytes_len); memcpy(buf + lo, bytes, bytes_len);
return 0; return res;
} }
static int static int
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment