]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-121485: Always use 64-bit integers for integers bits count (GH-121486)
authorSerhiy Storchaka <storchaka@gmail.com>
Fri, 30 Aug 2024 05:13:24 +0000 (08:13 +0300)
committerGitHub <noreply@github.com>
Fri, 30 Aug 2024 05:13:24 +0000 (08:13 +0300)
Use 64-bit integers instead of platform specific size_t or Py_ssize_t
to represent the number of bits in Python integer.

13 files changed:
Include/cpython/longobject.h
Include/internal/pycore_long.h
Lib/test/test_capi/test_long.py
Lib/test/test_long.py
Lib/test/test_math.py
Misc/NEWS.d/next/Library/2024-07-09-12-23-32.gh-issue-121486.Iultjh.rst [new file with mode: 0644]
Modules/_pickle.c
Modules/_randommodule.c
Modules/_testinternalcapi.c
Modules/mathmodule.c
Objects/floatobject.c
Objects/longobject.c
Python/ast_opt.c

index e7e0c3d9764f20e1a17b6dc2c1fa3b486b2a05cd..82f8cc8a159c7748b6f3d8fe56f022b9de7f4121 100644 (file)
@@ -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.
index 2bf6ff459ddc961ec2624198473e12b20f567a5f..2c7ca6723c1973a5158cf865c4044e0c0bcbfaff 100644 (file)
@@ -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);
index 48e795f97b3544631d50e041cd3b223da53042b2..925fccd660bde38758991d8b5232d9d6a02a3dda 100644 (file)
@@ -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 (
index 3b2e7c4e71d10d84e46b931a13510dd917b8e3fd..19978118c80dba56ee8e254f07e4a3b531513af1 100644 (file)
@@ -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)
index b68c442013c09f091a2f5139c3b6459934b06084..5c07d9e2c3a834c1eb157a83f9a8090e8dc77b70 100644 (file)
@@ -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 (file)
index 0000000..15130aa
--- /dev/null
@@ -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.
index 3efc05e8415f9d6cb38626613caac7028c309033..e0eda6080e42b3fce0c59b5d42da3049378170f4 100644 (file)
@@ -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");
index 140640ae8fbf3a62a49fd9af39cb7b8a7d320694..3835a3072d96c685efdd0d400c4b0015c798a66e 100644 (file)
@@ -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);
index 00174ffd75760c5c0f04bba03d735cc27f23fb96..0451688a46c75f246058591557420ac18c7ac686 100644 (file)
@@ -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;
 
index d91fa137314dae0ce8b4a7eca90d00597772658a..b7eb745177f37fd26df67be00c7de5a4da5e8dbb 100644 (file)
@@ -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)) {
index 82f39de421f2457b86638d3eee3f5ebe46393afc..68fd3e5463295075d5e114a8d3e88699a24af85d 100644 (file)
@@ -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;
index fde984189206734b0a2d7974e5e37dab9a452382..d34c8b6d71ab3f0bbd1bc85b3be4cecce7c94857 100644 (file)
@@ -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
index 503715e7405aefef41a674b4eb6c69e631c4c408..5a51305d2a7adeaadedbfd1f1c06918beabb5659 100644 (file)
@@ -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) {