From 32c7dbb2bc58bee953622fc5ac24aad123f0d8f2 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 30 Aug 2024 08:13:24 +0300 Subject: [PATCH] gh-121485: Always use 64-bit integers for integers bits count (GH-121486) Use 64-bit integers instead of platform specific size_t or Py_ssize_t to represent the number of bits in Python integer. --- Include/cpython/longobject.h | 4 +- Include/internal/pycore_long.h | 6 +- Lib/test/test_capi/test_long.py | 12 ++ Lib/test/test_long.py | 73 +++++++++- Lib/test/test_math.py | 16 +++ ...-07-09-12-23-32.gh-issue-121486.Iultjh.rst | 3 + Modules/_pickle.c | 6 +- Modules/_randommodule.c | 7 +- Modules/_testinternalcapi.c | 4 +- Modules/mathmodule.c | 8 +- Objects/floatobject.c | 20 +-- Objects/longobject.c | 125 ++++++++---------- Python/ast_opt.c | 14 +- 13 files changed, 187 insertions(+), 111 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-07-09-12-23-32.gh-issue-121486.Iultjh.rst diff --git a/Include/cpython/longobject.h b/Include/cpython/longobject.h index e7e0c3d9764..82f8cc8a159 100644 --- a/Include/cpython/longobject.h +++ b/Include/cpython/longobject.h @@ -71,10 +71,10 @@ PyAPI_FUNC(int) _PyLong_Sign(PyObject *v); absolute value of a long. For example, this returns 1 for 1 and -1, 2 for 2 and -2, and 2 for 3 and -3. It returns 0 for 0. v must not be NULL, and must be a normalized long. - (size_t)-1 is returned and OverflowError set if the true result doesn't + (uint64_t)-1 is returned and OverflowError set if the true result doesn't fit in a size_t. */ -PyAPI_FUNC(size_t) _PyLong_NumBits(PyObject *v); +PyAPI_FUNC(uint64_t) _PyLong_NumBits(PyObject *v); /* _PyLong_FromByteArray: View the n unsigned bytes as a binary integer in base 256, and return a Python int with the same numeric value. diff --git a/Include/internal/pycore_long.h b/Include/internal/pycore_long.h index 2bf6ff459dd..2c7ca6723c1 100644 --- a/Include/internal/pycore_long.h +++ b/Include/internal/pycore_long.h @@ -86,7 +86,7 @@ static inline PyObject* _PyLong_FromUnsignedChar(unsigned char i) // OverflowError and returns -1.0 for x, 0 for e. // // Export for 'math' shared extension -PyAPI_DATA(double) _PyLong_Frexp(PyLongObject *a, Py_ssize_t *e); +PyAPI_DATA(double) _PyLong_Frexp(PyLongObject *a, int64_t *e); extern PyObject* _PyLong_FromBytes(const char *, Py_ssize_t, int); @@ -105,10 +105,10 @@ PyAPI_DATA(PyObject*) _PyLong_DivmodNear(PyObject *, PyObject *); PyAPI_DATA(PyObject*) _PyLong_Format(PyObject *obj, int base); // Export for 'math' shared extension -PyAPI_DATA(PyObject*) _PyLong_Rshift(PyObject *, size_t); +PyAPI_DATA(PyObject*) _PyLong_Rshift(PyObject *, uint64_t); // Export for 'math' shared extension -PyAPI_DATA(PyObject*) _PyLong_Lshift(PyObject *, size_t); +PyAPI_DATA(PyObject*) _PyLong_Lshift(PyObject *, uint64_t); PyAPI_FUNC(PyObject*) _PyLong_Add(PyLongObject *left, PyLongObject *right); PyAPI_FUNC(PyObject*) _PyLong_Multiply(PyLongObject *left, PyLongObject *right); diff --git a/Lib/test/test_capi/test_long.py b/Lib/test/test_capi/test_long.py index 48e795f97b3..925fccd660b 100644 --- a/Lib/test/test_capi/test_long.py +++ b/Lib/test/test_capi/test_long.py @@ -340,6 +340,18 @@ class LongTests(unittest.TestCase): def test_long_aspid_limited(self): self._test_long_aspid(_testlimitedcapi.pylong_aspid) + @support.bigmemtest(2**32, memuse=0.35) + def test_long_asnativebytes_huge(self, size): + asnativebytes = _testcapi.pylong_asnativebytes + v = 1 << size + buffer = bytearray(size * 2 // 15 + 10) + r = asnativebytes(v, buffer, 0, -1) + self.assertEqual(r, size // 8 + 1) + self.assertEqual(buffer.count(0), len(buffer)) + r = asnativebytes(v, buffer, len(buffer), -1) + self.assertEqual(r, size // 8 + 1) + self.assertEqual(buffer.count(0), len(buffer) - 1) + def test_long_asnativebytes(self): import math from _testcapi import ( diff --git a/Lib/test/test_long.py b/Lib/test/test_long.py index 3b2e7c4e71d..19978118c80 100644 --- a/Lib/test/test_long.py +++ b/Lib/test/test_long.py @@ -473,6 +473,12 @@ class LongTest(unittest.TestCase): self.check_float_conversion(value) self.check_float_conversion(-value) + @support.requires_IEEE_754 + @support.bigmemtest(2**32, memuse=0.2) + def test_float_conversion_huge_integer(self, size): + v = 1 << size + self.assertRaises(OverflowError, float, v) + def test_float_overflow(self): for x in -2.0, -1.0, 0.0, 1.0, 2.0: self.assertEqual(float(int(x)), x) @@ -614,6 +620,56 @@ class LongTest(unittest.TestCase): eq(x > y, Rcmp > 0) eq(x >= y, Rcmp >= 0) + @support.requires_IEEE_754 + @support.bigmemtest(2**32, memuse=0.2) + def test_mixed_compares_huge_integer(self, size): + v = 1 << size + f = sys.float_info.max + self.assertIs(f == v, False) + self.assertIs(f != v, True) + self.assertIs(f < v, True) + self.assertIs(f <= v, True) + self.assertIs(f > v, False) + self.assertIs(f >= v, False) + f = float('inf') + self.assertIs(f == v, False) + self.assertIs(f != v, True) + self.assertIs(f < v, False) + self.assertIs(f <= v, False) + self.assertIs(f > v, True) + self.assertIs(f >= v, True) + f = float('nan') + self.assertIs(f == v, False) + self.assertIs(f != v, True) + self.assertIs(f < v, False) + self.assertIs(f <= v, False) + self.assertIs(f > v, False) + self.assertIs(f >= v, False) + + del v + v = (-1) << size + f = -sys.float_info.max + self.assertIs(f == v, False) + self.assertIs(f != v, True) + self.assertIs(f < v, False) + self.assertIs(f <= v, False) + self.assertIs(f > v, True) + self.assertIs(f >= v, True) + f = float('-inf') + self.assertIs(f == v, False) + self.assertIs(f != v, True) + self.assertIs(f < v, True) + self.assertIs(f <= v, True) + self.assertIs(f > v, False) + self.assertIs(f >= v, False) + f = float('nan') + self.assertIs(f == v, False) + self.assertIs(f != v, True) + self.assertIs(f < v, False) + self.assertIs(f <= v, False) + self.assertIs(f > v, False) + self.assertIs(f >= v, False) + def test__format__(self): self.assertEqual(format(123456789, 'd'), '123456789') self.assertEqual(format(123456789, 'd'), '123456789') @@ -933,9 +989,12 @@ class LongTest(unittest.TestCase): self.assertEqual(0 << (sys.maxsize + 1), 0) @support.cpython_only - @support.bigmemtest(sys.maxsize + 1000, memuse=2/15 * 2, dry_run=False) + @support.bigmemtest(2**32, memuse=0.2) def test_huge_lshift(self, size): - self.assertEqual(1 << (sys.maxsize + 1000), 1 << 1000 << sys.maxsize) + v = 5 << size + self.assertEqual(v.bit_length(), size + 3) + self.assertEqual(v.bit_count(), 2) + self.assertEqual(v >> size, 5) def test_huge_rshift(self): huge_shift = 1 << 1000 @@ -947,11 +1006,13 @@ class LongTest(unittest.TestCase): self.assertEqual(-2**128 >> huge_shift, -1) @support.cpython_only - @support.bigmemtest(sys.maxsize + 500, memuse=2/15, dry_run=False) + @support.bigmemtest(2**32, memuse=0.2) def test_huge_rshift_of_huge(self, size): - huge = ((1 << 500) + 11) << sys.maxsize - self.assertEqual(huge >> (sys.maxsize + 1), (1 << 499) + 5) - self.assertEqual(huge >> (sys.maxsize + 1000), 0) + huge = ((1 << 500) + 11) << size + self.assertEqual(huge.bit_length(), size + 501) + self.assertEqual(huge.bit_count(), 4) + self.assertEqual(huge >> (size + 1), (1 << 499) + 5) + self.assertEqual(huge >> (size + 1000), 0) def test_small_rshift(self): self.assertEqual(42 >> 1, 21) diff --git a/Lib/test/test_math.py b/Lib/test/test_math.py index b68c442013c..5c07d9e2c3a 100644 --- a/Lib/test/test_math.py +++ b/Lib/test/test_math.py @@ -1120,6 +1120,15 @@ class MathTests(unittest.TestCase): with self.assertRaises(TypeError): math.isqrt(value) + @support.bigmemtest(2**32, memuse=0.85) + def test_isqrt_huge(self, size): + if size & 1: + size += 1 + v = 1 << size + w = math.isqrt(v) + self.assertEqual(w.bit_length(), size // 2 + 1) + self.assertEqual(w.bit_count(), 1) + def test_lcm(self): lcm = math.lcm self.assertEqual(lcm(0, 0), 0) @@ -1261,6 +1270,13 @@ class MathTests(unittest.TestCase): self.assertEqual(math.log(INF), INF) self.assertTrue(math.isnan(math.log10(NAN))) + @support.bigmemtest(2**32, memuse=0.2) + def test_log_huge_integer(self, size): + v = 1 << size + self.assertAlmostEqual(math.log2(v), size) + self.assertAlmostEqual(math.log(v), size * 0.6931471805599453) + self.assertAlmostEqual(math.log10(v), size * 0.3010299956639812) + def testSumProd(self): sumprod = math.sumprod Decimal = decimal.Decimal diff --git a/Misc/NEWS.d/next/Library/2024-07-09-12-23-32.gh-issue-121486.Iultjh.rst b/Misc/NEWS.d/next/Library/2024-07-09-12-23-32.gh-issue-121486.Iultjh.rst new file mode 100644 index 00000000000..15130aafbc4 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-07-09-12-23-32.gh-issue-121486.Iultjh.rst @@ -0,0 +1,3 @@ +:mod:`math` functions :func:`~math.isqrt`, :func:`~math.log`, :func:`~math.log2` and +:func:`~math.log10` now support integers larger than ``2**2**32`` on 32-bit +platforms. diff --git a/Modules/_pickle.c b/Modules/_pickle.c index 3efc05e8415..e0eda6080e4 100644 --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -2140,7 +2140,7 @@ save_long(PicklerObject *self, PyObject *obj) if (self->proto >= 2) { /* Linear-time pickling. */ - size_t nbits; + uint64_t nbits; size_t nbytes; unsigned char *pdata; char header[5]; @@ -2155,7 +2155,7 @@ save_long(PicklerObject *self, PyObject *obj) return 0; } nbits = _PyLong_NumBits(obj); - if (nbits == (size_t)-1 && PyErr_Occurred()) + if (nbits == (uint64_t)-1 && PyErr_Occurred()) goto error; /* How many bytes do we need? There are nbits >> 3 full * bytes of data, and nbits & 7 leftover bits. If there @@ -2171,7 +2171,7 @@ save_long(PicklerObject *self, PyObject *obj) * for in advance, though, so we always grab an extra * byte at the start, and cut it back later if possible. */ - nbytes = (nbits >> 3) + 1; + nbytes = (size_t)((nbits >> 3) + 1); if (nbytes > 0x7fffffffL) { PyErr_SetString(PyExc_OverflowError, "int too large to pickle"); diff --git a/Modules/_randommodule.c b/Modules/_randommodule.c index 140640ae8fb..3835a3072d9 100644 --- a/Modules/_randommodule.c +++ b/Modules/_randommodule.c @@ -295,7 +295,8 @@ random_seed(RandomObject *self, PyObject *arg) int result = -1; /* guilty until proved innocent */ PyObject *n = NULL; uint32_t *key = NULL; - size_t bits, keyused; + uint64_t bits; + size_t keyused; int res; if (arg == NULL || arg == Py_None) { @@ -334,11 +335,11 @@ random_seed(RandomObject *self, PyObject *arg) /* Now split n into 32-bit chunks, from the right. */ bits = _PyLong_NumBits(n); - if (bits == (size_t)-1 && PyErr_Occurred()) + if (bits == (uint64_t)-1 && PyErr_Occurred()) goto Done; /* Figure out how many 32-bit chunks this gives us. */ - keyused = bits == 0 ? 1 : (bits - 1) / 32 + 1; + keyused = bits == 0 ? 1 : (size_t)((bits - 1) / 32 + 1); /* Convert seed to byte sequence. */ key = (uint32_t *)PyMem_Malloc((size_t)4 * keyused); diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index 00174ffd757..0451688a46c 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -1853,7 +1853,7 @@ _testinternalcapi_test_long_numbits_impl(PyObject *module) { struct triple { long input; - size_t nbits; + uint64_t nbits; int sign; } testcases[] = {{0, 0, 0}, {1L, 1, 1}, @@ -1873,7 +1873,7 @@ _testinternalcapi_test_long_numbits_impl(PyObject *module) size_t i; for (i = 0; i < Py_ARRAY_LENGTH(testcases); ++i) { - size_t nbits; + uint64_t nbits; int sign; PyObject *plong; diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c index d91fa137314..b7eb745177f 100644 --- a/Modules/mathmodule.c +++ b/Modules/mathmodule.c @@ -1657,7 +1657,7 @@ math_isqrt(PyObject *module, PyObject *n) /*[clinic end generated code: output=35a6f7f980beab26 input=5b6e7ae4fa6c43d6]*/ { int a_too_large, c_bit_length; - size_t c, d; + uint64_t c, d; uint64_t m; uint32_t u; PyObject *a = NULL, *b; @@ -1680,7 +1680,7 @@ math_isqrt(PyObject *module, PyObject *n) /* c = (n.bit_length() - 1) // 2 */ c = _PyLong_NumBits(n); - if (c == (size_t)(-1)) { + if (c == (uint64_t)(-1)) { goto error; } c = (c - 1U) / 2U; @@ -1727,7 +1727,7 @@ math_isqrt(PyObject *module, PyObject *n) for (int s = c_bit_length - 6; s >= 0; --s) { PyObject *q; - size_t e = d; + uint64_t e = d; d = c >> s; @@ -2185,7 +2185,7 @@ loghelper(PyObject* arg, double (*func)(double)) /* If it is int, do it ourselves. */ if (PyLong_Check(arg)) { double x, result; - Py_ssize_t e; + int64_t e; /* Negative or zero inputs give a ValueError. */ if (!_PyLong_IsPositive((PyLongObject *)arg)) { diff --git a/Objects/floatobject.c b/Objects/floatobject.c index 82f39de421f..68fd3e54632 100644 --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -399,7 +399,6 @@ float_richcompare(PyObject *v, PyObject *w, int op) else if (PyLong_Check(w)) { int vsign = i == 0.0 ? 0 : i < 0.0 ? -1 : 1; int wsign = _PyLong_Sign(w); - size_t nbits; int exponent; if (vsign != wsign) { @@ -412,20 +411,25 @@ float_richcompare(PyObject *v, PyObject *w, int op) } /* The signs are the same. */ /* Convert w to a double if it fits. In particular, 0 fits. */ - nbits = _PyLong_NumBits(w); - if (nbits == (size_t)-1 && PyErr_Occurred()) { - /* This long is so large that size_t isn't big enough - * to hold the # of bits. Replace with little doubles + uint64_t nbits64 = _PyLong_NumBits(w); + if (nbits64 > (unsigned int)DBL_MAX_EXP) { + /* This Python integer is larger than any finite C double. + * Replace with little doubles * that give the same outcome -- w is so large that * its magnitude must exceed the magnitude of any * finite float. */ - PyErr_Clear(); + if (nbits64 == (uint64_t)-1 && PyErr_Occurred()) { + /* This Python integer is so large that uint64_t isn't + * big enough to hold the # of bits. */ + PyErr_Clear(); + } i = (double)vsign; assert(wsign != 0); j = wsign * 2.0; goto Compare; } + int nbits = (int)nbits64; if (nbits <= 48) { j = PyLong_AsDouble(w); /* It's impossible that <= 48 bits overflowed. */ @@ -449,12 +453,12 @@ float_richcompare(PyObject *v, PyObject *w, int op) /* exponent is the # of bits in v before the radix point; * we know that nbits (the # of bits in w) > 48 at this point */ - if (exponent < 0 || (size_t)exponent < nbits) { + if (exponent < nbits) { i = 1.0; j = 2.0; goto Compare; } - if ((size_t)exponent > nbits) { + if (exponent > nbits) { i = 2.0; j = 1.0; goto Compare; diff --git a/Objects/longobject.c b/Objects/longobject.c index fde98418920..d34c8b6d71a 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -804,11 +804,11 @@ bit_length_digit(digit x) return _Py_bit_length((unsigned long)x); } -size_t +uint64_t _PyLong_NumBits(PyObject *vv) { PyLongObject *v = (PyLongObject *)vv; - size_t result = 0; + uint64_t result = 0; Py_ssize_t ndigits; int msd_bits; @@ -818,20 +818,21 @@ _PyLong_NumBits(PyObject *vv) assert(ndigits == 0 || v->long_value.ob_digit[ndigits - 1] != 0); if (ndigits > 0) { digit msd = v->long_value.ob_digit[ndigits - 1]; - if ((size_t)(ndigits - 1) > SIZE_MAX / (size_t)PyLong_SHIFT) + if ((uint64_t)(ndigits - 1) > UINT64_MAX / (uint64_t)PyLong_SHIFT) goto Overflow; - result = (size_t)(ndigits - 1) * (size_t)PyLong_SHIFT; + result = (uint64_t)(ndigits - 1) * (uint64_t)PyLong_SHIFT; msd_bits = bit_length_digit(msd); - if (SIZE_MAX - msd_bits < result) + if (UINT64_MAX - msd_bits < result) goto Overflow; result += msd_bits; } return result; Overflow: + /* Very unlikely. Such integer would require more than 2 exbibytes of RAM. */ PyErr_SetString(PyExc_OverflowError, "int has too many bits " - "to express in a platform size_t"); - return (size_t)-1; + "to express in a 64-bit integer"); + return (uint64_t)-1; } PyObject * @@ -1246,8 +1247,8 @@ PyLong_AsNativeBytes(PyObject* vv, void* buffer, Py_ssize_t n, int flags) /* Calculates the number of bits required for the *absolute* value * of v. This does not take sign into account, only magnitude. */ - size_t nb = _PyLong_NumBits((PyObject *)v); - if (nb == (size_t)-1) { + uint64_t nb = _PyLong_NumBits((PyObject *)v); + if (nb == (uint64_t)-1) { res = -1; } else { /* Normally this would be((nb - 1) / 8) + 1 to avoid rounding up @@ -3412,9 +3413,10 @@ x_divrem(PyLongObject *v1, PyLongObject *w1, PyLongObject **prem) #endif double -_PyLong_Frexp(PyLongObject *a, Py_ssize_t *e) +_PyLong_Frexp(PyLongObject *a, int64_t *e) { - Py_ssize_t a_size, a_bits, shift_digits, shift_bits, x_size; + Py_ssize_t a_size, shift_digits, shift_bits, x_size; + int64_t a_bits; /* See below for why x_digits is always large enough. */ digit rem; digit x_digits[2 + (DBL_MANT_DIG + 1) / PyLong_SHIFT] = {0,}; @@ -3430,14 +3432,14 @@ _PyLong_Frexp(PyLongObject *a, Py_ssize_t *e) *e = 0; return 0.0; } - a_bits = bit_length_digit(a->long_value.ob_digit[a_size-1]); + int msd_bits = bit_length_digit(a->long_value.ob_digit[a_size-1]); /* The following is an overflow-free version of the check - "if ((a_size - 1) * PyLong_SHIFT + a_bits > PY_SSIZE_T_MAX) ..." */ - if (a_size >= (PY_SSIZE_T_MAX - 1) / PyLong_SHIFT + 1 && - (a_size > (PY_SSIZE_T_MAX - 1) / PyLong_SHIFT + 1 || - a_bits > (PY_SSIZE_T_MAX - 1) % PyLong_SHIFT + 1)) + "if ((a_size - 1) * PyLong_SHIFT + msd_bits > PY_SSIZE_T_MAX) ..." */ + if (a_size >= (INT64_MAX - 1) / PyLong_SHIFT + 1 && + (a_size > (INT64_MAX - 1) / PyLong_SHIFT + 1 || + msd_bits > (INT64_MAX - 1) % PyLong_SHIFT + 1)) goto overflow; - a_bits = (a_size - 1) * PyLong_SHIFT + a_bits; + a_bits = (int64_t)(a_size - 1) * PyLong_SHIFT + msd_bits; /* Shift the first DBL_MANT_DIG + 2 bits of a into x_digits[0:x_size] (shifting left if a_bits <= DBL_MANT_DIG + 2). @@ -3465,8 +3467,8 @@ _PyLong_Frexp(PyLongObject *a, Py_ssize_t *e) in both cases. */ if (a_bits <= DBL_MANT_DIG + 2) { - shift_digits = (DBL_MANT_DIG + 2 - a_bits) / PyLong_SHIFT; - shift_bits = (DBL_MANT_DIG + 2 - a_bits) % PyLong_SHIFT; + shift_digits = (DBL_MANT_DIG + 2 - (Py_ssize_t)a_bits) / PyLong_SHIFT; + shift_bits = (DBL_MANT_DIG + 2 - (Py_ssize_t)a_bits) % PyLong_SHIFT; x_size = shift_digits; rem = v_lshift(x_digits + x_size, a->long_value.ob_digit, a_size, (int)shift_bits); @@ -3474,8 +3476,8 @@ _PyLong_Frexp(PyLongObject *a, Py_ssize_t *e) x_digits[x_size++] = rem; } else { - shift_digits = (a_bits - DBL_MANT_DIG - 2) / PyLong_SHIFT; - shift_bits = (a_bits - DBL_MANT_DIG - 2) % PyLong_SHIFT; + shift_digits = (Py_ssize_t)((a_bits - DBL_MANT_DIG - 2) / PyLong_SHIFT); + shift_bits = (Py_ssize_t)((a_bits - DBL_MANT_DIG - 2) % PyLong_SHIFT); rem = v_rshift(x_digits, a->long_value.ob_digit + shift_digits, a_size - shift_digits, (int)shift_bits); x_size = a_size - shift_digits; @@ -3503,7 +3505,7 @@ _PyLong_Frexp(PyLongObject *a, Py_ssize_t *e) /* Rescale; make correction if result is 1.0. */ dx /= 4.0 * EXP2_DBL_MANT_DIG; if (dx == 1.0) { - if (a_bits == PY_SSIZE_T_MAX) + if (a_bits == INT64_MAX) goto overflow; dx = 0.5; a_bits += 1; @@ -3526,7 +3528,7 @@ _PyLong_Frexp(PyLongObject *a, Py_ssize_t *e) double PyLong_AsDouble(PyObject *v) { - Py_ssize_t exponent; + int64_t exponent; double x; if (v == NULL) { @@ -5360,7 +5362,7 @@ long_rshift(PyObject *a, PyObject *b) /* Return a >> shiftby. */ PyObject * -_PyLong_Rshift(PyObject *a, size_t shiftby) +_PyLong_Rshift(PyObject *a, uint64_t shiftby) { Py_ssize_t wordshift; digit remshift; @@ -5369,8 +5371,18 @@ _PyLong_Rshift(PyObject *a, size_t shiftby) if (_PyLong_IsZero((PyLongObject *)a)) { return PyLong_FromLong(0); } - wordshift = shiftby / PyLong_SHIFT; - remshift = shiftby % PyLong_SHIFT; +#if PY_SSIZE_T_MAX <= UINT64_MAX / PyLong_SHIFT + if (shiftby > (uint64_t)PY_SSIZE_T_MAX * PyLong_SHIFT) { + if (_PyLong_IsNegative((PyLongObject *)a)) { + return PyLong_FromLong(-1); + } + else { + return PyLong_FromLong(0); + } + } +#endif + wordshift = (Py_ssize_t)(shiftby / PyLong_SHIFT); + remshift = (digit)(shiftby % PyLong_SHIFT); return long_rshift1((PyLongObject *)a, wordshift, remshift); } @@ -5437,7 +5449,7 @@ long_lshift(PyObject *a, PyObject *b) /* Return a << shiftby. */ PyObject * -_PyLong_Lshift(PyObject *a, size_t shiftby) +_PyLong_Lshift(PyObject *a, uint64_t shiftby) { Py_ssize_t wordshift; digit remshift; @@ -5446,8 +5458,15 @@ _PyLong_Lshift(PyObject *a, size_t shiftby) if (_PyLong_IsZero((PyLongObject *)a)) { return PyLong_FromLong(0); } - wordshift = shiftby / PyLong_SHIFT; - remshift = shiftby % PyLong_SHIFT; +#if PY_SSIZE_T_MAX <= UINT64_MAX / PyLong_SHIFT + if (shiftby > (uint64_t)PY_SSIZE_T_MAX * PyLong_SHIFT) { + PyErr_SetString(PyExc_OverflowError, + "too many digits in integer"); + return NULL; + } +#endif + wordshift = (Py_ssize_t)(shiftby / PyLong_SHIFT); + remshift = (digit)(shiftby % PyLong_SHIFT); return long_lshift1((PyLongObject *)a, wordshift, remshift); } @@ -6194,51 +6213,11 @@ static PyObject * int_bit_length_impl(PyObject *self) /*[clinic end generated code: output=fc1977c9353d6a59 input=e4eb7a587e849a32]*/ { - PyLongObject *result, *x, *y; - Py_ssize_t ndigits; - int msd_bits; - digit msd; - - assert(self != NULL); - assert(PyLong_Check(self)); - - ndigits = _PyLong_DigitCount((PyLongObject *)self); - if (ndigits == 0) - return PyLong_FromLong(0); - - msd = ((PyLongObject *)self)->long_value.ob_digit[ndigits-1]; - msd_bits = bit_length_digit(msd); - - if (ndigits <= PY_SSIZE_T_MAX/PyLong_SHIFT) - return PyLong_FromSsize_t((ndigits-1)*PyLong_SHIFT + msd_bits); - - /* expression above may overflow; use Python integers instead */ - result = (PyLongObject *)PyLong_FromSsize_t(ndigits - 1); - if (result == NULL) + uint64_t nbits = _PyLong_NumBits(self); + if (nbits == (uint64_t)-1) { return NULL; - x = (PyLongObject *)PyLong_FromLong(PyLong_SHIFT); - if (x == NULL) - goto error; - y = (PyLongObject *)long_mul(result, x); - Py_DECREF(x); - if (y == NULL) - goto error; - Py_SETREF(result, y); - - x = (PyLongObject *)PyLong_FromLong((long)msd_bits); - if (x == NULL) - goto error; - y = (PyLongObject *)long_add(result, x); - Py_DECREF(x); - if (y == NULL) - goto error; - Py_SETREF(result, y); - - return (PyObject *)result; - - error: - Py_DECREF(result); - return NULL; + } + return PyLong_FromUnsignedLongLong(nbits); } static int diff --git a/Python/ast_opt.c b/Python/ast_opt.c index 503715e7405..5a51305d2a7 100644 --- a/Python/ast_opt.c +++ b/Python/ast_opt.c @@ -169,9 +169,9 @@ safe_multiply(PyObject *v, PyObject *w) if (PyLong_Check(v) && PyLong_Check(w) && !_PyLong_IsZero((PyLongObject *)v) && !_PyLong_IsZero((PyLongObject *)w) ) { - size_t vbits = _PyLong_NumBits(v); - size_t wbits = _PyLong_NumBits(w); - if (vbits == (size_t)-1 || wbits == (size_t)-1) { + uint64_t vbits = _PyLong_NumBits(v); + uint64_t wbits = _PyLong_NumBits(w); + if (vbits == (uint64_t)-1 || wbits == (uint64_t)-1) { return NULL; } if (vbits + wbits > MAX_INT_SIZE) { @@ -215,9 +215,9 @@ safe_power(PyObject *v, PyObject *w) if (PyLong_Check(v) && PyLong_Check(w) && !_PyLong_IsZero((PyLongObject *)v) && _PyLong_IsPositive((PyLongObject *)w) ) { - size_t vbits = _PyLong_NumBits(v); + uint64_t vbits = _PyLong_NumBits(v); size_t wbits = PyLong_AsSize_t(w); - if (vbits == (size_t)-1 || wbits == (size_t)-1) { + if (vbits == (uint64_t)-1 || wbits == (size_t)-1) { return NULL; } if (vbits > MAX_INT_SIZE / wbits) { @@ -234,9 +234,9 @@ safe_lshift(PyObject *v, PyObject *w) if (PyLong_Check(v) && PyLong_Check(w) && !_PyLong_IsZero((PyLongObject *)v) && !_PyLong_IsZero((PyLongObject *)w) ) { - size_t vbits = _PyLong_NumBits(v); + uint64_t vbits = _PyLong_NumBits(v); size_t wbits = PyLong_AsSize_t(w); - if (vbits == (size_t)-1 || wbits == (size_t)-1) { + if (vbits == (uint64_t)-1 || wbits == (size_t)-1) { return NULL; } if (wbits > MAX_INT_SIZE || vbits > MAX_INT_SIZE - wbits) {