mirror of
				https://github.com/python/cpython.git
				synced 2025-10-30 21:21:22 +00:00 
			
		
		
		
	Issue #4509: bugs in bytearray with exports (buffer protocol)
This commit is contained in:
		
							parent
							
								
									e6d4a9bdbc
								
							
						
					
					
						commit
						5504e893f8
					
				
					 3 changed files with 65 additions and 11 deletions
				
			
		|  | @ -769,6 +769,37 @@ def test_partition_bytearray_doesnt_share_nullstring(self): | |||
|         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): | ||||
|     # | ||||
|  |  | |||
|  | @ -21,6 +21,9 @@ Core and Builtins | |||
|   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 | ||||
| ------- | ||||
|  |  | |||
|  | @ -100,6 +100,17 @@ _getbuffer(PyObject *obj, Py_buffer *view) | |||
|     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 @@ PyByteArray_Resize(PyObject *self, Py_ssize_t size) | |||
|     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 @@ PyByteArray_Resize(PyObject *self, Py_ssize_t size) | |||
|         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 @@ bytes_setslice(PyByteArrayObject *self, Py_ssize_t lo, Py_ssize_t hi, | |||
| 
 | ||||
|     if (avail != needed) { | ||||
|         if (avail > needed) { | ||||
|             if (!_canresize(self)) { | ||||
|                 res = -1; | ||||
|                 goto finish; | ||||
|             } | ||||
|             /*
 | ||||
|               0   lo               hi               old_size | ||||
|               |   |<----avail----->|<-----tomove------>| | ||||
|  | @ -605,6 +617,8 @@ bytes_ass_subscript(PyByteArrayObject *self, PyObject *index, PyObject *values) | |||
|         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 @@ bytes_ass_subscript(PyByteArrayObject *self, PyObject *index, PyObject *values) | |||
|             /* Delete slice */ | ||||
|             Py_ssize_t cur, i; | ||||
| 
 | ||||
|             if (!_canresize(self)) | ||||
|                 return -1; | ||||
|             if (step < 0) { | ||||
|                 stop = start + 1; | ||||
|                 start = stop + step * (slicelen - 1) - 1; | ||||
|  | @ -2659,6 +2675,8 @@ bytes_pop(PyByteArrayObject *self, PyObject *args) | |||
|         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 @@ bytes_remove(PyByteArrayObject *self, PyObject *arg) | |||
|         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) | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Antoine Pitrou
						Antoine Pitrou