]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-123497: New limit for Python integers on 64-bit platforms (GH-123724)
authorSerhiy Storchaka <storchaka@gmail.com>
Sun, 29 Sep 2024 07:40:20 +0000 (10:40 +0300)
committerGitHub <noreply@github.com>
Sun, 29 Sep 2024 07:40:20 +0000 (10:40 +0300)
Instead of be limited just by the size of addressable memory (2**63
bytes), Python integers are now also limited by the number of bits, so
the number of bit now always fit in a 64-bit integer.

Both limits are much larger than what might be available in practice,
so it doesn't affect users.

_PyLong_NumBits() and _PyLong_Frexp() are now always successful.

Include/cpython/longobject.h
Include/internal/pycore_long.h
Modules/_pickle.c
Modules/_randommodule.c
Modules/mathmodule.c
Objects/floatobject.c
Objects/longobject.c
Python/ast_opt.c

index 82f8cc8a159c7748b6f3d8fe56f022b9de7f4121..b239f7c557e016e8011ce1a91f205cc582523e18 100644 (file)
@@ -71,10 +71,9 @@ 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.
-   (uint64_t)-1 is returned and OverflowError set if the true result doesn't
-   fit in a size_t.
+   Always successful.
 */
-PyAPI_FUNC(uint64_t) _PyLong_NumBits(PyObject *v);
+PyAPI_FUNC(int64_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 8822147b636dd45976d991a0f4356903f4c22453..196b4152280a35665102b25f32258eee242d358a 100644 (file)
@@ -79,11 +79,10 @@ static inline PyObject* _PyLong_FromUnsignedChar(unsigned char i)
 }
 
 // _PyLong_Frexp returns a double x and an exponent e such that the
-// true value is approximately equal to x * 2**e.  e is >= 0.  x is
+// true value is approximately equal to x * 2**e.  x is
 // 0.0 if and only if the input is 0 (in which case, e and x are both
-// zeroes); otherwise, 0.5 <= abs(x) < 1.0.  On overflow, which is
-// possible if the number of bits doesn't fit into a Py_ssize_t, sets
-// OverflowError and returns -1.0 for x, 0 for e.
+// zeroes); otherwise, 0.5 <= abs(x) < 1.0.
+// Always successful.
 //
 // Export for 'math' shared extension
 PyAPI_DATA(double) _PyLong_Frexp(PyLongObject *a, int64_t *e);
@@ -105,10 +104,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 *, uint64_t);
+PyAPI_DATA(PyObject*) _PyLong_Rshift(PyObject *, int64_t);
 
 // Export for 'math' shared extension
-PyAPI_DATA(PyObject*) _PyLong_Lshift(PyObject *, uint64_t);
+PyAPI_DATA(PyObject*) _PyLong_Lshift(PyObject *, int64_t);
 
 PyAPI_FUNC(PyObject*) _PyLong_Add(PyLongObject *left, PyLongObject *right);
 PyAPI_FUNC(PyObject*) _PyLong_Multiply(PyLongObject *left, PyLongObject *right);
index 18affdd4875f3bb7c698bf1cc262b03c3a635203..b2bd9545c1b13048d84fc69747a0aa86d0679759 100644 (file)
@@ -2146,7 +2146,7 @@ save_long(PicklerObject *self, PyObject *obj)
 
     if (self->proto >= 2) {
         /* Linear-time pickling. */
-        uint64_t nbits;
+        int64_t nbits;
         size_t nbytes;
         unsigned char *pdata;
         char header[5];
@@ -2161,8 +2161,8 @@ save_long(PicklerObject *self, PyObject *obj)
             return 0;
         }
         nbits = _PyLong_NumBits(obj);
-        if (nbits == (uint64_t)-1 && PyErr_Occurred())
-            goto error;
+        assert(nbits >= 0);
+        assert(!PyErr_Occurred());
         /* How many bytes do we need?  There are nbits >> 3 full
          * bytes of data, and nbits & 7 leftover bits.  If there
          * are any leftover bits, then we clearly need another
index 3835a3072d96c685efdd0d400c4b0015c798a66e..ad66df47349db0575ae47c728d5e8b8177b01af4 100644 (file)
@@ -295,7 +295,7 @@ random_seed(RandomObject *self, PyObject *arg)
     int result = -1;  /* guilty until proved innocent */
     PyObject *n = NULL;
     uint32_t *key = NULL;
