Skip to content

Commit d4750a7

Browse files
authored
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.
1 parent c1c4c18 commit d4750a7

3 files changed

Lines changed: 16 additions & 1 deletion

File tree

‎Lib/test/test_long.py‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -996,6 +996,16 @@ def test_huge_lshift(self, size):
996996
self.assertEqual(v.bit_count(), 2)
997997
self.assertEqual(v >> size, 5)
998998

999+
@support.cpython_only
1000+
def test_huge_lshift_overflow(self):
1001+
# The number of digits of the result doesn't fit in Py_ssize_t.
1002+
for a in 1, -1, 1 << SHIFT, -1 << SHIFT, 1 << 10*SHIFT:
1003+
for ndigits in range(sys.maxsize - 12, sys.maxsize + 1):
1004+
for shift in ndigits*SHIFT - 1, ndigits*SHIFT:
1005+
with self.subTest(a=a, shift=shift):
1006+
with self.assertRaises(OverflowError):
1007+
a << shift
1008+
9991009
def test_huge_rshift(self):
10001010
huge_shift = 1 << 1000
10011011
self.assertEqual(42 >> huge_shift, 0)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix a crash on 32-bit platforms when left shifting an :class:`int` by a
2+
count close to ``sys.maxsize * sys.int_info.bits_per_digit``.
3+
:exc:`OverflowError` is now raised, as for other too large counts.

‎Objects/longobject.c‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5527,7 +5527,9 @@ long_lshift_int64(PyLongObject *a, int64_t shiftby)
55275527
return PyLong_FromLong(0);
55285528
}
55295529
#if PY_SSIZE_T_MAX <= INT64_MAX / PyLong_SHIFT
5530-
if (shiftby > (int64_t)PY_SSIZE_T_MAX * PyLong_SHIFT) {
5530+
/* Keep wordshift <= MAX_LONG_DIGITS, so that oldsize + wordshift
5531+
cannot overflow Py_ssize_t in long_lshift1(). */
5532+
if (shiftby > (int64_t)MAX_LONG_DIGITS * PyLong_SHIFT) {
55315533
PyErr_SetString(PyExc_OverflowError,
55325534
"too many digits in integer");
55335535
return NULL;

0 commit comments

Comments
 (0)