From 2d043c054e4a1f3d3c31eba0575f35d35b148558 Mon Sep 17 00:00:00 2001 From: Cody Maloney Date: Tue, 27 Oct 2026 15:48:59 -0700 Subject: [PATCH 1/3] gh-160781: Fix StringIO.truncate() rejecting sizes above 2**31 - 1 on Windows StringIO.truncate() converted its argument with PyLong_AsLong(), which rejects sizes above 2**31 - 1 on Windows where C long is 32-bit. Use PyNumber_AsSsize_t() like the Py_ssize_t Argument Clinic converter it used before. Co-Authored-By: Claude Opus 5.5 --- Lib/test/test_io/test_memoryio.py | 5 +++++ .../Library/2026-10-27-15-27-32.gh-issue-160781.kARuHu.rst | 2 ++ Modules/_io/stringio.c | 2 +- 3 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-10-27-15-27-32.gh-issue-160781.kARuHu.rst diff --git a/Lib/test/test_io/test_memoryio.py b/Lib/test/test_io/test_memoryio.py index 6a286e5a62ef44c..030c1a3833bdb42 100644 --- a/Lib/test/test_io/test_memoryio.py +++ b/Lib/test/test_io/test_memoryio.py @@ -1150,6 +1150,11 @@ def __index__(self): with self.assertRaises(ValueError): stream.truncate(Size()) + # Sizes above 2**31 - 1 must work where C long is 32-bit. + stream = self.ioclass("abc") + self.assertEqual(stream.truncate(2**31), 2**31) + self.assertEqual(stream.getvalue(), "abc") + # XXX: For the Python version of io.StringIO, this is highly # dependent on the encoding used for the underlying buffer. def test_widechar(self): diff --git a/Misc/NEWS.d/next/Library/2026-10-27-15-27-32.gh-issue-160781.kARuHu.rst b/Misc/NEWS.d/next/Library/2026-10-27-15-27-32.gh-issue-160781.kARuHu.rst new file mode 100644 index 000000000000000..7cf843e14a8b860 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-10-27-15-27-32.gh-issue-160781.kARuHu.rst @@ -0,0 +1,2 @@ +Fix :meth:`io.StringIO.truncate` rejecting sizes larger than ``2**31 - 1`` +on Windows. diff --git a/Modules/_io/stringio.c b/Modules/_io/stringio.c index 558fd57aa93c954..7800a4fcfca4dd8 100644 --- a/Modules/_io/stringio.c +++ b/Modules/_io/stringio.c @@ -490,7 +490,7 @@ _io_StringIO_truncate_impl(stringio *self, PyObject *pos) size = self->pos; } else { - size = PyLong_AsLong(pos); + size = PyNumber_AsSsize_t(pos, PyExc_OverflowError); if (size == -1 && PyErr_Occurred()) { return NULL; } From 5253df54c579547789a94133f4ee1728a1a3758e Mon Sep 17 00:00:00 2001 From: Cody Maloney Date: Tue, 27 Oct 2026 16:05:25 -0700 Subject: [PATCH 2/3] Fix docs reference --- .../Library/2026-10-27-15-27-32.gh-issue-160781.kARuHu.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS.d/next/Library/2026-10-27-15-27-32.gh-issue-160781.kARuHu.rst b/Misc/NEWS.d/next/Library/2026-10-27-15-27-32.gh-issue-160781.kARuHu.rst index 7cf843e14a8b860..1f1e25d8b461b4e 100644 --- a/Misc/NEWS.d/next/Library/2026-10-27-15-27-32.gh-issue-160781.kARuHu.rst +++ b/Misc/NEWS.d/next/Library/2026-10-27-15-27-32.gh-issue-160781.kARuHu.rst @@ -1,2 +1,2 @@ -Fix :meth:`io.StringIO.truncate` rejecting sizes larger than ``2**31 - 1`` -on Windows. +Fix :class:`io.StringIO` implementation of :meth:`io.IOBase.truncate` +rejecting sizes larger than ``2**31 - 1`` on Windows. From 69ad5e02dcec97787a719fe17218967072427053 Mon Sep 17 00:00:00 2001 From: Cody Maloney Date: Tue, 27 Oct 2026 16:05:25 -0700 Subject: [PATCH 3/3] Skip the 2**31 truncate when Py_ssize_t is 32-bit --- Lib/test/test_io/test_memoryio.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_io/test_memoryio.py b/Lib/test/test_io/test_memoryio.py index 030c1a3833bdb42..349c7281230eeba 100644 --- a/Lib/test/test_io/test_memoryio.py +++ b/Lib/test/test_io/test_memoryio.py @@ -1151,9 +1151,10 @@ def __index__(self): stream.truncate(Size()) # Sizes above 2**31 - 1 must work where C long is 32-bit. - stream = self.ioclass("abc") - self.assertEqual(stream.truncate(2**31), 2**31) - self.assertEqual(stream.getvalue(), "abc") + if sys.maxsize > 2**31: + stream = self.ioclass("abc") + self.assertEqual(stream.truncate(2**31), 2**31) + self.assertEqual(stream.getvalue(), "abc") # XXX: For the Python version of io.StringIO, this is highly # dependent on the encoding used for the underlying buffer.