-    uint64_t bits;
+    int64_t bits;
     size_t keyused;
     int res;
 
@@ -335,8 +335,8 @@ random_seed(RandomObject *self, PyObject *arg)
 
     /* Now split n into 32-bit chunks, from the right. */
     bits = _PyLong_NumBits(n);
-    if (bits == (uint64_t)-1 && PyErr_Occurred())
-        goto Done;
+    assert(bits >= 0);
+    assert(!PyErr_Occurred());
 
     /* Figure out how many 32-bit chunks this gives us. */
     keyused = bits == 0 ? 1 : (size_t)((bits - 1) / 32 + 1);
index baf2dc439b89596c400f15ee2803ac4cc4ee97d9..058f57770755aa2cee5c45eb25a339c22a5d831b 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;
-    uint64_t c, d;
+    int64_t c, d;
     uint64_t m;
     uint32_t u;
     PyObject *a = NULL, *b;
@@ -1680,14 +1680,13 @@ math_isqrt(PyObject *module, PyObject *n)
 
     /* c = (n.bit_length() - 1) // 2 */
     c = _PyLong_NumBits(n);
-    if (c == (uint64_t)(-1)) {
-        goto error;
-    }
-    c = (c - 1U) / 2U;
+    assert(c > 0);
+    assert(!PyErr_Occurred());
+    c = (c - 1) / 2;
 
     /* Fast path: if c <= 31 then n < 2**64 and we can compute directly with a
        fast, almost branch-free algorithm. */
