[Python-checkins] cpython: Close #19568: Fix bytearray_setslice_linear(), fix handling of
victor.stinner
python-checkins at python.org
Thu Nov 21 12:32:14 CET 2013
http://hg.python.org/cpython/rev/ab73b7fd7523
changeset: 87309:ab73b7fd7523
user: Victor Stinner <victor.stinner at gmail.com>
date: Thu Nov 21 12:29:51 2013 +0100
summary:
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.
files:
Objects/bytearrayobject.c | 100 ++++++++++++++++---------
1 files changed, 63 insertions(+), 37 deletions(-)
diff --git a/Objects/bytearrayobject.c b/Objects/bytearrayobject.c
--- a/Objects/bytearrayobject.c
+++ b/Objects/bytearrayobject.c
@@ -453,54 +453,80 @@
Py_ssize_t avail = hi - lo;
char *buf = PyByteArray_AS_STRING(self);
Py_ssize_t growth = bytes_len - avail;
+ int res = 0;
assert(avail >= 0);
- if (growth != 0) {
- if (growth < 0) {
- if (!_canresize(self))
+ if (growth < 0) {
+ if (!_canresize(self))
+ 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) {
+ self->ob_start += growth;
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);
- }
+ /* 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)
+ buf = PyByteArray_AS_STRING(self);
+ }
+ else if (growth > 0) {
+ if (Py_SIZE(self) > (Py_ssize_t)PY_SSIZE_T_MAX - growth) {
+ PyErr_NoMemory();
return -1;
+ }
+
+ if (PyByteArray_Resize((PyObject *)self,
+ Py_SIZE(self) + growth) < 0) {
+ return -1;
+ }
buf = PyByteArray_AS_STRING(self);
- if (growth > 0) {
- /* 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);
- }
+ /* 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)
memcpy(buf + lo, bytes, bytes_len);
- return 0;
+ return res;
}
static int
--
Repository URL: http://hg.python.org/cpython
More information about the Python-checkins
mailing list