mirror of
https://github.com/python/cpython.git
synced 2026-01-22 15:18:52 +00:00
gh-143602: Fix duplicate buffer exports in io.BytesIO.write (#143629)
Fix an inconsistency issue in io.BytesIO.write() where the buffer was exported twice, which could lead to unexpected data overwrites and position drift when the buffer changes between exports.
This commit is contained in:
parent
3514ba2175
commit
c461aa99e2
3 changed files with 36 additions and 11 deletions
23
Lib/_pyio.py
23
Lib/_pyio.py
|
|
@ -952,20 +952,21 @@ def write(self, b):
|
|||
if isinstance(b, str):
|
||||
raise TypeError("can't write str to binary stream")
|
||||
with memoryview(b) as view:
|
||||
n = view.nbytes # Size of any bytes-like object
|
||||
if self.closed:
|
||||
raise ValueError("write to closed file")
|
||||
if n == 0:
|
||||
return 0
|
||||
|
||||
with self._lock:
|
||||
pos = self._pos
|
||||
if pos > len(self._buffer):
|
||||
# Pad buffer to pos with null bytes.
|
||||
self._buffer.resize(pos)
|
||||
self._buffer[pos:pos + n] = b
|
||||
self._pos += n
|
||||
return n
|
||||
n = view.nbytes # Size of any bytes-like object
|
||||
if n == 0:
|
||||
return 0
|
||||
|
||||
with self._lock:
|
||||
pos = self._pos
|
||||
if pos > len(self._buffer):
|
||||
# Pad buffer to pos with null bytes.
|
||||
self._buffer.resize(pos)
|
||||
self._buffer[pos:pos + n] = view
|
||||
self._pos += n
|
||||
return n
|
||||
|
||||
def seek(self, pos, whence=0):
|
||||
if self.closed:
|
||||
|
|
|
|||
|
|
@ -629,6 +629,28 @@ def __buffer__(self, flags):
|
|||
memio = self.ioclass()
|
||||
self.assertRaises(BufferError, memio.writelines, [B()])
|
||||
|
||||
def test_write_mutating_buffer(self):
|
||||
# Test that buffer is exported only once during write().
|
||||
# See: https://github.com/python/cpython/issues/143602.
|
||||
class B:
|
||||
count = 0
|
||||
def __buffer__(self, flags):
|
||||
self.count += 1
|
||||
if self.count == 1:
|
||||
return memoryview(b"AAA")
|
||||
else:
|
||||
return memoryview(b"BBBBBBBBB")
|
||||
|
||||
memio = self.ioclass(b'0123456789')
|
||||
memio.seek(2)
|
||||
b = B()
|
||||
n = memio.write(b)
|
||||
|
||||
self.assertEqual(b.count, 1)
|
||||
self.assertEqual(n, 3)
|
||||
self.assertEqual(memio.getvalue(), b"01AAA56789")
|
||||
self.assertEqual(memio.tell(), 5)
|
||||
|
||||
|
||||
class TextIOTestMixin:
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
Fix a inconsistency issue in :meth:`~io.RawIOBase.write` that leads to
|
||||
unexpected buffer overwrite by deduplicating the buffer exports.
|
||||
Loading…
Add table
Add a link
Reference in a new issue