From 8681aea2decdaf54523db855697130b9156a46a4 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Thu, 11 Sep 2025 13:30:53 +0300 Subject: [PATCH] gh-71810: Fix corner case (length==0) for int.to_bytes() (GH-138739) ```pycon >>> (0).to_bytes(0, 'big', signed=True) b'' >>> (-1).to_bytes(0, 'big', signed=True) # was b'' Traceback (most recent call last): File "", line 1, in (-1).to_bytes(0, 'big', signed=True) ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^ OverflowError: int too big to convert ``` (cherry picked from commit 011179a79a0d7b93ce074b25b0819e96b6dd3315) Co-authored-by: Sergey B Kirpichev Co-authored-by: Serhiy Storchaka --- Lib/test/test_long.py | 9 +++++++-- .../2025-09-10-14-53-59.gh-issue-71810.ppf0J-.rst | 2 ++ Objects/longobject.c | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-09-10-14-53-59.gh-issue-71810.ppf0J-.rst diff --git a/Lib/test/test_long.py b/Lib/test/test_long.py index b247f3322c2b08..ad1968f709410a 100644 --- a/Lib/test/test_long.py +++ b/Lib/test/test_long.py @@ -1322,17 +1322,22 @@ def equivalent_python(n, length, byteorder, signed=False): check(tests4, 'little', signed=False) self.assertRaises(OverflowError, (256).to_bytes, 1, 'big', signed=False) - self.assertRaises(OverflowError, (256).to_bytes, 1, 'big', signed=True) self.assertRaises(OverflowError, (256).to_bytes, 1, 'little', signed=False) - self.assertRaises(OverflowError, (256).to_bytes, 1, 'little', signed=True) + self.assertRaises(OverflowError, (128).to_bytes, 1, 'big', signed=True) + self.assertRaises(OverflowError, (128).to_bytes, 1, 'little', signed=True) + self.assertRaises(OverflowError, (-129).to_bytes, 1, 'big', signed=True) + self.assertRaises(OverflowError, (-129).to_bytes, 1, 'little', signed=True) self.assertRaises(OverflowError, (-1).to_bytes, 2, 'big', signed=False) self.assertRaises(OverflowError, (-1).to_bytes, 2, 'little', signed=False) self.assertEqual((0).to_bytes(0, 'big'), b'') + self.assertEqual((0).to_bytes(0, 'big', signed=True), b'') self.assertEqual((1).to_bytes(5, 'big'), b'\x00\x00\x00\x00\x01') self.assertEqual((0).to_bytes(5, 'big'), b'\x00\x00\x00\x00\x00') self.assertEqual((-1).to_bytes(5, 'big', signed=True), b'\xff\xff\xff\xff\xff') self.assertRaises(OverflowError, (1).to_bytes, 0, 'big') + self.assertRaises(OverflowError, (-1).to_bytes, 0, 'big', signed=True) + self.assertRaises(OverflowError, (-1).to_bytes, 0, 'little', signed=True) # gh-98783 class SubStr(str): diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-09-10-14-53-59.gh-issue-71810.ppf0J-.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-09-10-14-53-59.gh-issue-71810.ppf0J-.rst new file mode 100644 index 00000000000000..a87db44225e825 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-09-10-14-53-59.gh-issue-71810.ppf0J-.rst @@ -0,0 +1,2 @@ +Raise :exc:`OverflowError` for ``(-1).to_bytes()`` for signed conversions +when bytes count is zero. Patch by Sergey B Kirpichev. diff --git a/Objects/longobject.c b/Objects/longobject.c index be5cbf0872b446..98bf50d01cc079 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -1041,7 +1041,7 @@ _PyLong_AsByteArray(PyLongObject* v, *p = (unsigned char)(accum & 0xff); p += pincr; } - else if (j == n && n > 0 && is_signed) { + else if (j == n && is_signed) { /* The main loop filled the byte array exactly, so the code just above didn't get to ensure there's a sign bit, and the loop below wouldn't add one either. Make sure a sign bit