Skip to content

Commit c2af856

Browse files
gh-123497: New limit for Python integers on 64-bit platforms
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 64-bit integer. Both limits are much larger than what can be available on practice, so there is no effect on users. _PyLong_NumBits() and _PyLong_Frexp() are now always successful.
1 parent 32c7dbb commit c2af856

File tree

8 files changed

+66
-149
lines changed

8 files changed

+66
-149
lines changed

Include/cpython/longobject.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,7 @@ PyAPI_FUNC(int) _PyLong_Sign(PyObject *v);
7171
absolute value of a long. For example, this returns 1 for 1 and -1, 2
7272
for 2 and -2, and 2 for 3 and -3. It returns 0 for 0.
7373
v must not be NULL, and must be a normalized long.
74-
(uint64_t)-1 is returned and OverflowError set if the true result doesn't
75-
fit in a size_t.
74+
Always successful.
7675
*/
7776
PyAPI_FUNC(uint64_t) _PyLong_NumBits(PyObject *v);
7877

Include/internal/pycore_long.h

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,14 +79,13 @@ static inline PyObject* _PyLong_FromUnsignedChar(unsigned char i)
7979
}
8080

8181
// _PyLong_Frexp returns a double x and an exponent e such that the
82-
// true value is approximately equal to x * 2**e. e is >= 0. x is
82+
// true value is approximately equal to x * 2**e. x is
8383
// 0.0 if and only if the input is 0 (in which case, e and x are both
84-
// zeroes); otherwise, 0.5 <= abs(x) < 1.0. On overflow, which is
85-
// possible if the number of bits doesn't fit into a Py_ssize_t, sets
86-
// OverflowError and returns -1.0 for x, 0 for e.
84+
// zeroes); otherwise, 0.5 <= abs(x) < 1.0.
85+
// Always successful.
8786
//
8887
// Export for 'math' shared extension
89-
PyAPI_DATA(double) _PyLong_Frexp(PyLongObject *a, int64_t *e);
88+
PyAPI_DATA(double) _PyLong_Frexp(PyLongObject *a, uint64_t *e);
9089

9190
extern PyObject* _PyLong_FromBytes(const char *, Py_ssize_t, int);
9291

Modules/_pickle.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2155,8 +2155,7 @@ save_long(PicklerObject *self, PyObject *obj)
21552155
return 0;
21562156
}
21572157
nbits = _PyLong_NumBits(obj);
2158-
if (nbits == (uint64_t)-1 && PyErr_Occurred())
2159-
goto error;
2158+
assert(!PyErr_Occurred());
21602159
/* How many bytes do we need? There are nbits >> 3 full
21612160
* bytes of data, and nbits & 7 leftover bits. If there
21622161
* are any leftover bits, then we clearly need another

Modules/_randommodule.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -335,8 +335,7 @@ random_seed(RandomObject *self, PyObject *arg)
335335

336336
/* Now split n into 32-bit chunks, from the right. */
337337
bits = _PyLong_NumBits(n);
338-
if (bits == (uint64_t)-1 && PyErr_Occurred())
339-
goto Done;
338+
assert(!PyErr_Occurred());
340339

341340
/* Figure out how many 32-bit chunks this gives us. */
342341
keyused = bits == 0 ? 1 : (size_t)((bits - 1) / 32 + 1);

Modules/mathmodule.c

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1680,9 +1680,7 @@ math_isqrt(PyObject *module, PyObject *n)
16801680

16811681
/* c = (n.bit_length() - 1) // 2 */
16821682
c = _PyLong_NumBits(n);
1683-
if (c == (uint64_t)(-1)) {
1684-
goto error;
1685-
}
1683+
assert(!PyErr_Occurred());
16861684
c = (c - 1U) / 2U;
16871685

16881686
/* Fast path: if c <= 31 then n < 2**64 and we can compute directly with a
@@ -2185,7 +2183,7 @@ loghelper(PyObject* arg, double (*func)(double))
21852183
/* If it is int, do it ourselves. */
21862184
if (PyLong_Check(arg)) {
21872185
double x, result;
2188-
int64_t e;
2186+
uint64_t e;
21892187

21902188
/* Negative or zero inputs give a ValueError. */
21912189
if (!_PyLong_IsPositive((PyLongObject *)arg)) {
@@ -2202,8 +2200,7 @@ loghelper(PyObject* arg, double (*func)(double))
22022200
to compute the log anyway. Clear the exception and continue. */
22032201
PyErr_Clear();
22042202
x = _PyLong_Frexp((PyLongObject *)arg, &e);
2205-
if (x == -1.0 && PyErr_Occurred())
2206-
return NULL;
2203+
assert(!PyErr_Occurred());
22072204
/* Value is ~= x * 2**e, so the log ~= log(x) + log(2) * e. */
22082205
result = func(x) + func(2.0) * e;
22092206
}

Objects/floatobject.c

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -419,11 +419,7 @@ float_richcompare(PyObject *v, PyObject *w, int op)
419419
* its magnitude must exceed the magnitude of any
420420
* finite float.
421421
*/
422-
if (nbits64 == (uint64_t)-1 && PyErr_Occurred()) {
423-
/* This Python integer is so large that uint64_t isn't
424-
* big enough to hold the # of bits. */
425-
PyErr_Clear();
426-
}
422+
assert(!PyErr_Occurred());
427423
i = (double)vsign;
428424
assert(wsign != 0);
429425
j = wsign * 2.0;

0 commit comments

Comments
 (0)