]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-111174: Fix crash in getbuffer() called repeatedly for empty BytesIO (GH-111210)
authorSerhiy Storchaka <storchaka@gmail.com>
Wed, 25 Oct 2023 10:50:16 +0000 (13:50 +0300)
committerGitHub <noreply@github.com>
Wed, 25 Oct 2023 10:50:16 +0000 (13:50 +0300)
Lib/test/test_memoryio.py
Misc/NEWS.d/next/Library/2023-10-23-13-53-58.gh-issue-111174.Oohmzd.rst [new file with mode: 0644]
Modules/_io/bytesio.c

index cd2faba1791c7723522d2ed7b9b1136f2ca71f5a..731299294e6877fdb7bceacc677b547fd93df0d8 100644 (file)
@@ -463,6 +463,20 @@ class PyBytesIOTest(MemoryTestMixin, MemorySeekTestMixin, unittest.TestCase):
         memio.close()
         self.assertRaises(ValueError, memio.getbuffer)
 
+    def test_getbuffer_empty(self):
+        memio = self.ioclass()
+        buf = memio.getbuffer()
+        self.assertEqual(bytes(buf), b"")
+        # Trying to change the size of the BytesIO while a buffer is exported
+        # raises a BufferError.
+        self.assertRaises(BufferError, memio.write, b'x')
+        buf2 = memio.getbuffer()
+        self.assertRaises(BufferError, memio.write, b'x')
+        buf.release()
+        self.assertRaises(BufferError, memio.write, b'x')
+        buf2.release()
+        memio.write(b'x')
+
     def test_read1(self):
         buf = self.buftype("1234567890")
         self.assertEqual(self.ioclass(buf).read1(), buf)
diff --git a/Misc/NEWS.d/next/Library/2023-10-23-13-53-58.gh-issue-111174.Oohmzd.rst b/Misc/NEWS.d/next/Library/2023-10-23-13-53-58.gh-issue-111174.Oohmzd.rst
new file mode 100644 (file)
index 0000000..95c3154
--- /dev/null
@@ -0,0 +1,2 @@
+Fix crash in :meth:`io.BytesIO.getbuffer` called repeatedly for empty
+BytesIO.
index f3074203f54ea2aa8864e819b153b765a9f7cb65..16b8ac600ace79fc60376c9ff802ec5e9158f0ba 100644 (file)
@@ -126,12 +126,13 @@ unshare_buffer(bytesio *self, size_t size)
 static int
 resize_buffer(bytesio *self, size_t size)
 {
+    assert(self->buf != NULL);
+    assert(self->exports == 0);
+
     /* Here, unsigned types are used to avoid dealing with signed integer
        overflow, which is undefined in C. */
     size_t alloc = PyBytes_GET_SIZE(self->buf);
 
-    assert(self->buf != NULL);
-
     /* For simplicity, stay in the range of the signed type. Anyway, Python
        doesn't allow strings to be longer than this. */
     if (size > PY_SSIZE_T_MAX)
@@ -1074,7 +1075,7 @@ bytesiobuf_getbuffer(bytesiobuf *obj, Py_buffer *view, int flags)
             "bytesiobuf_getbuffer: view==NULL argument is obsolete");
         return -1;
     }
-    if (SHARED_BUF(b)) {
+    if (b->exports == 0 && SHARED_BUF(b)) {
         if (unshare_buffer(b, b->string_size) < 0)
             return -1;
     }