-    if (c <= 31U) {
+    if (c <= 31) {
         int shift = 31 - (int)c;
         m = (uint64_t)PyLong_AsUnsignedLongLong(n);
         Py_DECREF(n);
@@ -1704,13 +1703,13 @@ math_isqrt(PyObject *module, PyObject *n)
 
     /* From n >= 2**64 it follows that c.bit_length() >= 6. */
     c_bit_length = 6;
-    while ((c >> c_bit_length) > 0U) {
+    while ((c >> c_bit_length) > 0) {
         ++c_bit_length;
     }
 
     /* Initialise d and a. */
     d = c >> (c_bit_length - 5);
-    b = _PyLong_Rshift(n, 2U*c - 62U);
+    b = _PyLong_Rshift(n, 2*c - 62);
     if (b == NULL) {
         goto error;
     }
@@ -1727,12 +1726,12 @@ math_isqrt(PyObject *module, PyObject *n)
 
     for (int s = c_bit_length - 6; s >= 0; --s) {
         PyObject *q;
-        uint64_t e = d;
+        int64_t e = d;
 
         d = c >> s;
 
         /* q = (n >> 2*c - e - d + 1) // a */
-        q = _PyLong_Rshift(n, 2U*c - d - e + 1U);
+        q = _PyLong_Rshift(n, 2*c - d - e + 1);
         if (q == NULL) {
             goto error;
         }
@@ -1742,7 +1741,7 @@ math_isqrt(PyObject *module, PyObject *n)
         }
 
         /* a = (a << d - 1 - e) + q */
-        Py_SETREF(a, _PyLong_Lshift(a, d - 1U - e));
+        Py_SETREF(a, _PyLong_Lshift(a, d - 1 - e));
         if (a == NULL) {
             Py_DECREF(q);
             goto error;
@@ -2202,8 +2201,8 @@ loghelper(PyObject* arg, double (*func)(double))
                to compute the log anyway.  Clear the exception and continue. */
             PyErr_Clear();
             x = _PyLong_Frexp((PyLongObject *)arg, &e);
-            if (x == -1.0 && PyErr_Occurred())
-                return NULL;
+            assert(e >= 0);
+            assert(!PyErr_Occurred());
             /* Value is ~= x * 2**e, so the log ~= log(x) + log(2) * e. */
             result = func(x) + func(2.0) * e;
         }
index dc3d8a3e5d0f4b76c53a9a00f56a33c3bfc3ffbb..a48a210adee3b9ad494de108017bad95fda74591 100644 (file)
@@ -406,19 +406,16 @@ 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. */
-        uint64_t nbits64 = _PyLong_NumBits(w);
-        if (nbits64 > (unsigned int)DBL_MAX_EXP) {
+        int64_t nbits64 = _PyLong_NumBits(w);
+        assert(nbits64 >= 0);
+        assert(!PyErr_Occurred());
+        if (nbits64 > 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.
              */
-            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;
index d34c8b6d71ab3f0bbd1bc85b3be4cecce7c94857..9beb5884a6932b07f9afe1b31b0c342dcd6d5f20 100644 (file)
@@ -133,8 +133,16 @@ long_normalize(PyLongObject *v)
 /* Allocate a new int object with size digits.
    Return NULL and set exception if we run out of memory. */
 
-#define MAX_LONG_DIGITS \
+#if SIZEOF_SIZE_T < 8
+# define MAX_LONG_DIGITS \
     ((PY_SSIZE_T_MAX - offsetof(PyLongObject, long_value.ob_digit))/sizeof(digit))
+#else
+/* Guarantee that the number of bits fits in int64_t.
+   This is more than an exbibyte, that is more than many of modern
+   architectures support in principle.
+   -1 is added to avoid overflow in _PyLong_Frexp(). */
+# define MAX_LONG_DIGITS ((INT64_MAX-1) / PyLong_SHIFT)
+#endif
 
 PyLongObject *
 _PyLong_New(Py_ssize_t size)
@@ -804,11 +812,11 @@ bit_length_digit(digit x)
     return _Py_bit_length((unsigned long)x);
 }
 
-uint64_t
+int64_t
 _PyLong_NumBits(PyObject *vv)
 {
     PyLongObject *v = (PyLongObject *)vv;
-    uint64_t result = 0;
+    int64_t result = 0;
     Py_ssize_t ndigits;
     int msd_bits;
 
@@ -818,21 +826,12 @@ _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 ((uint64_t)(ndigits - 1) > UINT64_MAX / (uint64_t)PyLong_SHIFT)
-            goto Overflow;
-        result = (uint64_t)(ndigits - 1) * (uint64_t)PyLong_SHIFT;
+        assert(ndigits <= INT64_MAX / PyLong_SHIFT);
+        result = (int64_t)(ndigits - 1) * PyLong_SHIFT;
         msd_bits = bit_length_digit(msd);
-        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 64-bit integer");
-    return (uint64_t)-1;
 }
 
 PyObject *
@@ -1247,15 +1246,12 @@ 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. */
-        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
-             * multiples of 8 to the next byte, but we add an implied bit for
-             * the sign and it cancels out. */
-            res = (Py_ssize_t)(nb / 8) + 1;
-        }
+        int64_t nb = _PyLong_NumBits((PyObject *)v);
+        assert(nb >= 0);
+        /* Normally this would be ((nb - 1) / 8) + 1 to avoid rounding up
+         * multiples of 8 to the next byte, but we add an implied bit for
+         * the sign and it cancels out. */
+        res = (Py_ssize_t)(nb / 8) + 1;
 
         /* Two edge cases exist that are best handled after extracting the
          * bits. These may result in us reporting overflow when the value
@@ -3415,7 +3411,8 @@ x_divrem(PyLongObject *v1, PyLongObject *w1, PyLongObject **prem)
 double
 _PyLong_Frexp(PyLongObject *a, int64_t *e)
 {
-    Py_ssize_t a_size, shift_digits, shift_bits, x_size;
+    Py_ssize_t a_size, shift_digits, x_size;
+    int shift_bits;
     int64_t a_bits;
     /* See below for why x_digits is always large enough. */
     digit rem;
@@ -3432,14 +3429,7 @@ _PyLong_Frexp(PyLongObject *a, int64_t *e)
         *e = 0;
         return 0.0;
     }
-    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 + 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 = (int64_t)(a_size - 1) * PyLong_SHIFT + msd_bits;
+    a_bits = _PyLong_NumBits((PyObject *)a);
 
     /* 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).
@@ -3468,18 +3458,18 @@ _PyLong_Frexp(PyLongObject *a, int64_t *e)
     */
     if (a_bits <= DBL_MANT_DIG + 2) {
         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;
+        shift_bits = (DBL_MANT_DIG + 2 - (int)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);
+                       shift_bits);
         x_size += a_size;
         x_digits[x_size++] = rem;
     }
     else {
         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);
+        shift_bits = (int)((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);
+                       a_size - shift_digits, shift_bits);
         x_size = a_size - shift_digits;
         /* For correct rounding below, we need the least significant
            bit of x to be 'sticky' for this shift: if any of the bits
@@ -3505,21 +3495,13 @@ _PyLong_Frexp(PyLongObject *a, int64_t *e)
     /* Rescale;  make correction if result is 1.0. */
     dx /= 4.0 * EXP2_DBL_MANT_DIG;
     if (dx == 1.0) {
-        if (a_bits == INT64_MAX)
-            goto overflow;
+        assert(a_bits < INT64_MAX);
         dx = 0.5;
         a_bits += 1;
     }
 
     *e = a_bits;
     return _PyLong_IsNegative(a) ? -dx : dx;
-
-  overflow:
-    /* exponent > PY_SSIZE_T_MAX */
-    PyErr_SetString(PyExc_OverflowError,
-                    "huge integer: number of bits overflows a Py_ssize_t");
-    *e = 0;
-    return -1.0;
 }
 
 /* Get a C double from an int object.  Rounds to the nearest double,
@@ -3547,7 +3529,9 @@ PyLong_AsDouble(PyObject *v)
         return (double)medium_value((PyLongObject *)v);
     }
     x = _PyLong_Frexp((PyLongObject *)v, &exponent);
-    if ((x == -1.0 && PyErr_Occurred()) || exponent > DBL_MAX_EXP) {
+    assert(exponent >= 0);
+    assert(!PyErr_Occurred());
+    if (exponent > DBL_MAX_EXP) {
         PyErr_SetString(PyExc_OverflowError,
                         "int too large to convert to float");
         return -1.0;
@@ -5217,39 +5201,6 @@ long_bool(PyLongObject *v)
     return !_PyLong_IsZero(v);
 }
 
-/* wordshift, remshift = divmod(shiftby, PyLong_SHIFT) */
-static int
-divmod_shift(PyObject *shiftby, Py_ssize_t *wordshift, digit *remshift)
-{
-    assert(PyLong_Check(shiftby));
-    assert(!_PyLong_IsNegative((PyLongObject *)shiftby));
-    Py_ssize_t lshiftby = PyLong_AsSsize_t((PyObject *)shiftby);
-    if (lshiftby >= 0) {
-        *wordshift = lshiftby / PyLong_SHIFT;
-        *remshift = lshiftby % PyLong_SHIFT;
-        return 0;
-    }
-    /* PyLong_Check(shiftby) is true and shiftby is not negative, so it must
-       be that PyLong_AsSsize_t raised an OverflowError. */
-    assert(PyErr_ExceptionMatches(PyExc_OverflowError));
-    PyErr_Clear();
-    PyLongObject *wordshift_obj = divrem1((PyLongObject *)shiftby, PyLong_SHIFT, remshift);
-    if (wordshift_obj == NULL) {
-        return -1;
-    }
-    *wordshift = PyLong_AsSsize_t((PyObject *)wordshift_obj);
-    Py_DECREF(wordshift_obj);
-    if (*wordshift >= 0 && *wordshift < PY_SSIZE_T_MAX / (Py_ssize_t)sizeof(digit)) {
-        return 0;
-    }
-    PyErr_Clear();
-    /* Clip the value.  With such large wordshift the right shift
-       returns 0 and the left shift raises an error in _PyLong_New(). */
-    *wordshift = PY_SSIZE_T_MAX / sizeof(digit);
-    *remshift = 0;
-    return 0;
-}
-
 /* Inner function for both long_rshift and _PyLong_Rshift, shifting an
    integer right by PyLong_SHIFT*wordshift + remshift bits.
    wordshift should be nonnegative. */
