From 1d3854a19a376c1fc7f71e96c620f6bc2de8cd74 Mon Sep 17 00:00:00 2001 From: yihong Date: Mon, 15 Dec 2025 22:13:58 +0800 Subject: [PATCH] gh-142594: fix by property calls io.TextIOWrapper.detach (GH-142706) Signed-off-by: yihong0618 --- Lib/test/test_io/test_textio.py | 16 ++++++++++++++++ ...025-12-14-18-30-48.gh-issue-142594.belDmD.rst | 2 ++ Modules/_io/textio.c | 3 +++ 3 files changed, 21 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2025-12-14-18-30-48.gh-issue-142594.belDmD.rst diff --git a/Lib/test/test_io/test_textio.py b/Lib/test/test_io/test_textio.py index 6331ed2b9585..d725f9212cea 100644 --- a/Lib/test/test_io/test_textio.py +++ b/Lib/test/test_io/test_textio.py @@ -1544,6 +1544,22 @@ class CTextIOWrapperTest(TextIOWrapperTest, CTestCase): 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, PyTestCase): shutdown_error = "LookupError: unknown encoding: ascii" 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 index 000000000000..ee6a958933f7 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-12-14-18-30-48.gh-issue-142594.belDmD.rst @@ -0,0 +1,2 @@ +Fix crash in ``TextIOWrapper.close()`` when the underlying buffer's +``closed`` property calls :meth:`~io.TextIOBase.detach`. diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index 65da300abcf3..f98819525612 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -3150,6 +3150,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) { -- 2.47.3