]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.13] gh-142594: fix by property calls io.TextIOWrapper.detach (GH-142706) (GH-142757)
authorCody Maloney <cmaloney@users.noreply.github.com>
Tue, 16 Dec 2025 09:55:35 +0000 (01:55 -0800)
committerGitHub <noreply@github.com>
Tue, 16 Dec 2025 09:55:35 +0000 (10:55 +0100)
(cherry picked from commit 1d3854a19a376c1fc7f71e96c620f6bc2de8cd74)

Signed-off-by: yihong0618 <zouzou0208@gmail.com>
Co-authored-by: yihong <zouzou0208@gmail.com>
Lib/test/test_io.py
Misc/NEWS.d/next/Library/2025-12-14-18-30-48.gh-issue-142594.belDmD.rst [new file with mode: 0644]
Modules/_io/textio.c

index fab1a0d4e51e511859c824f745a517875fe024b0..77b9b70d00f5adb6f75d20b77c71ece7e82ea2fe 100644 (file)
@@ -4160,6 +4160,22 @@ class CTextIOWrapperTest(TextIOWrapperTest):
         self.assertEqual([b"abcdef", b"middle", b"g"*chunk_size],
                          buf._write_stack)
 
+    def test_issue142594(self):
+        wrapper = None
+        detached = False
+        class ReentrantRawIO(self.RawIOBase):
+            @property
+            def closed(self):
+                nonlocal detached
+                if wrapper is not None and not detached:
+                    detached = True
+                    wrapper.detach()
+                return False
+
+        raw = ReentrantRawIO()
+        wrapper = self.TextIOWrapper(raw)
+        wrapper.close()  # should not crash
+
 
 class PyTextIOWrapperTest(TextIOWrapperTest):
     io = pyio
diff --git a/Misc/NEWS.d/next/Library/2025-12-14-18-30-48.gh-issue-142594.belDmD.rst b/Misc/NEWS.d/next/Library/2025-12-14-18-30-48.gh-issue-142594.belDmD.rst
new file mode 100644 (file)
index 0000000..ee6a958
--- /dev/null
@@ -0,0 +1,2 @@
+Fix crash in ``TextIOWrapper.close()`` when the underlying buffer's
+``closed`` property calls :meth:`~io.TextIOBase.detach`.
index 047d0fdfc76770feb271aea506c6d7c568a8a52e..db6c709c00cd22ce6aa9bc1bdf14c3a04e24666d 100644 (file)
@@ -3133,6 +3133,9 @@ _io_TextIOWrapper_close_impl(textio *self)
     if (r > 0) {
         Py_RETURN_NONE; /* stream already closed */
     }
+    if (self->detached) {
+        Py_RETURN_NONE; /* gh-142594 null pointer issue */
+    }
     else {
         PyObject *exc = NULL;
         if (self->finalizing) {