Skip to content

Commit 8b4fb4f

Browse files
committed
py/mpz: Fix calculation of max digit storage for mpz; fix sys.maxsize.
When creating constant mpz's, the length of the mpz must be exactly how many digits are used (not allocated) otherwise these numbers are not compatible with dynamically allocated numbers. Addresses issue adafruit#1448.
1 parent b230a86 commit 8b4fb4f

File tree

3 files changed

+27
-11
lines changed

3 files changed

+27
-11
lines changed

py/mpz.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,9 @@ typedef int8_t mpz_dbl_dig_signed_t;
7878
#define MPZ_LONG_1 1L
7979
#endif
8080

81-
#define MPZ_NUM_DIG_FOR_INT (sizeof(mp_int_t) * 8 / MPZ_DIG_SIZE + 1)
82-
#define MPZ_NUM_DIG_FOR_LL (sizeof(long long) * 8 / MPZ_DIG_SIZE + 1)
81+
// these define the maximum storage needed to hold an int or long long
82+
#define MPZ_NUM_DIG_FOR_INT ((sizeof(mp_int_t) * 8 + MPZ_DIG_SIZE - 1) / MPZ_DIG_SIZE)
83+
#define MPZ_NUM_DIG_FOR_LL ((sizeof(long long) * 8 + MPZ_DIG_SIZE - 1) / MPZ_DIG_SIZE)
8384

8485
typedef struct _mpz_t {
8586
mp_uint_t neg : 1;

py/objint_mpz.c

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -44,23 +44,34 @@
4444
#if MICROPY_PY_SYS_MAXSIZE
4545
// Export value for sys.maxsize
4646
#define DIG_MASK ((MPZ_LONG_1 << MPZ_DIG_SIZE) - 1)
47-
STATIC const mpz_dig_t maxsize_dig[MPZ_NUM_DIG_FOR_INT] = {
47+
STATIC const mpz_dig_t maxsize_dig[] = {
48+
#define NUM_DIG 1
4849
(MP_SSIZE_MAX >> MPZ_DIG_SIZE * 0) & DIG_MASK,
4950
#if (MP_SSIZE_MAX >> MPZ_DIG_SIZE * 0) > DIG_MASK
50-
(MP_SSIZE_MAX >> MPZ_DIG_SIZE * 1) & DIG_MASK,
51-
#if (MP_SSIZE_MAX >> MPZ_DIG_SIZE * 1) > DIG_MASK
52-
(MP_SSIZE_MAX >> MPZ_DIG_SIZE * 2) & DIG_MASK,
53-
(MP_SSIZE_MAX >> MPZ_DIG_SIZE * 3) & DIG_MASK,
54-
(MP_SSIZE_MAX >> MPZ_DIG_SIZE * 4) & DIG_MASK,
55-
// (MP_SSIZE_MAX >> MPZ_DIG_SIZE * 5) & DIG_MASK,
56-
#endif
51+
#undef NUM_DIG
52+
#define NUM_DIG 2
53+
(MP_SSIZE_MAX >> MPZ_DIG_SIZE * 1) & DIG_MASK,
54+
#if (MP_SSIZE_MAX >> MPZ_DIG_SIZE * 1) > DIG_MASK
55+
#undef NUM_DIG
56+
#define NUM_DIG 3
57+
(MP_SSIZE_MAX >> MPZ_DIG_SIZE * 2) & DIG_MASK,
58+
#if (MP_SSIZE_MAX >> MPZ_DIG_SIZE * 2) > DIG_MASK
59+
#undef NUM_DIG
60+
#define NUM_DIG 4
61+
(MP_SSIZE_MAX >> MPZ_DIG_SIZE * 3) & DIG_MASK,
62+
#if (MP_SSIZE_MAX >> MPZ_DIG_SIZE * 3) > DIG_MASK
63+
#error cannot encode MP_SSIZE_MAX as mpz
64+
#endif
65+
#endif
66+
#endif
5767
#endif
5868
};
5969
const mp_obj_int_t mp_maxsize_obj = {
6070
{&mp_type_int},
61-
{.fixed_dig = 1, .len = MPZ_NUM_DIG_FOR_INT, .alloc = MPZ_NUM_DIG_FOR_INT, .dig = (mpz_dig_t*)maxsize_dig}
71+
{.fixed_dig = 1, .len = NUM_DIG, .alloc = NUM_DIG, .dig = (mpz_dig_t*)maxsize_dig}
6272
};
6373
#undef DIG_MASK
74+
#undef NUM_DIG
6475
#endif
6576

6677
STATIC mp_obj_int_t *mp_obj_int_new_mpz(void) {

tests/basics/int_mpz.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,7 @@
7777
x = -4611686018427387903 # small
7878
x = 4611686018427387904 # big
7979
x = -4611686018427387904 # big
80+
81+
# sys.maxsize is a constant mpz, so test it's compatible with dynamic ones
82+
import sys
83+
print(sys.maxsize + 1 - 1 == sys.maxsize)

0 commit comments

Comments
 (0)