]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-138720: Make Buffered closed check match flush (GH-138724)
authorCody Maloney <cmaloney@users.noreply.github.com>
Thu, 18 Sep 2025 10:02:29 +0000 (03:02 -0700)
committerGitHub <noreply@github.com>
Thu, 18 Sep 2025 10:02:29 +0000 (12:02 +0200)
In `_io__Buffered_flush_impl` the macro `CHECK_CLOSED` is used to check
the `buffered*` is in a good state to be flushed. That differs slightly
from `buffered_closed`.

In some cases, that difference would result in `close()` thinking the
file needed to be flushed and closed while `flush()` thought the file
was already closed.

This could happen during GC and would result in an unraisable exception.

Lib/test/test_io/test_general.py
Misc/NEWS.d/next/Library/2025-09-09-17-57-49.gh-issue-138720.hAtsm-.rst [new file with mode: 0644]
Modules/_io/bufferedio.c

index c2f0e1877a69017f5f518bb927658178918799f9..b9abea71e01f0b8d4cfa91d7a2b8f886486bc9e6 100644 (file)
@@ -1980,6 +1980,10 @@ class BufferedRWPairTest:
                 self.assertEqual(getattr(pair, method)(data), 5)
                 self.assertEqual(bytes(data), b"abcde")
 
+        # gh-138720: C BufferedRWPair would destruct in a bad order resulting in
+        # an unraisable exception.
+        support.gc_collect()
+
     def test_write(self):
         w = self.MockRawIO()
         pair = self.tp(self.MockRawIO(), w)
diff --git a/Misc/NEWS.d/next/Library/2025-09-09-17-57-49.gh-issue-138720.hAtsm-.rst b/Misc/NEWS.d/next/Library/2025-09-09-17-57-49.gh-issue-138720.hAtsm-.rst
new file mode 100644 (file)
index 0000000..4f3f54e
--- /dev/null
@@ -0,0 +1,4 @@
+Fix an issue where :class:`io.BufferedWriter` and :class:`io.BufferedRandom`
+had different definitions of "closed" for :meth:`~io.IOBase.close` and
+:meth:`~io.IOBase.flush` which resulted in an exception when close called
+flush but flush thought the file was already closed.
index d0fe7ad61547da15f6d2a2afb342f5e478ea973d..2d2559c8219230ba4d57054280f552bab9b88448 100644 (file)
@@ -553,8 +553,8 @@ _io__Buffered_close_impl(buffered *self)
     if (!ENTER_BUFFERED(self)) {
         return NULL;
     }
-
-    r = buffered_closed(self);
+    /* gh-138720: Use IS_CLOSED to match flush CHECK_CLOSED. */
+    r = IS_CLOSED(self);
     if (r < 0)
         goto end;
     if (r > 0) {