[Python-checkins] r67623 - in python/branches/release30-maint: Lib/test/test_bytes.py Misc/NEWS Objects/bytearrayobject.c

antoine.pitrou python-checkins at python.org
Sun Dec 7 01:07:58 CET 2008


Author: antoine.pitrou
Date: Sun Dec  7 01:07:58 2008
New Revision: 67623

Log:
Merged revisions 67618 via svnmerge from 
svn+ssh://pythondev@svn.python.org/python/branches/py3k

........
  r67618 | antoine.pitrou | 2008-12-06 22:27:53 +0100 (sam., 06 déc. 2008) | 1 line
  
  Issue #4509: bugs in bytearray with exports (buffer protocol)
........


Modified:
   python/branches/release30-maint/   (props changed)
   python/branches/release30-maint/Lib/test/test_bytes.py
   python/branches/release30-maint/Misc/NEWS
   python/branches/release30-maint/Objects/bytearrayobject.c

Modified: python/branches/release30-maint/Lib/test/test_bytes.py
==============================================================================
--- python/branches/release30-maint/Lib/test/test_bytes.py	(original)
+++ python/branches/release30-maint/Lib/test/test_bytes.py	Sun Dec  7 01:07:58 2008
@@ -769,6 +769,37 @@
         self.assertEqual(b, b"")
         self.assertEqual(c, b"")
 
+    def test_resize_forbidden(self):
+        # #4509: can't resize a bytearray when there are buffer exports, even
+        # if it wouldn't reallocate the underlying buffer.
+        # Furthermore, no destructive changes to the buffer may be applied
+        # before raising the error.
+        b = bytearray(range(10))
+        v = memoryview(b)
+        def resize(n):
+            b[1:-1] = range(n + 1, 2*n - 1)
+        resize(10)
+        orig = b[:]
+        self.assertRaises(BufferError, resize, 11)
+        self.assertEquals(b, orig)
+        self.assertRaises(BufferError, resize, 9)
+        self.assertEquals(b, orig)
+        self.assertRaises(BufferError, resize, 0)
+        self.assertEquals(b, orig)
+        # Other operations implying resize
+        self.assertRaises(BufferError, b.pop, 0)
+        self.assertEquals(b, orig)
+        self.assertRaises(BufferError, b.remove, b[1])
+        self.assertEquals(b, orig)
+        def delitem():
+            del b[1]
+        self.assertRaises(BufferError, delitem)
+        self.assertEquals(b, orig)
+        # deleting a non-contiguous slice
+        def delslice():
+            b[1:-1:2] = b""
+        self.assertRaises(BufferError, delslice)
+        self.assertEquals(b, orig)
 
 class AssortedBytesTest(unittest.TestCase):
     #

Modified: python/branches/release30-maint/Misc/NEWS
==============================================================================
--- python/branches/release30-maint/Misc/NEWS	(original)
+++ python/branches/release30-maint/Misc/NEWS	Sun Dec  7 01:07:58 2008
@@ -16,6 +16,9 @@
   growing read buffer. Fixed by using the same growth rate algorithm as
   Python 2.x.
 
+- Issue #4509: Various issues surrounding resize of bytearray objects to
+  which there are buffer exports (e.g. memoryview instances).
+
 
 Library
 -------

Modified: python/branches/release30-maint/Objects/bytearrayobject.c
==============================================================================
--- python/branches/release30-maint/Objects/bytearrayobject.c	(original)
+++ python/branches/release30-maint/Objects/bytearrayobject.c	Sun Dec  7 01:07:58 2008
@@ -100,6 +100,17 @@
     return view->len;
 }
 
+static int
+_canresize(PyByteArrayObject *self)
+{
+    if (self->ob_exports > 0) {
+        PyErr_SetString(PyExc_BufferError,
+                "Existing exports of data: object cannot be re-sized");
+        return 0;
+    }
+    return 1;
+}
+
 /* Direct API functions */
 
 PyObject *
@@ -180,6 +191,13 @@
     assert(PyByteArray_Check(self));
     assert(size >= 0);
 
+    if (size == Py_SIZE(self)) {
+        return 0;
+    }
+    if (!_canresize((PyByteArrayObject *)self)) {
+        return -1;
+    }
+
     if (size < alloc / 2) {
         /* Major downsize; resize down to exact size */
         alloc = size + 1;
@@ -199,16 +217,6 @@
         alloc = size + 1;
     }
 
-    if (((PyByteArrayObject *)self)->ob_exports > 0) {
-            /*
-            fprintf(stderr, "%d: %s", ((PyByteArrayObject *)self)->ob_exports,
-                    ((PyByteArrayObject *)self)->ob_bytes);
-            */
-            PyErr_SetString(PyExc_BufferError,
-                    "Existing exports of data: object cannot be re-sized");
-            return -1;
-    }
-
     sval = PyMem_Realloc(((PyByteArrayObject *)self)->ob_bytes, alloc);
     if (sval == NULL) {
         PyErr_NoMemory();
@@ -473,6 +481,10 @@
 
     if (avail != needed) {
         if (avail > needed) {
+            if (!_canresize(self)) {
+                res = -1;
+                goto finish;
+            }
             /*
               0   lo               hi               old_size
               |   |<----avail----->|<-----tomove------>|
@@ -605,6 +617,8 @@
         stop = start;
     if (step == 1) {
         if (slicelen != needed) {
+            if (!_canresize(self))
+                return -1;
             if (slicelen > needed) {
                 /*
                   0   start           stop              old_size
@@ -640,6 +654,8 @@
             /* Delete slice */
             Py_ssize_t cur, i;
 
+            if (!_canresize(self))
+                return -1;
             if (step < 0) {
                 stop = start + 1;
                 start = stop + step * (slicelen - 1) - 1;
@@ -1401,7 +1417,7 @@
         }
         goto done;
     }
-
+    
     for (i = 0; i < 256; i++)
         trans_table[i] = Py_CHARMASK(table[i]);
 
@@ -2659,6 +2675,8 @@
         PyErr_SetString(PyExc_IndexError, "pop index out of range");
         return NULL;
     }
+    if (!_canresize(self))
+        return NULL;
 
     value = self->ob_bytes[where];
     memmove(self->ob_bytes + where, self->ob_bytes + where + 1, n - where);
@@ -2689,6 +2707,8 @@
         PyErr_SetString(PyExc_ValueError, "value not found in bytes");
         return NULL;
     }
+    if (!_canresize(self))
+        return NULL;
 
     memmove(self->ob_bytes + where, self->ob_bytes + where + 1, n - where);
     if (PyByteArray_Resize((PyObject *)self, n - 1) < 0)


More information about the Python-checkins mailing list