https://github.com/python/cpython/commit/8c66e51f79e6f0f2a9e6a7de2264cbc9dd8f7775 commit: 8c66e51f79e6f0f2a9e6a7de2264cbc9dd8f7775 branch: 3.14 author: Miss Islington (bot) <[email protected]> committer: gpshead <[email protected]> date: 2026-10-22T04:19:11Z summary:
[3.14] gh-160162: Fix crash in int left shift with huge count on 32-bit (GH-160163) (#160170) gh-160162: Fix crash in int left shift with huge count on 32-bit (GH-160163) Bound the shift count by MAX_LONG_DIGITS*PyLong_SHIFT instead of PY_SSIZE_T_MAX*PyLong_SHIFT, so that the result size computed in long_lshift1() cannot overflow Py_ssize_t. (cherry picked from commit d4750a77519d9936da875953d85e07a851a1d8cd) Co-authored-by: Gregory P. Smith <[email protected]> files: A Misc/NEWS.d/next/Core_and_Builtins/2026-10-22-00-30-21.gh-issue-160162.lShf32.rst M Lib/test/test_long.py M Objects/longobject.c diff --git a/Lib/test/test_long.py b/Lib/test/test_long.py index b48a8812a1a2d1..7c368e121024d2 100644 --- a/Lib/test/test_long.py +++ b/Lib/test/test_long.py @@ -996,6 +996,16 @@ def test_huge_lshift(self, size): self.assertEqual(v.bit_count(), 2) self.assertEqual(v >> size, 5) + @support.cpython_only + def test_huge_lshift_overflow(self): + # The number of digits of the result doesn't fit in Py_ssize_t. + for a in 1, -1, 1 << SHIFT, -1 << SHIFT, 1 << 10*SHIFT: + for ndigits in range(sys.maxsize - 12, sys.maxsize + 1): + for shift in ndigits*SHIFT - 1, ndigits*SHIFT: + with self.subTest(a=a, shift=shift): + with self.assertRaises(OverflowError): + a << shift + def test_huge_rshift(self): huge_shift = 1 << 1000 self.assertEqual(42 >> huge_shift, 0) diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-10-22-00-30-21.gh-issue-160162.lShf32.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-10-22-00-30-21.gh-issue-160162.lShf32.rst new file mode 100644 index 00000000000000..5aa2021bddd44e --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-10-22-00-30-21.gh-issue-160162.lShf32.rst @@ -0,0 +1,3 @@ +Fix a crash on 32-bit platforms when left shifting an :class:`int` by a +count close to ``sys.maxsize * sys.int_info.bits_per_digit``. +:exc:`OverflowError` is now raised, as for other too large counts. diff --git a/Objects/longobject.c b/Objects/longobject.c index 5c830cd330acc2..bafded6ced706a 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -5441,7 +5441,9 @@ long_lshift_int64(PyLongObject *a, int64_t shiftby) return PyLong_FromLong(0); } #if PY_SSIZE_T_MAX <= INT64_MAX / PyLong_SHIFT - if (shiftby > (int64_t)PY_SSIZE_T_MAX * PyLong_SHIFT) { + /* Keep wordshift <= MAX_LONG_DIGITS, so that oldsize + wordshift + cannot overflow Py_ssize_t in long_lshift1(). */ + if (shiftby > (int64_t)MAX_LONG_DIGITS * PyLong_SHIFT) { PyErr_SetString(PyExc_OverflowError, "too many digits in integer"); return NULL; _______________________________________________ Python-checkins mailing list -- [email protected] To unsubscribe send an email to [email protected] https://mail.python.org/mailman3//lists/python-checkins.python.org Member address: [email protected]