@@ -5343,8 +5294,7 @@ long_rshift1(PyLongObject *a, Py_ssize_t wordshift, digit remshift)
 static PyObject *
 long_rshift(PyObject *a, PyObject *b)
 {
-    Py_ssize_t wordshift;
-    digit remshift;
+    int64_t shiftby;
 
     CHECK_BINOP(a, b);
 
@@ -5355,24 +5305,35 @@ long_rshift(PyObject *a, PyObject *b)
     if (_PyLong_IsZero((PyLongObject *)a)) {
         return PyLong_FromLong(0);
     }
-    if (divmod_shift(b, &wordshift, &remshift) < 0)
-        return NULL;
-    return long_rshift1((PyLongObject *)a, wordshift, remshift);
+    if (PyLong_AsInt64(b, &shiftby) < 0) {
+        if (!PyErr_ExceptionMatches(PyExc_OverflowError)) {
+            return NULL;
+        }
+        PyErr_Clear();
+        if (_PyLong_IsNegative((PyLongObject *)a)) {
+            return PyLong_FromLong(-1);
+        }
+        else {
+            return PyLong_FromLong(0);
+        }
+    }
+    return _PyLong_Rshift(a, shiftby);
 }
 
 /* Return a >> shiftby. */
 PyObject *
-_PyLong_Rshift(PyObject *a, uint64_t shiftby)
+_PyLong_Rshift(PyObject *a, int64_t shiftby)
 {
     Py_ssize_t wordshift;
     digit remshift;
 
     assert(PyLong_Check(a));
+    assert(shiftby >= 0);
     if (_PyLong_IsZero((PyLongObject *)a)) {
         return PyLong_FromLong(0);
     }
-#if PY_SSIZE_T_MAX <= UINT64_MAX / PyLong_SHIFT
-    if (shiftby > (uint64_t)PY_SSIZE_T_MAX * PyLong_SHIFT) {
+#if PY_SSIZE_T_MAX <= INT64_MAX / PyLong_SHIFT
+    if (shiftby > (int64_t)PY_SSIZE_T_MAX * PyLong_SHIFT) {
         if (_PyLong_IsNegative((PyLongObject *)a)) {
             return PyLong_FromLong(-1);
         }
@@ -5430,8 +5391,7 @@ long_lshift1(PyLongObject *a, Py_ssize_t wordshift, digit remshift)
 static PyObject *
 long_lshift(PyObject *a, PyObject *b)
 {
-    Py_ssize_t wordshift;
-    digit remshift;
+    int64_t shiftby;
 
     CHECK_BINOP(a, b);
 
@@ -5442,24 +5402,30 @@ long_lshift(PyObject *a, PyObject *b)
     if (_PyLong_IsZero((PyLongObject *)a)) {
         return PyLong_FromLong(0);
     }
-    if (divmod_shift(b, &wordshift, &remshift) < 0)
+    if (PyLong_AsInt64(b, &shiftby) < 0) {
+        if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
+            PyErr_SetString(PyExc_OverflowError,
+                            "too many digits in integer");
+        }
         return NULL;
-    return long_lshift1((PyLongObject *)a, wordshift, remshift);
+    }
+    return _PyLong_Lshift(a, shiftby);
 }
 
 /* Return a << shiftby. */
 PyObject *
-_PyLong_Lshift(PyObject *a, uint64_t shiftby)
+_PyLong_Lshift(PyObject *a, int64_t shiftby)
 {
     Py_ssize_t wordshift;
     digit remshift;
 
     assert(PyLong_Check(a));
+    assert(shiftby >= 0);
     if (_PyLong_IsZero((PyLongObject *)a)) {
         return PyLong_FromLong(0);
     }
-#if PY_SSIZE_T_MAX <= UINT64_MAX / PyLong_SHIFT
-    if (shiftby > (uint64_t)PY_SSIZE_T_MAX * PyLong_SHIFT) {
+#if PY_SSIZE_T_MAX <= INT64_MAX / PyLong_SHIFT
+    if (shiftby > (int64_t)PY_SSIZE_T_MAX * PyLong_SHIFT) {
         PyErr_SetString(PyExc_OverflowError,
                         "too many digits in integer");
         return NULL;
@@ -6213,11 +6179,10 @@ static PyObject *
 int_bit_length_impl(PyObject *self)
 /*[clinic end generated code: output=fc1977c9353d6a59 input=e4eb7a587e849a32]*/
 {
-    uint64_t nbits = _PyLong_NumBits(self);
-    if (nbits == (uint64_t)-1) {
-        return NULL;
-    }
-    return PyLong_FromUnsignedLongLong(nbits);
+    int64_t nbits = _PyLong_NumBits(self);
+    assert(nbits >= 0);
+    assert(!PyErr_Occurred());
+    return PyLong_FromInt64(nbits);
 }
 
 static int
@@ -6251,40 +6216,13 @@ int_bit_count_impl(PyObject *self)
 
     PyLongObject *z = (PyLongObject *)self;
     Py_ssize_t ndigits = _PyLong_DigitCount(z);
-    Py_ssize_t bit_count = 0;
+    int64_t bit_count = 0;
 
-    /* Each digit has up to PyLong_SHIFT ones, so the accumulated bit count
-       from the first PY_SSIZE_T_MAX/PyLong_SHIFT digits can't overflow a
-       Py_ssize_t. */
-    Py_ssize_t ndigits_fast = Py_MIN(ndigits, PY_SSIZE_T_MAX/PyLong_SHIFT);
-    for (Py_ssize_t i = 0; i < ndigits_fast; i++) {
+    for (Py_ssize_t i = 0; i < ndigits; i++) {
         bit_count += popcount_digit(z->long_value.ob_digit[i]);
     }
 
-    PyObject *result = PyLong_FromSsize_t(bit_count);
-    if (result == NULL) {
-        return NULL;
-    }
-
-    /* Use Python integers if bit_count would overflow. */
-    for (Py_ssize_t i = ndigits_fast; i < ndigits; i++) {
-        PyObject *x = PyLong_FromLong(popcount_digit(z->long_value.ob_digit[i]));
-        if (x == NULL) {
-            goto error;
-        }
-        PyObject *y = long_add((PyLongObject *)result, (PyLongObject *)x);
-        Py_DECREF(x);
-        if (y == NULL) {
-            goto error;
-        }
-        Py_SETREF(result, y);
-    }
-
-    return result;
-
-  error:
-    Py_DECREF(result);
-    return NULL;
+    return PyLong_FromInt64(bit_count);
 }
 
 /*[clinic input]
index f5b04757e08bf3f5b65ff0d5dafb26320ea96330..01e208b88eca8be32b9c28496b6108379d55ca67 100644 (file)
@@ -169,11 +169,10 @@ safe_multiply(PyObject *v, PyObject *w)
     if (PyLong_Check(v) && PyLong_Check(w) &&
         !_PyLong_IsZero((PyLongObject *)v) && !_PyLong_IsZero((PyLongObject *)w)
     ) {
-        uint64_t vbits = _PyLong_NumBits(v);
-        uint64_t wbits = _PyLong_NumBits(w);
-        if (vbits == (uint64_t)-1 || wbits == (uint64_t)-1) {
-            return NULL;
-        }
+        int64_t vbits = _PyLong_NumBits(v);
+        int64_t wbits = _PyLong_NumBits(w);
+        assert(vbits >= 0);
+        assert(wbits >= 0);
         if (vbits + wbits > MAX_INT_SIZE) {
             return NULL;
         }
@@ -215,12 +214,13 @@ safe_power(PyObject *v, PyObject *w)
     if (PyLong_Check(v) && PyLong_Check(w) &&
         !_PyLong_IsZero((PyLongObject *)v) && _PyLong_IsPositive((PyLongObject *)w)
     ) {
-        uint64_t vbits = _PyLong_NumBits(v);
+        int64_t vbits = _PyLong_NumBits(v);
         size_t wbits = PyLong_AsSize_t(w);
-        if (vbits == (uint64_t)-1 || wbits == (size_t)-1) {
+        assert(vbits >= 0);
+        if (wbits == (size_t)-1) {
             return NULL;
         }
-        if (vbits > MAX_INT_SIZE / wbits) {
+        if ((uint64_t)vbits > MAX_INT_SIZE / wbits) {
             return NULL;
         }
     }
@@ -234,12 +234,13 @@ safe_lshift(PyObject *v, PyObject *w)
     if (PyLong_Check(v) && PyLong_Check(w) &&
         !_PyLong_IsZero((PyLongObject *)v) && !_PyLong_IsZero((PyLongObject *)w)
     ) {
-        uint64_t vbits = _PyLong_NumBits(v);
+        int64_t vbits = _PyLong_NumBits(v);
         size_t wbits = PyLong_AsSize_t(w);
-        if (vbits == (uint64_t)-1 || wbits == (size_t)-1) {
+        assert(vbits >= 0);
+        if (wbits == (size_t)-1) {
             return NULL;
         }
-        if (wbits > MAX_INT_SIZE || vbits > MAX_INT_SIZE - wbits) {
+        if (wbits > MAX_INT_SIZE || (uint64_t)vbits > MAX_INT_SIZE - wbits) {
             return NULL;
         }
     }